revert my pass through the tree to remove checks of the result of ast_strdupa
[asterisk/asterisk.git] / apps / app_externalivr.c
old mode 100755 (executable)
new mode 100644 (file)
index a80ee68..1023204
@@ -1,23 +1,40 @@
 /*
 /*
- * Asterisk -- A telephony toolkit for Linux.
+ * Asterisk -- An open source telephony toolkit.
  *
  *
- * External IVR application interface
- * 
- * Copyright (C) 2005, Digium, Inc.
+ * Copyright (C) 1999 - 2005, Digium, Inc.
  *
  * Kevin P. Fleming <kpfleming@digium.com>
  *
  * Portions taken from the file-based music-on-hold work
  * created by Anthony Minessale II in res_musiconhold.c
  *
  *
  * Kevin P. Fleming <kpfleming@digium.com>
  *
  * Portions taken from the file-based music-on-hold work
  * created by Anthony Minessale II in res_musiconhold.c
  *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
  * This program is free software, distributed under the terms of
  * This program is free software, distributed under the terms of
- * the GNU General Public License
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief External IVR application interface
+ *
+ * \author Kevin P. Fleming <kpfleming@digium.com>
+ *
+ * \note Portions taken from the file-based music-on-hold work
+ * created by Anthony Minessale II in res_musiconhold.c
+ *
+ * \ingroup applications
  */
 
 #include <stdlib.h>
  */
 
 #include <stdlib.h>
-#include <unistd.h>
+#include <stdio.h>
 #include <string.h>
 #include <string.h>
-#include <stdlib.h>
+#include <unistd.h>
 #include <errno.h>
 
 #include "asterisk.h"
 #include <errno.h>
 
 #include "asterisk.h"
@@ -31,6 +48,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 #include "asterisk/linkedlists.h"
+#include "asterisk/app.h"
+#include "asterisk/utils.h"
 
 static const char *tdesc = "External IVR Interface Application";
 
 
 static const char *tdesc = "External IVR Interface Application";
 
@@ -48,11 +67,8 @@ static const char *descrip =
 "when the channel is hung up.\n"
 "See doc/README.externalivr for a protocol specification.\n";
 
 "when the channel is hung up.\n"
 "See doc/README.externalivr for a protocol specification.\n";
 
-#define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, channel, ## __VA_ARGS__)
-
-#define send_child_event(fd, event) fprintf(fd, "%c,%10ld\n", event, time(NULL))
-
-#define send_child_event_data(fd, event, data) fprintf(fd, "%c,%10ld,%s\n", event, time(NULL), data)
+/* XXX the parser in gcc 2.95 gets confused if you don't put a space between 'name' and the comma */
+#define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, channel->name , ## __VA_ARGS__)
 
 struct playlist_entry {
        AST_LIST_ENTRY(playlist_entry) list;
 
 struct playlist_entry {
        AST_LIST_ENTRY(playlist_entry) list;
@@ -64,7 +80,7 @@ struct localuser {
        struct localuser *next;
        AST_LIST_HEAD(playlist, playlist_entry) playlist;
        AST_LIST_HEAD(finishlist, playlist_entry) finishlist;
        struct localuser *next;
        AST_LIST_HEAD(playlist, playlist_entry) playlist;
        AST_LIST_HEAD(finishlist, playlist_entry) finishlist;
-       int list_cleared;
+       int abort_current_sound;
        int playing_silence;
        int option_autoclear;
 };
        int playing_silence;
        int option_autoclear;
 };
@@ -78,14 +94,27 @@ struct gen_state {
        int sample_queue;
 };
 
        int sample_queue;
 };
 
