loader: Fix comments in struct ast_module.
[asterisk/asterisk.git] / main / pbx.c
index fe87d67..b5602b5 100644 (file)
@@ -657,7 +657,7 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
 static struct ast_context *find_context_locked(const char *context);
 static struct ast_context *find_context(const char *context);
 static void get_device_state_causing_channels(struct ao2_container *c);
-static int ext_strncpy(char *dst, const char *src, int len, int nofluff);
+static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff);
 
 /*!
  * \internal
@@ -4300,8 +4300,10 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
        ast_channel_pbx(c)->rtimeoutms = 10000;
        ast_channel_pbx(c)->dtimeoutms = 5000;
 
+       ast_channel_lock(c);
        autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP);       /* save value to restore at the end */
        ast_set_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP);
+       ast_channel_unlock(c);
 
        if (ast_strlen_zero(ast_channel_exten(c))) {
                /* If not successful fall back to 's' - but only if there is no given exten  */
@@ -4546,8 +4548,10 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
                ast_pbx_hangup_handler_run(c);
        }
 
+       ast_channel_lock(c);
        ast_set2_flag(ast_channel_flags(c), autoloopflag, AST_FLAG_IN_AUTOLOOP);
        ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
+       ast_channel_unlock(c);
        pbx_destroy(ast_channel_pbx(c));
        ast_channel_pbx_set(c, NULL);
 
@@ -6688,7 +6692,11 @@ int ast_context_add_include2(struct ast_context *con, const char *value,
        }
 
        /* ... include new context into context list, unlock, return */
-       AST_VECTOR_APPEND(&con->includes, new_include);
+       if (AST_VECTOR_APPEND(&con->includes, new_include)) {
+               include_free(new_include);
+               ast_unlock_context(con);
+               return -1;
+       }
        ast_verb(3, "Including context '%s' in context '%s'\n",
                ast_get_include_name(new_include), ast_get_context_name(con));
 
@@ -6750,7 +6758,11 @@ int ast_context_add_switch2(struct ast_context *con, const char *value,
        }
 
        /* ... sw new context into context list, unlock, return */
-       AST_VECTOR_APPEND(&con->alts, new_sw);
+       if (AST_VECTOR_APPEND(&con->alts, new_sw)) {
+               sw_free(new_sw);
+               ast_unlock_context(con);
+               return -1;
+       }
 
        ast_verb(3, "Including switch '%s/%s' in context '%s'\n",
                ast_get_switch_name(new_sw), ast_get_switch_data(new_sw), ast_get_context_name(con));
@@ -6838,7 +6850,11 @@ int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const
                        return -1;
                }
        }
-       AST_VECTOR_APPEND(&con->ignorepats, ignorepat);
+       if (AST_VECTOR_APPEND(&con->ignorepats, ignorepat)) {
+               ignorepat_free(ignorepat);
+               ast_unlock_context(con);
+               return -1;
+       }
        ast_unlock_context(con);
 
        return 0;
@@ -6980,32 +6996,51 @@ int ast_async_goto_by_name(const char *channame, const char *context, const char
        return res;
 }
 
