Replace most uses of ast_register_atexit with ast_register_cleanup.
[asterisk/asterisk.git] / main / app.c
index 822fe6c..f3fc298 100644 (file)
@@ -70,6 +70,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/stasis.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/json.h"
+#include "asterisk/format_cache.h"
 
 #define MWI_TOPIC_BUCKETS 57
 
@@ -256,7 +257,6 @@ enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *promp
 
        filename = ast_strdupa(prompt);
        while ((front = strsep(&filename, "&"))) {
-               ast_test_suite_event_notify("PLAYBACK", "Message: %s\r\nChannel: %s", front, ast_channel_name(c));
                if (!ast_strlen_zero(front)) {
                        res = ast_streamfile(c, front, ast_channel_language(c));
                        if (res)
@@ -519,6 +519,57 @@ void ast_vm_unregister(const char *module_name)
        ao2_cleanup(table);
 }
 
+#ifdef TEST_FRAMEWORK
+/*! \brief Holding container for the voicemail provider used while testing */
+static AO2_GLOBAL_OBJ_STATIC(vm_provider_holder);
+static int provider_is_swapped = 0;
+
+void ast_vm_test_swap_table_in(const struct ast_vm_functions *vm_table)
+{
+       RAII_VAR(struct ast_vm_functions *, holding_table, NULL, ao2_cleanup);
+       RAII_VAR(struct ast_vm_functions *, new_table, NULL, ao2_cleanup);
+
+       if (provider_is_swapped) {
+               ast_log(LOG_ERROR, "Attempted to swap in test function table without swapping out old test table.\n");
+               return;
+       }
+
+       holding_table = ao2_global_obj_ref(vm_provider);
+
+       if (holding_table) {
+               ao2_global_obj_replace_unref(vm_provider_holder, holding_table);
+       }
+
+       new_table = ao2_alloc_options(sizeof(*new_table), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!new_table) {
+               return;
+       }
+       *new_table = *vm_table;
+
+       ao2_global_obj_replace_unref(vm_provider, new_table);
+       provider_is_swapped = 1;
+}
+
+void ast_vm_test_swap_table_out(void)
+{
+       RAII_VAR(struct ast_vm_functions *, held_table, NULL, ao2_cleanup);
+
+       if (!provider_is_swapped) {
+               ast_log(LOG_ERROR, "Attempted to swap out test function table, but none is currently installed.\n");
+               return;
+       }
+
+       held_table = ao2_global_obj_ref(vm_provider_holder);
+       if (!held_table) {
+               return;
+       }
+
+       ao2_global_obj_replace_unref(vm_provider, held_table);
+       ao2_global_obj_release(vm_provider_holder);
+       provider_is_swapped = 0;
+}
+#endif
+
 /*! \brief The container for the voicemail greeter provider */
 static AO2_GLOBAL_OBJ_STATIC(vm_greeter_provider);
 
@@ -880,16 +931,18 @@ struct linear_state {
        int fd;
        int autoclose;
        int allowoverride;
-       struct ast_format origwfmt;
+       struct ast_format *origwfmt;
 };
 
 static void linear_release(struct ast_channel *chan, void *params)
 {
        struct linear_state *ls = params;
 
-       if (ls->origwfmt.id && ast_set_write_format(chan, &ls->origwfmt)) {
-               ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%u'\n", ast_channel_name(chan), ls->origwfmt.id);
+       if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
+               ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n",
+                       ast_channel_name(chan), ast_format_get_name(ls->origwfmt));
        }
+       ao2_cleanup(ls->origwfmt);
 
        if (ls->autoclose) {
                close(ls->fd);
@@ -909,7 +962,7 @@ static int linear_generator(struct ast_channel *chan, void *data, int len, int s
        };
        int res;
 
-       ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0);
+       f.subclass.format = ast_format_slin;
 
        len = samples * 2;
        if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
@@ -943,10 +996,11 @@ static void *linear_alloc(struct ast_channel *chan, void *params)
                ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT);
        }
 