+static void send_child_event(FILE *handle, const char event, const char *data,
+                            const struct ast_channel *chan)
+{
+       char tmp[256];
+
+       if (!data) {
+               snprintf(tmp, sizeof(tmp), "%c,%10d", event, (int)time(NULL));
+       } else {
+               snprintf(tmp, sizeof(tmp), "%c,%10d,%s", event, (int)time(NULL), data);
+       }
+
+       fprintf(handle, "%s\n", tmp);
+       ast_chan_log(LOG_DEBUG, chan, "sent '%s'\n", tmp);
+}
+
 static void *gen_alloc(struct ast_channel *chan, void *params)
 {
        struct localuser *u = params;
        struct gen_state *state;
 static void *gen_alloc(struct ast_channel *chan, void *params)
 {
        struct localuser *u = params;
        struct gen_state *state;
-
-       state = calloc(1, sizeof(*state));
-
-       if (!state)
+       
+       if (!(state = ast_calloc(1, sizeof(*state))))
                return NULL;
 
        state->u = u;
                return NULL;
 
        state->u = u;
@@ -114,35 +143,24 @@ static void gen_release(struct ast_channel *chan, void *data)
 /* caller has the playlist locked */
 static int gen_nextfile(struct gen_state *state)
 {
 /* caller has the playlist locked */
 static int gen_nextfile(struct gen_state *state)
 {
-       struct playlist_entry *entry;
        struct localuser *u = state->u;
        char *file_to_stream;
        
        struct localuser *u = state->u;
        char *file_to_stream;
        
-       u->list_cleared = 0;
+       u->abort_current_sound = 0;
        u->playing_silence = 0;
        gen_closestream(state);
        u->playing_silence = 0;
        gen_closestream(state);
-       if (state->current) {
-               if (!u->playing_silence) {
-                       AST_LIST_LOCK(&u->finishlist);
-                       AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list);
-                       AST_LIST_UNLOCK(&u->finishlist);
-               }
-               state->current = NULL;
-       }
 
        while (!state->stream) {
 
        while (!state->stream) {
-               entry = AST_LIST_REMOVE_HEAD(&u->playlist, list);
-               if (entry) {
-                       file_to_stream = entry->filename;
+               state->current = AST_LIST_REMOVE_HEAD(&u->playlist, list);
+               if (state->current) {
+                       file_to_stream = state->current->filename;
                } else {
                        file_to_stream = "silence-10";
                        u->playing_silence = 1;
                }
 
                } else {
                        file_to_stream = "silence-10";
                        u->playing_silence = 1;
                }
 
-               state->current = entry;
-
                if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, u->chan->language, 1))) {
                if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, u->chan->language, 1))) {
-                       ast_chan_log(LOG_WARNING, u->chan->name, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno));
+                       ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno));
                        if (!u->playing_silence) {
                                continue;
                        } else { 
                        if (!u->playing_silence) {
                                continue;
                        } else { 
@@ -159,7 +177,7 @@ static struct ast_frame *gen_readframe(struct gen_state *state)
        struct ast_frame *f = NULL;
        struct localuser *u = state->u;
        
        struct ast_frame *f = NULL;
        struct localuser *u = state->u;
        
-       if (u->list_cleared ||
+       if (u->abort_current_sound ||
            (u->playing_silence && AST_LIST_FIRST(&u->playlist))) {
                gen_closestream(state);
                AST_LIST_LOCK(&u->playlist);
            (u->playing_silence && AST_LIST_FIRST(&u->playlist))) {
                gen_closestream(state);
                AST_LIST_LOCK(&u->playlist);
@@ -168,6 +186,12 @@ static struct ast_frame *gen_readframe(struct gen_state *state)
        }
 
        if (!(state->stream && (f = ast_readframe(state->stream)))) {
        }
 
        if (!(state->stream && (f = ast_readframe(state->stream)))) {
+               if (state->current) {
+                       AST_LIST_LOCK(&u->finishlist);
+                       AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list);
+                       AST_LIST_UNLOCK(&u->finishlist);
+                       state->current = NULL;
+               }
                if (!gen_nextfile(state))
                        f = ast_readframe(state->stream);
        }
                if (!gen_nextfile(state))
                        f = ast_readframe(state->stream);
        }
@@ -190,7 +214,7 @@ static int gen_generate(struct ast_channel *chan, void *data, int len, int sampl
                res = ast_write(chan, f);
                ast_frfree(f);
                if (res < 0) {
                res = ast_write(chan, f);
                ast_frfree(f);
                if (res < 0) {
-                       ast_chan_log(LOG_WARNING, chan->name, "Failed to write frame: %s\n", strerror(errno));
+                       ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno));
                        return -1;
                }
                state->sample_queue -= f->samples;
                        return -1;
                }
                state->sample_queue -= f->samples;