-/*! \brief copy a string skipping whitespace and dashes */
-static int ext_strncpy(char *dst, const char *src, int len, int nofluff)
+/*!
+ * \internal
+ * \brief Copy a string skipping whitespace and optionally dashes.
+ *
+ * \param dst Destination buffer to copy src string.
+ * \param src Null terminated string to copy.
+ * \param dst_size Number of bytes in the dst buffer.
+ * \param nofluf Nonzero if '-' chars are not copied.
+ *
+ * \return Number of bytes written to dst including null terminator.
+ */
+static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff)
 {
-       int count = 0;
-       int insquares = 0;
+       unsigned int count;
+       unsigned int insquares;
+       unsigned int is_pattern;
+
+       if (!dst_size--) {
+               /* There really is no dst buffer */
+               return 0;
+       }
 
-       while (*src && (count < len - 1)) {
+       count = 0;
+       insquares = 0;
+       is_pattern = *src == '_';
+       while (*src && count < dst_size) {
                if (*src == '[') {
-                       insquares = 1;
+                       if (is_pattern) {
+                               insquares = 1;
+                       }
                } else if (*src == ']') {
                        insquares = 0;
                } else if (*src == ' ' && !insquares) {
-                       src++;
+                       ++src;
                        continue;
                } else if (*src == '-' && !insquares && nofluff) {
-                       src++;
+                       ++src;
                        continue;
                }
-               *dst = *src;
-               dst++;
-               src++;
-               count++;
+               *dst++ = *src++;
+               ++count;
        }
        *dst = '\0';
 
-       return count;
+       return count + 1;
 }
 
 /*!
@@ -7322,10 +7357,10 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
                p += strlen(label) + 1;
        }
        tmp->name = p;
-       p += ext_strncpy(p, extension, strlen(extension) + 1, 0) + 1;
+       p += ext_strncpy(p, extension, strlen(extension) + 1, 0);
        if (exten_fluff) {
                tmp->exten = p;
-               p += ext_strncpy(p, extension, strlen(extension) + 1, 1) + 1;
+               p += ext_strncpy(p, extension, strlen(extension) + 1 - exten_fluff, 1);
        } else {
                /* no fluff, we don't need a copy. */
                tmp->exten = tmp->name;
@@ -7335,10 +7370,10 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
 
        /* Blank callerid and NULL callerid are two SEPARATE things.  Do NOT confuse the two!!! */
        if (callerid) {
-               p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0) + 1;
+               p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0);
                if (callerid_fluff) {
                        tmp->cidmatch = p;
-                       p += ext_strncpy(p, callerid, strlen(callerid) + 1, 1) + 1;
+                       p += ext_strncpy(p, callerid, strlen(callerid) + 1 - callerid_fluff, 1);
                }
                tmp->matchcid = AST_EXT_MATCHCID_ON;
        } else {
@@ -7510,8 +7545,8 @@ struct pbx_outgoing {
        int dial_res;
        /*! \brief Set when dialing is completed */
        unsigned int dialed:1;
-       /*! \brief Set when execution is completed */
-       unsigned int executed:1;
+       /*! \brief Set if we've spawned a thread to do our work */
+       unsigned int in_separate_thread:1;
 };
 
 /*! \brief Destructor for outgoing structure */
@@ -7534,13 +7569,19 @@ static void *pbx_outgoing_exec(void *data)
        RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup);
        enum ast_dial_result res;
 
-       /* Notify anyone interested that dialing is complete */
        res = ast_dial_run(outgoing->dial, NULL, 0);
-       ao2_lock(outgoing);
-       outgoing->dial_res = res;
-       outgoing->dialed = 1;
-       ast_cond_signal(&outgoing->cond);
-       ao2_unlock(outgoing);
+
+       if (outgoing->in_separate_thread) {
+               /* Notify anyone interested that dialing is complete */
+               ao2_lock(outgoing);
+               outgoing->dial_res = res;
+               outgoing->dialed = 1;
+               ast_cond_signal(&outgoing->cond);
+               ao2_unlock(outgoing);
+       } else {
+               /* We still need the dial result, but we don't need to lock */
+               outgoing->dial_res = res;
+       }
 
        /* If the outgoing leg was not answered we can immediately return and go no further */
        if (res != AST_DIAL_RESULT_ANSWERED) {
@@ -7580,12 +7621,6 @@ static void *pbx_outgoing_exec(void *data)
                }
        }
 
-       /* Notify anyone else again that may be interested that execution is complete */
-       ao2_lock(outgoing);
-       outgoing->executed = 1;
-       ast_cond_signal(&outgoing->cond);
-       ao2_unlock(outgoing);
-
        return NULL;
 }
 
@@ -7791,34 +7826,42 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
                }
        }
 
+       /* This extra reference is dereferenced by pbx_outgoing_exec */
        ao2_ref(outgoing, +1);