-       ast_format_copy(&ls->origwfmt, ast_channel_writeformat(chan));
+       ls->origwfmt = ao2_bump(ast_channel_writeformat(chan));
 
-       if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
+       if (ast_set_write_format(chan, ast_format_slin)) {
                ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", ast_channel_name(chan));
+               ao2_cleanup(ls->origwfmt);
                ast_free(ls);
                ls = params = NULL;
        }
@@ -1043,9 +1097,6 @@ static int control_streamfile(struct ast_channel *chan,
                        strcat(breaks, restart);
                }
        }
-       if (ast_channel_state(chan) != AST_STATE_UP) {
-               res = ast_answer(chan);
-       }
 
        if ((end = strchr(file, ':'))) {
                if (!strcasecmp(end, ":end")) {
@@ -1325,7 +1376,6 @@ int ast_play_and_wait(struct ast_channel *chan, const char *fn)
 {
        int d = 0;
 
-       ast_test_suite_event_notify("PLAYBACK", "Message: %s\r\nChannel: %s", fn, ast_channel_name(chan));
        if ((d = ast_streamfile(chan, fn, ast_channel_language(chan)))) {
                return d;
        }
@@ -1358,7 +1408,7 @@ static struct ast_frame *make_silence(const struct ast_frame *orig)
                return NULL;
        }
 
-       if (orig->subclass.format.id != AST_FORMAT_SLINEAR) {
+       if (ast_format_cmp(orig->subclass.format, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
                ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n");
                return NULL;
        }
@@ -1385,7 +1435,7 @@ static struct ast_frame *make_silence(const struct ast_frame *orig)
        silence->samples = samples;
        silence->datalen = datalen;
 
-       ast_format_set(&silence->subclass.format, AST_FORMAT_SLINEAR, 0);
+       silence->subclass.format = ast_format_slin;
 
        return silence;
 }
@@ -1400,13 +1450,13 @@ static struct ast_frame *make_silence(const struct ast_frame *orig)
  * \return 0 on success.
  * \return -1 on error.
  */
-static int set_read_to_slin(struct ast_channel *chan, struct ast_format *orig_format)
+static int set_read_to_slin(struct ast_channel *chan, struct ast_format **orig_format)
 {
        if (!chan || !orig_format) {
                return -1;
        }
-       ast_format_copy(orig_format, ast_channel_readformat(chan));
-       return ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
+       *orig_format = ao2_bump(ast_channel_readformat(chan));
+       return ast_set_read_format(chan, ast_format_slin);
 }
 
 static int global_silence_threshold = 128;
@@ -1448,7 +1498,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
        int totalsilence = 0;
        int dspsilence = 0;
        int olddspsilence = 0;
-       struct ast_format rfmt;
+       struct ast_format *rfmt = NULL;
        struct ast_silence_generator *silgen = NULL;
        char prependfile[PATH_MAX];
        int ioflags;    /* IO flags for writing output file */
@@ -1467,7 +1517,6 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
                break;
        }
 
-       ast_format_clear(&rfmt);
        if (silencethreshold < 0) {
                silencethreshold = global_silence_threshold;
        }
@@ -1542,6 +1591,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
                if (res < 0) {
                        ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
                        ast_dsp_free(sildet);
+                       ao2_cleanup(rfmt);
                        return -1;
                }
        }
@@ -1692,7 +1742,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
                                         * set the mode, if we haven't already
                                         * for sildet
                                         */
-                                       if (muted && !rfmt.id) {
+                                       if (muted && !rfmt) {
                                                ast_verb(3, "Setting read format to linear mode\n");
                                                res = set_read_to_slin(chan, &rfmt);
                                                if (res < 0) {
@@ -1783,18 +1833,20 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
                        ast_truncstream(others[x]);
                        ast_closestream(others[x]);
                }
-       }
-
-       if (prepend && outmsg) {
+       } else if (prepend && outmsg) {
                struct ast_filestream *realfiles[AST_MAX_FORMATS];
                struct ast_frame *fr;
 
                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]) {
+                       if (!others[x]) {
                                break;
                        }
+                       if (!realfiles[x]) {
+                               ast_closestream(others[x]);
+                               continue;
+                       }
                        /*!\note Same logic as above. */
                        if (dspsilence) {
                                ast_stream_rewind(others[x], dspsilence - 200);
@@ -1811,10 +1863,19 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
                        ast_verb(4, "Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x], prependfile, recordfile);
                        ast_filedelete(prependfile, sfmt[x]);
                }
+       } else {
+               for (x = 0; x < fmtcnt; x++) {
+                       if (!others[x]) {
+                               break;
+                       }
+                       ast_closestream(others[x]);
+               }
        }
-       if (rfmt.id && ast_set_read_format(chan, &rfmt)) {
-               ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(&rfmt), ast_channel_name(chan));
+
+       if (rfmt && ast_set_read_format(chan, rfmt)) {
+               ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_format_get_name(rfmt), ast_channel_name(chan));
        }
+       ao2_cleanup(rfmt);
        if ((outmsg == 2) && (!skip_confirmation_sound)) {
                ast_stream_and_wait(chan, "auth-thankyou", "");
        }
@@ -1829,7 +1890,7 @@ static const 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 *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
 {
-       return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf), skip_confirmation_sound, if_exists);
+       return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, ""), S_OR(canceldtmf, default_canceldtmf), skip_confirmation_sound, if_exists);
 }
 
 int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path)