@@ -209,10 +233,8 @@ static struct ast_generator gen =
 static struct playlist_entry *make_entry(const char *filename)
 {
        struct playlist_entry *entry;
 static struct playlist_entry *make_entry(const char *filename)
 {
        struct playlist_entry *entry;
-
-       entry = calloc(1, sizeof(*entry) + strlen(filename));
-
-       if (!entry)
+       
+       if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10)))
                return NULL;
 
        strcpy(entry->filename, filename);
                return NULL;
 
        strcpy(entry->filename, filename);
@@ -231,52 +253,54 @@ static int app_exec(struct ast_channel *chan, void *data)
        int res = -1;
        int gen_active = 0;
        int pid;
        int res = -1;
        int gen_active = 0;
        int pid;
-       char *command;
        char *argv[32];
        int argc = 1;
        char *argv[32];
        int argc = 1;
-       char *buf;
+       char *buf, *command;
        FILE *child_commands = NULL;
        FILE *child_errors = NULL;
        FILE *child_events = NULL;
 
        FILE *child_commands = NULL;
        FILE *child_errors = NULL;
        FILE *child_events = NULL;
 
-       if (!args || ast_strlen_zero(args)) {
+       LOCAL_USER_ADD(u);
+       
+       AST_LIST_HEAD_INIT(&u->playlist);
+       AST_LIST_HEAD_INIT(&u->finishlist);
+       u->abort_current_sound = 0;
+       
+       if (ast_strlen_zero(args)) {
                ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
                goto exit;
        }
 
        buf = ast_strdupa(data);
                ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
                goto exit;
        }
 
        buf = ast_strdupa(data);
-       command = strsep(&buf, "|");
-       argv[0] = command;
-       while ((argc < 31) && (argv[argc++] = strsep(&buf, "|")));
-       argv[argc] = NULL;
+       if (!buf) {
+               ast_log(LOG_ERROR, "Out of memory!\n");
+               LOCAL_USER_REMOVE(u);
+               return -1;
+       }
 
 
-       LOCAL_USER_ADD(u);
+       argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0]));
 
        if (pipe(child_stdin)) {
 
        if (pipe(child_stdin)) {
-               ast_chan_log(LOG_WARNING, chan->name, "Could not create pipe for child input: %s\n", strerror(errno));
+               ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
                goto exit;
        }
 
        if (pipe(child_stdout)) {
                goto exit;
        }
 
        if (pipe(child_stdout)) {
-               ast_chan_log(LOG_WARNING, chan->name, "Could not create pipe for child output: %s\n", strerror(errno));
+               ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
                goto exit;
        }
 
        if (pipe(child_stderr)) {
                goto exit;
        }
 
        if (pipe(child_stderr)) {
-               ast_chan_log(LOG_WARNING, chan->name, "Could not create pipe for child errors: %s\n", strerror(errno));
+               ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
                goto exit;
        }
 
                goto exit;
        }
 
-       u->list_cleared = 0;
-       AST_LIST_HEAD_INIT(&u->playlist);
-       AST_LIST_HEAD_INIT(&u->finishlist);
-
        if (chan->_state != AST_STATE_UP) {
                ast_answer(chan);
        }
 
        if (ast_activate_generator(chan, &gen, u) < 0) {
        if (chan->_state != AST_STATE_UP) {
                ast_answer(chan);
        }
 
        if (ast_activate_generator(chan, &gen, u) < 0) {
-               ast_chan_log(LOG_WARNING, chan->name, "Failed to activate generator\n");
+               ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
                goto exit;
        } else
                gen_active = 1;
                goto exit;
        } else
                gen_active = 1;
@@ -294,13 +318,10 @@ static int app_exec(struct ast_channel *chan, void *data)
                dup2(child_stdin[0], STDIN_FILENO);
                dup2(child_stdout[1], STDOUT_FILENO);
                dup2(child_stderr[1], STDERR_FILENO);
                dup2(child_stdin[0], STDIN_FILENO);
                dup2(child_stdout[1], STDOUT_FILENO);
                dup2(child_stderr[1], STDERR_FILENO);
-               close(child_stdin[1]);
-               close(child_stdout[0]);
-               close(child_stderr[0]);
                for (i = STDERR_FILENO + 1; i < 1024; i++)
                        close(i);
                for (i = STDERR_FILENO + 1; i < 1024; i++)
                        close(i);
