#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/callerid.h"
#include "asterisk/cdr.h"
#include "asterisk/cel.h"
#include "asterisk/config.h"
#include "asterisk/term.h"
#include "asterisk/manager.h"
#include "asterisk/ast_expr.h"
#include "asterisk/linkedlists.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/musiconhold.h"
#include "asterisk/app.h"
#include "asterisk/devicestate.h"
#include "asterisk/event.h"
#include "asterisk/hashtab.h"
#include "asterisk/module.h"
#include "asterisk/indications.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/xmldoc.h"

Go to the source code of this file.
Data Structures | |
| struct | acf_root |
| struct | app_tmp |
| struct | apps |
| struct | ast_app |
| ast_app: A registered application More... | |
| struct | ast_context |
| ast_context: An extension context More... | |
| struct | ast_exten |
| ast_exten: An extension The dialplan is saved as a linked list with each context having it's own linked list of extensions - one item per priority. More... | |
| struct | ast_hint |
| Structure for dial plan hints. More... | |
| struct | ast_ignorepat |
| ast_ignorepat: Ignore patterns in dial plan More... | |
| struct | ast_include |
| ast_include: include= support in extensions.conf More... | |
| struct | ast_state_cb |
| ast_state_cb: An extension state notify register item More... | |
| struct | ast_sw |
| ast_sw: Switch statement in extensions.conf More... | |
| struct | async_stat |
| struct | cfextension_states |
| struct | dialplan_counters |
| Counters for the show dialplan manager command. More... | |
| struct | fake_context |
| struct | hints |
| struct | match_char |
| match_char: forms a syntax tree for quick matching of extension patterns More... | |
| struct | pbx_builtin |
| Declaration of builtin applications. More... | |
| struct | pbx_exception |
| struct | scoreboard |
| struct | statecbs |
| struct | statechange |
| struct | store_hint |
| struct | store_hints |
| struct | switches |
Defines | |
| #define | AST_PBX_MAX_STACK 128 |
| #define | BACKGROUND_MATCHEXTEN (1 << 2) |
| #define | BACKGROUND_NOANSWER (1 << 1) |
| #define | BACKGROUND_PLAYBACK (1 << 3) |
| #define | BACKGROUND_SKIP (1 << 0) |
| #define | EXT_DATA_SIZE 8192 |
| #define | NEW_MATCHER_CHK_MATCH |
| #define | NEW_MATCHER_RECURSE |
| #define | SAY_STUBS |
| #define | STATUS_NO_CONTEXT 1 |
| #define | STATUS_NO_EXTENSION 2 |
| #define | STATUS_NO_LABEL 4 |
| #define | STATUS_NO_PRIORITY 3 |
| #define | STATUS_SUCCESS 5 |
| #define | SWITCH_DATA_LENGTH 256 |
| #define | VAR_BUF_SIZE 4096 |
| #define | VAR_HARDTRAN 3 |
| #define | VAR_NORMAL 1 |
| #define | VAR_SOFTTRAN 2 |
| #define | WAITEXTEN_DIALTONE (1 << 1) |
| #define | WAITEXTEN_MOH (1 << 0) |
Functions | |
| void | __ast_context_destroy (struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar) |
| int | __ast_custom_function_register (struct ast_custom_function *acf, struct ast_module *mod) |
| Register a custom function. | |
| static int | __ast_goto_if_exists (struct ast_channel *chan, const char *context, const char *exten, int priority, int async) |
| static void | __ast_internal_context_destroy (struct ast_context *con) |
| static enum ast_pbx_result | __ast_pbx_run (struct ast_channel *c, struct ast_pbx_args *args) |
| static void | __fini_acf_root (void) |
| static void | __fini_apps (void) |
| static void | __fini_hints (void) |
| static void | __fini_switches (void) |
| static void | __init_acf_root (void) |
| static void | __init_apps (void) |
| static void | __init_extensionstate_buf (void) |
| static void | __init_hints (void) |
| static void | __init_switch_data (void) |
| static void | __init_switches (void) |
| static int | _extension_match_core (const char *pattern, const char *data, enum ext_match_t mode) |
| static int | acf_exception_read (struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen) |
| static int | acf_retrieve_docs (struct ast_custom_function *acf) |
| static struct match_char * | add_exten_to_pattern_tree (struct ast_context *con, struct ast_exten *e1, int findonly) |
| static struct match_char * | add_pattern_node (struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity, struct match_char **parent) |
| static int | add_pri (struct ast_context *con, struct ast_exten *tmp, struct ast_exten *el, struct ast_exten *e, int replace) |
| add the extension in the priority chain. | |
| static int | add_pri_lockopt (struct ast_context *con, struct ast_exten *tmp, struct ast_exten *el, struct ast_exten *e, int replace, int lockhints) |
| add the extension in the priority chain. | |
| static struct match_char * | already_in_tree (struct match_char *current, char *pat, int is_pattern) |
| int | ast_active_calls (void) |
| Retrieve the number of active calls. | |
| int | ast_add_extension (const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar) |
| Add and extension to an extension context. | |
| int | ast_add_extension2 (struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar) |
| Main interface to add extensions to the list for out context. | |
| static int | ast_add_extension2_lockopt (struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, int lockconts, int lockhints) |
| Does all the work of ast_add_extension2, but adds two args, to determine if context and hint locking should be done. In merge_and_delete, we need to do this without locking, as the locks are already held. | |
| static int | ast_add_extension_nolock (const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar) |
| static int | ast_add_hint (struct ast_exten *e) |
| Add hint to hint list, check initial extension state. | |
| static int | ast_add_hint_nolock (struct ast_exten *e) |
| Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already! | |
| int | ast_async_goto (struct ast_channel *chan, const char *context, const char *exten, int priority) |
| Set the channel to next execute the specified dialplan location. | |
| int | ast_async_goto_by_name (const char *channame, const char *context, const char *exten, int priority) |
| Set the channel to next execute the specified dialplan location. | |
| int | ast_async_goto_if_exists (struct ast_channel *chan, const char *context, const char *exten, int priority) |
| int | ast_async_parseable_goto (struct ast_channel *chan, const char *goto_string) |
| int | ast_build_timing (struct ast_timing *i, const char *info_in) |
| Construct a timing bitmap, for use in time-based conditionals. | |
| int | ast_canmatch_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) |
| Looks for a valid matching extension. | |
| static int | ast_change_hint (struct ast_exten *oe, struct ast_exten *ne) |
| Change hint for an extension. | |
| int | ast_check_timing (const struct ast_timing *i) |
| Evaluate a pre-constructed bitmap as to whether the current time falls within the range specified. | |
| char * | ast_complete_applications (const char *line, const char *word, int state) |
| Command completion for the list of installed applications. | |
| int | ast_context_add_ignorepat (const char *context, const char *value, const char *registrar) |
| Add an ignorepat. | |
| int | ast_context_add_ignorepat2 (struct ast_context *con, const char *value, const char *registrar) |
| int | ast_context_add_include (const char *context, const char *include, const char *registrar) |
| Add a context include. | |
| int | ast_context_add_include2 (struct ast_context *con, const char *value, const char *registrar) |
| Add a context include. | |
| int | ast_context_add_switch (const char *context, const char *sw, const char *data, int eval, const char *registrar) |
| Add a switch. | |
| int | ast_context_add_switch2 (struct ast_context *con, const char *value, const char *data, int eval, const char *registrar) |
| Adds a switch (first param is a ast_context). | |
| void | ast_context_destroy (struct ast_context *con, const char *registrar) |
| Destroy a context (matches the specified context (or ANY context if NULL). | |
| struct ast_context * | ast_context_find (const char *name) |
| Find a context. | |
| struct ast_context * | ast_context_find_or_create (struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar) |
| Register a new context or find an existing one. | |
| int | ast_context_lockmacro (const char *context) |
| locks the macrolock in the given given context | |
| int | ast_context_remove_extension (const char *context, const char *extension, int priority, const char *registrar) |
| Simply remove extension from context. | |
| int | ast_context_remove_extension2 (struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked) |
| This functionc locks given context, search for the right extension and fires out all peer in this extensions with given priority. If priority is set to 0, all peers are removed. After that, unlock context and return. | |
| int | ast_context_remove_extension_callerid (const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar) |
| int | ast_context_remove_extension_callerid2 (struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar, int already_locked) |
| int | ast_context_remove_ignorepat (const char *context, const char *ignorepat, const char *registrar) |
| int | ast_context_remove_ignorepat2 (struct ast_context *con, const char *ignorepat, const char *registrar) |
| int | ast_context_remove_include (const char *context, const char *include, const char *registrar) |
| Remove included contexts. This function locks contexts list by &conlist, search for the right context structure, leave context list locked and call ast_context_remove_include2 which removes include, unlock contexts list and return ... | |
| int | ast_context_remove_include2 (struct ast_context *con, const char *include, const char *registrar) |
| Locks context, remove included contexts, unlocks context. When we call this function, &conlock lock must be locked, because when we giving *con argument, some process can remove/change this context and after that there can be segfault. | |
| int | ast_context_remove_switch (const char *context, const char *sw, const char *data, const char *registrar) |
| Remove a switch. | |
| int | ast_context_remove_switch2 (struct ast_context *con, const char *sw, const char *data, const char *registrar) |
| This function locks given context, removes switch, unlock context and return. | |
| int | ast_context_unlockmacro (const char *context) |
| Unlocks the macrolock in the given context. | |
| int | ast_context_verify_includes (struct ast_context *con) |
| Verifies includes in an ast_contect structure. | |
| struct ast_custom_function * | ast_custom_function_find (const char *name) |
| int | ast_custom_function_unregister (struct ast_custom_function *acf) |
| Unregister a custom function. | |
| int | ast_destroy_timing (struct ast_timing *i) |
| Deallocates memory structures associated with a timing bitmap. | |
| enum ast_extension_states | ast_devstate_to_extenstate (enum ast_device_state devstate) |
| Map devstate to an extension state. | |
| int | ast_exists_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) |
| Determine whether an extension exists. | |
| int | ast_explicit_goto (struct ast_channel *chan, const char *context, const char *exten, int priority) |
| int | ast_extension_close (const char *pattern, const char *data, int needmore) |
| int | ast_extension_cmp (const char *a, const char *b) |
| Determine if one extension should match before another. | |
| int | ast_extension_match (const char *pattern, const char *data) |
| Determine if a given extension matches a given pattern (in NXX format). | |
| int | ast_extension_state (struct ast_channel *c, const char *context, const char *exten) |
| Check extension state for an extension by using hint. | |
| static int | ast_extension_state2 (struct ast_exten *e) |
| Check state of extension by using hints. | |
| const char * | ast_extension_state2str (int extension_state) |
| Return extension_state as string. | |
| int | ast_extension_state_add (const char *context, const char *exten, ast_state_cb_type callback, void *data) |
| Add watcher for extension states. | |
| int | ast_extension_state_del (int id, ast_state_cb_type callback) |
| Remove a watcher from the callback list. | |
| int | ast_findlabel_extension (struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid) |
| Find the priority of an extension that has the specified label. | |
| int | ast_findlabel_extension2 (struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid) |
| Find the priority of an extension that has the specified label. | |
| int | ast_func_read (struct ast_channel *chan, const char *function, char *workspace, size_t len) |
| executes a read operation on a function | |
| int | ast_func_read2 (struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen) |
| executes a read operation on a function | |
| int | ast_func_write (struct ast_channel *chan, const char *function, const char *value) |
| executes a write operation on a function | |
| const char * | ast_get_context_name (struct ast_context *con) |
| const char * | ast_get_context_registrar (struct ast_context *c) |
| const char * | ast_get_extension_app (struct ast_exten *e) |
| void * | ast_get_extension_app_data (struct ast_exten *e) |
| const char * | ast_get_extension_cidmatch (struct ast_exten *e) |
| struct ast_context * | ast_get_extension_context (struct ast_exten *exten) |
| const char * | ast_get_extension_label (struct ast_exten *exten) |
| int | ast_get_extension_matchcid (struct ast_exten *e) |
| const char * | ast_get_extension_name (struct ast_exten *exten) |
| int | ast_get_extension_priority (struct ast_exten *exten) |
| const char * | ast_get_extension_registrar (struct ast_exten *e) |
| int | ast_get_hint (char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten) |
| Get hint for channel. | |
| const char * | ast_get_ignorepat_name (struct ast_ignorepat *ip) |
| const char * | ast_get_ignorepat_registrar (struct ast_ignorepat *ip) |
| const char * | ast_get_include_name (struct ast_include *inc) |
| const char * | ast_get_include_registrar (struct ast_include *i) |
| const char * | ast_get_switch_data (struct ast_sw *sw) |
| int | ast_get_switch_eval (struct ast_sw *sw) |
| const char * | ast_get_switch_name (struct ast_sw *sw) |
| const char * | ast_get_switch_registrar (struct ast_sw *sw) |
| int | ast_goto_if_exists (struct ast_channel *chan, const char *context, const char *exten, int priority) |
| int | ast_hashtab_compare_contexts (const void *ah_a, const void *ah_b) |
| hashtable functions for contexts | |
| unsigned int | ast_hashtab_hash_contexts (const void *obj) |
| static struct ast_exten * | ast_hint_extension (struct ast_channel *c, const char *context, const char *exten) |
| static struct ast_exten * | ast_hint_extension_nolock (struct ast_channel *c, const char *context, const char *exten) |
| Find hint for given extension in context. | |
| int | ast_ignore_pattern (const char *context, const char *pattern) |
| Checks to see if a number should be ignored. | |
| int | ast_matchmore_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) |
| Looks to see if adding anything to this extension might match something. (exists ^ canmatch). | |
| void | ast_merge_contexts_and_delete (struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar) |
| Merge the temporary contexts into a global contexts list and delete from the global list the ones that are being added. | |
| int | ast_parseable_goto (struct ast_channel *chan, const char *goto_string) |
| int | ast_pbx_outgoing_app (const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel) |
| static int | ast_pbx_outgoing_cdr_failed (void) |
| Function to post an empty cdr after a spool call fails. | |
| int | ast_pbx_outgoing_exten (const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel) |
| enum ast_pbx_result | ast_pbx_run (struct ast_channel *c) |
| Execute the PBX in the current thread. | |
| static void * | ast_pbx_run_app (void *data) |
| run the application and free the descriptor once done | |
| enum ast_pbx_result | ast_pbx_run_args (struct ast_channel *c, struct ast_pbx_args *args) |
| Execute the PBX in the current thread. | |
| enum ast_pbx_result | ast_pbx_start (struct ast_channel *c) |
| Create a new thread and start the PBX. | |
| int | ast_processed_calls (void) |
| Retrieve the total number of calls processed through the PBX since last restart. | |
| int | ast_rdlock_context (struct ast_context *con) |
| Read locks a given context. | |
| int | ast_rdlock_contexts () |
| Read locks the context list. | |
| int | ast_register_application2 (const char *app, int(*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod) |
| Dynamically register a new dial plan application. | |
| int | ast_register_switch (struct ast_switch *sw) |
| Register an alternative dialplan switch. | |
| static int | ast_remove_hint (struct ast_exten *e) |
| Remove hint from extension. | |
| int | ast_spawn_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn) |
| Launch a new extension (i.e. new stack). | |
| int | ast_str_get_hint (struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten) |
| Get hint for channel. | |
| const char * | ast_str_retrieve_variable (struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var) |
| void | ast_str_substitute_variables (struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ) |
| void | ast_str_substitute_variables_full (struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used) |
| void | ast_str_substitute_variables_varshead (struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ) |
| static const char * | ast_str_substring (struct ast_str *value, int offset, int length) |
| int | ast_unlock_context (struct ast_context *con) |
| int | ast_unlock_contexts () |
| Unlocks contexts. | |
| int | ast_unregister_application (const char *app) |
| Unregister an application. | |
| void | ast_unregister_switch (struct ast_switch *sw) |
| Unregister an alternative switch. | |
| struct ast_exten * | ast_walk_context_extensions (struct ast_context *con, struct ast_exten *exten) |
| struct ast_ignorepat * | ast_walk_context_ignorepats (struct ast_context *con, struct ast_ignorepat *ip) |
| struct ast_include * | ast_walk_context_includes (struct ast_context *con, struct ast_include *inc) |
| struct ast_sw * | ast_walk_context_switches (struct ast_context *con, struct ast_sw *sw) |
| struct ast_context * | ast_walk_contexts (struct ast_context *con) |
| struct ast_exten * | ast_walk_extension_priorities (struct ast_exten *exten, struct ast_exten *priority) |
| int | ast_wrlock_context (struct ast_context *con) |
| Write locks a given context. | |
| int | ast_wrlock_contexts () |
| Write locks the context list. | |
| int | ast_wrlock_contexts_version (void) |
| static void * | async_wait (void *data) |
| static void | cli_match_char_tree (struct match_char *node, char *prefix, int fd) |
| static int | collect_digits (struct ast_channel *c, int waittime, char *buf, int buflen, int pos) |
| collect digits from the channel into the buffer. | |
| static int | compare_char (const void *a, const void *b) |
| static char * | complete_core_show_hint (const char *line, const char *word, int pos, int state) |
| autocomplete for CLI command 'core show hint' | |
| static char * | complete_show_dialplan_context (const char *line, const char *word, int pos, int state) |
| static void | context_merge (struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar) |
| static void | context_merge_incls_swits_igps_other_registrars (struct ast_context *new, struct ast_context *old, const char *registrar) |
| static void | create_match_char_tree (struct ast_context *con) |
| static void | decrease_call_count (void) |
| static void | destroy_exten (struct ast_exten *e) |
| static void | destroy_pattern_tree (struct match_char *pattern_tree) |
| static void | device_state_cb (const struct ast_event *event, void *unused) |
| static void | exception_store_free (void *data) |
| static int | ext_cmp (const char *a, const char *b) |
| the full routine to compare extensions in rules. | |
| static int | ext_cmp1 (const char **p) |
| helper functions to sort extensions and patterns in the desired way, so that more specific patterns appear first. | |
| static int | ext_strncpy (char *dst, const char *src, int len) |
| copy a string skipping whitespace | |
| static int | extension_match_core (const char *pattern, const char *data, enum ext_match_t mode) |
| static struct ast_context * | find_context (const char *context) |
| lookup for a context with a given name, | |
| static struct ast_context * | find_context_locked (const char *context) |
| lookup for a context with a given name, | |
| static char * | func_args (char *function) |
| return a pointer to the arguments of the function, and terminates the function name with '\0' | |
| static struct ast_exten * | get_canmatch_exten (struct match_char *node) |
| static unsigned | get_range (char *src, int max, const char *const names[], const char *msg) |
| helper function to return a range up to max (7, 12, 31 respectively). names, if supplied, is an array of names that should be mapped to numbers. | |
| static void | get_timerange (struct ast_timing *i, char *times) |
| store a bitmask of valid times, one bit each 1 minute | |
| static char * | handle_debug_dialplan (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| Send ack once. | |
| static char * | handle_set_chanvar (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_set_extenpatternmatchnew (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_set_global (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_show_application (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_show_applications (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_show_chanvar (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI support for listing chanvar's variables in a parseable way. | |
| static char * | handle_show_dialplan (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_show_function (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_show_functions (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_show_globals (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI support for listing global variables in a parseable way. | |
| static char * | handle_show_hint (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| handle_show_hint: CLI support for listing registered dial plan hint | |
| static char * | handle_show_hints (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| handle_show_hints: CLI support for listing registered dial plan hints | |
| static char * | handle_show_switches (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| handle_show_switches: CLI support for listing registered dial plan switches | |
| static int | handle_statechange (void *datap) |
| static char * | handle_unset_extenpatternmatchnew (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | hashtab_compare_exten_labels (const void *ah_a, const void *ah_b) |
| static int | hashtab_compare_exten_numbers (const void *ah_a, const void *ah_b) |
| static int | hashtab_compare_extens (const void *ha_a, const void *ah_b) |
| static unsigned int | hashtab_hash_extens (const void *obj) |
| static unsigned int | hashtab_hash_labels (const void *obj) |
| static unsigned int | hashtab_hash_priority (const void *obj) |
| static int | include_valid (struct ast_include *i) |
| static int | increase_call_count (const struct ast_channel *c) |
| Increase call count for channel. | |
| static void | insert_in_next_chars_alt_char_list (struct match_char **parent_ptr, struct match_char *node) |
| int | load_pbx (void) |
| static int | lookup_name (const char *s, const char *const names[], int max) |
| Helper for get_range. return the index of the matching entry, starting from 1. If names is not supplied, try numeric values. | |
| static void | manager_dpsendack (struct mansession *s, const struct message *m) |
| Send ack once. | |
| static int | manager_show_dialplan (struct mansession *s, const struct message *m) |
| Manager listing of dial plan. | |
| static int | manager_show_dialplan_helper (struct mansession *s, const struct message *m, const char *actionidtext, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude) |
| Show dialplan extensions XXX this function is similar but not exactly the same as the CLI's show dialplan. Must check whether the difference is intentional or not. | |
| static int | matchcid (const char *cidpattern, const char *callerid) |
| static void | new_find_extension (const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid, const char *label, enum ext_match_t action) |
| static int | parse_variable_name (char *var, int *offset, int *length, int *isfunc) |
| extract offset:length from variable name. | |
| static int | pbx_builtin_answer (struct ast_channel *, const char *) |
| static int | pbx_builtin_background (struct ast_channel *, const char *) |
| static int | pbx_builtin_busy (struct ast_channel *, const char *) |
| void | pbx_builtin_clear_globals (void) |
| static int | pbx_builtin_congestion (struct ast_channel *, const char *) |
| static int | pbx_builtin_execiftime (struct ast_channel *, const char *) |
| const char * | pbx_builtin_getvar_helper (struct ast_channel *chan, const char *name) |
| Return a pointer to the value of the corresponding channel variable. | |
| static int | pbx_builtin_goto (struct ast_channel *, const char *) |
| static int | pbx_builtin_gotoif (struct ast_channel *, const char *) |
| static int | pbx_builtin_gotoiftime (struct ast_channel *, const char *) |
| static int | pbx_builtin_hangup (struct ast_channel *, const char *) |
| static int | pbx_builtin_importvar (struct ast_channel *, const char *) |
| static int | pbx_builtin_incomplete (struct ast_channel *, const char *) |
| static int | pbx_builtin_noop (struct ast_channel *, const char *) |
| static int | pbx_builtin_proceeding (struct ast_channel *, const char *) |
| static int | pbx_builtin_progress (struct ast_channel *, const char *) |
| void | pbx_builtin_pushvar_helper (struct ast_channel *chan, const char *name, const char *value) |
| Add a variable to the channel variable stack, without removing any previously set value. | |
| int | pbx_builtin_raise_exception (struct ast_channel *chan, const char *reason) |
| static int | pbx_builtin_resetcdr (struct ast_channel *, const char *) |
| static int | pbx_builtin_ringing (struct ast_channel *, const char *) |
| static int | pbx_builtin_saycharacters (struct ast_channel *, const char *) |
| static int | pbx_builtin_saydigits (struct ast_channel *, const char *) |
| static int | pbx_builtin_saynumber (struct ast_channel *, const char *) |
| static int | pbx_builtin_sayphonetic (struct ast_channel *, const char *) |
| int | pbx_builtin_serialize_variables (struct ast_channel *chan, struct ast_str **buf) |
| Create a human-readable string, specifying all variables and their corresponding values. | |
| static int | pbx_builtin_setamaflags (struct ast_channel *, const char *) |
| int | pbx_builtin_setvar (struct ast_channel *chan, const char *data) |
| Parse and set a single channel variable, where the name and value are separated with an '=' character. | |
| void | pbx_builtin_setvar_helper (struct ast_channel *chan, const char *name, const char *value) |
| Add a variable to the channel variable stack, removing the most recently set value for the same name. | |
| int | pbx_builtin_setvar_multiple (struct ast_channel *chan, const char *vdata) |
| Parse and set multiple channel variables, where the pairs are separated by the ',' character, and name and value are separated with an '=' character. | |
| static int | pbx_builtin_wait (struct ast_channel *, const char *) |
| static int | pbx_builtin_waitexten (struct ast_channel *, const char *) |
| int | pbx_checkcondition (const char *condition) |
| Evaluate a condition. | |
| static void | pbx_destroy (struct ast_pbx *p) |
| int | pbx_exec (struct ast_channel *c, struct ast_app *app, const char *data) |
| Execute an application. | |
| static int | pbx_extension_helper (struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn) |
| The return value depends on the action:. | |
| struct ast_exten * | pbx_find_extension (struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action) |
| struct ast_app * | pbx_findapp (const char *app) |
| Find application handle in linked list. | |
| static struct ast_switch * | pbx_findswitch (const char *sw) |
| static int | pbx_parseable_goto (struct ast_channel *chan, const char *goto_string, int async) |
| void | pbx_retrieve_variable (struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp) |
| Support for Asterisk built-in variables in the dialplan. | |
| int | pbx_set_autofallthrough (int newval) |
| int | pbx_set_extenpatternmatchnew (int newval) |
| void | pbx_set_overrideswitch (const char *newval) |
| static void | pbx_substitute_variables (char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) |
| void | pbx_substitute_variables_helper (struct ast_channel *c, const char *cp1, char *cp2, int count) |
| void | pbx_substitute_variables_helper_full (struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used) |
| void | pbx_substitute_variables_varshead (struct varshead *headp, const char *cp1, char *cp2, int count) |
| static void * | pbx_thread (void *data) |
| static void | print_app_docs (struct ast_app *aa, int fd) |
| static void | print_ext (struct ast_exten *e, char *buf, int buflen) |
| helper function to print an extension | |
| static void | set_ext_pri (struct ast_channel *c, const char *exten, int pri) |
| static int | show_debug_helper (int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[]) |
| static int | show_dialplan_helper (int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[]) |
| static char * | substring (const char *value, int offset, int length, char *workspace, size_t workspace_len) |
| takes a substring. It is ok to call with value == workspace. | |
| static struct ast_exten * | trie_find_next_match (struct match_char *node) |
| static void | unreference_cached_app (struct ast_app *app) |
| static void | update_scoreboard (struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node) |
| static void | wait_for_hangup (struct ast_channel *chan, const void *data) |
Variables | |
| static int | autofallthrough = 1 |
| static struct ast_app_option | background_opts [128] = { [ 's' ] = { .flag = (1 << 0) }, [ 'n' ] = { .flag = (1 << 1) }, [ 'm' ] = { .flag = (1 << 2) }, [ 'p' ] = { .flag = (1 << 3) },} |
| static struct pbx_builtin | builtins [] |
| Declaration of builtin applications. | |
| static ast_rwlock_t | conlock = { 0 } |
| static int | conlock_wrlock_version = 0 |
| static struct ast_context * | contexts |
| static struct ast_hashtab * | contexts_table = NULL |
| static int | countcalls |
| static const char *const | days [] |
| static struct ast_event_sub * | device_state_sub |
| Subscription for device state change events. | |
| static struct ast_taskprocessor * | device_state_tps |
| static struct ast_custom_function | exception_function |
| static struct ast_datastore_info | exception_store_info |
| static int | extenpatternmatchnew = 0 |
| static struct cfextension_states | extension_states [] |
| static struct ast_threadstorage | extensionstate_buf = { .once = PTHREAD_ONCE_INIT, .key_init = __init_extensionstate_buf , .custom_init = NULL , } |
| static struct varshead | globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE |
| static ast_rwlock_t | globalslock = { 0 } |
| static ast_mutex_t | maxcalllock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
| static const char *const | months [] |
| static char * | overrideswitch = NULL |
| static struct ast_cli_entry | pbx_cli [] |
| static struct ast_app_option | resetcdr_opts [128] = { [ 'w' ] = { .flag = (1 << 1) }, [ 'a' ] = { .flag = (1 << 2) }, [ 'v' ] = { .flag = (1 << 0) }, [ 'e' ] = { .flag = (1 << 10) },} |
| static int | stateid = 1 |
| static struct ast_threadstorage | switch_data = { .once = PTHREAD_ONCE_INIT, .key_init = __init_switch_data , .custom_init = NULL , } |
| static int | totalcalls |
| static struct ast_app_option | waitexten_opts [128] = { [ 'm' ] = { .flag = (1 << 0) , .arg_index = 0 + 1 }, [ 'd' ] = { .flag = (1 << 1) , .arg_index = 0 + 1 },} |
Definition in file pbx.c.
| #define AST_PBX_MAX_STACK 128 |
| #define BACKGROUND_MATCHEXTEN (1 << 2) |
| #define BACKGROUND_NOANSWER (1 << 1) |
| #define BACKGROUND_PLAYBACK (1 << 3) |
| #define BACKGROUND_SKIP (1 << 0) |
| #define EXT_DATA_SIZE 8192 |
A new algorithm to do searching based on a 'compiled' pattern tree is introduced here, and shows a fairly flat (constant) search time, even for over 10000 patterns.
Also, using a hash table for context/priority name lookup can help prevent the find_extension routines from absorbing exponential cpu cycles as the number of contexts/priorities grow. I've previously tested find_extension with red-black trees, which have O(log2(n)) speed. Right now, I'm using hash tables, which do searches (ideally) in O(1) time. While these techniques do not yield much speed in small dialplans, they are worth the trouble in large dialplans.
Definition at line 743 of file pbx.c.
Referenced by pbx_extension_helper(), and realtime_exec().
| #define NEW_MATCHER_CHK_MATCH |
Referenced by new_find_extension().
| #define NEW_MATCHER_RECURSE |
Referenced by new_find_extension().
| #define VAR_BUF_SIZE 4096 |
Definition at line 748 of file pbx.c.
Referenced by ast_add_extension2_lockopt(), ast_func_read2(), pbx_builtin_importvar(), and pbx_substitute_variables_helper_full().
| #define WAITEXTEN_DIALTONE (1 << 1) |
| #define WAITEXTEN_MOH (1 << 0) |
| void __ast_context_destroy | ( | struct ast_context * | list, | |
| struct ast_hashtab * | contexttab, | |||
| struct ast_context * | con, | |||
| const char * | registrar | |||
| ) |
Definition at line 8563 of file pbx.c.
References __ast_internal_context_destroy(), ast_context::alts, ast_context_remove_extension_callerid2(), ast_debug, ast_free, ast_hashtab_end_traversal(), ast_hashtab_next(), ast_hashtab_remove_this_object(), ast_hashtab_start_traversal(), AST_LIST_EMPTY, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_exten::cidmatch, contexts, ast_exten::exten, ast_context::ignorepats, ast_context::includes, ast_context::name, ast_include::next, ast_ignorepat::next, ast_context::next, ast_sw::next, ast_exten::peer_table, ast_exten::priority, ast_context::refcount, ast_exten::registrar, ast_sw::registrar, ast_include::registrar, ast_ignorepat::registrar, ast_context::registrar, ast_context::root, and ast_context::root_table.
Referenced by ast_context_destroy().
08564 { 08565 struct ast_context *tmp, *tmpl=NULL; 08566 struct ast_exten *exten_item, *prio_item; 08567 08568 for (tmp = list; tmp; ) { 08569 struct ast_context *next = NULL; /* next starting point */ 08570 /* The following code used to skip forward to the next 08571 context with matching registrar, but this didn't 08572 make sense; individual priorities registrar'd to 08573 the matching registrar could occur in any context! */ 08574 ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar); 08575 if (con) { 08576 for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */ 08577 ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar); 08578 if ( !strcasecmp(tmp->name, con->name) ) { 08579 break; /* found it */ 08580 } 08581 } 08582 } 08583 08584 if (!tmp) /* not found, we are done */ 08585 break; 08586 ast_wrlock_context(tmp); 08587 08588 if (registrar) { 08589 /* then search thru and remove any extens that match registrar. */ 08590 struct ast_hashtab_iter *exten_iter; 08591 struct ast_hashtab_iter *prio_iter; 08592 struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL; 08593 struct ast_include *i, *pi = NULL, *ni = NULL; 08594 struct ast_sw *sw = NULL; 08595 08596 /* remove any ignorepats whose registrar matches */ 08597 for (ip = tmp->ignorepats; ip; ip = ipn) { 08598 ipn = ip->next; 08599 if (!strcmp(ip->registrar, registrar)) { 08600 if (ipl) { 08601 ipl->next = ip->next; 08602 ast_free(ip); 08603 continue; /* don't change ipl */ 08604 } else { 08605 tmp->ignorepats = ip->next; 08606 ast_free(ip); 08607 continue; /* don't change ipl */ 08608 } 08609 } 08610 ipl = ip; 08611 } 08612 /* remove any includes whose registrar matches */ 08613 for (i = tmp->includes; i; i = ni) { 08614 ni = i->next; 08615 if (strcmp(i->registrar, registrar) == 0) { 08616 /* remove from list */ 08617 if (pi) { 08618 pi->next = i->next; 08619 /* free include */ 08620 ast_free(i); 08621 continue; /* don't change pi */ 08622 } else { 08623 tmp->includes = i->next; 08624 /* free include */ 08625 ast_free(i); 08626 continue; /* don't change pi */ 08627 } 08628 } 08629 pi = i; 08630 } 08631 /* remove any switches whose registrar matches */ 08632 AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) { 08633 if (strcmp(sw->registrar,registrar) == 0) { 08634 AST_LIST_REMOVE_CURRENT(list); 08635 ast_free(sw); 08636 } 08637 } 08638 AST_LIST_TRAVERSE_SAFE_END; 08639 08640 if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */ 08641 exten_iter = ast_hashtab_start_traversal(tmp->root_table); 08642 while ((exten_item=ast_hashtab_next(exten_iter))) { 08643 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table); 08644 while ((prio_item=ast_hashtab_next(prio_iter))) { 08645 if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) { 08646 continue; 08647 } 08648 ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n", 08649 tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL); 08650 /* set matchcid to 1 to insure we get a direct match, and NULL registrar to make sure no wildcarding is done */ 08651 ast_context_remove_extension_callerid2(tmp, prio_item->exten, prio_item->priority, prio_item->cidmatch, 1, NULL, 1); 08652 } 08653 ast_hashtab_end_traversal(prio_iter); 08654 } 08655 ast_hashtab_end_traversal(exten_iter); 08656 } 08657 08658 /* delete the context if it's registrar matches, is empty, has refcount of 1, */ 08659 /* it's not empty, if it has includes, ignorepats, or switches that are registered from 08660 another registrar. It's not empty if there are any extensions */ 08661 if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) { 08662 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar); 08663 ast_hashtab_remove_this_object(contexttab, tmp); 08664 08665 next = tmp->next; 08666 if (tmpl) 08667 tmpl->next = next; 08668 else 08669 contexts = next; 08670 /* Okay, now we're safe to let it go -- in a sense, we were 08671 ready to let it go as soon as we locked it. */ 08672 ast_unlock_context(tmp); 08673 __ast_internal_context_destroy(tmp); 08674 } else { 08675 ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar, 08676 tmp->refcount, tmp->root); 08677 ast_unlock_context(tmp); 08678 next = tmp->next; 08679 tmpl = tmp; 08680 } 08681 } else if (con) { 08682 ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar); 08683 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar); 08684 ast_hashtab_remove_this_object(contexttab, tmp); 08685 08686 next = tmp->next; 08687 if (tmpl) 08688 tmpl->next = next; 08689 else 08690 contexts = next; 08691 /* Okay, now we're safe to let it go -- in a sense, we were 08692 ready to let it go as soon as we locked it. */ 08693 ast_unlock_context(tmp); 08694 __ast_internal_context_destroy(tmp); 08695 } 08696 08697 /* if we have a specific match, we are done, otherwise continue */ 08698 tmp = con ? NULL : next; 08699 } 08700 }
| int __ast_custom_function_register | ( | struct ast_custom_function * | acf, | |
| struct ast_module * | mod | |||
| ) |
Register a custom function.
Definition at line 3358 of file pbx.c.
References acf_retrieve_docs(), ast_custom_function::acflist, ast_log(), AST_RWLIST_INSERT_BEFORE_CURRENT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, AST_STATIC_DOC, ast_verb, COLOR_BRCYAN, ast_custom_function::docsrc, LOG_ERROR, ast_custom_function::mod, ast_custom_function::name, and term_color().
Referenced by load_pbx().
03359 { 03360 struct ast_custom_function *cur; 03361 char tmps[80]; 03362 03363 if (!acf) { 03364 return -1; 03365 } 03366 03367 acf->mod = mod; 03368 #ifdef AST_XML_DOCS 03369 acf->docsrc = AST_STATIC_DOC; 03370 #endif 03371 03372 if (acf_retrieve_docs(acf)) { 03373 return -1; 03374 } 03375 03376 AST_RWLIST_WRLOCK(&acf_root); 03377 03378 AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) { 03379 if (!strcmp(acf->name, cur->name)) { 03380 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name); 03381 AST_RWLIST_UNLOCK(&acf_root); 03382 return -1; 03383 } 03384 } 03385 03386 /* Store in alphabetical order */ 03387 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) { 03388 if (strcasecmp(acf->name, cur->name) < 0) { 03389 AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist); 03390 break; 03391 } 03392 } 03393 AST_RWLIST_TRAVERSE_SAFE_END; 03394 03395 if (!cur) { 03396 AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist); 03397 } 03398 03399 AST_RWLIST_UNLOCK(&acf_root); 03400 03401 ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps))); 03402 03403 return 0; 03404 }
| static int __ast_goto_if_exists | ( | struct ast_channel * | chan, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority, | |||
| int | async | |||
| ) | [static] |
Definition at line 9822 of file pbx.c.
References ast_async_goto(), ast_exists_extension(), ast_explicit_goto(), AST_PBX_GOTO_FAILED, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, and ast_channel::exten.
Referenced by ast_async_goto_if_exists(), and ast_goto_if_exists().
09823 { 09824 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority); 09825 09826 if (!chan) 09827 return -2; 09828 09829 if (context == NULL) 09830 context = chan->context; 09831 if (exten == NULL) 09832 exten = chan->exten; 09833 09834 goto_func = (async) ? ast_async_goto : ast_explicit_goto; 09835 if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num)) 09836 return goto_func(chan, context, exten, priority); 09837 else { 09838 return AST_PBX_GOTO_FAILED; 09839 } 09840 }
| static void __ast_internal_context_destroy | ( | struct ast_context * | con | ) | [static] |
Definition at line 8516 of file pbx.c.
References ast_context::alts, ast_free, ast_hashtab_destroy(), AST_LIST_REMOVE_HEAD, ast_rwlock_destroy(), destroy_exten(), destroy_pattern_tree(), el, ast_context::ignorepats, ast_context::includes, ast_context::lock, ast_exten::next, ast_ignorepat::next, ast_include::next, ast_context::pattern_tree, ast_exten::peer, ast_context::registrar, ast_context::root, and ast_context::root_table.
Referenced by __ast_context_destroy(), and ast_merge_contexts_and_delete().
08517 { 08518 struct ast_include *tmpi; 08519 struct ast_sw *sw; 08520 struct ast_exten *e, *el, *en; 08521 struct ast_ignorepat *ipi; 08522 struct ast_context *tmp = con; 08523 08524 for (tmpi = tmp->includes; tmpi; ) { /* Free includes */ 08525 struct ast_include *tmpil = tmpi; 08526 tmpi = tmpi->next; 08527 ast_free(tmpil); 08528 } 08529 for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */ 08530 struct ast_ignorepat *ipl = ipi; 08531 ipi = ipi->next; 08532 ast_free(ipl); 08533 } 08534 if (tmp->registrar) 08535 ast_free(tmp->registrar); 08536 08537 /* destroy the hash tabs */ 08538 if (tmp->root_table) { 08539 ast_hashtab_destroy(tmp->root_table, 0); 08540 } 08541 /* and destroy the pattern tree */ 08542 if (tmp->pattern_tree) 08543 destroy_pattern_tree(tmp->pattern_tree); 08544 08545 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list))) 08546 ast_free(sw); 08547 for (e = tmp->root; e;) { 08548 for (en = e->peer; en;) { 08549 el = en; 08550 en = en->peer; 08551 destroy_exten(el); 08552 } 08553 el = e; 08554 e = e->next; 08555 destroy_exten(el); 08556 } 08557 tmp->root = NULL; 08558 ast_rwlock_destroy(&tmp->lock); 08559 ast_free(tmp); 08560 }
| static enum ast_pbx_result __ast_pbx_run | ( | struct ast_channel * | c, | |
| struct ast_pbx_args * | args | |||
| ) | [static] |
If there is no match at priority 1, it is not a valid extension anymore. Try to continue at "i" (for invalid) or "e" (for exception) or exit if neither exist.
Definition at line 4551 of file pbx.c.
References ast_channel::_softhangup, ast_calloc, ast_cdr_end(), ast_cdr_update(), ast_check_hangup(), ast_clear_flag, ast_copy_string(), ast_debug, ast_exists_extension(), AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, ast_free, ast_hangup(), ast_log(), ast_matchmore_extension(), ast_opt_end_cdr_before_h_exten, AST_PBX_ERROR, AST_PBX_INCOMPLETE, ast_set2_flag, ast_set_flag, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_TIMEOUT, ast_spawn_extension(), ast_strlen_zero(), ast_test_flag, ast_verb, autofallthrough, ast_channel::cdr, ast_channel::cid, ast_callerid::cid_num, collect_digits(), ast_channel::context, ast_pbx::dtimeoutms, ast_channel::exten, LOG_WARNING, ast_channel::name, ast_pbx_args::no_hangup_chan, ast_channel::pbx, pbx_builtin_busy(), pbx_builtin_congestion(), pbx_builtin_getvar_helper(), pbx_builtin_raise_exception(), pbx_builtin_setvar_helper(), pbx_destroy(), ast_channel::priority, ast_pbx::rtimeoutms, set_ext_pri(), status, and ast_channel::whentohangup.
Referenced by ast_pbx_run_args(), and pbx_thread().
04553 { 04554 int found = 0; /* set if we find at least one match */ 04555 int res = 0; 04556 int autoloopflag; 04557 int error = 0; /* set an error conditions */ 04558 04559 /* A little initial setup here */ 04560 if (c->pbx) { 04561 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name); 04562 /* XXX and now what ? */ 04563 ast_free(c->pbx); 04564 } 04565 if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx)))) 04566 return -1; 04567 /* Set reasonable defaults */ 04568 c->pbx->rtimeoutms = 10000; 04569 c->pbx->dtimeoutms = 5000; 04570 04571 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */ 04572 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP); 04573 04574 /* Start by trying whatever the channel is set to */ 04575 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) { 04576 /* If not successful fall back to 's' */ 04577 ast_verb(2, "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority); 04578 /* XXX the original code used the existing priority in the call to 04579 * ast_exists_extension(), and reset it to 1 afterwards. 04580 * I believe the correct thing is to set it to 1 immediately. 04581 */ 04582 set_ext_pri(c, "s", 1); 04583 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) { 04584 /* JK02: And finally back to default if everything else failed */ 04585 ast_verb(2, "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority); 04586 ast_copy_string(c->context, "default", sizeof(c->context)); 04587 } 04588 } 04589 for (;;) { 04590 char dst_exten[256]; /* buffer to accumulate digits */ 04591 int pos = 0; /* XXX should check bounds */ 04592 int digit = 0; 04593 int invalid = 0; 04594 int timeout = 0; 04595 04596 /* loop on priorities in this context/exten */ 04597 while ( !(res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found,1))) { 04598 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) { 04599 set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */ 04600 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */ 04601 memset(&c->whentohangup, 0, sizeof(c->whentohangup)); 04602 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT; 04603 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) { 04604 pbx_builtin_raise_exception(c, "ABSOLUTETIMEOUT"); 04605 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */ 04606 memset(&c->whentohangup, 0, sizeof(c->whentohangup)); 04607 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT; 04608 } else if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) { 04609 c->_softhangup = 0; 04610 continue; 04611 } else if (ast_check_hangup(c)) { 04612 ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n", 04613 c->exten, c->priority); 04614 error = 1; 04615 break; 04616 } 04617 c->priority++; 04618 } /* end while - from here on we can use 'break' to go out */ 04619 if (found && res) { 04620 /* Something bad happened, or a hangup has been requested. */ 04621 if (strchr("0123456789ABCDEF*#", res)) { 04622 ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res); 04623 pos = 0; 04624 dst_exten[pos++] = digit = res; 04625 dst_exten[pos] = '\0'; 04626 } else if (res == AST_PBX_INCOMPLETE) { 04627 ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name); 04628 ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name); 04629 04630 /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */ 04631 if (!ast_matchmore_extension(c, c->context, c->exten, 1, c->cid.cid_num)) { 04632 invalid = 1; 04633 } else { 04634 ast_copy_string(dst_exten, c->exten, sizeof(dst_exten)); 04635 digit = 1; 04636 pos = strlen(dst_exten); 04637 } 04638 } else { 04639 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); 04640 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); 04641 04642 if ((res == AST_PBX_ERROR) && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) { 04643 /* if we are already on the 'e' exten, don't jump to it again */ 04644 if (!strcmp(c->exten, "e")) { 04645 ast_verb(2, "Spawn extension (%s, %s, %d) exited ERROR while already on 'e' exten on '%s'\n", c->context, c->exten, c->priority, c->name); 04646 error = 1; 04647 } else { 04648 pbx_builtin_raise_exception(c, "ERROR"); 04649 continue; 04650 } 04651 } 04652 04653 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) { 04654 c->_softhangup = 0; 04655 continue; 04656 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) { 04657 set_ext_pri(c, "T", 1); 04658 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */ 04659 memset(&c->whentohangup, 0, sizeof(c->whentohangup)); 04660 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT; 04661 continue; 04662 } else { 04663 if (c->cdr) 04664 ast_cdr_update(c); 04665 error = 1; 04666 break; 04667 } 04668 } 04669 } 04670 if (error) 04671 break; 04672 04673 /*!\note 04674 * We get here on a failure of some kind: non-existing extension or 04675 * hangup. We have options, here. We can either catch the failure 04676 * and continue, or we can drop out entirely. */ 04677 04678 if (invalid || !ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) { 04679 /*!\note 04680 * If there is no match at priority 1, it is not a valid extension anymore. 04681 * Try to continue at "i" (for invalid) or "e" (for exception) or exit if 04682 * neither exist. 04683 */ 04684 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) { 04685 ast_verb(3, "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name); 04686 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten); 04687 set_ext_pri(c, "i", 1); 04688 } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) { 04689 pbx_builtin_raise_exception(c, "INVALID"); 04690 } else { 04691 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n", 04692 c->name, c->exten, c->context); 04693 error = 1; /* we know what to do with it */ 04694 break; 04695 } 04696 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) { 04697 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */ 04698 c->_softhangup = 0; 04699 } else { /* keypress received, get more digits for a full extension */ 04700 int waittime = 0; 04701 if (digit) 04702 waittime = c->pbx->dtimeoutms; 04703 else if (!autofallthrough) 04704 waittime = c->pbx->rtimeoutms; 04705 if (!waittime) { 04706 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS"); 04707 if (!status) 04708 status = "UNKNOWN"; 04709 ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status); 04710 if (!strcasecmp(status, "CONGESTION")) 04711 res = pbx_builtin_congestion(c, "10"); 04712 else if (!strcasecmp(status, "CHANUNAVAIL")) 04713 res = pbx_builtin_congestion(c, "10"); 04714 else if (!strcasecmp(status, "BUSY")) 04715 res = pbx_builtin_busy(c, "10"); 04716 error = 1; /* XXX disable message */ 04717 break; /* exit from the 'for' loop */ 04718 } 04719 04720 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos)) 04721 break; 04722 if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos])) 04723 timeout = 1; 04724 if (!timeout && ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */ 04725 set_ext_pri(c, dst_exten, 1); 04726 else { 04727 /* No such extension */ 04728 if (!timeout && !ast_strlen_zero(dst_exten)) { 04729 /* An invalid extension */ 04730 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) { 04731 ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name); 04732 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten); 04733 set_ext_pri(c, "i", 1); 04734 } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) { 04735 pbx_builtin_raise_exception(c, "INVALID"); 04736 } else { 04737 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context); 04738 found = 1; /* XXX disable message */ 04739 break; 04740 } 04741 } else { 04742 /* A simple timeout */ 04743 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) { 04744 ast_verb(3, "Timeout on %s\n", c->name); 04745 set_ext_pri(c, "t", 1); 04746 } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) { 04747 pbx_builtin_raise_exception(c, "RESPONSETIMEOUT"); 04748 } else { 04749 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context); 04750 found = 1; /* XXX disable message */ 04751 break; 04752 } 04753 } 04754 } 04755 if (c->cdr) { 04756 ast_verb(2, "CDR updated on %s\n",c->name); 04757 ast_cdr_update(c); 04758 } 04759 } 04760 } 04761 04762 if (!found && !error) { 04763 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name); 04764 } 04765 04766 if (!args || !args->no_hangup_chan) { 04767 ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD); 04768 } 04769 04770 if ((!args || !args->no_hangup_chan) && 04771 !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) && 04772 ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) { 04773 set_ext_pri(c, "h", 1); 04774 if (c->cdr && ast_opt_end_cdr_before_h_exten) { 04775 ast_cdr_end(c->cdr); 04776 } 04777 while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found, 1)) == 0) { 04778 c->priority++; 04779 } 04780 if (found && res) { 04781 /* Something bad happened, or a hangup has been requested. */ 04782 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); 04783 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); 04784 } 04785 } 04786 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04787 ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */ 04788 pbx_destroy(c->pbx); 04789 c->pbx = NULL; 04790 04791 if (!args || !args->no_hangup_chan) { 04792 ast_hangup(c); 04793 } 04794 04795 return 0; 04796 }
| static void __fini_apps | ( | void | ) | [static] |
| static void __fini_switches | ( | void | ) | [static] |
| static void __init_apps | ( | void | ) | [static] |
| static void __init_extensionstate_buf | ( | void | ) | [static] |
| static void __init_switch_data | ( | void | ) | [static] |
| static void __init_switches | ( | void | ) | [static] |
| static int _extension_match_core | ( | const char * | pattern, | |
| const char * | data, | |||
| enum ext_match_t | mode | |||
| ) | [static] |
Definition at line 2250 of file pbx.c.
References ast_log(), E_MATCH, E_MATCH_MASK, E_MATCHMORE, LOG_NOTICE, and LOG_WARNING.
Referenced by extension_match_core().
02251 { 02252 mode &= E_MATCH_MASK; /* only consider the relevant bits */ 02253 02254 #ifdef NEED_DEBUG_HERE 02255 ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode); 02256 #endif 02257 02258 if ( (mode == E_MATCH) && (pattern[0] == '_') && (!strcasecmp(pattern,data)) ) { /* note: if this test is left out, then _x. will not match _x. !!! */ 02259 #ifdef NEED_DEBUG_HERE 02260 ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n"); 02261 #endif 02262 return 1; 02263 } 02264 02265 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */ 02266 int ld = strlen(data), lp = strlen(pattern); 02267 02268 if (lp < ld) { /* pattern too short, cannot match */ 02269 #ifdef NEED_DEBUG_HERE 02270 ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n"); 02271 #endif 02272 return 0; 02273 } 02274 /* depending on the mode, accept full or partial match or both */ 02275 if (mode == E_MATCH) { 02276 #ifdef NEED_DEBUG_HERE 02277 ast_log(LOG_NOTICE,"return (!strcmp(%s,%s) when mode== E_MATCH)\n", pattern, data); 02278 #endif 02279 return !strcmp(pattern, data); /* 1 on match, 0 on fail */ 02280 } 02281 if (ld == 0 || !strncasecmp(pattern, data, ld)) { /* partial or full match */ 02282 #ifdef NEED_DEBUG_HERE 02283 ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld); 02284 #endif 02285 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */ 02286 } else { 02287 #ifdef NEED_DEBUG_HERE 02288 ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data); 02289 #endif 02290 return 0; 02291 } 02292 } 02293 pattern++; /* skip leading _ */ 02294 /* 02295 * XXX below we stop at '/' which is a separator for the CID info. However we should 02296 * not store '/' in the pattern at all. When we insure it, we can remove the checks. 02297 */ 02298 while (*data && *pattern && *pattern != '/') { 02299 const char *end; 02300 02301 if (*data == '-') { /* skip '-' in data (just a separator) */ 02302 data++; 02303 continue; 02304 } 02305 switch (toupper(*pattern)) { 02306 case '[': /* a range */ 02307 end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */ 02308 if (end == NULL) { 02309 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n"); 02310 return 0; /* unconditional failure */ 02311 } 02312 for (pattern++; pattern != end; pattern++) { 02313 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */ 02314 if (*data >= pattern[0] && *data <= pattern[2]) 02315 break; /* match found */ 02316 else { 02317 pattern += 2; /* skip a total of 3 chars */ 02318 continue; 02319 } 02320 } else if (*data == pattern[0]) 02321 break; /* match found */ 02322 } 02323 if (pattern == end) { 02324 #ifdef NEED_DEBUG_HERE 02325 ast_log(LOG_NOTICE,"return (0) when pattern==end\n"); 02326 #endif 02327 return 0; 02328 } 02329 pattern = end; /* skip and continue */ 02330 break; 02331 case 'N': 02332 if (*data < '2' || *data > '9') { 02333 #ifdef NEED_DEBUG_HERE 02334 ast_log(LOG_NOTICE,"return (0) N is matched\n"); 02335 #endif 02336 return 0; 02337 } 02338 break; 02339 case 'X': 02340 if (*data < '0' || *data > '9') { 02341 #ifdef NEED_DEBUG_HERE 02342 ast_log(LOG_NOTICE,"return (0) X is matched\n"); 02343 #endif 02344 return 0; 02345 } 02346 break; 02347 case 'Z': 02348 if (*data < '1' || *data > '9') { 02349 #ifdef NEED_DEBUG_HERE 02350 ast_log(LOG_NOTICE,"return (0) Z is matched\n"); 02351 #endif 02352 return 0; 02353 } 02354 break; 02355 case '.': /* Must match, even with more digits */ 02356 #ifdef NEED_DEBUG_HERE 02357 ast_log(LOG_NOTICE, "return (1) when '.' is matched\n"); 02358 #endif 02359 return 1; 02360 case '!': /* Early match */ 02361 #ifdef NEED_DEBUG_HERE 02362 ast_log(LOG_NOTICE, "return (2) when '!' is matched\n"); 02363 #endif 02364 return 2; 02365 case ' ': 02366 case '-': /* Ignore these in patterns */ 02367 data--; /* compensate the final data++ */ 02368 break; 02369 default: 02370 if (*data != *pattern) { 02371 #ifdef NEED_DEBUG_HERE 02372 ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern); 02373 #endif 02374 return 0; 02375 } 02376 } 02377 data++; 02378 pattern++; 02379 } 02380 if (*data) /* data longer than pattern, no match */ { 02381 #ifdef NEED_DEBUG_HERE 02382 ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n"); 02383 #endif 02384 return 0; 02385 } 02386 02387 /* 02388 * match so far, but ran off the end of the data. 02389 * Depending on what is next, determine match or not. 02390 */ 02391 if (*pattern == '\0' || *pattern == '/') { /* exact match */ 02392 #ifdef NEED_DEBUG_HERE 02393 ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1); 02394 #endif 02395 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */ 02396 } else if (*pattern == '!') { /* early match */ 02397 #ifdef NEED_DEBUG_HERE 02398 ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n"); 02399 #endif 02400 return 2; 02401 } else { /* partial match */ 02402 #ifdef NEED_DEBUG_HERE 02403 ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1); 02404 #endif 02405 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */ 02406 } 02407 }
| static int acf_exception_read | ( | struct ast_channel * | chan, | |
| const char * | name, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | buflen | |||
| ) | [static] |
Definition at line 3098 of file pbx.c.
References ast_channel_datastore_find(), ast_copy_string(), pbx_exception::context, ast_datastore::data, exception_store_info, pbx_exception::exten, pbx_exception::priority, and pbx_exception::reason.
03099 { 03100 struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL); 03101 struct pbx_exception *exception = NULL; 03102 if (!ds || !ds->data) 03103 return -1; 03104 exception = ds->data; 03105 if (!strcasecmp(data, "REASON")) 03106 ast_copy_string(buf, exception->reason, buflen); 03107 else if (!strcasecmp(data, "CONTEXT")) 03108 ast_copy_string(buf, exception->context, buflen); 03109 else if (!strncasecmp(data, "EXTEN", 5)) 03110 ast_copy_string(buf, exception->exten, buflen); 03111 else if (!strcasecmp(data, "PRIORITY")) 03112 snprintf(buf, buflen, "%d", exception->priority); 03113 else 03114 return -1; 03115 return 0; 03116 }
| static int acf_retrieve_docs | ( | struct ast_custom_function * | acf | ) | [static] |
Definition at line 3313 of file pbx.c.
References ast_custom_function::arguments, ast_free, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), AST_XML_DOC, desc, ast_custom_function::desc, ast_custom_function::docsrc, ast_custom_function::name, ast_custom_function::seealso, synopsis, ast_custom_function::synopsis, and ast_custom_function::syntax.
Referenced by __ast_custom_function_register().
03314 { 03315 #ifdef AST_XML_DOCS 03316 char *tmpxml; 03317 03318 /* Let's try to find it in the Documentation XML */ 03319 if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) { 03320 return 0; 03321 } 03322 03323 if (ast_string_field_init(acf, 128)) { 03324 return -1; 03325 } 03326 03327 /* load synopsis */ 03328 tmpxml = ast_xmldoc_build_synopsis("function", acf->name); 03329 ast_string_field_set(acf, synopsis, tmpxml); 03330 ast_free(tmpxml); 03331 03332 /* load description */ 03333 tmpxml = ast_xmldoc_build_description("function", acf->name); 03334 ast_string_field_set(acf, desc, tmpxml); 03335 ast_free(tmpxml); 03336 03337 /* load syntax */ 03338 tmpxml = ast_xmldoc_build_syntax("function", acf->name); 03339 ast_string_field_set(acf, syntax, tmpxml); 03340 ast_free(tmpxml); 03341 03342 /* load arguments */ 03343 tmpxml = ast_xmldoc_build_arguments("function", acf->name); 03344 ast_string_field_set(acf, arguments, tmpxml); 03345 ast_free(tmpxml); 03346 03347 /* load seealso */ 03348 tmpxml = ast_xmldoc_build_seealso("function", acf->name); 03349 ast_string_field_set(acf, seealso, tmpxml); 03350 ast_free(tmpxml); 03351 03352 acf->docsrc = AST_XML_DOC; 03353 #endif 03354 03355 return 0; 03356 }
| static struct match_char * add_exten_to_pattern_tree | ( | struct ast_context * | con, | |
| struct ast_exten * | e1, | |||
| int | findonly | |||
| ) | [static, read] |
Definition at line 1906 of file pbx.c.
References add_pattern_node(), already_in_tree(), ast_copy_string(), ast_log(), buf, ast_exten::cidmatch, compare_char(), match_char::deleted, match_char::exten, ast_exten::exten, LOG_DEBUG, LOG_ERROR, LOG_WARNING, m1, m2, ast_exten::matchcid, match_char::next_char, and ast_context::pattern_tree.
Referenced by add_pri_lockopt(), ast_add_extension2_lockopt(), ast_context_remove_extension_callerid2(), and create_match_char_tree().
01907 { 01908 struct match_char *m1 = NULL, *m2 = NULL, **m0; 01909 int specif; 01910 int already; 01911 int pattern = 0; 01912 char buf[256]; 01913 char extenbuf[512]; 01914 char *s1 = extenbuf; 01915 int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2; 01916 01917 01918 ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf)); 01919 01920 if (e1->matchcid && l1 <= sizeof(extenbuf)) { 01921 strcat(extenbuf, "/"); 01922 strcat(extenbuf, e1->cidmatch); 01923 } else if (l1 > sizeof(extenbuf)) { 01924 ast_log(LOG_ERROR, "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n", e1->exten, e1->cidmatch); 01925 return 0; 01926 } 01927 #ifdef NEED_DEBUG 01928 ast_log(LOG_DEBUG, "Adding exten %s%c%s to tree\n", s1, e1->matchcid ? '/' : ' ', e1->matchcid ? e1->cidmatch : ""); 01929 #endif 01930 m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */ 01931 m0 = &con->pattern_tree; 01932 already = 1; 01933 01934 if ( *s1 == '_') { 01935 pattern = 1; 01936 s1++; 01937 } 01938 while (*s1) { 01939 if (pattern && *s1 == '[' && *(s1 - 1) != '\\') { 01940 char *s2 = buf; 01941 buf[0] = 0; 01942 s1++; /* get past the '[' */ 01943 while (*s1 != ']' && *(s1 - 1) != '\\') { 01944 if (*s1 == '\\') { 01945 if (*(s1 + 1) == ']') { 01946 *s2++ = ']'; 01947 s1 += 2; 01948 } else if (*(s1 + 1) == '\\') { 01949 *s2++ = '\\'; 01950 s1 += 2; 01951 } else if (*(s1 + 1) == '-') { 01952 *s2++ = '-'; 01953 s1 += 2; 01954 } else if (*(s1 + 1) == '[') { 01955 *s2++ = '['; 01956 s1 += 2; 01957 } 01958 } else if (*s1 == '-') { /* remember to add some error checking to all this! */ 01959 char s3 = *(s1 - 1); 01960 char s4 = *(s1 + 1); 01961 for (s3++; s3 <= s4; s3++) { 01962 *s2++ = s3; 01963 } 01964 s1 += 2; 01965 } else if (*s1 == '\0') { 01966 ast_log(LOG_WARNING, "A matching ']' was not found for '[' in pattern string '%s'\n", extenbuf); 01967 break; 01968 } else { 01969 *s2++ = *s1++; 01970 } 01971 } 01972 *s2 = 0; /* null terminate the exploded range */ 01973 /* sort the characters */ 01974 01975 specif = strlen(buf); 01976 qsort(buf, specif, 1, compare_char); 01977 specif <<= 8; 01978 specif += buf[0]; 01979 } else { 01980 if (*s1 == '\\') { 01981 s1++; 01982 buf[0] = *s1; 01983 } else { 01984 if (pattern) { 01985 if (*s1 == 'n') { /* make sure n,x,z patterns are canonicalized to N,X,Z */ 01986 *s1 = 'N'; 01987 } else if (*s1 == 'x') { 01988 *s1 = 'X'; 01989 } else if (*s1 == 'z') { 01990 *s1 = 'Z'; 01991 } 01992 } 01993 buf[0] = *s1; 01994 } 01995 buf[1] = 0; 01996 specif = 1; 01997 } 01998 m2 = 0; 01999 if (already && (m2 = already_in_tree(m1, buf, pattern)) && m2->next_char) { 02000 if (!(*(s1 + 1))) { /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten... 02001 a shorter pattern might win if the longer one doesn't match */ 02002 if (m2->exten) { 02003 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", m2->exten->exten, e1->exten); 02004 } 02005 m2->exten = e1; 02006 m2->deleted = 0; 02007 } 02008 m1 = m2->next_char; /* m1 points to the node to compare against */ 02009 m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */ 02010 } else { /* not already OR not m2 OR nor m2->next_char */ 02011 if (m2) { 02012 if (findonly) { 02013 return m2; 02014 } 02015 m1 = m2; /* while m0 stays the same */ 02016 } else { 02017 if (findonly) { 02018 return m1; 02019 } 02020 if (!(m1 = add_pattern_node(con, m1, buf, pattern, already,specif, m0))) { /* m1 is the node just added */ 02021 return NULL; 02022 } 02023 m0 = &m1->next_char; 02024 } 02025 if (!(*(s1 + 1))) { 02026 if (m2 && m2->exten) { 02027 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", m2->exten->exten, e1->exten); 02028 } 02029 m1->deleted = 0; 02030 m1->exten = e1; 02031 } 02032 02033 /* The 'already' variable is a mini-optimization designed to make it so that we 02034 * don't have to call already_in_tree when we know it will return false. 02035 */ 02036 already = 0; 02037 } 02038 s1++; /* advance to next char */ 02039 } 02040 return m1; 02041 }
| static struct match_char * add_pattern_node | ( | struct ast_context * | con, | |
| struct match_char * | current, | |||
| char * | pattern, | |||
| int | is_pattern, | |||
| int | already, | |||
| int | specificity, | |||
| struct match_char ** | parent | |||
| ) | [static, read] |
Definition at line 1864 of file pbx.c.
References ast_calloc, insert_in_next_chars_alt_char_list(), match_char::is_pattern, match_char::next_char, ast_context::pattern_tree, match_char::specificity, and match_char::x.
Referenced by add_exten_to_pattern_tree().
01865 { 01866 struct match_char *m; 01867 01868 if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern)))) { 01869 return NULL; 01870 } 01871 01872 /* strcpy is safe here since we know its size and have allocated 01873 * just enough space for when we allocated m 01874 */ 01875 strcpy(m->x, pattern); 01876 01877 /* the specificity scores are the same as used in the old 01878 pattern matcher. */ 01879 m->is_pattern = is_pattern; 01880 if (specificity == 1 && is_pattern && pattern[0] == 'N') 01881 m->specificity = 0x0802; 01882 else if (specificity == 1 && is_pattern && pattern[0] == 'Z') 01883 m->specificity = 0x0901; 01884 else if (specificity == 1 && is_pattern && pattern[0] == 'X') 01885 m->specificity = 0x0a00; 01886 else if (specificity == 1 && is_pattern && pattern[0] == '.') 01887 m->specificity = 0x10000; 01888 else if (specificity == 1 && is_pattern && pattern[0] == '!') 01889 m->specificity = 0x20000; 01890 else 01891 m->specificity = specificity; 01892 01893 if (!con->pattern_tree) { 01894 insert_in_next_chars_alt_char_list(&con->pattern_tree, m); 01895 } else { 01896 if (already) { /* switch to the new regime (traversing vs appending)*/ 01897 insert_in_next_chars_alt_char_list(nextcharptr, m); 01898 } else { 01899 insert_in_next_chars_alt_char_list(¤t->next_char, m); 01900 } 01901 } 01902 01903 return m; 01904 }
| static int add_pri | ( | struct ast_context * | con, | |
| struct ast_exten * | tmp, | |||
| struct ast_exten * | el, | |||
| struct ast_exten * | e, | |||
| int | replace | |||
| ) | [static] |
add the extension in the priority chain.
| 0 | on success. | |
| -1 | on failure. |
Definition at line 7727 of file pbx.c.
References add_pri_lockopt().
Referenced by ast_add_extension2_lockopt().
07729 { 07730 return add_pri_lockopt(con, tmp, el, e, replace, 1); 07731 }
| static int add_pri_lockopt | ( | struct ast_context * | con, | |
| struct ast_exten * | tmp, | |||
| struct ast_exten * | el, | |||
| struct ast_exten * | e, | |||
| int | replace, | |||
| int | lockhints | |||
| ) | [static] |
add the extension in the priority chain.
| 0 | on success. | |
| -1 | on failure. |
Definition at line 7738 of file pbx.c.
References add_exten_to_pattern_tree(), ast_add_hint(), ast_add_hint_nolock(), ast_change_hint(), ast_free, ast_hashtab_insert_safe(), ast_hashtab_remove_object_via_lookup(), ast_log(), ast_exten::data, ast_exten::datad, match_char::exten, ast_exten::exten, ast_exten::label, LOG_ERROR, LOG_WARNING, ast_context::name, ast_exten::next, ast_exten::peer, ast_exten::peer_label_table, ast_exten::peer_table, ast_exten::priority, PRIORITY_HINT, ast_context::root, ast_context::root_table, and match_char::x.
Referenced by add_pri().
07740 { 07741 struct ast_exten *ep; 07742 struct ast_exten *eh=e; 07743 07744 for (ep = NULL; e ; ep = e, e = e->peer) { 07745 if (e->priority >= tmp->priority) 07746 break; 07747 } 07748 if (!e) { /* go at the end, and ep is surely set because the list is not empty */ 07749 ast_hashtab_insert_safe(eh->peer_table, tmp); 07750 07751 if (tmp->label) { 07752 ast_hashtab_insert_safe(eh->peer_label_table, tmp); 07753 } 07754 ep->peer = tmp; 07755 return 0; /* success */ 07756 } 07757 if (e->priority == tmp->priority) { 07758 /* Can't have something exactly the same. Is this a 07759 replacement? If so, replace, otherwise, bonk. */ 07760 if (!replace) { 07761 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name); 07762 if (tmp->datad) { 07763 tmp->datad(tmp->data); 07764 /* if you free this, null it out */ 07765 tmp->data = NULL; 07766 } 07767 07768 ast_free(tmp); 07769 return -1; 07770 } 07771 /* we are replacing e, so copy the link fields and then update 07772 * whoever pointed to e to point to us 07773 */ 07774 tmp->next = e->next; /* not meaningful if we are not first in the peer list */ 07775 tmp->peer = e->peer; /* always meaningful */ 07776 if (ep) { /* We're in the peer list, just insert ourselves */ 07777 ast_hashtab_remove_object_via_lookup(eh->peer_table,e); 07778 07779 if (e->label) { 07780 ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e); 07781 } 07782 07783 ast_hashtab_insert_safe(eh->peer_table,tmp); 07784 if (tmp->label) { 07785 ast_hashtab_insert_safe(eh->peer_label_table,tmp); 07786 } 07787 07788 ep->peer = tmp; 07789 } else if (el) { /* We're the first extension. Take over e's functions */ 07790 struct match_char *x = add_exten_to_pattern_tree(con, e, 1); 07791 tmp->peer_table = e->peer_table; 07792 tmp->peer_label_table = e->peer_label_table; 07793 ast_hashtab_remove_object_via_lookup(tmp->peer_table,e); 07794 ast_hashtab_insert_safe(tmp->peer_table,tmp); 07795 if (e->label) { 07796 ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e); 07797 } 07798 if (tmp->label) { 07799 ast_hashtab_insert_safe(tmp->peer_label_table, tmp); 07800 } 07801 07802 ast_hashtab_remove_object_via_lookup(con->root_table, e); 07803 ast_hashtab_insert_safe(con->root_table, tmp); 07804 el->next = tmp; 07805 /* The pattern trie points to this exten; replace the pointer, 07806 and all will be well */ 07807 if (x) { /* if the trie isn't formed yet, don't sweat this */ 07808 if (x->exten) { /* this test for safety purposes */ 07809 x->exten = tmp; /* replace what would become a bad pointer */ 07810 } else { 07811 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n"); 07812 } 07813 } 07814 } else { /* We're the very first extension. */ 07815 struct match_char *x = add_exten_to_pattern_tree(con, e, 1); 07816 ast_hashtab_remove_object_via_lookup(con->root_table, e); 07817 ast_hashtab_insert_safe(con->root_table, tmp); 07818 tmp->peer_table = e->peer_table; 07819 tmp->peer_label_table = e->peer_label_table; 07820 ast_hashtab_remove_object_via_lookup(tmp->peer_table, e); 07821 ast_hashtab_insert_safe(tmp->peer_table, tmp); 07822 if (e->label) { 07823 ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e); 07824 } 07825 if (tmp->label) { 07826 ast_hashtab_insert_safe(tmp->peer_label_table, tmp); 07827 } 07828 07829 ast_hashtab_remove_object_via_lookup(con->root_table, e); 07830 ast_hashtab_insert_safe(con->root_table, tmp); 07831 con->root = tmp; 07832 /* The pattern trie points to this exten; replace the pointer, 07833 and all will be well */ 07834 if (x) { /* if the trie isn't formed yet; no problem */ 07835 if (x->exten) { /* this test for safety purposes */ 07836 x->exten = tmp; /* replace what would become a bad pointer */ 07837 } else { 07838 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n"); 07839 } 07840 } 07841 } 07842 if (tmp->priority == PRIORITY_HINT) 07843 ast_change_hint(e,tmp); 07844 /* Destroy the old one */ 07845 if (e->datad) 07846 e->datad(e->data); 07847 ast_free(e); 07848 } else { /* Slip ourselves in just before e */ 07849 tmp->peer = e; 07850 tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */ 07851 if (ep) { /* Easy enough, we're just in the peer list */ 07852 if (tmp->label) { 07853 ast_hashtab_insert_safe(eh->peer_label_table, tmp); 07854 } 07855 ast_hashtab_insert_safe(eh->peer_table, tmp); 07856 ep->peer = tmp; 07857 } else { /* we are the first in some peer list, so link in the ext list */ 07858 tmp->peer_table = e->peer_table; 07859 tmp->peer_label_table = e->peer_label_table; 07860 e->peer_table = 0; 07861 e->peer_label_table = 0; 07862 ast_hashtab_insert_safe(tmp->peer_table, tmp); 07863 if (tmp->label) { 07864 ast_hashtab_insert_safe(tmp->peer_label_table, tmp); 07865 } 07866 ast_hashtab_remove_object_via_lookup(con->root_table, e); 07867 ast_hashtab_insert_safe(con->root_table, tmp); 07868 if (el) 07869 el->next = tmp; /* in the middle... */ 07870 else 07871 con->root = tmp; /* ... or at the head */ 07872 e->next = NULL; /* e is no more at the head, so e->next must be reset */ 07873 } 07874 /* And immediately return success. */ 07875 if (tmp->priority == PRIORITY_HINT) { 07876 if (lockhints) { 07877 ast_add_hint(tmp); 07878 } else { 07879 ast_add_hint_nolock(tmp); 07880 } 07881 } 07882 } 07883 return 0; 07884 }
| static struct match_char * already_in_tree | ( | struct match_char * | current, | |
| char * | pat, | |||
| int | is_pattern | |||
| ) | [static, read] |
Definition at line 1809 of file pbx.c.
References match_char::alt_char, match_char::is_pattern, and match_char::x.
Referenced by add_exten_to_pattern_tree().
01810 { 01811 struct match_char *t; 01812 01813 if (!current) { 01814 return 0; 01815 } 01816 01817 for (t = current; t; t = t->alt_char) { 01818 if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {/* uh, we may want to sort exploded [] contents to make matching easy */ 01819 return t; 01820 } 01821 } 01822 01823 return 0; 01824 }
| int ast_active_calls | ( | void | ) |
Retrieve the number of active calls.
Definition at line 4934 of file pbx.c.
References countcalls.
Referenced by ast_var_Config(), handle_chanlist(), handle_showcalls(), and sysinfo_helper().
04935 { 04936 return countcalls; 04937 }
| int ast_add_extension | ( | const char * | context, | |
| int | replace, | |||
| const char * | extension, | |||
| int | priority, | |||
| const char * | label, | |||
| const char * | callerid, | |||
| const char * | application, | |||
| void * | data, | |||
| void(*)(void *) | datad, | |||
| const char * | registrar | |||
| ) |
Add and extension to an extension context.
| context | context to add the extension to | |
| replace | ||
| extension | extension to add | |
| priority | priority level of extension addition | |
| label | extension label | |
| callerid | pattern to match CallerID, or NULL to match any CallerID | |
| application | application to run on the extension with that priority level | |
| data | data to pass to the application | |
| datad | ||
| registrar | who registered the extension |
| 0 | success | |
| -1 | failure |
Definition at line 7590 of file pbx.c.
References ast_add_extension2(), ast_unlock_contexts(), and find_context_locked().
Referenced by ast_extension_state_add(), handle_cli_dialplan_add_extension(), park_add_hints(), register_exten(), register_peer_exten(), and RegisterExtension().
07593 { 07594 int ret = -1; 07595 struct ast_context *c = find_context_locked(context); 07596 07597 if (c) { 07598 ret = ast_add_extension2(c, replace, extension, priority, label, callerid, 07599 application, data, datad, registrar); 07600 ast_unlock_contexts(); 07601 } 07602 07603 return ret; 07604 }
| int ast_add_extension2 | ( | struct ast_context * | con, | |
| int | replace, | |||
| const char * | extension, | |||
| int | priority, | |||
| const char * | label, | |||
| const char * | callerid, | |||
| const char * | application, | |||
| void * | data, | |||
| void(*)(void *) | datad, | |||
| const char * | registrar | |||
| ) |
Main interface to add extensions to the list for out context.
Add an extension to an extension context, this time with an ast_context *.
We sort extensions in order of matching preference, so that we can stop the search as soon as we find a suitable match. This ordering also takes care of wildcards such as '.' (meaning "one or more of any character") and '!' (which is 'earlymatch', meaning "zero or more of any character" but also impacts the return value from CANMATCH and EARLYMATCH.
The extension match rules defined in the devmeeting 2006.05.05 are quite simple: WE SELECT THE LONGEST MATCH. In detail, "longest" means the number of matched characters in the extension. In case of ties (e.g. _XXX and 333) in the length of a pattern, we give priority to entries with the smallest cardinality (e.g, [5-9] comes before [2-8] before the former has only 5 elements, while the latter has 7, etc. In case of same cardinality, the first element in the range counts. If we still have a tie, any final '!' will make this as a possibly less specific pattern.
EBUSY - can't lock EEXIST - extension with the same priority exist and no replace is set
Definition at line 7911 of file pbx.c.
References ast_add_extension2_lockopt().
Referenced by add_extensions(), ast_add_extension(), build_parkinglot(), context_merge(), load_config(), load_module(), manage_parkinglot(), park_call_full(), pbx_load_config(), pbx_load_users(), sla_build_station(), and sla_build_trunk().
07915 { 07916 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1); 07917 }
| static int ast_add_extension2_lockopt | ( | struct ast_context * | con, | |
| int | replace, | |||
| const char * | extension, | |||
| int | priority, | |||
| const char * | label, | |||
| const char * | callerid, | |||
| const char * | application, | |||
| void * | data, | |||
| void(*)(void *) | datad, | |||
| const char * | registrar, | |||
| int | lockconts, | |||
| int | lockhints | |||
| ) | [static] |
Does all the work of ast_add_extension2, but adds two args, to determine if context and hint locking should be done. In merge_and_delete, we need to do this without locking, as the locks are already held.
Definition at line 7924 of file pbx.c.
References add_exten_to_pattern_tree(), add_pri(), ast_exten::app, ast_add_hint(), ast_add_hint_nolock(), ast_calloc, ast_channel_release(), ast_copy_string(), ast_debug, ast_dummy_channel_alloc(), ast_hashtab_create(), ast_hashtab_insert_safe(), ast_hashtab_lookup(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), ast_log(), ast_strlen_zero(), ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_exten::cidmatch, ast_channel::context, ast_exten::data, ast_exten::datad, el, errno, ext_cmp(), ext_strncpy(), ast_exten::exten, ast_channel::exten, hashtab_compare_exten_labels(), hashtab_compare_exten_numbers(), hashtab_compare_extens(), hashtab_hash_extens(), hashtab_hash_labels(), hashtab_hash_priority(), ast_exten::label, LOG_ERROR, ast_exten::matchcid, ast_context::name, ast_exten::next, option_debug, ast_exten::parent, ast_context::pattern_tree, pbx_substitute_variables_helper(), ast_exten::peer_label_table, ast_exten::peer_table, ast_exten::priority, PRIORITY_HINT, ast_exten::registrar, ast_context::root, ast_context::root_table, ast_exten::stuff, and VAR_BUF_SIZE.
Referenced by ast_add_extension2(), and ast_add_extension_nolock().
07928 { 07929 /* 07930 * Sort extensions (or patterns) according to the rules indicated above. 07931 * These are implemented by the function ext_cmp()). 07932 * All priorities for the same ext/pattern/cid are kept in a list, 07933 * using the 'peer' field as a link field.. 07934 */ 07935 struct ast_exten *tmp, *tmp2, *e, *el = NULL; 07936 int res; 07937 int length; 07938 char *p; 07939 char expand_buf[VAR_BUF_SIZE]; 07940 struct ast_exten dummy_exten = {0}; 07941 char dummy_name[1024]; 07942 07943 if (ast_strlen_zero(extension)) { 07944 ast_log(LOG_ERROR,"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n", 07945 con->name); 07946 return -1; 07947 } 07948 07949 /* If we are adding a hint evalulate in variables and global variables */ 07950 if (priority == PRIORITY_HINT && strstr(application, "${") && !strstr(extension, "_")) { 07951 struct ast_channel *c = ast_dummy_channel_alloc(); 07952 ast_copy_string(c->exten, extension, sizeof(c->exten)); 07953 ast_copy_string(c->context, con->name, sizeof(c->context)); 07954 07955 pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf)); 07956 application = expand_buf; 07957 ast_channel_release(c); 07958 } 07959 07960 length = sizeof(struct ast_exten); 07961 length += strlen(extension) + 1; 07962 length += strlen(application) + 1; 07963 if (label) 07964 length += strlen(label) + 1; 07965 if (callerid) 07966 length += strlen(callerid) + 1; 07967 else 07968 length ++; /* just the '\0' */ 07969 07970 /* Be optimistic: Build the extension structure first */ 07971 if (!(tmp = ast_calloc(1, length))) 07972 return -1; 07973 07974 if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */ 07975 label = 0; 07976 07977 /* use p as dst in assignments, as the fields are const char * */ 07978 p = tmp->stuff; 07979 if (label) { 07980 tmp->label = p; 07981 strcpy(p, label); 07982 p += strlen(label) + 1; 07983 } 07984 tmp->exten = p; 07985 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1; 07986 tmp->priority = priority; 07987 tmp->cidmatch = p; /* but use p for assignments below */ 07988 if (!ast_strlen_zero(callerid)) { 07989 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1; 07990 tmp->matchcid = 1; 07991 } else { 07992 *p++ = '\0'; 07993 tmp->matchcid = 0; 07994 } 07995 tmp->app = p; 07996 strcpy(p, application); 07997 tmp->parent = con; 07998 tmp->data = data; 07999 tmp->datad = datad; 08000 tmp->registrar = registrar; 08001 08002 if (lockconts) { 08003 ast_wrlock_context(con); 08004 } 08005 08006 if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding 08007 an extension, and the trie exists, then we need to incrementally add this pattern to it. */ 08008 ast_copy_string(dummy_name, extension, sizeof(dummy_name)); 08009 dummy_exten.exten = dummy_name; 08010 dummy_exten.matchcid = 0; 08011 dummy_exten.cidmatch = 0; 08012 tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten); 08013 if (!tmp2) { 08014 /* hmmm, not in the trie; */ 08015 add_exten_to_pattern_tree(con, tmp, 0); 08016 ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */ 08017 } 08018 } 08019 res = 0; /* some compilers will think it is uninitialized otherwise */ 08020 for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */ 08021 res = ext_cmp(e->exten, tmp->exten); 08022 if (res == 0) { /* extension match, now look at cidmatch */ 08023 if (!e->matchcid && !tmp->matchcid) 08024 res = 0; 08025 else if (tmp->matchcid && !e->matchcid) 08026 res = 1; 08027 else if (e->matchcid && !tmp->matchcid) 08028 res = -1; 08029 else 08030 res = ext_cmp(e->cidmatch, tmp->cidmatch); 08031 } 08032 if (res >= 0) 08033 break; 08034 } 08035 if (e && res == 0) { /* exact match, insert in the pri chain */ 08036 res = add_pri(con, tmp, el, e, replace); 08037 if (lockconts) { 08038 ast_unlock_context(con); 08039 } 08040 if (res < 0) { 08041 errno = EEXIST; /* XXX do we care ? */ 08042 return 0; /* XXX should we return -1 maybe ? */ 08043 } 08044 } else { 08045 /* 08046 * not an exact match, this is the first entry with this pattern, 08047 * so insert in the main list right before 'e' (if any) 08048 */ 08049 tmp->next = e; 08050 if (el) { /* there is another exten already in this context */ 08051 el->next = tmp; 08052 tmp->peer_table = ast_hashtab_create(13, 08053 hashtab_compare_exten_numbers, 08054 ast_hashtab_resize_java, 08055 ast_hashtab_newsize_java, 08056 hashtab_hash_priority, 08057 0); 08058 tmp->peer_label_table = ast_hashtab_create(7, 08059 hashtab_compare_exten_labels, 08060 ast_hashtab_resize_java, 08061 ast_hashtab_newsize_java, 08062 hashtab_hash_labels, 08063 0); 08064 if (label) { 08065 ast_hashtab_insert_safe(tmp->peer_label_table, tmp); 08066 } 08067 ast_hashtab_insert_safe(tmp->peer_table, tmp); 08068 } else { /* this is the first exten in this context */ 08069 if (!con->root_table) 08070 con->root_table = ast_hashtab_create(27, 08071 hashtab_compare_extens, 08072 ast_hashtab_resize_java, 08073 ast_hashtab_newsize_java, 08074 hashtab_hash_extens, 08075 0); 08076 con->root = tmp; 08077 con->root->peer_table = ast_hashtab_create(13, 08078 hashtab_compare_exten_numbers, 08079 ast_hashtab_resize_java, 08080 ast_hashtab_newsize_java, 08081 hashtab_hash_priority, 08082 0); 08083 con->root->peer_label_table = ast_hashtab_create(7, 08084 hashtab_compare_exten_labels, 08085 ast_hashtab_resize_java, 08086 ast_hashtab_newsize_java, 08087 hashtab_hash_labels, 08088 0); 08089 if (label) { 08090 ast_hashtab_insert_safe(con->root->peer_label_table, tmp); 08091 } 08092 ast_hashtab_insert_safe(con->root->peer_table, tmp); 08093 08094 } 08095 ast_hashtab_insert_safe(con->root_table, tmp); 08096 if (lockconts) { 08097 ast_unlock_context(con); 08098 } 08099 if (tmp->priority == PRIORITY_HINT) { 08100 if (lockhints) { 08101 ast_add_hint(tmp); 08102 } else { 08103 ast_add_hint_nolock(tmp); 08104 } 08105 } 08106 } 08107 if (option_debug) { 08108 if (tmp->matchcid) { 08109 ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n", 08110 tmp->exten, tmp->priority, tmp->cidmatch, con->name, con); 08111 } else { 08112 ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n", 08113 tmp->exten, tmp->priority, con->name, con); 08114 } 08115 } 08116 08117 if (tmp->matchcid) { 08118 ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n", 08119 tmp->exten, tmp->priority, tmp->cidmatch, con->name, con); 08120 } else { 08121 ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n", 08122 tmp->exten, tmp->priority, con->name, con); 08123 } 08124 08125 return 0; 08126 }
| static int ast_add_extension_nolock | ( | const char * | context, | |
| int | replace, | |||
| const char * | extension, | |||
| int | priority, | |||
| const char * | label, | |||
| const char * | callerid, | |||
| const char * | application, | |||
| void * | data, | |||
| void(*)(void *) | datad, | |||
| const char * | registrar | |||
| ) | [static] |
Definition at line 7571 of file pbx.c.
References ast_add_extension2_lockopt(), and find_context().
Referenced by ast_merge_contexts_and_delete().
07574 { 07575 int ret = -1; 07576 struct ast_context *c = find_context(context); 07577 07578 if (c) { 07579 ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid, 07580 application, data, datad, registrar, 0, 0); 07581 } 07582 07583 return ret; 07584 }
| static int ast_add_hint | ( | struct ast_exten * | e | ) | [static] |
Add hint to hint list, check initial extension state.
Definition at line 4376 of file pbx.c.
References ast_add_hint_nolock(), AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
Referenced by add_pri_lockopt(), and ast_add_extension2_lockopt().
04377 { 04378 int ret; 04379 04380 AST_RWLIST_WRLOCK(&hints); 04381 ret = ast_add_hint_nolock(e); 04382 AST_RWLIST_UNLOCK(&hints); 04383 04384 return ret; 04385 }
| static int ast_add_hint_nolock | ( | struct ast_exten * | e | ) | [static] |
Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already!
Definition at line 4347 of file pbx.c.
References ast_calloc, ast_debug, ast_extension_state2(), ast_get_extension_app(), ast_get_extension_name(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, ast_hint::exten, and ast_hint::laststate.
Referenced by add_pri_lockopt(), ast_add_extension2_lockopt(), and ast_add_hint().
04348 { 04349 struct ast_hint *hint; 04350 04351 if (!e) 04352 return -1; 04353 04354 /* Search if hint exists, do nothing */ 04355 AST_RWLIST_TRAVERSE(&hints, hint, list) { 04356 if (hint->exten == e) { 04357 ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e)); 04358 return -1; 04359 } 04360 } 04361 04362 ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e)); 04363 04364 if (!(hint = ast_calloc(1, sizeof(*hint)))) { 04365 return -1; 04366 } 04367 /* Initialize and insert new item at the top */ 04368 hint->exten = e; 04369 hint->laststate = ast_extension_state2(e); 04370 AST_RWLIST_INSERT_HEAD(&hints, hint, list); 04371 04372 return 0; 04373 }
| int ast_async_goto | ( | struct ast_channel * | chan, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority | |||
| ) |
Set the channel to next execute the specified dialplan location.
Definition at line 7629 of file pbx.c.
References ast_channel::_state, ast_channel::accountcode, ast_channel::amaflags, ast_cdr_discard(), ast_cdr_dup(), ast_channel_alloc, ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_explicit_goto(), ast_hangup(), ast_log(), ast_pbx_start(), AST_SOFTHANGUP_ASYNCGOTO, ast_softhangup_nolock(), ast_channel::cdr, ast_channel::context, ast_channel::exten, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_channel::pbx, ast_channel::readformat, S_OR, and ast_channel::writeformat.
Referenced by __ast_goto_if_exists(), action_redirect(), ast_async_goto_by_name(), builtin_blindtransfer(), change_t38_state(), console_transfer(), dahdi_handle_dtmfup(), handle_request_bye(), handle_request_refer(), my_handle_dtmfup(), pbx_parseable_goto(), process_ast_dsp(), and socket_process().
07630 { 07631 int res = 0; 07632 07633 ast_channel_lock(chan); 07634 07635 if (chan->pbx) { /* This channel is currently in the PBX */ 07636 ast_explicit_goto(chan, context, exten, priority + 1); 07637 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO); 07638 } else { 07639 /* In order to do it when the channel doesn't really exist within 07640 the PBX, we have to make a new channel, masquerade, and start the PBX 07641 at the new location */ 07642 struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->linkedid, chan->amaflags, "AsyncGoto/%s", chan->name); 07643 if (!tmpchan) { 07644 res = -1; 07645 } else { 07646 if (chan->cdr) { 07647 ast_cdr_discard(tmpchan->cdr); 07648 tmpchan->cdr = ast_cdr_dup(chan->cdr); /* share the love */ 07649 } 07650 /* Make formats okay */ 07651 tmpchan->readformat = chan->readformat; 07652 tmpchan->writeformat = chan->writeformat; 07653 /* Setup proper location */ 07654 ast_explicit_goto(tmpchan, 07655 S_OR(context, chan->context), S_OR(exten, chan->exten), priority); 07656 07657 /* Masquerade into temp channel */ 07658 if (ast_channel_masquerade(tmpchan, chan)) { 07659 /* Failed to set up the masquerade. It's probably chan_local 07660 * in the middle of optimizing itself out. Sad. :( */ 07661 ast_hangup(tmpchan); 07662 tmpchan = NULL; 07663 res = -1; 07664 } else { 07665 /* it may appear odd to unlock chan here since the masquerade is on 07666 * tmpchan, but no channel locks should be held when doing a masquerade 07667 * since a masquerade requires a lock on the channels ao2 container. */ 07668 ast_channel_unlock(chan); 07669 ast_do_masquerade(tmpchan); 07670 ast_channel_lock(chan); 07671 /* Start the PBX going on our stolen channel */ 07672 if (ast_pbx_start(tmpchan)) { 07673 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name); 07674 ast_hangup(tmpchan); 07675 res = -1; 07676 } 07677 } 07678 } 07679 } 07680 ast_channel_unlock(chan); 07681 return res; 07682 }
| int ast_async_goto_by_name | ( | const char * | channame, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority | |||
| ) |
Set the channel to next execute the specified dialplan location.
Definition at line 7684 of file pbx.c.
References ast_async_goto(), ast_channel_get_by_name(), and ast_channel_unref.
07685 { 07686 struct ast_channel *chan; 07687 int res = -1; 07688 07689 if ((chan = ast_channel_get_by_name(channame))) { 07690 res = ast_async_goto(chan, context, exten, priority); 07691 chan = ast_channel_unref(chan); 07692 } 07693 07694 return res; 07695 }
| int ast_async_goto_if_exists | ( | struct ast_channel * | chan, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority | |||
| ) |
Definition at line 9847 of file pbx.c.
References __ast_goto_if_exists().
09848 { 09849 return __ast_goto_if_exists(chan, context, exten, priority, 1); 09850 }
| int ast_async_parseable_goto | ( | struct ast_channel * | chan, | |
| const char * | goto_string | |||
| ) |
Definition at line 9910 of file pbx.c.
References pbx_parseable_goto().
Referenced by asyncgoto_exec(), and handle_redirect().
09911 { 09912 return pbx_parseable_goto(chan, goto_string, 1); 09913 }
| int ast_build_timing | ( | struct ast_timing * | i, | |
| const char * | info | |||
| ) |
Construct a timing bitmap, for use in time-based conditionals.
| i | Pointer to an ast_timing structure. | |
| info | Standard string containing a timerange, weekday range, monthday range, and month range, as well as an optional timezone. |
| Returns | 1 on success or 0 on failure. |
Definition at line 7224 of file pbx.c.
References ast_strdup, ast_strdupa, ast_strlen_zero(), ast_timing::daymask, days, ast_timing::dowmask, get_range(), get_timerange(), ast_timing::monthmask, months, strsep(), and ast_timing::timezone.
Referenced by ast_context_add_include2(), iftime(), pbx_builtin_execiftime(), and pbx_builtin_gotoiftime().
07225 { 07226 char *info_save, *info; 07227 int j, num_fields, last_sep = -1; 07228 07229 /* Check for empty just in case */ 07230 if (ast_strlen_zero(info_in)) { 07231 return 0; 07232 } 07233 07234 /* make a copy just in case we were passed a static string */ 07235 info_save = info = ast_strdupa(info_in); 07236 07237 /* count the number of fields in the timespec */ 07238 for (j = 0, num_fields = 1; info[j] != '\0'; j++) { 07239 if (info[j] == ',') { 07240 last_sep = j; 07241 num_fields++; 07242 } 07243 } 07244 07245 /* save the timezone, if it is specified */ 07246 if (num_fields == 5) { 07247 i->timezone = ast_strdup(info + last_sep + 1); 07248 } else { 07249 i->timezone = NULL; 07250 } 07251 07252 /* Assume everything except time */ 07253 i->monthmask = 0xfff; /* 12 bits */ 07254 i->daymask = 0x7fffffffU; /* 31 bits */ 07255 i->dowmask = 0x7f; /* 7 bits */ 07256 /* on each call, use strsep() to move info to the next argument */ 07257 get_timerange(i, strsep(&info, "|,")); 07258 if (info) 07259 i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week"); 07260 if (info) 07261 i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day"); 07262 if (info) 07263 i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month"); 07264 return 1; 07265 }
| int ast_canmatch_extension | ( | struct ast_channel * | c, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority, | |||
| const char * | callerid | |||
| ) |
Looks for a valid matching extension.
| c | not really important | |
| context | context to serach within | |
| exten | extension to check | |
| priority | priority of extension path | |
| callerid | callerid of extension being searched for |
Definition at line 4495 of file pbx.c.
References E_CANMATCH, and pbx_extension_helper().
Referenced by __analog_ss_thread(), analog_ss_thread(), background_detect_exec(), cb_events(), do_immediate_setup(), dp_lookup(), dundi_lookup_local(), get_also_info(), get_destination(), handle_link_data(), handle_link_phone_dtmf(), leave_voicemail(), local_dtmf_helper(), loopback_canmatch(), mgcp_ss(), phone_check_exception(), skinny_ss(), and valid_exit().
04496 { 04497 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0); 04498 }
Change hint for an extension.
Definition at line 4388 of file pbx.c.
References AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_hint::exten.
Referenced by add_pri_lockopt().
04389 { 04390 struct ast_hint *hint; 04391 int res = -1; 04392 04393 AST_RWLIST_WRLOCK(&hints); 04394 AST_RWLIST_TRAVERSE(&hints, hint, list) { 04395 if (hint->exten == oe) { 04396 hint->exten = ne; 04397 res = 0; 04398 break; 04399 } 04400 } 04401 AST_RWLIST_UNLOCK(&hints); 04402 04403 return res; 04404 }
| int ast_check_timing | ( | const struct ast_timing * | i | ) |
Evaluate a pre-constructed bitmap as to whether the current time falls within the range specified.
| i | Pointer to an ast_timing structure. |
| Returns | 1, if the time matches or 0, if the current time falls outside of the specified range. |
Definition at line 7267 of file pbx.c.
References ast_localtime(), ast_log(), ast_tvnow(), ast_timing::daymask, ast_timing::dowmask, LOG_WARNING, ast_timing::minmask, ast_timing::monthmask, ast_timing::timezone, ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, and ast_tm::tm_wday.
Referenced by iftime(), include_valid(), pbx_builtin_execiftime(), and pbx_builtin_gotoiftime().
07268 { 07269 struct ast_tm tm; 07270 struct timeval now = ast_tvnow(); 07271 07272 ast_localtime(&now, &tm, i->timezone); 07273 07274 /* If it's not the right month, return */ 07275 if (!(i->monthmask & (1 << tm.tm_mon))) 07276 return 0; 07277 07278 /* If it's not that time of the month.... */ 07279 /* Warning, tm_mday has range 1..31! */ 07280 if (!(i->daymask & (1 << (tm.tm_mday-1)))) 07281 return 0; 07282 07283 /* If it's not the right day of the week */ 07284 if (!(i->dowmask & (1 << tm.tm_wday))) 07285 return 0; 07286 07287 /* Sanity check the hour just to be safe */ 07288 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) { 07289 ast_log(LOG_WARNING, "Insane time...\n"); 07290 return 0; 07291 } 07292 07293 /* Now the tough part, we calculate if it fits 07294 in the right time based on min/hour */ 07295 if (!(i->minmask[tm.tm_hour * 2 + (tm.tm_min >= 30 ? 1 : 0)] & (1 << (tm.tm_min >= 30 ? tm.tm_min - 30 : tm.tm_min)))) 07296 return 0; 07297 07298 /* If we got this far, then we're good */ 07299 return 1; 07300 }
| char* ast_complete_applications | ( | const char * | line, | |
| const char * | word, | |||
| int | state | |||
| ) |
Command completion for the list of installed applications.
This can be called from a CLI command completion function that wants to complete from the list of available applications.
Definition at line 9915 of file pbx.c.
References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, and ast_app::name.
Referenced by handle_orig(), and handle_show_application().
09916 { 09917 struct ast_app *app = NULL; 09918 int which = 0; 09919 char *ret = NULL; 09920 size_t wordlen = strlen(word); 09921 09922 AST_RWLIST_RDLOCK(&apps); 09923 AST_RWLIST_TRAVERSE(&apps, app, list) { 09924 if (!strncasecmp(word, app->name, wordlen) && ++which > state) { 09925 ret = ast_strdup(app->name); 09926 break; 09927 } 09928 } 09929 AST_RWLIST_UNLOCK(&apps); 09930 09931 return ret; 09932 }
| int ast_context_add_ignorepat | ( | const char * | context, | |
| const char * | ignorepat, | |||
| const char * | registrar | |||
| ) |
Add an ignorepat.
| context | which context to add the ignorpattern to | |
| ignorepat | ignorepattern to set up for the extension | |
| registrar | registrar of the ignore pattern |
| 0 | on success | |
| -1 | on failure |
Definition at line 7502 of file pbx.c.
References ast_context_add_ignorepat2(), ast_unlock_contexts(), and find_context_locked().
Referenced by handle_cli_dialplan_add_ignorepat().
07503 { 07504 int ret = -1; 07505 struct ast_context *c = find_context_locked(context); 07506 07507 if (c) { 07508 ret = ast_context_add_ignorepat2(c, value, registrar); 07509 ast_unlock_contexts(); 07510 } 07511 return ret; 07512 }
| int ast_context_add_ignorepat2 | ( | struct ast_context * | con, | |
| const char * | value, | |||
| const char * | registrar | |||
| ) |
Definition at line 7514 of file pbx.c.
References ast_calloc, ast_unlock_context(), ast_wrlock_context(), errno, ast_context::ignorepats, ast_ignorepat::next, ast_ignorepat::pattern, and ast_ignorepat::registrar.
Referenced by ast_compile_ael2(), ast_context_add_ignorepat(), context_merge_incls_swits_igps_other_registrars(), and pbx_load_config().
07515 { 07516 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL; 07517 int length; 07518 char *pattern; 07519 length = sizeof(struct ast_ignorepat); 07520 length += strlen(value) + 1; 07521 if (!(ignorepat = ast_calloc(1, length))) 07522 return -1; 07523 /* The cast to char * is because we need to write the initial value. 07524 * The field is not supposed to be modified otherwise. Also, gcc 4.2 07525 * sees the cast as dereferencing a type-punned pointer and warns about 07526 * it. This is the workaround (we're telling gcc, yes, that's really 07527 * what we wanted to do). 07528 */ 07529 pattern = (char *) ignorepat->pattern; 07530 strcpy(pattern, value); 07531 ignorepat->next = NULL; 07532 ignorepat->registrar = registrar; 07533 ast_wrlock_context(con); 07534 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) { 07535 ignorepatl = ignorepatc; 07536 if (!strcasecmp(ignorepatc->pattern, value)) { 07537 /* Already there */ 07538 ast_unlock_context(con); 07539 errno = EEXIST; 07540 return -1; 07541 } 07542 } 07543 if (ignorepatl) 07544 ignorepatl->next = ignorepat; 07545 else 07546 con->ignorepats = ignorepat; 07547 ast_unlock_context(con); 07548 return 0; 07549 07550 }
| int ast_context_add_include | ( | const char * | context, | |
| const char * | include, | |||
| const char * | registrar | |||
| ) |
Add a context include.
| context | context to add include to | |
| include | new include to add | |
| registrar | who's registering it |
| 0 | on success | |
| -1 | on error |
Definition at line 7053 of file pbx.c.
References ast_context_add_include2(), ast_unlock_contexts(), and find_context_locked().
Referenced by handle_cli_dialplan_add_include().
07054 { 07055 int ret = -1; 07056 struct ast_context *c = find_context_locked(context); 07057 07058 if (c) { 07059 ret = ast_context_add_include2(c, include, registrar); 07060 ast_unlock_contexts(); 07061 } 07062 return ret; 07063 }
| int ast_context_add_include2 | ( | struct ast_context * | con, | |
| const char * | include, | |||
| const char * | registrar | |||
| ) |
Add a context include.
| con | context to add the include to | |
| include | include to add | |
| registrar | who registered the context |
| 0 | on success | |
| -1 | on failure |
Definition at line 7317 of file pbx.c.
References ast_build_timing(), ast_calloc, ast_destroy_timing(), ast_free, ast_get_context_name(), ast_unlock_context(), ast_verb, ast_wrlock_context(), errno, ast_include::hastime, ast_context::includes, ast_include::name, ast_include::next, ast_include::registrar, ast_include::rname, ast_include::stuff, and ast_include::timing.
Referenced by ast_compile_ael2(), ast_context_add_include(), context_merge_incls_swits_igps_other_registrars(), and pbx_load_config().
07319 { 07320 struct ast_include *new_include; 07321 char *c; 07322 struct ast_include *i, *il = NULL; /* include, include_last */ 07323 int length; 07324 char *p; 07325 07326 length = sizeof(struct ast_include); 07327 length += 2 * (strlen(value) + 1); 07328 07329 /* allocate new include structure ... */ 07330 if (!(new_include = ast_calloc(1, length))) 07331 return -1; 07332 /* Fill in this structure. Use 'p' for assignments, as the fields 07333 * in the structure are 'const char *' 07334 */ 07335 p = new_include->stuff; 07336 new_include->name = p; 07337 strcpy(p, value); 07338 p += strlen(value) + 1; 07339 new_include->rname = p; 07340 strcpy(p, value); 07341 /* Strip off timing info, and process if it is there */ 07342 if ( (c = strchr(p, ',')) ) { 07343 *c++ = '\0'; 07344 new_include->hastime = ast_build_timing(&(new_include->timing), c); 07345 } 07346 new_include->next = NULL; 07347 new_include->registrar = registrar; 07348 07349 ast_wrlock_context(con); 07350 07351 /* ... go to last include and check if context is already included too... */ 07352 for (i = con->includes; i; i = i->next) { 07353 if (!strcasecmp(i->name, new_include->name)) { 07354 ast_destroy_timing(&(new_include->timing)); 07355 ast_free(new_include); 07356 ast_unlock_context(con); 07357 errno = EEXIST; 07358 return -1; 07359 } 07360 il = i; 07361 } 07362 07363 /* ... include new context into context list, unlock, return */ 07364 if (il) 07365 il->next = new_include; 07366 else 07367 con->includes = new_include; 07368 ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con)); 07369 07370 ast_unlock_context(con); 07371 07372 return 0; 07373 }
| int ast_context_add_switch | ( | const char * | context, | |
| const char * | sw, | |||
| const char * | data, | |||
| int | eval, | |||
| const char * | registrar | |||
| ) |
Add a switch.
| context | context to which to add the switch | |
| sw | switch to add | |
| data | data to pass to switch | |
| eval | whether to evaluate variables when running switch | |
| registrar | whoever registered the switch |
| 0 | on success | |
| -1 | on failure |
Definition at line 7380 of file pbx.c.
References ast_context_add_switch2(), ast_unlock_contexts(), and find_context_locked().
07381 { 07382 int ret = -1; 07383 struct ast_context *c = find_context_locked(context); 07384 07385 if (c) { /* found, add switch to this context */ 07386 ret = ast_context_add_switch2(c, sw, data, eval, registrar); 07387 ast_unlock_contexts(); 07388 } 07389 return ret; 07390 }
| int ast_context_add_switch2 | ( | struct ast_context * | con, | |
| const char * | sw, | |||
| const char * | data, | |||
| int | eval, | |||
| const char * | registrar | |||
| ) |
Adds a switch (first param is a ast_context).
Definition at line 7399 of file pbx.c.
References ast_context::alts, ast_calloc, ast_free, ast_get_context_name(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_sw::data, errno, ast_sw::eval, ast_sw::name, ast_sw::registrar, and ast_sw::stuff.
Referenced by ast_compile_ael2(), ast_context_add_switch(), context_merge_incls_swits_igps_other_registrars(), lua_register_switches(), and pbx_load_config().
07401 { 07402 struct ast_sw *new_sw; 07403 struct ast_sw *i; 07404 int length; 07405 char *p; 07406 07407 length = sizeof(struct ast_sw); 07408 length += strlen(value) + 1; 07409 if (data) 07410 length += strlen(data); 07411 length++; 07412 07413 /* allocate new sw structure ... */ 07414 if (!(new_sw = ast_calloc(1, length))) 07415 return -1; 07416 /* ... fill in this structure ... */ 07417 p = new_sw->stuff; 07418 new_sw->name = p; 07419 strcpy(new_sw->name, value); 07420 p += strlen(value) + 1; 07421 new_sw->data = p; 07422 if (data) { 07423 strcpy(new_sw->data, data); 07424 p += strlen(data) + 1; 07425 } else { 07426 strcpy(new_sw->data, ""); 07427 p++; 07428 } 07429 new_sw->eval = eval; 07430 new_sw->registrar = registrar; 07431 07432 /* ... try to lock this context ... */ 07433 ast_wrlock_context(con); 07434 07435 /* ... go to last sw and check if context is already swd too... */ 07436 AST_LIST_TRAVERSE(&con->alts, i, list) { 07437 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) { 07438 ast_free(new_sw); 07439 ast_unlock_context(con); 07440 errno = EEXIST; 07441 return -1; 07442 } 07443 } 07444 07445 /* ... sw new context into context list, unlock, return */ 07446 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list); 07447 07448 ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); 07449 07450 ast_unlock_context(con); 07451 07452 return 0; 07453 }
| void ast_context_destroy | ( | struct ast_context * | con, | |
| const char * | registrar | |||
| ) |
Destroy a context (matches the specified context (or ANY context if NULL).
| con | context to destroy | |
| registrar | who registered it |
Definition at line 8702 of file pbx.c.
References __ast_context_destroy(), ast_unlock_contexts(), ast_wrlock_contexts(), contexts, and contexts_table.
Referenced by __unload_module(), cleanup_stale_contexts(), parkinglot_destroy(), sla_destroy(), and unload_module().
08703 { 08704 ast_wrlock_contexts(); 08705 __ast_context_destroy(contexts, contexts_table, con,registrar); 08706 ast_unlock_contexts(); 08707 }
| struct ast_context* ast_context_find | ( | const char * | name | ) | [read] |
Find a context.
| name | name of the context to find |
Definition at line 2454 of file pbx.c.
References ast_copy_string(), ast_hashtab_lookup(), ast_rdlock_contexts(), ast_unlock_contexts(), ast_walk_contexts(), contexts_table, ast_context::name, and fake_context::name.
Referenced by __unload_module(), _macro_exec(), ast_context_verify_includes(), ast_ignore_pattern(), cleanup_stale_contexts(), isexten_function_read(), load_config(), manage_parkinglot(), park_exec_full(), parkinglot_destroy(), register_exten(), register_peer_exten(), unload_module(), and unregister_exten().
02455 { 02456 struct ast_context *tmp = NULL; 02457 struct fake_context item; 02458 02459 ast_copy_string(item.name, name, sizeof(item.name)); 02460 02461 ast_rdlock_contexts(); 02462 if( contexts_table ) { 02463 tmp = ast_hashtab_lookup(contexts_table,&item); 02464 } else { 02465 while ( (tmp = ast_walk_contexts(tmp)) ) { 02466 if (!name || !strcasecmp(name, tmp->name)) { 02467 break; 02468 } 02469 } 02470 } 02471 ast_unlock_contexts(); 02472 return tmp; 02473 }
| struct ast_context* ast_context_find_or_create | ( | struct ast_context ** | extcontexts, | |
| struct ast_hashtab * | exttable, | |||
| const char * | name, | |||
| const char * | registrar | |||
| ) | [read] |
Register a new context or find an existing one.
| extcontexts | pointer to the ast_context structure pointer | |
| exttable | pointer to the hashtable that contains all the elements in extcontexts | |
| name | name of the new context | |
| registrar | registrar of the context |
This will first search for a context with your name. If it exists already, it will not create a new one. If it does not exist, it will create a new one with the given name and registrar.
Definition at line 6710 of file pbx.c.
References ast_calloc, ast_copy_string(), ast_debug, ast_hashtab_compare_contexts(), ast_hashtab_create(), ast_hashtab_hash_contexts(), ast_hashtab_insert_immediate(), ast_hashtab_insert_safe(), ast_hashtab_lookup(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), ast_log(), ast_mutex_init(), ast_rdlock_contexts(), ast_rwlock_init(), ast_strdup, ast_unlock_contexts(), ast_verb, ast_wrlock_contexts(), contexts, contexts_table, ast_context::ignorepats, ast_context::includes, local_contexts, ast_context::lock, LOG_ERROR, ast_context::macrolock, ast_context::name, fake_context::name, ast_context::next, ast_context::refcount, ast_context::registrar, ast_context::root, and ast_context::root_table.
Referenced by ast_compile_ael2(), build_parkinglot(), config_parse_variables(), context_merge(), load_config(), load_module(), lua_register_switches(), manage_parkinglot(), park_call_full(), pbx_load_config(), pbx_load_users(), reload_config(), set_config(), sla_build_station(), and sla_build_trunk().
06711 { 06712 struct ast_context *tmp, **local_contexts; 06713 struct fake_context search; 06714 int length = sizeof(struct ast_context) + strlen(name) + 1; 06715 06716 if (!contexts_table) { 06717 contexts_table = ast_hashtab_create(17, 06718 ast_hashtab_compare_contexts, 06719 ast_hashtab_resize_java, 06720 ast_hashtab_newsize_java, 06721 ast_hashtab_hash_contexts, 06722 0); 06723 } 06724 06725 ast_copy_string(search.name, name, sizeof(search.name)); 06726 if (!extcontexts) { 06727 ast_rdlock_contexts(); 06728 local_contexts = &contexts; 06729 tmp = ast_hashtab_lookup(contexts_table, &search); 06730 ast_unlock_contexts(); 06731 if (tmp) { 06732 tmp->refcount++; 06733 return tmp; 06734 } 06735 } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */ 06736 local_contexts = extcontexts; 06737 tmp = ast_hashtab_lookup(exttable, &search); 06738 if (tmp) { 06739 tmp->refcount++; 06740 return tmp; 06741 } 06742 } 06743 06744 if ((tmp = ast_calloc(1, length))) { 06745 ast_rwlock_init(&tmp->lock); 06746 ast_mutex_init(&tmp->macrolock); 06747 strcpy(tmp->name, name); 06748 tmp->root = NULL; 06749 tmp->root_table = NULL; 06750 tmp->registrar = ast_strdup(registrar); 06751 tmp->includes = NULL; 06752 tmp->ignorepats = NULL; 06753 tmp->refcount = 1; 06754 } else { 06755 ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name); 06756 return NULL; 06757 } 06758 06759 if (!extcontexts) { 06760 ast_wrlock_contexts(); 06761 tmp->next = *local_contexts; 06762 *local_contexts = tmp; 06763 ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */ 06764 ast_unlock_contexts(); 06765 ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar); 06766 ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar); 06767 } else { 06768 tmp->next = *local_contexts; 06769 if (exttable) 06770 ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */ 06771 06772 *local_contexts = tmp; 06773 ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar); 06774 ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar); 06775 } 06776 return tmp; 06777 }
| int ast_context_lockmacro | ( | const char * | context | ) |
locks the macrolock in the given given context
Definition at line 5314 of file pbx.c.
References ast_copy_string(), ast_hashtab_lookup(), ast_mutex_lock(), ast_rdlock_contexts(), ast_unlock_contexts(), contexts_table, ast_context::macrolock, and fake_context::name.
Referenced by _macro_exec().
05315 { 05316 struct ast_context *c = NULL; 05317 int ret = -1; 05318 struct fake_context item; 05319 05320 ast_rdlock_contexts(); 05321 05322 ast_copy_string(item.name, context, sizeof(item.name)); 05323 05324 c = ast_hashtab_lookup(contexts_table,&item); 05325 if (c) 05326 ret = 0; 05327 ast_unlock_contexts(); 05328 05329 /* if we found context, lock macrolock */ 05330 if (ret == 0) { 05331 ret = ast_mutex_lock(&c->macrolock); 05332 } 05333 05334 return ret; 05335 }
| int ast_context_remove_extension | ( | const char * | context, | |
| const char * | extension, | |||
| int | priority, | |||
| const char * | registrar | |||
| ) |
Simply remove extension from context.
| context | context to remove extension from | |
| extension | which extension to remove | |
| priority | priority of extension to remove (0 to remove all) | |
| callerid | NULL to remove all; non-NULL to match a single record per priority | |
| matchcid | non-zero to match callerid element (if non-NULL); 0 to match default case | |
| registrar | registrar of the extension |
| 0 | on success | |
| -1 | on failure |
Definition at line 5122 of file pbx.c.
References ast_context_remove_extension_callerid().
Referenced by destroy_station(), destroy_trunk(), register_peer_exten(), unregister_exten(), and UnregisterExtension().
05123 { 05124 return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar); 05125 }
| int ast_context_remove_extension2 | ( | struct ast_context * | con, | |
| const char * | extension, | |||
| int | priority, | |||
| const char * | registrar, | |||
| int | already_locked | |||
| ) |
This functionc locks given context, search for the right extension and fires out all peer in this extensions with given priority. If priority is set to 0, all peers are removed. After that, unlock context and return.
Definition at line 5149 of file pbx.c.
References ast_context_remove_extension_callerid2().
Referenced by load_config(), manage_parkinglot(), park_exec_full(), and unload_module().
05150 { 05151 return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked); 05152 }
| int ast_context_remove_extension_callerid | ( | const char * | context, | |
| const char * | extension, | |||
| int | priority, | |||
| const char * | callerid, | |||
| int | matchcallerid, | |||
| const char * | registrar | |||
| ) |
Definition at line 5127 of file pbx.c.
References ast_context_remove_extension_callerid2(), ast_unlock_contexts(), and find_context_locked().
Referenced by ast_context_remove_extension(), and handle_cli_dialplan_remove_extension().
05128 { 05129 int ret = -1; /* default error return */ 05130 struct ast_context *c = find_context_locked(context); 05131 05132 if (c) { /* ... remove extension ... */ 05133 ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcallerid, registrar, 1); 05134 ast_unlock_contexts(); 05135 } 05136 return ret; 05137 }
| int ast_context_remove_extension_callerid2 | ( | struct ast_context * | con, | |
| const char * | extension, | |||
| int | priority, | |||
| const char * | callerid, | |||
| int | matchcallerid, | |||
| const char * | registrar, | |||
| int | already_locked | |||
| ) |
Definition at line 5154 of file pbx.c.
References add_exten_to_pattern_tree(), ast_copy_string(), ast_hashtab_insert_immediate(), ast_hashtab_lookup(), ast_hashtab_remove_this_object(), ast_hashtab_size(), ast_log(), ast_strlen_zero(), ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_exten::cidmatch, match_char::deleted, destroy_exten(), match_char::exten, ast_exten::exten, ast_exten::label, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_exten::matchcid, ast_context::name, ast_exten::next, ast_context::pattern_tree, ast_exten::peer, ast_exten::peer_label_table, ast_exten::peer_table, ast_exten::priority, ast_exten::registrar, ast_context::root, ast_context::root_table, and match_char::x.
Referenced by __ast_context_destroy(), ast_context_remove_extension2(), and ast_context_remove_extension_callerid().
05155 { 05156 struct ast_exten *exten, *prev_exten = NULL; 05157 struct ast_exten *peer; 05158 struct ast_exten ex, *exten2, *exten3; 05159 char dummy_name[1024]; 05160 struct ast_exten *previous_peer = NULL; 05161 struct ast_exten *next_peer = NULL; 05162 int found = 0; 05163 05164 if (!already_locked) 05165 ast_wrlock_context(con); 05166 05167 /* Handle this is in the new world */ 05168 05169 /* FIXME For backwards compatibility, if callerid==NULL, then remove ALL 05170 * peers, not just those matching the callerid. */ 05171 #ifdef NEED_DEBUG 05172 ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar); 05173 #endif 05174 #ifdef CONTEXT_DEBUG 05175 check_contexts(__FILE__, __LINE__); 05176 #endif 05177 /* find this particular extension */ 05178 ex.exten = dummy_name; 05179 ex.matchcid = matchcallerid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */ 05180 ex.cidmatch = callerid; 05181 ast_copy_string(dummy_name, extension, sizeof(dummy_name)); 05182 exten = ast_hashtab_lookup(con->root_table, &ex); 05183 if (exten) { 05184 if (priority == 0) { 05185 exten2 = ast_hashtab_remove_this_object(con->root_table, exten); 05186 if (!exten2) 05187 ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name); 05188 if (con->pattern_tree) { 05189 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1); 05190 05191 if (x->exten) { /* this test for safety purposes */ 05192 x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */ 05193 x->exten = 0; /* get rid of what will become a bad pointer */ 05194 } else { 05195 ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n"); 05196 } 05197 } 05198 } else { 05199 ex.priority = priority; 05200 exten2 = ast_hashtab_lookup(exten->peer_table, &ex); 05201 if (exten2) { 05202 05203 if (exten2->label) { /* if this exten has a label, remove that, too */ 05204 exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2); 05205 if (!exten3) 05206 ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten); 05207 } 05208 05209 exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2); 05210 if (!exten3) 05211 ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten); 05212 if (exten2 == exten && exten2->peer) { 05213 exten2 = ast_hashtab_remove_this_object(con->root_table, exten); 05214 ast_hashtab_insert_immediate(con->root_table, exten2->peer); 05215 } 05216 if (ast_hashtab_size(exten->peer_table) == 0) { 05217 /* well, if the last priority of an exten is to be removed, 05218 then, the extension is removed, too! */ 05219 exten3 = ast_hashtab_remove_this_object(con->root_table, exten); 05220 if (!exten3) 05221 ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority); 05222 if (con->pattern_tree) { 05223 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1); 05224 if (x->exten) { /* this test for safety purposes */ 05225 x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */ 05226 x->exten = 0; /* get rid of what will become a bad pointer */ 05227 } 05228 } 05229 } 05230 } else { 05231 ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n", 05232 priority, exten->exten, con->name); 05233 } 05234 } 05235 } else { 05236 /* hmmm? this exten is not in this pattern tree? */ 05237 ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n", 05238 extension, con->name); 05239 } 05240 #ifdef NEED_DEBUG 05241 if (con->pattern_tree) { 05242 ast_log(LOG_NOTICE,"match char tree after exten removal:\n"); 05243 log_match_char_tree(con->pattern_tree, " "); 05244 } 05245 #endif 05246 05247 /* scan the extension list to find first matching extension-registrar */ 05248 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) { 05249 if (!strcmp(exten->exten, extension) && 05250 (!registrar || !strcmp(exten->registrar, registrar)) && 05251 (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch)))) 05252 break; 05253 } 05254 if (!exten) { 05255 /* we can't find right extension */ 05256 if (!already_locked) 05257 ast_unlock_context(con); 05258 return -1; 05259 } 05260 05261 /* scan the priority list to remove extension with exten->priority == priority */ 05262 for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next; 05263 peer && !strcmp(peer->exten, extension) && (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(peer->cidmatch) && !strcmp(peer->cidmatch,callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(peer->cidmatch))); 05264 peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) { 05265 if ((priority == 0 || peer->priority == priority) && 05266 (!callerid || !matchcallerid || (matchcallerid && !strcmp(peer->cidmatch, callerid))) && 05267 (!registrar || !strcmp(peer->registrar, registrar) )) { 05268 found = 1; 05269 05270 /* we are first priority extension? */ 05271 if (!previous_peer) { 05272 /* 05273 * We are first in the priority chain, so must update the extension chain. 05274 * The next node is either the next priority or the next extension 05275 */ 05276 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next; 05277 if (peer->peer) { 05278 /* move the peer_table and peer_label_table down to the next peer, if 05279 it is there */ 05280 peer->peer->peer_table = peer->peer_table; 05281 peer->peer->peer_label_table = peer->peer_label_table; 05282 peer->peer_table = NULL; 05283 peer->peer_label_table = NULL; 05284 } 05285 if (!prev_exten) { /* change the root... */ 05286 con->root = next_node; 05287 } else { 05288 prev_exten->next = next_node; /* unlink */ 05289 } 05290 if (peer->peer) { /* update the new head of the pri list */ 05291 peer->peer->next = peer->next; 05292 } 05293 } else { /* easy, we are not first priority in extension */ 05294 previous_peer->peer = peer->peer; 05295 } 05296 05297 /* now, free whole priority extension */ 05298 destroy_exten(peer); 05299 } else { 05300 previous_peer = peer; 05301 } 05302 } 05303 if (!already_locked) 05304 ast_unlock_context(con); 05305 return found ? 0 : -1; 05306 }
| int ast_context_remove_ignorepat | ( | const char * | context, | |
| const char * | ignorepat, | |||
| const char * | registrar | |||
| ) |
Definition at line 7459 of file pbx.c.
References ast_context_remove_ignorepat2(), ast_unlock_contexts(), and find_context_locked().
Referenced by handle_cli_dialplan_remove_ignorepat().
07460 { 07461 int ret = -1; 07462 struct ast_context *c = find_context_locked(context); 07463 07464 if (c) { 07465 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar); 07466 ast_unlock_contexts(); 07467 } 07468 return ret; 07469 }
| int ast_context_remove_ignorepat2 | ( | struct ast_context * | con, | |
| const char * | ignorepat, | |||
| const char * | registrar | |||
| ) |
Definition at line 7471 of file pbx.c.
References ast_free, ast_unlock_context(), ast_wrlock_context(), errno, ast_context::ignorepats, ast_ignorepat::next, ast_ignorepat::pattern, and ast_ignorepat::registrar.
Referenced by ast_context_remove_ignorepat().
07472 { 07473 struct ast_ignorepat *ip, *ipl = NULL; 07474 07475 ast_wrlock_context(con); 07476 07477 for (ip = con->ignorepats; ip; ip = ip->next) { 07478 if (!strcmp(ip->pattern, ignorepat) && 07479 (!registrar || (registrar == ip->registrar))) { 07480 if (ipl) { 07481 ipl->next = ip->next; 07482 ast_free(ip); 07483 } else { 07484 con->ignorepats = ip->next; 07485 ast_free(ip); 07486 } 07487 ast_unlock_context(con); 07488 return 0; 07489 } 07490 ipl = ip; 07491 } 07492 07493 ast_unlock_context(con); 07494 errno = EINVAL; 07495 return -1; 07496 }
| int ast_context_remove_include | ( | const char * | context, | |
| const char * | include, | |||
| const char * | registrar | |||
| ) |
Remove included contexts. This function locks contexts list by &conlist, search for the right context structure, leave context list locked and call ast_context_remove_include2 which removes include, unlock contexts list and return ...
Remove a context include.
Definition at line 5013 of file pbx.c.
References ast_context_remove_include2(), ast_unlock_contexts(), and find_context_locked().
Referenced by handle_cli_dialplan_remove_include().
05014 { 05015 int ret = -1; 05016 struct ast_context *c = find_context_locked(context); 05017 05018 if (c) { 05019 /* found, remove include from this context ... */ 05020 ret = ast_context_remove_include2(c, include, registrar); 05021 ast_unlock_contexts(); 05022 } 05023 return ret; 05024 }
| int ast_context_remove_include2 | ( | struct ast_context * | con, | |
| const char * | include, | |||
| const char * | registrar | |||
| ) |
Locks context, remove included contexts, unlocks context. When we call this function, &conlock lock must be locked, because when we giving *con argument, some process can remove/change this context and after that there can be segfault.
Removes an include by an ast_context structure.
| 0 | on success. | |
| -1 | on failure. |
Definition at line 5035 of file pbx.c.
References ast_destroy_timing(), ast_free, ast_get_context_name(), ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_context::includes, ast_include::name, ast_include::next, ast_include::registrar, and ast_include::timing.
Referenced by ast_context_remove_include().
05036 { 05037 struct ast_include *i, *pi = NULL; 05038 int ret = -1; 05039 05040 ast_wrlock_context(con); 05041 05042 /* find our include */ 05043 for (i = con->includes; i; pi = i, i = i->next) { 05044 if (!strcmp(i->name, include) && 05045 (!registrar || !strcmp(i->registrar, registrar))) { 05046 /* remove from list */ 05047 ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar); 05048 if (pi) 05049 pi->next = i->next; 05050 else 05051 con->includes = i->next; 05052 /* free include and return */ 05053 ast_destroy_timing(&(i->timing)); 05054 ast_free(i); 05055 ret = 0; 05056 break; 05057 } 05058 } 05059 05060 ast_unlock_context(con); 05061 05062 return ret; 05063 }
| int ast_context_remove_switch | ( | const char * | context, | |
| const char * | sw, | |||
| const char * | data, | |||
| const char * | registrar | |||
| ) |
Remove a switch.
Definition at line 5070 of file pbx.c.
References ast_context_remove_switch2(), ast_unlock_contexts(), and find_context_locked().
05071 { 05072 int ret = -1; /* default error return */ 05073 struct ast_context *c = find_context_locked(context); 05074 05075 if (c) { 05076 /* remove switch from this context ... */ 05077 ret = ast_context_remove_switch2(c, sw, data, registrar); 05078 ast_unlock_contexts(); 05079 } 05080 return ret; 05081 }
| int ast_context_remove_switch2 | ( | struct ast_context * | con, | |
| const char * | sw, | |||
| const char * | data, | |||
| const char * | registrar | |||
| ) |
This function locks given context, removes switch, unlock context and return.
Definition at line 5091 of file pbx.c.
References ast_context::alts, ast_free, ast_get_context_name(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_sw::data, ast_sw::name, and ast_sw::registrar.
Referenced by ast_context_remove_switch().
05092 { 05093 struct ast_sw *i; 05094 int ret = -1; 05095 05096 ast_wrlock_context(con); 05097 05098 /* walk switches */ 05099 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) { 05100 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 05101 (!registrar || !strcmp(i->registrar, registrar))) { 05102 /* found, remove from list */ 05103 ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar); 05104 AST_LIST_REMOVE_CURRENT(list); 05105 ast_free(i); /* free switch and return */ 05106 ret = 0; 05107 break; 05108 } 05109 } 05110 AST_LIST_TRAVERSE_SAFE_END; 05111 05112 ast_unlock_context(con); 05113 05114 return ret; 05115 }
| int ast_context_unlockmacro | ( | const char * | context | ) |
Unlocks the macrolock in the given context.
Definition at line 5342 of file pbx.c.
References ast_copy_string(), ast_hashtab_lookup(), ast_mutex_unlock(), ast_rdlock_contexts(), ast_unlock_contexts(), contexts_table, ast_context::macrolock, and fake_context::name.
Referenced by _macro_exec().
05343 { 05344 struct ast_context *c = NULL; 05345 int ret = -1; 05346 struct fake_context item; 05347 05348 ast_rdlock_contexts(); 05349 05350 ast_copy_string(item.name, context, sizeof(item.name)); 05351 05352 c = ast_hashtab_lookup(contexts_table,&item); 05353 if (c) 05354 ret = 0; 05355 ast_unlock_contexts(); 05356 05357 /* if we found context, unlock macrolock */ 05358 if (ret == 0) { 05359 ret = ast_mutex_unlock(&c->macrolock); 05360 } 05361 05362 return ret; 05363 }
| int ast_context_verify_includes | ( | struct ast_context * | con | ) |
Verifies includes in an ast_contect structure.
| con | context in which to verify the includes |
| 0 | if no problems found | |
| -1 | if there were any missing context |
Definition at line 9803 of file pbx.c.
References ast_context_find(), ast_get_context_name(), ast_log(), ast_walk_context_includes(), LOG_WARNING, and ast_include::rname.
Referenced by pbx_load_module().
09804 { 09805 struct ast_include *inc = NULL; 09806 int res = 0; 09807 09808 while ( (inc = ast_walk_context_includes(con, inc)) ) { 09809 if (ast_context_find(inc->rname)) 09810 continue; 09811 09812 res = -1; 09813 ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n", 09814 ast_get_context_name(con), inc->rname); 09815 break; 09816 } 09817 09818 return res; 09819 }
| struct ast_custom_function* ast_custom_function_find | ( | const char * | name | ) | [read] |
Definition at line 3269 of file pbx.c.
References ast_custom_function::acflist, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, and ast_custom_function::name.
Referenced by ast_func_read(), ast_func_read2(), ast_func_write(), config_curl(), destroy_curl(), handle_show_function(), op_func(), realtime_curl(), realtime_multi_curl(), require_curl(), store_curl(), update2_curl(), and update_curl().
03270 { 03271 struct ast_custom_function *acf = NULL; 03272 03273 AST_RWLIST_RDLOCK(&acf_root); 03274 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) { 03275 if (!strcmp(name, acf->name)) 03276 break; 03277 } 03278 AST_RWLIST_UNLOCK(&acf_root); 03279 03280 return acf; 03281 }
| int ast_custom_function_unregister | ( | struct ast_custom_function * | acf | ) |
Unregister a custom function.
Definition at line 3283 of file pbx.c.
References ast_custom_function::acflist, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, ast_verb, AST_XML_DOC, ast_custom_function::docsrc, and ast_custom_function::name.
Referenced by load_module(), reload(), and unload_module().
03284 { 03285 struct ast_custom_function *cur; 03286 03287 if (!acf) { 03288 return -1; 03289 } 03290 03291 AST_RWLIST_WRLOCK(&acf_root); 03292 if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) { 03293 #ifdef AST_XML_DOCS 03294 if (cur->docsrc == AST_XML_DOC) { 03295 ast_string_field_free_memory(acf); 03296 } 03297 #endif 03298 ast_verb(2, "Unregistered custom function %s\n", cur->name); 03299 } 03300 AST_RWLIST_UNLOCK(&acf_root); 03301 03302 return cur ? 0 : -1; 03303 }
| int ast_destroy_timing | ( | struct ast_timing * | i | ) |
Deallocates memory structures associated with a timing bitmap.
| i | Pointer to an ast_timing structure. |
| 0 | success | |
| non-zero | failure (number suitable to pass to |
Definition at line 7302 of file pbx.c.
References ast_free, and ast_timing::timezone.
Referenced by ast_context_add_include2(), ast_context_remove_include2(), iftime(), pbx_builtin_execiftime(), and pbx_builtin_gotoiftime().
07303 { 07304 if (i->timezone) { 07305 ast_free(i->timezone); 07306 i->timezone = NULL; 07307 } 07308 return 0; 07309 }
| enum ast_extension_states ast_devstate_to_extenstate | ( | enum ast_device_state | devstate | ) |
Map devstate to an extension state.
| [in] | device | state |
Definition at line 4086 of file pbx.c.
References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_TOTAL, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_EXTENSION_BUSY, AST_EXTENSION_INUSE, AST_EXTENSION_NOT_INUSE, AST_EXTENSION_ONHOLD, AST_EXTENSION_RINGING, and AST_EXTENSION_UNAVAILABLE.
Referenced by ast_extension_state2().
04087 { 04088 switch (devstate) { 04089 case AST_DEVICE_ONHOLD: 04090 return AST_EXTENSION_ONHOLD; 04091 case AST_DEVICE_BUSY: 04092 return AST_EXTENSION_BUSY; 04093 case AST_DEVICE_UNAVAILABLE: 04094 case AST_DEVICE_UNKNOWN: 04095 case AST_DEVICE_INVALID: 04096 return AST_EXTENSION_UNAVAILABLE; 04097 case AST_DEVICE_RINGINUSE: 04098 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING); 04099 case AST_DEVICE_RINGING: 04100 return AST_EXTENSION_RINGING; 04101 case AST_DEVICE_INUSE: 04102 return AST_EXTENSION_INUSE; 04103 case AST_DEVICE_NOT_INUSE: 04104 return AST_EXTENSION_NOT_INUSE; 04105 case AST_DEVICE_TOTAL: /* not a device state, included for completeness */ 04106 break; 04107 } 04108 04109 return AST_EXTENSION_NOT_INUSE; 04110 }
| int ast_exists_extension | ( | struct ast_channel * | c, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority, | |||
| const char * | callerid | |||
| ) |
Determine whether an extension exists.
| c | this is not important | |
| context | which context to look in | |
| exten | which extension to search for | |
| priority | priority of the action within the extension | |
| callerid | callerid to search for |
Definition at line 4480 of file pbx.c.
References E_MATCH, and pbx_extension_helper().
Referenced by __analog_ss_thread(), __ast_goto_if_exists(), __ast_pbx_run(), _macro_exec(), acf_isexten_exec(), analog_ss_thread(), answer_call(), ast_app_dtget(), ast_bridge_call(), ast_pbx_outgoing_exten(), builtin_atxfer(), builtin_blindtransfer(), cb_events(), change_t38_state(), cli_console_dial(), conf_run(), console_dial(), console_transfer(), dahdi_handle_dtmfup(), dial_exec_full(), disa_exec(), dp_lookup(), dundi_lookup_local(), get_also_info(), get_destination(), get_refer_info(), gosub_exec(), handle_gosub(), handle_link_data(), handle_link_phone_dtmf(), handle_stimulus_message(), isexten_function_read(), leave_voicemail(), local_alloc(), local_call(), local_devicestate(), local_dtmf_helper(), loopback_exists(), metermaidstate(), mgcp_ss(), minivm_greet_exec(), misdn_overlap_dial_task(), my_handle_dtmfup(), park_space_reserve(), parkandannounce_exec(), pbx_builtin_waitexten(), phone_check_exception(), privacy_exec(), process_ast_dsp(), readexten_exec(), register_peer_exten(), rpt_exec(), show_debug_helper(), skinny_ss(), socket_process(), and waitstream_core().
04481 { 04482 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0); 04483 }
| int ast_explicit_goto | ( | struct ast_channel * | chan, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority | |||
| ) |
Definition at line 7606 of file pbx.c.
References ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_FLAG_IN_AUTOLOOP, ast_strlen_zero(), ast_test_flag, ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by __ast_goto_if_exists(), ast_async_goto(), builtin_atxfer(), disa_exec(), do_bridge_masquerade(), handle_setpriority(), pbx_parseable_goto(), and return_exec().
07607 { 07608 if (!chan) 07609 return -1; 07610 07611 ast_channel_lock(chan); 07612 07613 if (!ast_strlen_zero(context)) 07614 ast_copy_string(chan->context, context, sizeof(chan->context)); 07615 if (!ast_strlen_zero(exten)) 07616 ast_copy_string(chan->exten, exten, sizeof(chan->exten)); 07617 if (priority > -1) { 07618 chan->priority = priority; 07619 /* see flag description in channel.h for explanation */ 07620 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP)) 07621 chan->priority--; 07622 } 07623 07624 ast_channel_unlock(chan); 07625 07626 return 0; 07627 }
| int ast_extension_close | ( | const char * | pattern, | |
| const char * | data, | |||
| int | needmore | |||
| ) |
Definition at line 2431 of file pbx.c.
References ast_log(), E_CANMATCH, E_MATCHMORE, extension_match_core(), and LOG_WARNING.
Referenced by lua_find_extension(), and realtime_switch_common().
02432 { 02433 if (needmore != E_MATCHMORE && needmore != E_CANMATCH) 02434 ast_log(LOG_WARNING, "invalid argument %d\n", needmore); 02435 return extension_match_core(pattern, data, needmore); 02436 }
| int ast_extension_cmp | ( | const char * | a, | |
| const char * | b | |||
| ) |
Determine if one extension should match before another.
Checks whether or extension a should match before extension b
| 0 | if the two extensions have equal matching priority | |
| 1 | on a > b | |
| -1 | on a < b |
Definition at line 2233 of file pbx.c.
References ext_cmp().
Referenced by lua_extension_cmp().
02234 { 02235 return ext_cmp(a, b); 02236 }
| int ast_extension_match | ( | const char * | pattern, | |
| const char * | extension | |||
| ) |
Determine if a given extension matches a given pattern (in NXX format).
Checks whether or not the given extension matches the given pattern.
| 1 | on match | |
| 0 | on failure |
Definition at line 2426 of file pbx.c.
References E_MATCH, and extension_match_core().
Referenced by ast_ignore_pattern(), do_say(), find_matching_priority(), load_module(), loopback_canmatch(), loopback_exists(), loopback_matchmore(), lua_find_extension(), manager_show_dialplan_helper(), matchcid(), misdn_cfg_is_msn_valid(), realtime_switch_common(), reload(), and show_dialplan_helper().
02427 { 02428 return extension_match_core(pattern, data, E_MATCH); 02429 }
| int ast_extension_state | ( | struct ast_channel * | c, | |
| const char * | context, | |||
| const char * | exten | |||
| ) |
Check extension state for an extension by using hint.
Uses hint and devicestate callback to get the state of an extension.
Definition at line 4148 of file pbx.c.
References ast_extension_state2(), and ast_hint_extension().
Referenced by action_extensionstate(), extstate_read(), and handle_request_subscribe().
04149 { 04150 struct ast_exten *e; 04151 04152 if (!(e = ast_hint_extension(c, context, exten))) { /* Do we have a hint for this extension ? */ 04153 return -1; /* No hint, return -1 */ 04154 } 04155 04156 return ast_extension_state2(e); /* Check all devices in the hint */ 04157 }
| static int ast_extension_state2 | ( | struct ast_exten * | e | ) | [static] |
Check state of extension by using hints.
Definition at line 4113 of file pbx.c.
References ast_devstate_aggregate_add(), ast_devstate_aggregate_init(), ast_devstate_aggregate_result(), ast_devstate_to_extenstate(), ast_get_extension_app(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), extensionstate_buf, and strsep().
Referenced by ast_add_hint_nolock(), ast_extension_state(), and handle_statechange().
04114 { 04115 struct ast_str *hint = ast_str_thread_get(&extensionstate_buf, 16); 04116 char *cur, *rest; 04117 struct ast_devstate_aggregate agg; 04118 04119 if (!e) 04120 return -1; 04121 04122 ast_devstate_aggregate_init(&agg); 04123 04124 ast_str_set(&hint, 0, "%s", ast_get_extension_app(e)); 04125 04126 rest = ast_str_buffer(hint); /* One or more devices separated with a & character */ 04127 04128 while ( (cur = strsep(&rest, "&")) ) { 04129 ast_devstate_aggregate_add(&agg, ast_device_state(cur)); 04130 } 04131 04132 return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg)); 04133 }
| const char* ast_extension_state2str | ( | int | extension_state | ) |
Return extension_state as string.
Return string representation of the state of an extension.
Definition at line 4136 of file pbx.c.
References ARRAY_LEN, extension_states, and cfextension_states::text.
Referenced by cb_extensionstate(), handle_request_subscribe(), handle_show_hint(), handle_show_hints(), and show_channels_cb().
04137 { 04138 int i; 04139 04140 for (i = 0; (i < ARRAY_LEN(extension_states)); i++) { 04141 if (extension_states[i].extension_state == extension_state) 04142 return extension_states[i].text; 04143 } 04144 return "Unknown"; 04145 }
| int ast_extension_state_add | ( | const char * | context, | |
| const char * | exten, | |||
| ast_state_cb_type | callback, | |||
| void * | data | |||
| ) |
Add watcher for extension states.
Registers a state change callback.
Definition at line 4212 of file pbx.c.
References ast_exten::app, ast_add_extension(), ast_calloc, ast_free_ptr, ast_hint_extension(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_state_cb::callback, ast_hint::callbacks, ast_exten::cidmatch, ast_exten::data, ast_state_cb::data, ast_hint::exten, ast_exten::exten, ast_state_cb::id, ast_exten::label, ast_context::name, ast_exten::parent, ast_exten::priority, ast_exten::registrar, and stateid.
Referenced by __init_manager(), handle_request_subscribe(), and skinny_register().
04214 { 04215 struct ast_hint *hint; 04216 struct ast_state_cb *cblist; 04217 struct ast_exten *e; 04218 04219 /* If there's no context and extension: add callback to statecbs list */ 04220 if (!context && !exten) { 04221 AST_RWLIST_WRLOCK(&hints); 04222 04223 AST_LIST_TRAVERSE(&statecbs, cblist, entry) { 04224 if (cblist->callback == callback) { 04225 cblist->data = data; 04226 AST_RWLIST_UNLOCK(&hints); 04227 return 0; 04228 } 04229 } 04230 04231 /* Now insert the callback */ 04232 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) { 04233 AST_RWLIST_UNLOCK(&hints); 04234 return -1; 04235 } 04236 cblist->id = 0; 04237 cblist->callback = callback; 04238 cblist->data = data; 04239 04240 AST_LIST_INSERT_HEAD(&statecbs, cblist, entry); 04241 04242 AST_RWLIST_UNLOCK(&hints); 04243 04244 return 0; 04245 } 04246 04247 if (!context || !exten) 04248 return -1; 04249 04250 /* This callback type is for only one hint, so get the hint */ 04251 e = ast_hint_extension(NULL, context, exten); 04252 if (!e) { 04253 return -1; 04254 } 04255 04256 /* If this is a pattern, dynamically create a new extension for this 04257 * particular match. Note that this will only happen once for each 04258 * individual extension, because the pattern will no longer match first. 04259 */ 04260 if (e->exten[0] == '_') { 04261 ast_add_extension(e->parent->name, 0, exten, e->priority, e->label, 04262 e->cidmatch, e->app, ast_strdup(e->data), ast_free_ptr, 04263 e->registrar); 04264 e = ast_hint_extension(NULL, context, exten); 04265 if (!e || e->exten[0] == '_') { 04266 return -1; 04267 } 04268 } 04269 04270 /* Find the hint in the list of hints */ 04271 AST_RWLIST_WRLOCK(&hints); 04272 04273 AST_RWLIST_TRAVERSE(&hints, hint, list) { 04274 if (hint->exten == e) 04275 break; 04276 } 04277 04278 if (!hint) { 04279 /* We have no hint, sorry */ 04280 AST_RWLIST_UNLOCK(&hints); 04281 return -1; 04282 } 04283 04284 /* Now insert the callback in the callback list */ 04285 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) { 04286 AST_RWLIST_UNLOCK(&hints); 04287 return -1; 04288 } 04289 04290 cblist->id = stateid++; /* Unique ID for this callback */ 04291 cblist->callback = callback; /* Pointer to callback routine */ 04292 cblist->data = data; /* Data for the callback */ 04293 04294 AST_LIST_INSERT_HEAD(&hint->callbacks, cblist, entry); 04295 04296 AST_RWLIST_UNLOCK(&hints); 04297 04298 return cblist->id; 04299 }
| int ast_extension_state_del | ( | int | id, | |
| ast_state_cb_type | callback | |||
| ) |
Remove a watcher from the callback list.
Deletes a registered state change callback by ID.
Definition at line 4302 of file pbx.c.
References ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_state_cb::callback, ast_hint::callbacks, and ast_state_cb::id.
Referenced by dialog_unlink_all(), handle_request_subscribe(), and skinny_unregister().
04303 { 04304 struct ast_state_cb *p_cur = NULL; 04305 int ret = -1; 04306 04307 if (!id && !callback) 04308 return -1; 04309 04310 AST_RWLIST_WRLOCK(&hints); 04311 04312 if (!id) { /* id == 0 is a callback without extension */ 04313 AST_LIST_TRAVERSE_SAFE_BEGIN(&statecbs, p_cur, entry) { 04314 if (p_cur->callback == callback) { 04315 AST_LIST_REMOVE_CURRENT(entry); 04316 break; 04317 } 04318 } 04319 AST_LIST_TRAVERSE_SAFE_END; 04320 } else { /* callback with extension, find the callback based on ID */ 04321 struct ast_hint *hint; 04322 AST_RWLIST_TRAVERSE(&hints, hint, list) { 04323 AST_LIST_TRAVERSE_SAFE_BEGIN(&hint->callbacks, p_cur, entry) { 04324 if (p_cur->id == id) { 04325 AST_LIST_REMOVE_CURRENT(entry); 04326 break; 04327 } 04328 } 04329 AST_LIST_TRAVERSE_SAFE_END; 04330 04331 if (p_cur) 04332 break; 04333 } 04334 } 04335 04336 if (p_cur) { 04337 ast_free(p_cur); 04338 } 04339 04340 AST_RWLIST_UNLOCK(&hints); 04341 04342 return ret; 04343 }
| int ast_findlabel_extension | ( | struct ast_channel * | c, | |
| const char * | context, | |||
| const char * | exten, | |||
| const char * | label, | |||
| const char * | callerid | |||
| ) |
Find the priority of an extension that has the specified label.
| c | this is not important | |
| context | which context to look in | |
| exten | which extension to search for | |
| label | label of the action within the extension to match to priority | |
| callerid | callerid to search for |
| the | priority which matches the given label in the extension | |
| -1 | if not found. |
Definition at line 4485 of file pbx.c.
References E_FINDLABEL, and pbx_extension_helper().
Referenced by action_originate(), action_redirect(), handle_gosub(), handle_setpriority(), isexten_function_read(), and pbx_parseable_goto().
04486 { 04487 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0); 04488 }
| int ast_findlabel_extension2 | ( | struct ast_channel * | c, | |
| struct ast_context * | con, | |||
| const char * | exten, | |||
| const char * | label, | |||
| const char * | callerid | |||
| ) |
Find the priority of an extension that has the specified label.
This function is the same as ast_findlabel_extension, except that it accepts a pointer to an ast_context structure to specify the context instead of the name of the context. Otherwise, the functions behave the same.
Definition at line 4490 of file pbx.c.
References E_FINDLABEL, and pbx_extension_helper().
Referenced by pbx_load_config().
04491 { 04492 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0); 04493 }
| int ast_func_read | ( | struct ast_channel * | chan, | |
| const char * | function, | |||
| char * | workspace, | |||
| size_t | len | |||
| ) |
executes a read operation on a function
| chan | Channel to execute on | |
| function | Data containing the function call string (will be modified) | |
| workspace | A pointer to safe memory to use for a return value | |
| len | the number of bytes in workspace |
| 0 | success | |
| non-zero | failure |
Definition at line 3427 of file pbx.c.
References __ast_module_user_add(), __ast_module_user_remove(), ast_copy_string(), ast_custom_function_find(), ast_free, ast_log(), ast_str_buffer(), ast_str_create(), ast_str_size(), ast_strdupa, copy(), func_args(), LOG_ERROR, ast_custom_function::mod, ast_custom_function::read, ast_custom_function::read2, and str.
Referenced by action_getvar(), action_status(), handle_getvariable(), lua_get_variable_value(), and pbx_substitute_variables_helper_full().
03428 { 03429 char *copy = ast_strdupa(function); 03430 char *args = func_args(copy); 03431 struct ast_custom_function *acfptr = ast_custom_function_find(copy); 03432 int res; 03433 struct ast_module_user *u = NULL; 03434 03435 if (acfptr == NULL) { 03436 ast_log(LOG_ERROR, "Function %s not registered\n", copy); 03437 } else if (!acfptr->read && !acfptr->read2) { 03438 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy); 03439 } else if (acfptr->read) { 03440 if (acfptr->mod) { 03441 u = __ast_module_user_add(acfptr->mod, chan); 03442 } 03443 res = acfptr->read(chan, copy, args, workspace, len); 03444 if (acfptr->mod && u) { 03445 __ast_module_user_remove(acfptr->mod, u); 03446 } 03447 return res; 03448 } else { 03449 struct ast_str *str = ast_str_create(16); 03450 if (acfptr->mod) { 03451 u = __ast_module_user_add(acfptr->mod, chan); 03452 } 03453 res = acfptr->read2(chan, copy, args, &str, 0); 03454 if (acfptr->mod && u) { 03455 __ast_module_user_remove(acfptr->mod, u); 03456 } 03457 ast_copy_string(workspace, ast_str_buffer(str), len > ast_str_size(str) ? ast_str_size(str) : len); 03458 ast_free(str); 03459 return res; 03460 } 03461 return -1; 03462 }
| int ast_func_read2 | ( | struct ast_channel * | chan, | |
| const char * | function, | |||
| struct ast_str ** | str, | |||
| ssize_t | maxlen | |||
| ) |
executes a read operation on a function
| chan | Channel to execute on | |
| function | Data containing the function call string (will be modified) | |
| str | A dynamic string buffer into which to place the result. | |
| maxlen | <0 if the dynamic buffer should not grow; >0 if the dynamic buffer should be limited to that number of bytes; 0 if the dynamic buffer has no upper limit |
| 0 | success | |
| non-zero | failure |
Definition at line 3464 of file pbx.c.
References __ast_module_user_add(), __ast_module_user_remove(), ast_custom_function_find(), ast_log(), ast_str_buffer(), ast_str_make_space(), ast_str_reset(), ast_str_size(), ast_strdupa, copy(), func_args(), LOG_ERROR, maxsize, ast_custom_function::mod, ast_custom_function::read, ast_custom_function::read2, ast_custom_function::read_max, and VAR_BUF_SIZE.
Referenced by ast_str_substitute_variables_full().
03465 { 03466 char *copy = ast_strdupa(function); 03467 char *args = func_args(copy); 03468 struct ast_custom_function *acfptr = ast_custom_function_find(copy); 03469 int res; 03470 struct ast_module_user *u = NULL; 03471 03472 if (acfptr == NULL) { 03473 ast_log(LOG_ERROR, "Function %s not registered\n", copy); 03474 } else if (!acfptr->read && !acfptr->read2) { 03475 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy); 03476 } else { 03477 if (acfptr->mod) { 03478 u = __ast_module_user_add(acfptr->mod, chan); 03479 } 03480 if (acfptr->read2) { 03481 /* ast_str enabled */ 03482 ast_str_reset(*str); 03483 res = acfptr->read2(chan, copy, args, str, maxlen); 03484 } else { 03485 /* Legacy function pointer, allocate buffer for result */ 03486 int maxsize = ast_str_size(*str); 03487 if (maxlen > -1) { 03488 if (maxlen == 0) { 03489 if (acfptr->read_max) { 03490 maxsize = acfptr->read_max; 03491 } else { 03492 maxsize = VAR_BUF_SIZE; 03493 } 03494 } else { 03495 maxsize = maxlen; 03496 } 03497 ast_str_make_space(str, maxsize); 03498 } 03499 res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize); 03500 } 03501 if (acfptr->mod && u) { 03502 __ast_module_user_remove(acfptr->mod, u); 03503 } 03504 return res; 03505 } 03506 return -1; 03507 }
| int ast_func_write | ( | struct ast_channel * | chan, | |
| const char * | function, | |||
| const char * | value | |||
| ) |
executes a write operation on a function
| chan | Channel to execute on | |
| function | Data containing the function call string (will be modified) | |
| value | A value parameter to pass for writing |
| 0 | success | |
| non-zero | failure |
Definition at line 3509 of file pbx.c.
References __ast_module_user_add(), __ast_module_user_remove(), ast_custom_function_find(), ast_log(), ast_strdupa, copy(), func_args(), LOG_ERROR, ast_custom_function::mod, and ast_custom_function::write.
Referenced by conf_run(), pbx_builtin_pushvar_helper(), and pbx_builtin_setvar_helper().
03510 { 03511 char *copy = ast_strdupa(function); 03512 char *args = func_args(copy); 03513 struct ast_custom_function *acfptr = ast_custom_function_find(copy); 03514 03515 if (acfptr == NULL) 03516 ast_log(LOG_ERROR, "Function %s not registered\n", copy); 03517 else if (!acfptr->write) 03518 ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy); 03519 else { 03520 int res; 03521 struct ast_module_user *u = NULL; 03522 if (acfptr->mod) 03523 u = __ast_module_user_add(acfptr->mod, chan); 03524 res = acfptr->write(chan, copy, args, value); 03525 if (acfptr->mod && u) 03526 __ast_module_user_remove(acfptr->mod, u); 03527 return res; 03528 } 03529 03530 return -1; 03531 }
| const char* ast_get_context_name | ( | struct ast_context * | con | ) |
Definition at line 9655 of file pbx.c.
References ast_context::name.
Referenced by _macro_exec(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_remove_include2(), ast_context_remove_switch2(), ast_context_verify_includes(), complete_dialplan_add_extension(), complete_dialplan_add_ignorepat(), complete_dialplan_add_include(), complete_dialplan_remove_extension(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), complete_show_dialplan_context(), context_merge_incls_swits_igps_other_registrars(), dundi_precache_full(), find_matching_endwhile(), find_matching_priority(), handle_cli_dialplan_save(), handle_show_hint(), handle_show_hints(), manager_show_dialplan_helper(), show_debug_helper(), and show_dialplan_helper().
09656 { 09657 return con ? con->name : NULL; 09658 }
| const char* ast_get_context_registrar | ( | struct ast_context * | c | ) |
Definition at line 9693 of file pbx.c.
References ast_context::registrar.
Referenced by handle_cli_dialplan_save(), show_debug_helper(), and show_dialplan_helper().
09694 { 09695 return c ? c->registrar : NULL; 09696 }
| const char* ast_get_extension_app | ( | struct ast_exten * | e | ) |
Definition at line 9723 of file pbx.c.
References ast_exten::app.
Referenced by _macro_exec(), ast_add_hint_nolock(), ast_extension_state2(), ast_get_hint(), ast_str_get_hint(), find_matching_endwhile(), handle_cli_dialplan_save(), handle_show_hint(), handle_show_hints(), handle_statechange(), manager_show_dialplan_helper(), and print_ext().
09724 { 09725 return e ? e->app : NULL; 09726 }
| void* ast_get_extension_app_data | ( | struct ast_exten * | e | ) |
Definition at line 9728 of file pbx.c.
References ast_exten::data.
Referenced by _macro_exec(), ast_get_hint(), ast_str_get_hint(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and print_ext().
09729 { 09730 return e ? e->data : NULL; 09731 }
| const char* ast_get_extension_cidmatch | ( | struct ast_exten * | e | ) |
Definition at line 9718 of file pbx.c.
References ast_exten::cidmatch.
Referenced by complete_dialplan_remove_extension(), find_matching_priority(), and handle_cli_dialplan_save().
09719 { 09720 return e ? e->cidmatch : NULL; 09721 }
| struct ast_context* ast_get_extension_context | ( | struct ast_exten * | exten | ) | [read] |
Definition at line 9660 of file pbx.c.
References ast_exten::parent.
Referenced by handle_show_hint(), and handle_show_hints().
09661 { 09662 return exten ? exten->parent : NULL; 09663 }
| const char* ast_get_extension_label | ( | struct ast_exten * | exten | ) |
Definition at line 9670 of file pbx.c.
References ast_exten::label.
Referenced by handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().
09671 { 09672 return exten ? exten->label : NULL; 09673 }
| int ast_get_extension_matchcid | ( | struct ast_exten * | e | ) |
Definition at line 9713 of file pbx.c.
References ast_exten::matchcid.
Referenced by complete_dialplan_remove_extension(), find_matching_priority(), and handle_cli_dialplan_save().
09714 { 09715 return e ? e->matchcid : 0; 09716 }
| const char* ast_get_extension_name | ( | struct ast_exten * | exten | ) |
Definition at line 9665 of file pbx.c.
References ast_exten::exten.
Referenced by ast_add_hint_nolock(), complete_core_show_hint(), complete_dialplan_remove_extension(), dundi_precache_full(), find_matching_priority(), handle_cli_dialplan_save(), handle_show_hint(), handle_show_hints(), manager_show_dialplan_helper(), and show_dialplan_helper().
09666 { 09667 return exten ? exten->exten : NULL; 09668 }
| int ast_get_extension_priority | ( | struct ast_exten * | exten | ) |
Definition at line 9685 of file pbx.c.
References ast_exten::priority.
Referenced by complete_dialplan_remove_extension(), find_matching_priority(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and print_ext().
09686 { 09687 return exten ? exten->priority : -1; 09688 }
| const char* ast_get_extension_registrar | ( | struct ast_exten * | e | ) |
Definition at line 9698 of file pbx.c.
References ast_exten::registrar.
Referenced by handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().
09699 { 09700 return e ? e->registrar : NULL; 09701 }
| int ast_get_hint | ( | char * | hint, | |
| int | hintsize, | |||
| char * | name, | |||
| int | namesize, | |||
| struct ast_channel * | c, | |||
| const char * | context, | |||
| const char * | exten | |||
| ) |
Get hint for channel.
If an extension hint exists, return non-zero.
Definition at line 4442 of file pbx.c.
References ast_copy_string(), ast_get_extension_app(), ast_get_extension_app_data(), and ast_hint_extension().
Referenced by action_extensionstate(), get_cid_name(), get_destination(), hint_read(), manager_state_cb(), skinny_extensionstate_cb(), and state_notify_build_xml().
04443 { 04444 struct ast_exten *e = ast_hint_extension(c, context, exten); 04445 04446 if (e) { 04447 if (hint) 04448 ast_copy_string(hint, ast_get_extension_app(e), hintsize); 04449 if (name) { 04450 const char *tmp = ast_get_extension_app_data(e); 04451 if (tmp) 04452 ast_copy_string(name, tmp, namesize); 04453 } 04454 return -1; 04455 } 04456 return 0; 04457 }
| const char* ast_get_ignorepat_name | ( | struct ast_ignorepat * | ip | ) |
Definition at line 9680 of file pbx.c.
References ast_ignorepat::pattern.
Referenced by complete_dialplan_remove_ignorepat(), context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), lookup_c_ip(), manager_show_dialplan_helper(), and show_dialplan_helper().
09681 { 09682 return ip ? ip->pattern : NULL; 09683 }
| const char* ast_get_ignorepat_registrar | ( | struct ast_ignorepat * | ip | ) |
Definition at line 9708 of file pbx.c.
References ast_ignorepat::registrar.
Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().
09709 { 09710 return ip ? ip->registrar : NULL; 09711 }
| const char* ast_get_include_name | ( | struct ast_include * | inc | ) |
Definition at line 9675 of file pbx.c.
References ast_include::name.
Referenced by complete_dialplan_remove_include(), context_merge_incls_swits_igps_other_registrars(), find_matching_priority(), handle_cli_dialplan_save(), lookup_ci(), manager_show_dialplan_helper(), and show_dialplan_helper().
09676 { 09677 return inc ? inc->name : NULL; 09678 }
| const char* ast_get_include_registrar | ( | struct ast_include * | i | ) |
Definition at line 9703 of file pbx.c.
References ast_include::registrar.
Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().
09704 { 09705 return i ? i->registrar : NULL; 09706 }
| const char* ast_get_switch_data | ( | struct ast_sw * | sw | ) |
Definition at line 9738 of file pbx.c.
References ast_sw::data.
Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().
09739 { 09740 return sw ? sw->data : NULL; 09741 }
| int ast_get_switch_eval | ( | struct ast_sw * | sw | ) |
Definition at line 9743 of file pbx.c.
References ast_sw::eval.
Referenced by context_merge_incls_swits_igps_other_registrars().
09744 { 09745 return sw->eval; 09746 }
| const char* ast_get_switch_name | ( | struct ast_sw * | sw | ) |
Definition at line 9733 of file pbx.c.
References ast_sw::name.
Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().
09734 { 09735 return sw ? sw->name : NULL; 09736 }
| const char* ast_get_switch_registrar | ( | struct ast_sw * | sw | ) |
Definition at line 9748 of file pbx.c.
References ast_sw::registrar.
Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().
09749 { 09750 return sw ? sw->registrar : NULL; 09751 }
| int ast_goto_if_exists | ( | struct ast_channel * | chan, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority | |||
| ) |
Definition at line 9842 of file pbx.c.
References __ast_goto_if_exists().
Referenced by background_detect_exec(), channel_spy(), common_exec(), conf_run(), dial_exec_full(), goto_exten(), onedigit_goto(), priority_jump(), select_entry(), and valid_exit().
09843 { 09844 return __ast_goto_if_exists(chan, context, exten, priority, 0); 09845 }
| int ast_hashtab_compare_contexts | ( | const void * | ah_a, | |
| const void * | ah_b | |||
| ) |
hashtable functions for contexts
Definition at line 1013 of file pbx.c.
References ast_context::name.
Referenced by ast_context_find_or_create(), lua_register_switches(), and pbx_load_module().
01014 { 01015 const struct ast_context *ac = ah_a; 01016 const struct ast_context *bc = ah_b; 01017 if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */ 01018 return 1; 01019 /* assume context names are registered in a string table! */ 01020 return strcmp(ac->name, bc->name); 01021 }
| unsigned int ast_hashtab_hash_contexts | ( | const void * | obj | ) |
Definition at line 1056 of file pbx.c.
References ast_hashtab_hash_string(), and ast_context::name.
Referenced by ast_context_find_or_create(), lua_register_switches(), and pbx_load_module().
01057 { 01058 const struct ast_context *ac = obj; 01059 return ast_hashtab_hash_string(ac->name); 01060 }
| static struct ast_exten* ast_hint_extension | ( | struct ast_channel * | c, | |
| const char * | context, | |||
| const char * | exten | |||
| ) | [static, read] |
Definition at line 4077 of file pbx.c.
References ast_hint_extension_nolock(), ast_rdlock_contexts(), and ast_unlock_contexts().
Referenced by ast_extension_state(), ast_extension_state_add(), ast_get_hint(), and ast_str_get_hint().
04078 { 04079 struct ast_exten *e; 04080 ast_rdlock_contexts(); 04081 e = ast_hint_extension_nolock(c, context, exten); 04082 ast_unlock_contexts(); 04083 return e; 04084 }
| static struct ast_exten* ast_hint_extension_nolock | ( | struct ast_channel * | c, | |
| const char * | context, | |||
| const char * | exten | |||
| ) | [static, read] |
Find hint for given extension in context.
Definition at line 4071 of file pbx.c.
References E_MATCH, pbx_find_extension(), PRIORITY_HINT, and pbx_find_info::stacklen.
Referenced by ast_hint_extension(), and ast_merge_contexts_and_delete().
04072 { 04073 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */ 04074 return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH); 04075 }
| int ast_ignore_pattern | ( | const char * | context, | |
| const char * | pattern | |||
| ) |
Checks to see if a number should be ignored.
| context | context to search within | |
| pattern | to check whether it should be ignored or not |
| 0 | if the pattern should not be ignored | |
| non-zero | if the pattern should be ignored |
Definition at line 7552 of file pbx.c.
References ast_context_find(), ast_extension_match(), ast_context::ignorepats, ast_ignorepat::next, and ast_ignorepat::pattern.
Referenced by __analog_ss_thread(), analog_ss_thread(), ast_app_dtget(), disa_exec(), dp_lookup(), dundi_lookup_local(), handle_enbloc_call_message(), handle_soft_key_event_message(), handle_stimulus_message(), mgcp_ss(), and skinny_ss().
07553 { 07554 struct ast_context *con = ast_context_find(context); 07555 if (con) { 07556 struct ast_ignorepat *pat; 07557 for (pat = con->ignorepats; pat; pat = pat->next) { 07558 if (ast_extension_match(pat->pattern, pattern)) 07559 return 1; 07560 } 07561 } 07562 07563 return 0; 07564 }
| int ast_matchmore_extension | ( | struct ast_channel * | c, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority, | |||
| const char * | callerid | |||
| ) |
Looks to see if adding anything to this extension might match something. (exists ^ canmatch).
| c | not really important XXX | |
| context | context to serach within | |
| exten | extension to check | |
| priority | priority of extension path | |
| callerid | callerid of extension being searched for |
Definition at line 4500 of file pbx.c.
References E_MATCHMORE, and pbx_extension_helper().
Referenced by __analog_ss_thread(), __ast_pbx_run(), analog_ss_thread(), ast_app_dtget(), collect_digits(), disa_exec(), dp_lookup(), dundi_lookup_local(), handle_link_data(), handle_link_phone_dtmf(), local_dtmf_helper(), loopback_matchmore(), mgcp_ss(), pbx_builtin_background(), readexten_exec(), and skinny_ss().
04501 { 04502 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0); 04503 }
| void ast_merge_contexts_and_delete | ( | struct ast_context ** | extcontexts, | |
| struct ast_hashtab * | exttable, | |||
| const char * | registrar | |||
| ) |
Merge the temporary contexts into a global contexts list and delete from the global list the ones that are being added.
| extcontexts | pointer to the ast_context structure | |
| exttable | pointer to the ast_hashtab structure that contains all the elements in extcontexts | |
| registrar | of the context; if it's set the routine will delete all contexts that belong to that registrar; if NULL only the contexts that are specified in extcontexts |
Definition at line 6909 of file pbx.c.
References __ast_internal_context_destroy(), ast_exten::app, ast_add_extension_nolock(), ast_calloc, AST_EXTENSION_REMOVED, ast_free, ast_free_ptr, ast_hashtab_destroy(), ast_hashtab_end_traversal(), ast_hashtab_next(), ast_hashtab_start_traversal(), ast_hint_extension_nolock(), AST_LIST_APPEND_LIST, AST_LIST_EMPTY, AST_LIST_HEAD_INIT_VALUE, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_rdlock_contexts(), AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_tvdiff_us(), ast_tvnow(), ast_unlock_contexts(), ast_verb, ast_wrlock_contexts(), ast_wrlock_contexts_version(), ast_state_cb::callback, ast_hint::callbacks, context_merge(), contexts, contexts_table, ast_state_cb::data, ast_exten::data, E_MATCH, ast_exten::exten, ast_hint::exten, ast_hint::laststate, LOG_WARNING, ast_context::name, ast_context::next, ast_sw::next, ast_exten::parent, pbx_find_extension(), PRIORITY_HINT, ast_context::registrar, and pbx_find_info::stacklen.
Referenced by lua_reload_extensions(), and pbx_load_module().
06910 { 06911 double ft; 06912 struct ast_context *tmp, *oldcontextslist; 06913 struct ast_hashtab *oldtable; 06914 struct store_hints store = AST_LIST_HEAD_INIT_VALUE; 06915 struct store_hint *this; 06916 struct ast_hint *hint; 06917 struct ast_exten *exten; 06918 int length; 06919 struct ast_state_cb *thiscb; 06920 struct ast_hashtab_iter *iter; 06921 06922 /* it is very important that this function hold the hint list lock _and_ the conlock 06923 during its operation; not only do we need to ensure that the list of contexts 06924 and extensions does not change, but also that no hint callbacks (watchers) are 06925 added or removed during the merge/delete process 06926 06927 in addition, the locks _must_ be taken in this order, because there are already 06928 other code paths that use this order 06929 */ 06930 06931 struct timeval begintime, writelocktime, endlocktime, enddeltime; 06932 int wrlock_ver; 06933 06934 begintime = ast_tvnow(); 06935 ast_rdlock_contexts(); 06936 iter = ast_hashtab_start_traversal(contexts_table); 06937 while ((tmp = ast_hashtab_next(iter))) { 06938 context_merge(extcontexts, exttable, tmp, registrar); 06939 } 06940 ast_hashtab_end_traversal(iter); 06941 wrlock_ver = ast_wrlock_contexts_version(); 06942 06943 ast_unlock_contexts(); /* this feels real retarded, but you must do 06944 what you must do If this isn't done, the following 06945 wrlock is a guraranteed deadlock */ 06946 ast_wrlock_contexts(); 06947 if (ast_wrlock_contexts_version() > wrlock_ver+1) { 06948 ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n"); 06949 } 06950 06951 AST_RWLIST_WRLOCK(&hints); 06952 writelocktime = ast_tvnow(); 06953 06954 /* preserve all watchers for hints associated with this registrar */ 06955 AST_RWLIST_TRAVERSE(&hints, hint, list) { 06956 if (!AST_LIST_EMPTY(&hint->callbacks) && !strcmp(registrar, hint->exten->parent->registrar)) { 06957 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this); 06958 if (!(this = ast_calloc(1, length))) 06959 continue; 06960 AST_LIST_APPEND_LIST(&this->callbacks, &hint->callbacks, entry); 06961 this->laststate = hint->laststate; 06962 this->context = this->data; 06963 strcpy(this->data, hint->exten->parent->name); 06964 this->exten = this->data + strlen(this->context) + 1; 06965 strcpy(this->exten, hint->exten->exten); 06966 AST_LIST_INSERT_HEAD(&store, this, list); 06967 } 06968 } 06969 06970 /* save the old table and list */ 06971 oldtable = contexts_table; 06972 oldcontextslist = contexts; 06973 06974 /* move in the new table and list */ 06975 contexts_table = exttable; 06976 contexts = *extcontexts; 06977 06978 /* restore the watchers for hints that can be found; notify those that 06979 cannot be restored 06980 */ 06981 while ((this = AST_LIST_REMOVE_HEAD(&store, list))) { 06982 struct pbx_find_info q = { .stacklen = 0 }; 06983 exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH); 06984 /* If this is a pattern, dynamically create a new extension for this 06985 * particular match. Note that this will only happen once for each 06986 * individual extension, because the pattern will no longer match first. 06987 */ 06988 if (exten && exten->exten[0] == '_') { 06989 ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL, 06990 0, exten->app, ast_strdup(exten->data), ast_free_ptr, registrar); 06991 /* rwlocks are not recursive locks */ 06992 exten = ast_hint_extension_nolock(NULL, this->context, this->exten); 06993 } 06994 06995 /* Find the hint in the list of hints */ 06996 AST_RWLIST_TRAVERSE(&hints, hint, list) { 06997 if (hint->exten == exten) 06998 break; 06999 } 07000 if (!exten || !hint) { 07001 /* this hint has been removed, notify the watchers */ 07002 while ((thiscb = AST_LIST_REMOVE_HEAD(&this->callbacks, entry))) { 07003 thiscb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, thiscb->data); 07004 ast_free(thiscb); 07005 } 07006 } else { 07007 AST_LIST_APPEND_LIST(&hint->callbacks, &this->callbacks, entry); 07008 hint->laststate = this->laststate; 07009 } 07010 ast_free(this); 07011 } 07012 07013 AST_RWLIST_UNLOCK(&hints); 07014 ast_unlock_contexts(); 07015 endlocktime = ast_tvnow(); 07016 07017 /* the old list and hashtab no longer are relevant, delete them while the rest of asterisk 07018 is now freely using the new stuff instead */ 07019 07020 ast_hashtab_destroy(oldtable, NULL); 07021 07022 for (tmp = oldcontextslist; tmp; ) { 07023 struct ast_context *next; /* next starting point */ 07024 next = tmp->next; 07025 __ast_internal_context_destroy(tmp); 07026 tmp = next; 07027 } 07028 enddeltime = ast_tvnow(); 07029 07030 ft = ast_tvdiff_us(writelocktime, begintime); 07031 ft /= 1000000.0; 07032 ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft); 07033 07034 ft = ast_tvdiff_us(endlocktime, writelocktime); 07035 ft /= 1000000.0; 07036 ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft); 07037 07038 ft = ast_tvdiff_us(enddeltime, endlocktime); 07039 ft /= 1000000.0; 07040 ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft); 07041 07042 ft = ast_tvdiff_us(enddeltime, begintime); 07043 ft /= 1000000.0; 07044 ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft); 07045 return; 07046 }
| int ast_parseable_goto | ( | struct ast_channel * | chan, | |
| const char * | goto_string | |||
| ) |
Definition at line 9905 of file pbx.c.
References pbx_parseable_goto().
Referenced by _while_exec(), check_goto_on_transfer(), dial_exec_full(), gosub_exec(), ivr_dispatch(), parkandannounce_exec(), pbx_builtin_goto(), and while_continue_exec().
09906 { 09907 return pbx_parseable_goto(chan, goto_string, 0); 09908 }
| int ast_pbx_outgoing_app | ( | const char * | type, | |
| int | format, | |||
| void * | data, | |||
| int | timeout, | |||
| const char * | app, | |||
| const char * | appdata, | |||
| int * | reason, | |||
| int | sync, | |||
| const char * | cid_num, | |||
| const char * | cid_name, | |||
| struct ast_variable * | vars, | |||
| const char * | account, | |||
| struct ast_channel ** | locked_channel | |||
| ) |
Synchronously or asynchronously make an outbound call and send it to a particular application with given extension
Definition at line 8393 of file pbx.c.
References __ast_request_and_dial(), ast_channel::_state, outgoing_helper::account, async_stat::app, app_tmp::app, async_stat::appdata, ast_calloc, ast_cdr_disposition(), ast_cdr_failed(), ast_cdr_setaccount(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_free, ast_hangup(), ast_log(), ast_pbx_outgoing_cdr_failed(), ast_pbx_run_app(), ast_pthread_create_detached, ast_set_variables(), AST_STATE_UP, ast_strlen_zero(), ast_variables_destroy(), ast_verb, async_wait(), ast_channel::cdr, async_stat::chan, app_tmp::chan, app_tmp::data, errno, ast_channel::hangupcause, LOG_WARNING, ast_channel::name, async_stat::p, app_tmp::t, async_stat::timeout, and outgoing_helper::vars.
Referenced by action_originate(), attempt_thread(), fast_originate(), orig_app(), and originate_exec().
08394 { 08395 struct ast_channel *chan; 08396 struct app_tmp *tmp; 08397 int res = -1, cdr_res = -1; 08398 struct outgoing_helper oh; 08399 08400 memset(&oh, 0, sizeof(oh)); 08401 oh.vars = vars; 08402 oh.account = account; 08403 08404 if (locked_channel) 08405 *locked_channel = NULL; 08406 if (ast_strlen_zero(app)) { 08407 res = -1; 08408 goto outgoing_app_cleanup; 08409 } 08410 if (synchronous) { 08411 chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh); 08412 if (chan) { 08413 ast_set_variables(chan, vars); 08414 if (account) 08415 ast_cdr_setaccount(chan, account); 08416 if (chan->_state == AST_STATE_UP) { 08417 res = 0; 08418 ast_verb(4, "Channel %s was answered.\n", chan->name); 08419 tmp = ast_calloc(1, sizeof(*tmp)); 08420 if (!tmp) 08421 res = -1; 08422 else { 08423 ast_copy_string(tmp->app, app, sizeof(tmp->app)); 08424 if (appdata) 08425 ast_copy_string(tmp->data, appdata, sizeof(tmp->data)); 08426 tmp->chan = chan; 08427 if (synchronous > 1) { 08428 if (locked_channel) 08429 ast_channel_unlock(chan); 08430 ast_pbx_run_app(tmp); 08431 } else { 08432 if (locked_channel) 08433 ast_channel_lock(chan); 08434 if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) { 08435 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno)); 08436 ast_free(tmp); 08437 if (locked_channel) 08438 ast_channel_unlock(chan); 08439 ast_hangup(chan); 08440 res = -1; 08441 } else { 08442 if (locked_channel) 08443 *locked_channel = chan; 08444 } 08445 } 08446 } 08447 } else { 08448 ast_verb(4, "Channel %s was never answered.\n", chan->name); 08449 if (chan->cdr) { /* update the cdr */ 08450 /* here we update the status of the call, which sould be busy. 08451 * if that fails then we set the status to failed */ 08452 if (ast_cdr_disposition(chan->cdr, chan->hangupcause)) 08453 ast_cdr_failed(chan->cdr); 08454 } 08455 ast_hangup(chan); 08456 } 08457 } 08458 08459 if (res < 0) { /* the call failed for some reason */ 08460 if (*reason == 0) { /* if the call failed (not busy or no answer) 08461 * update the cdr with the failed message */ 08462 cdr_res = ast_pbx_outgoing_cdr_failed(); 08463 if (cdr_res != 0) { 08464 res = cdr_res; 08465 goto outgoing_app_cleanup; 08466 } 08467 } 08468 } 08469 08470 } else { 08471 struct async_stat *as; 08472 if (!(as = ast_calloc(1, sizeof(*as)))) { 08473 res = -1; 08474 goto outgoing_app_cleanup; 08475 } 08476 chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh); 08477 if (!chan) { 08478 ast_free(as); 08479 res = -1; 08480 goto outgoing_app_cleanup; 08481 } 08482 as->chan = chan; 08483 ast_copy_string(as->app, app, sizeof(as->app)); 08484 if (appdata) 08485 ast_copy_string(as->appdata, appdata, sizeof(as->appdata)); 08486 as->timeout = timeout; 08487 ast_set_variables(chan, vars); 08488 if (account) 08489 ast_cdr_setaccount(chan, account); 08490 /* Start a new thread, and get something handling this channel. */ 08491 if (locked_channel) 08492 ast_channel_lock(chan); 08493 if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) { 08494 ast_log(LOG_WARNING, "Failed to start async wait\n"); 08495 ast_free(as); 08496 if (locked_channel) 08497 ast_channel_unlock(chan); 08498 ast_hangup(chan); 08499 res = -1; 08500 goto outgoing_app_cleanup; 08501 } else { 08502 if (locked_channel) 08503 *locked_channel = chan; 08504 } 08505 res = 0; 08506 } 08507 outgoing_app_cleanup: 08508 ast_variables_destroy(vars); 08509 return res; 08510 }
| static int ast_pbx_outgoing_cdr_failed | ( | void | ) | [static] |
Function to post an empty cdr after a spool call fails.
Definition at line 8200 of file pbx.c.
References ast_cdr_alloc(), ast_cdr_detach(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_start(), ast_channel_release(), ast_dummy_channel_alloc(), and ast_channel::cdr.
Referenced by ast_pbx_outgoing_app(), and ast_pbx_outgoing_exten().
08201 { 08202 /* allocate a channel */ 08203 struct ast_channel *chan = ast_dummy_channel_alloc(); 08204 08205 if (!chan) 08206 return -1; /* failure */ 08207 08208 chan->cdr = ast_cdr_alloc(); 08209 if (!chan->cdr) { 08210 /* allocation of the cdr failed */ 08211 chan = ast_channel_release(chan); /* free the channel */ 08212 return -1; /* return failure */ 08213 } 08214 08215 /* allocation of the cdr was successful */ 08216 ast_cdr_init(chan->cdr, chan); /* initialize our channel's cdr */ 08217 ast_cdr_start(chan->cdr); /* record the start and stop time */ 08218 ast_cdr_end(chan->cdr); 08219 ast_cdr_failed(chan->cdr); /* set the status to failed */ 08220 ast_cdr_detach(chan->cdr); /* post and free the record */ 08221 chan->cdr = NULL; 08222 chan = ast_channel_release(chan); /* free the channel */ 08223 08224 return 0; /* success */ 08225 }
| int ast_pbx_outgoing_exten | ( | const char * | type, | |
| int | format, | |||
| void * | data, | |||
| int | timeout, | |||
| const char * | context, | |||
| const char * | exten, | |||
| int | priority, | |||
| int * | reason, | |||
| int | sync, | |||
| const char * | cid_num, | |||
| const char * | cid_name, | |||
| struct ast_variable * | vars, | |||
| const char * | account, | |||
| struct ast_channel ** | locked_channel | |||
| ) |
Synchronously or asynchronously make an outbound call and send it to a particular extension
Definition at line 8227 of file pbx.c.
References __ast_request_and_dial(), ast_channel::_state, outgoing_helper::account, ast_calloc, ast_cdr_disposition(), ast_cdr_failed(), ast_cdr_setaccount(), ast_channel_alloc, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_exists_extension(), ast_free, ast_hangup(), ast_log(), ast_pbx_outgoing_cdr_failed(), ast_pbx_run(), ast_pbx_start(), ast_pthread_create_detached, ast_request_and_dial(), ast_set_variables(), AST_STATE_DOWN, AST_STATE_UP, ast_strlen_zero(), ast_variables_destroy(), ast_verb, async_wait(), ast_channel::cdr, async_stat::chan, outgoing_helper::cid_name, outgoing_helper::cid_num, async_stat::context, ast_channel::context, outgoing_helper::context, outgoing_helper::exten, ast_channel::hangupcause, LOG_ERROR, LOG_WARNING, ast_channel::name, async_stat::p, outgoing_helper::parent_channel, pbx_builtin_setvar_helper(), outgoing_helper::priority, set_ext_pri(), async_stat::timeout, and outgoing_helper::vars.
Referenced by action_originate(), attempt_thread(), fast_originate(), orig_exten(), and originate_exec().
08228 { 08229 struct ast_channel *chan; 08230 struct async_stat *as; 08231 int res = -1, cdr_res = -1; 08232 struct outgoing_helper oh; 08233 08234 if (synchronous) { 08235 oh.context = context; 08236 oh.exten = exten; 08237 oh.priority = priority; 08238 oh.cid_num = cid_num; 08239 oh.cid_name = cid_name; 08240 oh.account = account; 08241 oh.vars = vars; 08242 oh.parent_channel = NULL; 08243 08244 chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh); 08245 if (channel) { 08246 *channel = chan; 08247 if (chan) 08248 ast_channel_lock(chan); 08249 } 08250 if (chan) { 08251 if (chan->_state == AST_STATE_UP) { 08252 res = 0; 08253 ast_verb(4, "Channel %s was answered.\n", chan->name); 08254 08255 if (synchronous > 1) { 08256 if (channel) 08257 ast_channel_unlock(chan); 08258 if (ast_pbx_run(chan)) { 08259 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name); 08260 if (channel) 08261 *channel = NULL; 08262 ast_hangup(chan); 08263 chan = NULL; 08264 res = -1; 08265 } 08266 } else { 08267 if (ast_pbx_start(chan)) { 08268 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name); 08269 if (channel) { 08270 *channel = NULL; 08271 ast_channel_unlock(chan); 08272 } 08273 ast_hangup(chan); 08274 res = -1; 08275 } 08276 chan = NULL; 08277 } 08278 } else { 08279 ast_verb(4, "Channel %s was never answered.\n", chan->name); 08280 08281 if (chan->cdr) { /* update the cdr */ 08282 /* here we update the status of the call, which sould be busy. 08283 * if that fails then we set the status to failed */ 08284 if (ast_cdr_disposition(chan->cdr, chan->hangupcause)) 08285 ast_cdr_failed(chan->cdr); 08286 } 08287 08288 if (channel) { 08289 *channel = NULL; 08290 ast_channel_unlock(chan); 08291 } 08292 ast_hangup(chan); 08293 chan = NULL; 08294 } 08295 } 08296 08297 if (res < 0) { /* the call failed for some reason */ 08298 if (*reason == 0) { /* if the call failed (not busy or no answer) 08299 * update the cdr with the failed message */ 08300 cdr_res = ast_pbx_outgoing_cdr_failed(); 08301 if (cdr_res != 0) { 08302 res = cdr_res; 08303 goto outgoing_exten_cleanup; 08304 } 08305 } 08306 08307 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */ 08308 /* check if "failed" exists */ 08309 if (ast_exists_extension(chan, context, "failed", 1, NULL)) { 08310 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", NULL, 0, "OutgoingSpoolFailed"); 08311 if (chan) { 08312 char failed_reason[4] = ""; 08313 if (!ast_strlen_zero(context)) 08314 ast_copy_string(chan->context, context, sizeof(chan->context)); 08315 set_ext_pri(chan, "failed", 1); 08316 ast_set_variables(chan, vars); 08317 snprintf(failed_reason, sizeof(failed_reason), "%d", *reason); 08318 pbx_builtin_setvar_helper(chan, "REASON", failed_reason); 08319 if (account) 08320 ast_cdr_setaccount(chan, account); 08321 if (ast_pbx_run(chan)) { 08322 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name); 08323 ast_hangup(chan); 08324 } 08325 chan = NULL; 08326 } 08327 } 08328 } 08329 } else { 08330 if (!(as = ast_calloc(1, sizeof(*as)))) { 08331 res = -1; 08332 goto outgoing_exten_cleanup; 08333 } 08334 chan = ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name); 08335 if (channel) { 08336 *channel = chan; 08337 if (chan) 08338 ast_channel_lock(chan); 08339 } 08340 if (!chan) { 08341 ast_free(as); 08342 res = -1; 08343 goto outgoing_exten_cleanup; 08344 } 08345 as->chan = chan; 08346 ast_copy_string(as->context, context, sizeof(as->context)); 08347 set_ext_pri(as->chan, exten, priority); 08348 as->timeout = timeout; 08349 ast_set_variables(chan, vars); 08350 if (account) 08351 ast_cdr_setaccount(chan, account); 08352 if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) { 08353 ast_log(LOG_WARNING, "Failed to start async wait\n"); 08354 ast_free(as); 08355 if (channel) { 08356 *channel = NULL; 08357 ast_channel_unlock(chan); 08358 } 08359 ast_hangup(chan); 08360 res = -1; 08361 goto outgoing_exten_cleanup; 08362 } 08363 res = 0; 08364 } 08365 outgoing_exten_cleanup: 08366 ast_variables_destroy(vars); 08367 return res; 08368 }
| enum ast_pbx_result ast_pbx_run | ( | struct ast_channel * | c | ) |
Execute the PBX in the current thread.
| c | channel to run the pbx on |
| Zero | on success | |
| non-zero | on failure |
Definition at line 4929 of file pbx.c.
References ast_pbx_run_args().
Referenced by __analog_ss_thread(), analog_ss_thread(), ast_pbx_outgoing_exten(), async_wait(), do_notify(), mgcp_ss(), skinny_newcall(), and unistim_ss().
04930 { 04931 return ast_pbx_run_args(c, NULL); 04932 }
| static void* ast_pbx_run_app | ( | void * | data | ) | [static] |
run the application and free the descriptor once done
Definition at line 8378 of file pbx.c.
References app_tmp::app, ast_free, ast_hangup(), ast_log(), ast_verb, app_tmp::chan, app_tmp::data, LOG_WARNING, ast_channel::name, pbx_exec(), and pbx_findapp().
Referenced by ast_pbx_outgoing_app().
08379 { 08380 struct app_tmp *tmp = data; 08381 struct ast_app *app; 08382 app = pbx_findapp(tmp->app); 08383 if (app) { 08384 ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name); 08385 pbx_exec(tmp->chan, app, tmp->data); 08386 } else 08387 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app); 08388 ast_hangup(tmp->chan); 08389 ast_free(tmp); 08390 return NULL; 08391 }
| enum ast_pbx_result ast_pbx_run_args | ( | struct ast_channel * | c, | |
| struct ast_pbx_args * | args | |||
| ) |
Execute the PBX in the current thread.
| c | channel to run the pbx on | |
| args | options for the pbx |
| Zero | on success | |
| non-zero | on failure |
Definition at line 4914 of file pbx.c.
References __ast_pbx_run(), AST_PBX_CALL_LIMIT, AST_PBX_SUCCESS, decrease_call_count(), and increase_call_count().
Referenced by ast_pbx_run(), dial_exec_full(), handle_gosub(), and try_calling().
04915 { 04916 enum ast_pbx_result res = AST_PBX_SUCCESS; 04917 04918 if (increase_call_count(c)) { 04919 return AST_PBX_CALL_LIMIT; 04920 } 04921 04922 res = __ast_pbx_run(c, args); 04923 04924 decrease_call_count(); 04925 04926 return res; 04927 }
| enum ast_pbx_result ast_pbx_start | ( | struct ast_channel * | c | ) |
Create a new thread and start the PBX.
| c | channel to start the pbx on |
| Zero | on success | |
| non-zero | on failure |
Definition at line 4892 of file pbx.c.
References ast_log(), AST_PBX_CALL_LIMIT, AST_PBX_FAILED, AST_PBX_SUCCESS, ast_pthread_create_detached, decrease_call_count(), increase_call_count(), LOG_WARNING, and pbx_thread().
Referenced by __oh323_new(), alsa_new(), ast_async_goto(), ast_iax2_new(), ast_pbx_outgoing_exten(), bridge_call_thread(), bridge_exec(), check_goto_on_transfer(), console_new(), dahdi_new(), dial_exec_full(), gtalk_new(), gtalk_newcall(), handle_request_invite(), jingle_new(), jingle_newcall(), local_call(), manage_parkinglot(), mgcp_new(), nbs_new(), oss_new(), pbx_start_chan(), phone_new(), rpt_call(), sip_new(), skinny_new(), unistim_new(), and usbradio_new().
04893 { 04894 pthread_t t; 04895 04896 if (!c) { 04897 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n"); 04898 return AST_PBX_FAILED; 04899 } 04900 04901 if (increase_call_count(c)) 04902 return AST_PBX_CALL_LIMIT; 04903 04904 /* Start a new thread, and get something handling this channel. */ 04905 if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) { 04906 ast_log(LOG_WARNING, "Failed to create new channel thread\n"); 04907 decrease_call_count(); 04908 return AST_PBX_FAILED; 04909 } 04910 04911 return AST_PBX_SUCCESS; 04912 }
| int ast_processed_calls | ( | void | ) |
Retrieve the total number of calls processed through the PBX since last restart.
Definition at line 4939 of file pbx.c.
References totalcalls.
Referenced by ast_var_Config(), handle_chanlist(), and handle_showcalls().
04940 { 04941 return totalcalls; 04942 }
| int ast_rdlock_context | ( | struct ast_context * | con | ) |
Read locks a given context.
| con | context to lock |
| 0 | on success | |
| -1 | on failure |
Definition at line 9642 of file pbx.c.
References ast_rwlock_rdlock(), and ast_context::lock.
Referenced by _macro_exec(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), dundi_precache_full(), find_matching_endwhile(), handle_cli_dialplan_save(), lookup_c_ip(), lookup_ci(), manager_show_dialplan_helper(), show_debug_helper(), and show_dialplan_helper().
09643 { 09644 return ast_rwlock_rdlock(&con->lock); 09645 }
| int ast_rdlock_contexts | ( | void | ) |
Read locks the context list.
| 0 | on success | |
| -1 | on error |
Definition at line 9624 of file pbx.c.
References ast_rwlock_rdlock(), and conlock.
Referenced by _macro_exec(), ast_context_find(), ast_context_find_or_create(), ast_context_lockmacro(), ast_context_unlockmacro(), ast_hint_extension(), ast_merge_contexts_and_delete(), complete_dialplan_add_extension(), complete_dialplan_add_ignorepat(), complete_dialplan_add_include(), complete_dialplan_remove_extension(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), complete_show_dialplan_context(), dundi_precache_full(), find_context_locked(), find_matching_endwhile(), handle_cli_dialplan_save(), handle_statechange(), manager_show_dialplan_helper(), pbx_extension_helper(), show_debug_helper(), show_dialplan_helper(), and unreference_cached_app().
09625 { 09626 return ast_rwlock_rdlock(&conlock); 09627 }
| int ast_register_application2 | ( | const char * | app, | |
| int(*)(struct ast_channel *, const char *) | execute, | |||
| const char * | synopsis, | |||
| const char * | description, | |||
| void * | mod | |||
| ) |
Dynamically register a new dial plan application.
Register an application.
Definition at line 5366 of file pbx.c.
References ast_app::arguments, ast_calloc, ast_free, ast_log(), AST_RWLIST_INSERT_BEFORE_CURRENT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, AST_STATIC_DOC, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_verb, AST_XML_DOC, COLOR_BRCYAN, ast_app::execute, LOG_WARNING, ast_app::module, ast_app::name, ast_app::seealso, ast_app::syntax, and term_color().
Referenced by ast_features_init(), and load_pbx().
05367 { 05368 struct ast_app *tmp, *cur = NULL; 05369 char tmps[80]; 05370 int length, res; 05371 #ifdef AST_XML_DOCS 05372 char *tmpxml; 05373 #endif 05374 05375 AST_RWLIST_WRLOCK(&apps); 05376 AST_RWLIST_TRAVERSE(&apps, tmp, list) { 05377 if (!(res = strcasecmp(app, tmp->name))) { 05378 ast_log(LOG_WARNING, "Already have an application '%s'\n", app); 05379 AST_RWLIST_UNLOCK(&apps); 05380 return -1; 05381 } else if (res < 0) 05382 break; 05383 } 05384 05385 length = sizeof(*tmp) + strlen(app) + 1; 05386 05387 if (!(tmp = ast_calloc(1, length))) { 05388 AST_RWLIST_UNLOCK(&apps); 05389 return -1; 05390 } 05391 05392 if (ast_string_field_init(tmp, 128)) { 05393 AST_RWLIST_UNLOCK(&apps); 05394 ast_free(tmp); 05395 return -1; 05396 } 05397 05398 #ifdef AST_XML_DOCS 05399 /* Try to lookup the docs in our XML documentation database */ 05400 if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) { 05401 /* load synopsis */ 05402 tmpxml = ast_xmldoc_build_synopsis("application", app); 05403 ast_string_field_set(tmp, synopsis, tmpxml); 05404 ast_free(tmpxml); 05405 05406 /* load description */ 05407 tmpxml = ast_xmldoc_build_description("application", app); 05408 ast_string_field_set(tmp, description, tmpxml); 05409 ast_free(tmpxml); 05410 05411 /* load syntax */ 05412 tmpxml = ast_xmldoc_build_syntax("application", app); 05413 ast_string_field_set(tmp, syntax, tmpxml); 05414 ast_free(tmpxml); 05415 05416 /* load arguments */ 05417 tmpxml = ast_xmldoc_build_arguments("application", app); 05418 ast_string_field_set(tmp, arguments, tmpxml); 05419 ast_free(tmpxml); 05420 05421 /* load seealso */ 05422 tmpxml = ast_xmldoc_build_seealso("application", app); 05423 ast_string_field_set(tmp, seealso, tmpxml); 05424 ast_free(tmpxml); 05425 tmp->docsrc = AST_XML_DOC; 05426 } else { 05427 #endif 05428 ast_string_field_set(tmp, synopsis, synopsis); 05429 ast_string_field_set(tmp, description, description); 05430 #ifdef AST_XML_DOCS 05431 tmp->docsrc = AST_STATIC_DOC; 05432 } 05433 #endif 05434 05435 strcpy(tmp->name, app); 05436 tmp->execute = execute; 05437 tmp->module = mod; 05438 05439 /* Store in alphabetical order */ 05440 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) { 05441 if (strcasecmp(tmp->name, cur->name) < 0) { 05442 AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list); 05443 break; 05444 } 05445 } 05446 AST_RWLIST_TRAVERSE_SAFE_END; 05447 if (!cur) 05448 AST_RWLIST_INSERT_TAIL(&apps, tmp, list); 05449 05450 ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps))); 05451 05452 AST_RWLIST_UNLOCK(&apps); 05453 05454 return 0; 05455 }
| int ast_register_switch | ( | struct ast_switch * | sw | ) |
Register an alternative dialplan switch.
| sw | switch to register |
| 0 | success | |
| non-zero | failure |
Definition at line 5461 of file pbx.c.
References ast_log(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, LOG_WARNING, and ast_switch::name.
Referenced by load_module().
05462 { 05463 struct ast_switch *tmp; 05464 05465 AST_RWLIST_WRLOCK(&switches); 05466 AST_RWLIST_TRAVERSE(&switches, tmp, list) { 05467 if (!strcasecmp(tmp->name, sw->name)) { 05468 AST_RWLIST_UNLOCK(&switches); 05469 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name); 05470 return -1; 05471 } 05472 } 05473 AST_RWLIST_INSERT_TAIL(&switches, sw, list); 05474 AST_RWLIST_UNLOCK(&switches); 05475 05476 return 0; 05477 }
| static int ast_remove_hint | ( | struct ast_exten * | e | ) | [static] |
Remove hint from extension.
Definition at line 4407 of file pbx.c.
References AST_EXTENSION_DEACTIVATED, ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, ast_state_cb::callback, ast_hint::callbacks, ast_state_cb::data, ast_exten::exten, ast_hint::exten, ast_context::name, and ast_exten::parent.
Referenced by destroy_exten().
04408 { 04409 /* Cleanup the Notifys if hint is removed */ 04410 struct ast_hint *hint; 04411 struct ast_state_cb *cblist; 04412 int res = -1; 04413 04414 if (!e) 04415 return -1; 04416 04417 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) { 04418 if (hint->exten != e) 04419 continue; 04420 04421 while ((cblist = AST_LIST_REMOVE_HEAD(&hint->callbacks, entry))) { 04422 /* Notify with -1 and remove all callbacks */ 04423 cblist->callback(hint->exten->parent->name, hint->exten->exten, 04424 AST_EXTENSION_DEACTIVATED, cblist->data); 04425 ast_free(cblist); 04426 } 04427 04428 AST_RWLIST_REMOVE_CURRENT(list); 04429 ast_free(hint); 04430 04431 res = 0; 04432 04433 break; 04434 } 04435 AST_RWLIST_TRAVERSE_SAFE_END; 04436 04437 return res; 04438 }
| int ast_spawn_extension | ( | struct ast_channel * | c, | |
| const char * | context, | |||
| const char * | exten, | |||
| int | priority, | |||
| const char * | callerid, | |||
| int * | found, | |||
| int | combined_find_spawn | |||
| ) |
Launch a new extension (i.e. new stack).
| c | not important | |
| context | which context to generate the extension within | |
| exten | new extension to add | |
| priority | priority of new extension | |
| callerid | callerid of extension | |
| found | ||
| combined_find_spawn | This adds a new extension to the asterisk extension list. |
| 0 | on success | |
| -1 | on failure. |
Definition at line 4505 of file pbx.c.
References E_SPAWN, and pbx_extension_helper().
Referenced by __ast_pbx_run(), _macro_exec(), ast_bridge_call(), dial_exec_full(), and loopback_exec().
04506 { 04507 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn); 04508 }
| int ast_str_get_hint | ( | struct ast_str ** | hint, | |
| ssize_t | hintsize, | |||
| struct ast_str ** | name, | |||
| ssize_t | namesize, | |||
| struct ast_channel * | c, | |||
| const char * | context, | |||
| const char * | exten | |||
| ) |
Get hint for channel.
If an extension hint exists, return non-zero.
Definition at line 4460 of file pbx.c.
References ast_get_extension_app(), ast_get_extension_app_data(), ast_hint_extension(), and ast_str_set().
Referenced by ast_str_retrieve_variable().
04461 { 04462 struct ast_exten *e = ast_hint_extension(c, context, exten); 04463 04464 if (!e) { 04465 return 0; 04466 } 04467 04468 if (hint) { 04469 ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e)); 04470 } 04471 if (name) { 04472 const char *tmp = ast_get_extension_app_data(e); 04473 if (tmp) { 04474 ast_str_set(name, namesize, "%s", tmp); 04475 } 04476 } 04477 return -1; 04478 }
| const char* ast_str_retrieve_variable | ( | struct ast_str ** | buf, | |
| ssize_t | maxlen, | |||
| struct ast_channel * | chan, | |||
| struct varshead * | headp, | |||
| const char * | var | |||
| ) |
| buf | Result will be placed in this buffer. | |
| maxlen | -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes. | |
| chan | Channel variables from which to extract values, and channel to pass to any dialplan functions. | |
| headp | If no channel is specified, a channel list from which to extract variable values | |
| var | Variable name to retrieve. |
Definition at line 2929 of file pbx.c.
References ARRAY_LEN, ast_channel_lock, ast_channel_unlock, ast_config_AST_SYSTEM_NAME, ast_debug, ast_eid_default, ast_eid_to_str(), AST_LIST_TRAVERSE, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_str_buffer(), ast_str_get_hint(), ast_str_set(), ast_str_substring(), ast_strdupa, ast_var_name(), ast_var_value(), ast_channel::cid, ast_callerid::cid_ani2, ast_callerid::cid_pres, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_var_t::entries, ast_channel::exten, globals, globalslock, ast_channel::hangupcause, ast_channel::name, parse_variable_name(), ast_channel::priority, s, ast_channel::uniqueid, and ast_channel::varshead.
Referenced by ast_str_substitute_variables_full(), and pbx_retrieve_variable().
02930 { 02931 const char not_found = '\0'; 02932 char *tmpvar; 02933 const char *ret; 02934 const char *s; /* the result */ 02935 int offset, length; 02936 int i, need_substring; 02937 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */ 02938 02939 if (c) { 02940 ast_channel_lock(c); 02941 places[0] = &c->varshead; 02942 } 02943 /* 02944 * Make a copy of var because parse_variable_name() modifies the string. 02945 * Then if called directly, we might need to run substring() on the result; 02946 * remember this for later in 'need_substring', 'offset' and 'length' 02947 */ 02948 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */ 02949 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */); 02950 02951 /* 02952 * Look first into predefined variables, then into variable lists. 02953 * Variable 's' points to the result, according to the following rules: 02954 * s == ¬_found (set at the beginning) means that we did not find a 02955 * matching variable and need to look into more places. 02956 * If s != ¬_found, s is a valid result string as follows: 02957 * s = NULL if the variable does not have a value; 02958 * you typically do this when looking for an unset predefined variable. 02959 * s = workspace if the result has been assembled there; 02960 * typically done when the result is built e.g. with an snprintf(), 02961 * so we don't need to do an additional copy. 02962 * s != workspace in case we have a string, that needs to be copied 02963 * (the ast_copy_string is done once for all at the end). 02964 * Typically done when the result is already available in some string. 02965 */ 02966 s = ¬_found; /* default value */ 02967 if (c) { /* This group requires a valid channel */ 02968 /* Names with common parts are looked up a piece at a time using strncmp. */ 02969 if (!strncmp(var, "CALL", 4)) { 02970 if (!strncmp(var + 4, "ING", 3)) { 02971 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */ 02972 ast_str_set(str, maxlen, "%d", c->cid.cid_pres); 02973 s = ast_str_buffer(*str); 02974 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */ 02975 ast_str_set(str, maxlen, "%d", c->cid.cid_ani2); 02976 s = ast_str_buffer(*str); 02977 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */ 02978 ast_str_set(str, maxlen, "%d", c->cid.cid_ton); 02979 s = ast_str_buffer(*str); 02980 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */ 02981 ast_str_set(str, maxlen, "%d", c->cid.cid_tns); 02982 s = ast_str_buffer(*str); 02983 } 02984 } 02985 } else if (!strcmp(var, "HINT")) { 02986 s = ast_str_get_hint(str, maxlen, NULL, 0, c, c->context, c->exten) ? ast_str_buffer(*str) : NULL; 02987 } else if (!strcmp(var, "HINTNAME")) { 02988 s = ast_str_get_hint(NULL, 0, str, maxlen, c, c->context, c->exten) ? ast_str_buffer(*str) : NULL; 02989 } else if (!strcmp(var, "EXTEN")) { 02990 s = c->exten; 02991 } else if (!strcmp(var, "CONTEXT")) { 02992 s = c->context; 02993 } else if (!strcmp(var, "PRIORITY")) { 02994 ast_str_set(str, maxlen, "%d", c->priority); 02995 s = ast_str_buffer(*str); 02996 } else if (!strcmp(var, "CHANNEL")) { 02997 s = c->name; 02998 } else if (!strcmp(var, "UNIQUEID")) { 02999 s = c->uniqueid; 03000 } else if (!strcmp(var, "HANGUPCAUSE")) { 03001 ast_str_set(str, maxlen, "%d", c->hangupcause); 03002 s = ast_str_buffer(*str); 03003 } 03004 } 03005 if (s == ¬_found) { /* look for more */ 03006 if (!strcmp(var, "EPOCH")) { 03007 ast_str_set(str, maxlen, "%u", (int) time(NULL)); 03008 s = ast_str_buffer(*str); 03009 } else if (!strcmp(var, "SYSTEMNAME")) { 03010 s = ast_config_AST_SYSTEM_NAME; 03011 } else if (!strcmp(var, "ENTITYID")) { 03012 char workspace[20]; 03013 ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default); 03014 s = workspace; 03015 } 03016 } 03017 /* if not found, look into chanvars or global vars */ 03018 for (i = 0; s == ¬_found && i < ARRAY_LEN(places); i++) { 03019 struct ast_var_t *variables; 03020 if (!places[i]) 03021 continue; 03022 if (places[i] == &globals) 03023 ast_rwlock_rdlock(&globalslock); 03024 AST_LIST_TRAVERSE(places[i], variables, entries) { 03025 if (!strcasecmp(ast_var_name(variables), var)) { 03026 s = ast_var_value(variables); 03027 break; 03028 } 03029 } 03030 if (places[i] == &globals) 03031 ast_rwlock_unlock(&globalslock); 03032 } 03033 if (s == ¬_found || s == NULL) { 03034 ast_debug(5, "Result of '%s' is NULL\n", var); 03035 ret = NULL; 03036 } else { 03037 ast_debug(5, "Result of '%s' is '%s'\n", var, s); 03038 if (s != ast_str_buffer(*str)) { 03039 ast_str_set(str, maxlen, "%s", s); 03040 } 03041 ret = ast_str_buffer(*str); 03042 if (need_substring) { 03043 ret = ast_str_substring(*str, offset, length); 03044 ast_debug(2, "Final result of '%s' is '%s'\n", var, ret); 03045 } 03046 } 03047 03048 if (c) { 03049 ast_channel_unlock(c); 03050 } 03051 return ret; 03052 }
| void ast_str_substitute_variables | ( | struct ast_str ** | buf, | |
| ssize_t | maxlen, | |||
| struct ast_channel * | chan, | |||
| const char * | templ | |||
| ) |
| buf | Result will be placed in this buffer. | |
| maxlen | -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes. | |
| chan | Channel variables from which to extract values, and channel to pass to any dialplan functions. | |
| templ | Variable template to expand. |
Definition at line 3709 of file pbx.c.
References ast_str_substitute_variables_full().
Referenced by _macro_exec(), acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), cli_odbc_write(), config_curl(), custom_log(), cut_internal(), destroy_curl(), exec_exec(), func_mchan_read(), function_eval2(), function_fieldqty_helper(), handle_getvariablefull(), import_helper(), make_email_file(), realtime_curl(), realtime_multi_curl(), require_curl(), sendmail(), sendpage(), store_curl(), syslog_log(), tryexec_exec(), update2_curl(), and update_curl().
03710 { 03711 size_t used; 03712 ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, &used); 03713 }
| void ast_str_substitute_variables_full | ( | struct ast_str ** | buf, | |
| ssize_t | maxlen, | |||
| struct ast_channel * | c, | |||
| struct varshead * | headp, | |||
| const char * | templ, | |||
| size_t * | used | |||
| ) |
| buf | Result will be placed in this buffer. | |
| maxlen | -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes. | |
| c | Channel variables from which to extract values, and channel to pass to any dialplan functions. | |
| headp | If no channel is specified, a channel list from which to extract variable values | |
| templ | Variable template to expand. | |
| used | Number of bytes read from the template. |
Definition at line 3533 of file pbx.c.
References ast_channel_release(), ast_debug, ast_dummy_channel_alloc(), ast_free, ast_func_read2(), ast_log(), ast_str_append(), ast_str_append_substr(), ast_str_buffer(), ast_str_create(), ast_str_expr(), ast_str_reset(), ast_str_retrieve_variable(), ast_str_set_substr(), ast_str_strlen(), ast_str_substitute_variables_full(), ast_str_substring(), ast_strlen_zero(), len(), LOG_ERROR, LOG_WARNING, parse_variable_name(), and ast_channel::varshead.
Referenced by ast_str_substitute_variables(), ast_str_substitute_variables_full(), and ast_str_substitute_variables_varshead().
03534 { 03535 /* Substitutes variables into buf, based on string templ */ 03536 char *cp4 = NULL; 03537 const char *tmp, *whereweare; 03538 int orig_size = 0; 03539 int offset, offset2, isfunction; 03540 const char *nextvar, *nextexp, *nextthing; 03541 const char *vars, *vare; 03542 char *finalvars; 03543 int pos, brackets, needsub, len; 03544 struct ast_str *substr1 = ast_str_create(16), *substr2 = NULL, *substr3 = ast_str_create(16); 03545 03546 ast_str_reset(*buf); 03547 whereweare = tmp = templ; 03548 while (!ast_strlen_zero(whereweare)) { 03549 /* Assume we're copying the whole remaining string */ 03550 pos = strlen(whereweare); 03551 nextvar = NULL; 03552 nextexp = NULL; 03553 nextthing = strchr(whereweare, '$'); 03554 if (nextthing) { 03555 switch (nextthing[1]) { 03556 case '{': 03557 nextvar = nextthing; 03558 pos = nextvar - whereweare; 03559 break; 03560 case '[': 03561 nextexp = nextthing; 03562 pos = nextexp - whereweare; 03563 break; 03564 default: 03565 pos = 1; 03566 } 03567 } 03568 03569 if (pos) { 03570 /* Copy that many bytes */ 03571 ast_str_append_substr(buf, maxlen, whereweare, pos); 03572 03573 templ += pos; 03574 whereweare += pos; 03575 } 03576 03577 if (nextvar) { 03578 /* We have a variable. Find the start and end, and determine 03579 if we are going to have to recursively call ourselves on the 03580 contents */ 03581 vars = vare = nextvar + 2; 03582 brackets = 1; 03583 needsub = 0; 03584 03585 /* Find the end of it */ 03586 while (brackets && *vare) { 03587 if ((vare[0] == '$') && (vare[1] == '{')) { 03588 needsub++; 03589 } else if (vare[0] == '{') { 03590 brackets++; 03591 } else if (vare[0] == '}') { 03592 brackets--; 03593 } else if ((vare[0] == '$') && (vare[1] == '[')) 03594 needsub++; 03595 vare++; 03596 } 03597 if (brackets) 03598 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n"); 03599 len = vare - vars - 1; 03600 03601 /* Skip totally over variable string */ 03602 whereweare += (len + 3); 03603 03604 /* Store variable name (and truncate) */ 03605 ast_str_set_substr(&substr1, 0, vars, len); 03606 ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len); 03607 03608 /* Substitute if necessary */ 03609 if (needsub) { 03610 size_t used; 03611 if (!substr2) { 03612 substr2 = ast_str_create(16); 03613 } 03614 03615 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used); 03616 finalvars = ast_str_buffer(substr2); 03617 } else { 03618 finalvars = ast_str_buffer(substr1); 03619 } 03620 03621 parse_variable_name(finalvars, &offset, &offset2, &isfunction); 03622 if (isfunction) { 03623 /* Evaluate function */ 03624 if (c || !headp) { 03625 cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3); 03626 } else { 03627 struct varshead old; 03628 struct ast_channel *bogus = ast_dummy_channel_alloc(); 03629 if (bogus) { 03630 memcpy(&old, &bogus->varshead, sizeof(old)); 03631 memcpy(&bogus->varshead, headp, sizeof(bogus->varshead)); 03632 cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3); 03633 /* Don't deallocate the varshead that was passed in */ 03634 memcpy(&bogus->varshead, &old, sizeof(bogus->varshead)); 03635 ast_channel_release(bogus); 03636 } else { 03637 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n"); 03638 } 03639 } 03640 ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)"); 03641 } else { 03642 /* Retrieve variable value */ 03643 ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars); 03644 cp4 = ast_str_buffer(substr3); 03645 } 03646 if (cp4) { 03647 ast_str_substring(substr3, offset, offset2); 03648 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3)); 03649 } 03650 } else if (nextexp) { 03651 /* We have an expression. Find the start and end, and determine 03652 if we are going to have to recursively call ourselves on the 03653 contents */ 03654 vars = vare = nextexp + 2; 03655 brackets = 1; 03656 needsub = 0; 03657 03658 /* Find the end of it */ 03659 while (brackets && *vare) { 03660 if ((vare[0] == '$') && (vare[1] == '[')) { 03661 needsub++; 03662 brackets++; 03663 vare++; 03664 } else if (vare[0] == '[') { 03665 brackets++; 03666 } else if (vare[0] == ']') { 03667 brackets--; 03668 } else if ((vare[0] == '$') && (vare[1] == '{')) { 03669 needsub++; 03670 vare++; 03671 } 03672 vare++; 03673 } 03674 if (brackets) 03675 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n"); 03676 len = vare - vars - 1; 03677 03678 /* Skip totally over expression */ 03679 whereweare += (len + 3); 03680 03681 /* Store variable name (and truncate) */ 03682 ast_str_set_substr(&substr1, 0, vars, len); 03683 03684 /* Substitute if necessary */ 03685 if (needsub) { 03686 size_t used; 03687 if (!substr2) { 03688 substr2 = ast_str_create(16); 03689 } 03690 03691 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used); 03692 finalvars = ast_str_buffer(substr2); 03693 } else { 03694 finalvars = ast_str_buffer(substr1); 03695 } 03696 03697 if (ast_str_expr(&substr3, 0, c, finalvars)) { 03698 ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3)); 03699 } 03700 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3)); 03701 } 03702 } 03703 *used = ast_str_strlen(*buf) - orig_size; 03704 ast_free(substr1); 03705 ast_free(substr2); 03706 ast_free(substr3); 03707 }
| void ast_str_substitute_variables_varshead | ( | struct ast_str ** | buf, | |
| ssize_t | maxlen, | |||
| struct varshead * | headp, | |||
| const char * | templ | |||
| ) |
| buf | Result will be placed in this buffer. | |
| maxlen | -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes. | |
| headp | If no channel is specified, a channel list from which to extract variable values | |
| templ | Variable template to expand. |
Definition at line 3715 of file pbx.c.
References ast_str_substitute_variables_full().
Referenced by add_user_extension(), build_user_routes(), phoneprov_callback(), pp_each_extension_helper(), and pp_each_user_helper().
03716 { 03717 size_t used; 03718 ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, &used); 03719 }
| static const char* ast_str_substring | ( | struct ast_str * | value, | |
| int | offset, | |||
| int | length | |||
| ) | [static] |
Definition at line 2864 of file pbx.c.
References ast_str_buffer(), ast_str_reset(), ast_str_strlen(), and ast_str_update().
Referenced by ast_str_retrieve_variable(), and ast_str_substitute_variables_full().
02865 { 02866 int lr; /* length of the input string after the copy */ 02867 02868 lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */ 02869 02870 /* Quick check if no need to do anything */ 02871 if (offset == 0 && length >= lr) /* take the whole string */ 02872 return ast_str_buffer(value); 02873 02874 if (offset < 0) { /* translate negative offset into positive ones */ 02875 offset = lr + offset; 02876 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */ 02877 offset = 0; 02878 } 02879 02880 /* too large offset result in empty string so we know what to return */ 02881 if (offset >= lr) { 02882 ast_str_reset(value); 02883 return ast_str_buffer(value); 02884 } 02885 02886 if (offset > 0) { 02887 /* Go ahead and chop off the beginning */ 02888 memcpy(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1); 02889 lr -= offset; 02890 } 02891 02892 if (length >= 0 && length < lr) { /* truncate if necessary */ 02893 char *tmp = ast_str_buffer(value); 02894 tmp[length] = '\0'; 02895 ast_str_update(value); 02896 } else if (length < 0) { 02897 if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */ 02898 char *tmp = ast_str_buffer(value); 02899 tmp[lr + length] = '\0'; 02900 ast_str_update(value); 02901 } else { 02902 ast_str_reset(value); 02903 } 02904 } else { 02905 /* Nothing to do, but update the buffer length */ 02906 ast_str_update(value); 02907 } 02908 02909 return ast_str_buffer(value); 02910 }
| int ast_unlock_context | ( | struct ast_context * | con | ) |
| Unlocks | the given context |
| con | context to unlock |
| 0 | on success | |
| -1 | on failure |
Definition at line 9647 of file pbx.c.
References ast_rwlock_unlock(), and ast_context::lock.
Referenced by __ast_context_destroy(), _macro_exec(), ast_add_extension2_lockopt(), ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_remove_extension_callerid2(), ast_context_remove_ignorepat2(), ast_context_remove_include2(), ast_context_remove_switch2(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), dundi_precache_full(), find_matching_endwhile(), handle_cli_dialplan_save(), lookup_c_ip(), lookup_ci(), manager_show_dialplan_helper(), show_debug_helper(), and show_dialplan_helper().
09648 { 09649 return ast_rwlock_unlock(&con->lock); 09650 }
| int ast_unlock_contexts | ( | void | ) |
Unlocks contexts.
| 0 | on success | |
| -1 | on failure |
Definition at line 9629 of file pbx.c.
References ast_rwlock_unlock(), and conlock.
Referenced by _macro_exec(), ast_add_extension(), ast_context_add_ignorepat(), ast_context_add_include(), ast_context_add_switch(), ast_context_destroy(), ast_context_find(), ast_context_find_or_create(), ast_context_lockmacro(), ast_context_remove_extension_callerid(), ast_context_remove_ignorepat(), ast_context_remove_include(), ast_context_remove_switch(), ast_context_unlockmacro(), ast_hint_extension(), ast_merge_contexts_and_delete(), complete_dialplan_add_extension(), complete_dialplan_add_ignorepat(), complete_dialplan_add_include(), complete_dialplan_remove_extension(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), complete_show_dialplan_context(), dundi_precache_full(), find_context_locked(), find_matching_endwhile(), handle_cli_dialplan_save(), handle_statechange(), manager_show_dialplan_helper(), pbx_extension_helper(), show_debug_helper(), show_dialplan_helper(), and unreference_cached_app().
09630 { 09631 return ast_rwlock_unlock(&conlock); 09632 }