@@ -1892,7 +1953,7 @@ int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
        AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
                if ((gi->chan == chan) && ((ast_strlen_zero(category) && ast_strlen_zero(gi->category)) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
                        AST_RWLIST_REMOVE_CURRENT(group_list);
-                       free(gi);
+                       ast_free(gi);
                        break;
                }
        }
@@ -1900,7 +1961,7 @@ int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
 
        if (ast_strlen_zero(group)) {
                /* Enable unsetting the group */
-       } else if ((gi = calloc(1, len))) {
+       } else if ((gi = ast_calloc(1, len))) {
                gi->chan = chan;
                gi->group = (char *) gi + sizeof(*gi);
                strcpy(gi->group, group);
@@ -2176,9 +2237,9 @@ static void path_lock_destroy(struct path_lock *obj)
                close(obj->fd);
        }
        if (obj->path) {
-               free(obj->path);
+               ast_free(obj->path);
        }
-       free(obj);
+       ast_free(obj);
 }
 
 static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
@@ -2222,7 +2283,7 @@ static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
                return AST_LOCK_FAILURE;
        }
        pl->fd = fd;
-       pl->path = strdup(path);
+       pl->path = ast_strdup(path);
 
        time(&start);
        while (
@@ -2901,7 +2962,9 @@ int ast_safe_fork(int stop_reaper)
                ast_replace_sigchld();
        }
 
-       sigfillset(&signal_set);
+       /* GCC 4.9 gives a bogus "right-hand operand of comma expression has
+        * no effect" warning */
+       (void) sigfillset(&signal_set);
        pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
 
        pid = fork();
@@ -3099,6 +3162,10 @@ static struct stasis_message *mwi_state_create_message(
        struct ast_mwi_state *mwi_state;
        struct stasis_message *message;
 
+       if (!ast_mwi_state_type()) {
+               return NULL;
+       }
+
        mwi_state = ast_mwi_create(mailbox, context);
        if (!mwi_state) {
                return NULL;
@@ -3242,6 +3309,10 @@ struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state,
 
        ast_assert(blob != NULL);
 
+       if (!message_type) {
+               return NULL;
+       }
+
        obj = ao2_alloc(sizeof(*obj), mwi_blob_dtor);
        if (!obj) {
                return NULL;