-               execv(command, argv);
-               fprintf(stderr, "Failed to execute '%s': %s\n", command, strerror(errno));
+               execv(argv[0], argv);
+               fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno));
                exit(1);
        } else {
                /* parent process */
                exit(1);
        } else {
                /* parent process */
@@ -315,38 +336,43 @@ static int app_exec(struct ast_channel *chan, void *data)
                struct ast_channel *rchan;
 
                close(child_stdin[0]);
                struct ast_channel *rchan;
 
                close(child_stdin[0]);
+               child_stdin[0] = 0;
                close(child_stdout[1]);
                close(child_stdout[1]);
+               child_stdout[1] = 0;
                close(child_stderr[1]);
                close(child_stderr[1]);
+               child_stderr[1] = 0;
 
                if (!(child_events = fdopen(child_events_fd, "w"))) {
 
                if (!(child_events = fdopen(child_events_fd, "w"))) {
-                       ast_chan_log(LOG_WARNING, chan->name, "Could not open stream for child events\n");
+                       ast_chan_log(LOG_WARNING, chan, "Could not open stream for child events\n");
                        goto exit;
                }
 
                        goto exit;
                }
 
-               setvbuf(child_events, NULL, _IONBF, 0);
-
                if (!(child_commands = fdopen(child_commands_fd, "r"))) {
                if (!(child_commands = fdopen(child_commands_fd, "r"))) {
-                       ast_chan_log(LOG_WARNING, chan->name, "Could not open stream for child commands\n");
+                       ast_chan_log(LOG_WARNING, chan, "Could not open stream for child commands\n");
                        goto exit;
                }
 
                if (!(child_errors = fdopen(child_errors_fd, "r"))) {
                        goto exit;
                }
 
                if (!(child_errors = fdopen(child_errors_fd, "r"))) {
-                       ast_chan_log(LOG_WARNING, chan->name, "Could not open stream for child errors\n");
+                       ast_chan_log(LOG_WARNING, chan, "Could not open stream for child errors\n");
                        goto exit;
                }
 
                        goto exit;
                }
 
+               setvbuf(child_events, NULL, _IONBF, 0);
+               setvbuf(child_commands, NULL, _IONBF, 0);
+               setvbuf(child_errors, NULL, _IONBF, 0);
+
                res = 0;
 
                while (1) {
                        if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
                res = 0;
 
                while (1) {
                        if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
-                               ast_chan_log(LOG_NOTICE, chan->name, "Is a zombie\n");
+                               ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
                                res = -1;
                                break;
                        }
 
                        if (ast_check_hangup(chan)) {
                                res = -1;
                                break;
                        }
 
                        if (ast_check_hangup(chan)) {
-                               ast_chan_log(LOG_NOTICE, chan->name, "Got check_hangup\n");
-                               send_child_event(child_events, 'H');
+                               ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
+                               send_child_event(child_events, 'H', NULL, chan);
                                res = -1;
                                break;
                        }
                                res = -1;
                                break;
                        }
@@ -361,7 +387,7 @@ static int app_exec(struct ast_channel *chan, void *data)
                        if (!AST_LIST_EMPTY(&u->finishlist)) {
                                AST_LIST_LOCK(&u->finishlist);
                                while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
                        if (!AST_LIST_EMPTY(&u->finishlist)) {
                                AST_LIST_LOCK(&u->finishlist);
                                while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
-                                       send_child_event_data(child_events, 'F', entry->filename);
+                                       send_child_event(child_events, 'F', entry->filename, chan);
                                        free(entry);
                                }
                                AST_LIST_UNLOCK(&u->finishlist);
                                        free(entry);
                                }
                                AST_LIST_UNLOCK(&u->finishlist);
@@ -371,29 +397,29 @@ static int app_exec(struct ast_channel *chan, void *data)
                                /* the channel has something */
                                f = ast_read(chan);
                                if (!f) {
                                /* the channel has something */
                                f = ast_read(chan);
                                if (!f) {
-                                       ast_chan_log(LOG_NOTICE, chan->name, "Returned no frame\n");
-                                       send_child_event(child_events, 'H');
+                                       ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
+                                       send_child_event(child_events, 'H', NULL, chan);
                                        res = -1;
                                        break;
                                }
 
                                if (f->frametype == AST_FRAME_DTMF) {
                                        res = -1;
                                        break;
                                }
 
                                if (f->frametype == AST_FRAME_DTMF) {
-                                       send_child_event(child_events, f->subclass);
+                                       send_child_event(child_events, f->subclass, NULL, chan);
                                        if (u->option_autoclear) {
                                        if (u->option_autoclear) {
-                                               if (!u->playing_silence)
-                                                       send_child_event(child_events, 'T');
+                                               if (!u->abort_current_sound && !u->playing_silence)
+                                                       send_child_event(child_events, 'T', NULL, chan);
                                                AST_LIST_LOCK(&u->playlist);
                                                while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
                                                AST_LIST_LOCK(&u->playlist);
                                                while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
-                                                       if (!u->playing_silence)
-                                                               send_child_event_data(child_events, 'D', entry->filename);
+                                                       send_child_event(child_events, 'D', entry->filename, chan);
                                                        free(entry);
                                                }
                                                        free(entry);
                                                }
-                                               u->list_cleared = 1;
+                                               if (!u->playing_silence)
+                                                       u->abort_current_sound = 1;
                                                AST_LIST_UNLOCK(&u->playlist);
                                        }
                                } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
                                                AST_LIST_UNLOCK(&u->playlist);
                                        }
                                } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