-       if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) {
-               ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
-               ao2_ref(outgoing, -1);
-               if (locked_channel) {
-                       if (!synchronous) {
-                               ast_channel_unlock(dialed);
+
+       if (synchronous == AST_OUTGOING_WAIT_COMPLETE) {
+               /*
+                * Because we are waiting until this is complete anyway, there is no
+                * sense in creating another thread that we will just need to wait
+                * for, so instead we commandeer the current thread.
+                */
+               pbx_outgoing_exec(outgoing);
+       } else {
+               outgoing->in_separate_thread = 1;
+
+               if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) {
+                       ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
+                       ao2_ref(outgoing, -1);
+                       if (locked_channel) {
+                               if (!synchronous) {
+                                       ast_channel_unlock(dialed);
+                               }
+                               ast_channel_unref(dialed);
                        }
-                       ast_channel_unref(dialed);
+                       return -1;
                }
-               return -1;
-       }
 
-       if (synchronous) {
-               ao2_lock(outgoing);
-               /* Wait for dialing to complete */
-               while (!outgoing->dialed) {
-                       ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
-               }
-               if (1 < synchronous
-                       && outgoing->dial_res == AST_DIAL_RESULT_ANSWERED) {
-                       /* Wait for execution to complete */
-                       while (!outgoing->executed) {
+               if (synchronous) {
+                       ao2_lock(outgoing);
+                       /* Wait for dialing to complete */
+                       while (!outgoing->dialed) {
                                ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
                        }
+                       ao2_unlock(outgoing);
                }
-               ao2_unlock(outgoing);
+       }
 
+       if (synchronous) {
                /* Determine the outcome of the dialing attempt up to it being answered. */
                if (reason) {
                        *reason = pbx_dial_reason(outgoing->dial_res,
@@ -8275,56 +8318,6 @@ static void presence_state_cb(void *unused, struct stasis_subscription *sub, str
        ast_free(hint_app);
 }
 
-/*!
- * \internal
- * \brief Implements the hints data provider.
- */
-static int hints_data_provider_get(const struct ast_data_search *search,
-       struct ast_data *data_root)
-{
-       struct ast_data *data_hint;
-       struct ast_hint *hint;
-       int watchers;
-       struct ao2_iterator i;
-
-       if (ao2_container_count(hints) == 0) {
-               return 0;
-       }
-
-       i = ao2_iterator_init(hints, 0);
-       for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
-               watchers = ao2_container_count(hint->callbacks);
-               data_hint = ast_data_add_node(data_root, "hint");
-               if (!data_hint) {
-                       continue;
-               }
-               ast_data_add_str(data_hint, "extension", ast_get_extension_name(hint->exten));
-               ast_data_add_str(data_hint, "context", ast_get_context_name(ast_get_extension_context(hint->exten)));
-               ast_data_add_str(data_hint, "application", ast_get_extension_app(hint->exten));
-               ast_data_add_str(data_hint, "state", ast_extension_state2str(hint->laststate));
-               ast_data_add_str(data_hint, "presence_state", ast_presence_state2str(hint->last_presence_state));
-               ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_subtype, ""));
-               ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_message, ""));
-               ast_data_add_int(data_hint, "watchers", watchers);
-
-               if (!ast_data_search_match(search, data_hint)) {
-                       ast_data_remove_node(data_root, data_hint);
-               }
-       }
-       ao2_iterator_destroy(&i);
-
-       return 0;
-}
-
-static const struct ast_data_handler hints_data_provider = {
-       .version = AST_DATA_HANDLER_VERSION,
-       .get = hints_data_provider_get
-};
-
-static const struct ast_data_entry pbx_data_providers[] = {
-       AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider),
-};
-
 static int action_extensionstatelist(struct mansession *s, const struct message *m)
 {
        const char *action_id = astman_get_header(m, "ActionID");
@@ -8400,7 +8393,6 @@ static void unload_pbx(void)
        ast_cli_unregister_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
        ast_custom_function_unregister(&exception_function);
        ast_custom_function_unregister(&testtime_function);
-       ast_data_unregister(NULL);
 }
 
 int load_pbx(void)
@@ -8414,7 +8406,6 @@ int load_pbx(void)
 
        ast_verb(2, "Registering builtin functions:\n");
        ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
-       ast_data_register_multiple_core(pbx_data_providers, ARRAY_LEN(pbx_data_providers));
        __ast_custom_function_register(&exception_function, NULL);
        __ast_custom_function_register(&testtime_function, NULL);