-                                       ast_chan_log(LOG_NOTICE, chan->name, "Got AST_CONTROL_HANGUP\n");
-                                       send_child_event(child_events, 'H');
+                                       ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
+                                       send_child_event(child_events, 'H', NULL, chan);
                                        ast_frfree(f);
                                        res = -1;
                                        break;
                                        ast_frfree(f);
                                        res = -1;
                                        break;
@@ -403,7 +429,7 @@ static int app_exec(struct ast_channel *chan, void *data)
                                char input[1024];
 
                                if (exception || feof(child_commands)) {
                                char input[1024];
 
                                if (exception || feof(child_commands)) {
-                                       ast_chan_log(LOG_WARNING, chan->name, "Child process went away\n");
+                                       ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
                                        res = -1;
                                        break;
                                }
                                        res = -1;
                                        break;
                                }
@@ -413,32 +439,34 @@ static int app_exec(struct ast_channel *chan, void *data)
 
                                command = ast_strip(input);
 
 
                                command = ast_strip(input);
 
+                               ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input);
+
                                if (strlen(input) < 4)
                                        continue;
 
                                if (input[0] == 'S') {
                                        if (ast_fileexists(&input[2], NULL, NULL) == -1) {
                                if (strlen(input) < 4)
                                        continue;
 
                                if (input[0] == 'S') {
                                        if (ast_fileexists(&input[2], NULL, NULL) == -1) {
-                                               ast_chan_log(LOG_WARNING, chan->name, "Unknown file requested '%s'\n", &input[2]);
-                                               send_child_event(child_events, 'Z');
+                                               ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
+                                               send_child_event(child_events, 'Z', NULL, chan);
                                                strcpy(&input[2], "exception");
                                        }
                                                strcpy(&input[2], "exception");
                                        }
-                                       if (!u->playing_silence)
-                                               send_child_event(child_events, 'T');
+                                       if (!u->abort_current_sound && !u->playing_silence)
+                                               send_child_event(child_events, 'T', NULL, chan);
                                        AST_LIST_LOCK(&u->playlist);
                                        while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
                                        AST_LIST_LOCK(&u->playlist);
                                        while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
-                                               if (!u->playing_silence)
-                                                       send_child_event_data(child_events, 'D', entry->filename);
+                                               send_child_event(child_events, 'D', entry->filename, chan);
                                                free(entry);
                                        }
                                                free(entry);
                                        }
-                                       u->list_cleared = 1;
+                                       if (!u->playing_silence)
+                                               u->abort_current_sound = 1;
                                        entry = make_entry(&input[2]);
                                        if (entry)
                                                AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
                                        AST_LIST_UNLOCK(&u->playlist);
                                } else if (input[0] == 'A') {
                                        if (ast_fileexists(&input[2], NULL, NULL) == -1) {
                                        entry = make_entry(&input[2]);
                                        if (entry)
                                                AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
                                        AST_LIST_UNLOCK(&u->playlist);
                                } else if (input[0] == 'A') {
                                        if (ast_fileexists(&input[2], NULL, NULL) == -1) {
-                                               ast_chan_log(LOG_WARNING, chan->name, "Unknown file requested '%s'\n", &input[2]);
-                                               send_child_event(child_events, 'Z');
+                                               ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
+                                               send_child_event(child_events, 'Z', NULL, chan);
                                                strcpy(&input[2], "exception");
                                        }
                                        entry = make_entry(&input[2]);
                                                strcpy(&input[2], "exception");
                                        }
                                        entry = make_entry(&input[2]);
@@ -448,8 +476,8 @@ static int app_exec(struct ast_channel *chan, void *data)
                                                AST_LIST_UNLOCK(&u->playlist);
                                        }
                                } else if (input[0] == 'H') {
                                                AST_LIST_UNLOCK(&u->playlist);
                                        }
                                } else if (input[0] == 'H') {
-                                       ast_chan_log(LOG_NOTICE, chan->name, "Hanging up: %s\n", &input[2]);
-                                       send_child_event(child_events, 'H');
+                                       ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
+                                       send_child_event(child_events, 'H', NULL, chan);
                                        break;
                                } else if (input[0] == 'O') {
                                        if (!strcasecmp(&input[2], "autoclear"))
                                        break;
                                } else if (input[0] == 'O') {
                                        if (!strcasecmp(&input[2], "autoclear"))
@@ -457,26 +485,26 @@ static int app_exec(struct ast_channel *chan, void *data)
                                        else if (!strcasecmp(&input[2], "noautoclear"))
                                                u->option_autoclear = 0;
                                        else
                                        else if (!strcasecmp(&input[2], "noautoclear"))
                                                u->option_autoclear = 0;
                                        else
-                                               ast_chan_log(LOG_WARNING, chan->name, "Unknown option requested '%s'\n", &input[2]);
+                                               ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
                                }
                        } else if (ready_fd == child_errors_fd) {
                                char input[1024];
 
                                if (exception || feof(child_errors)) {
                                }
                        } else if (ready_fd == child_errors_fd) {
                                char input[1024];
 
                                if (exception || feof(child_errors)) {
-                                       ast_chan_log(LOG_WARNING, chan->name, "Child process went away\n");
+                                       ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
                                        res = -1;
                                        break;
                                }
 
                                if (fgets(input, sizeof(input), child_errors)) {
                                        command = ast_strip(input);
                                        res = -1;
                                        break;
                                }
 
                                if (fgets(input, sizeof(input), child_errors)) {
                                        command = ast_strip(input);
-                                       ast_chan_log(LOG_NOTICE, chan->name, "stderr: %s\n", command);
+                                       ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
                                }
                        } else if ((ready_fd < 0) && ms) { 
                                if (errno == 0 || errno == EINTR)
                                        continue;
 
                                }
                        } else if ((ready_fd < 0) && ms) { 
                                if (errno == 0 || errno == EINTR)
                                        continue;
 
-                               ast_chan_log(LOG_WARNING, chan->name, "Wait failed (%s)\n", strerror(errno));
+                               ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
                                break;
                        }
                }
                                break;
                        }
                }
@@ -495,36 +523,41 @@ static int app_exec(struct ast_channel *chan, void *data)
        if (child_errors)
                fclose(child_errors);
 
        if (child_errors)
                fclose(child_errors);
 
-       if (child_stdin[0]) {
+       if (child_stdin[0])
                close(child_stdin[0]);
                close(child_stdin[0]);
+
+       if (child_stdin[1])
                close(child_stdin[1]);
                close(child_stdin[1]);
-       }
 
 
-       if (child_stdout[0]) {
+       if (child_stdout[0])
                close(child_stdout[0]);
                close(child_stdout[0]);
+
+       if (child_stdout[1])
                close(child_stdout[1]);
                close(child_stdout[1]);
-       }
 
 
-       if (child_stderr[0]) {
+       if (child_stderr[0])
                close(child_stderr[0]);
                close(child_stderr[0]);
+
+       if (child_stderr[1])
                close(child_stderr[1]);
                close(child_stderr[1]);
-       }
 
 
-       if (u) {
-               while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
-                       free(entry);
+       while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
+               free(entry);
 
 
-               LOCAL_USER_REMOVE(u);
-       }
+       LOCAL_USER_REMOVE(u);
 
        return res;
 }
 
 int unload_module(void)
 {
 
        return res;
 }
 
 int unload_module(void)
 {
+       int res;
+
+       res = ast_unregister_application(app);
+
        STANDARD_HANGUP_LOCALUSERS;
 
        STANDARD_HANGUP_LOCALUSERS;
 
-       return ast_unregister_application(app);
+       return res;
 }
 
 int load_module(void)
 }
 
 int load_module(void)