Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Functions | Variables
pbx.c File Reference

Core PBX routines. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#include <sys/sysinfo.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/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/presencestate.h"
#include "asterisk/hashtab.h"
#include "asterisk/module.h"
#include "asterisk/indications.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/xmldoc.h"
#include "asterisk/astobj2.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/dial.h"
#include "asterisk/vector.h"
#include "pbx_private.h"
Include dependency graph for pbx.c:

Go to the source code of this file.

Data Structures

struct  ast_autohint
 Structure for dial plan autohints. More...
 
struct  ast_context
 ast_context: An extension context - must remain in sync with fake_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_hintdevice
 Structure for dial plan hint devices. More...
 
struct  ast_state_cb
 ast_state_cb: An extension state notify register item More...
 
struct  cfextension_states
 
struct  dialplan_counters
 Counters for the show dialplan manager command. More...
 
struct  fake_context
 
struct  match_char
 match_char: forms a syntax tree for quick matching of extension patterns More...
 
struct  pattern_node
 
struct  pbx_exception
 
struct  pbx_outgoing
 Structure which contains information about an outgoing dial. More...
 
struct  scoreboard
 
struct  store_hint
 
struct  store_hints
 

Macros

#define ADVANCE(s)   candidate_exten_advance(s)
 
#define BITS_PER   8 /* Number of bits per unit (byte). */
 
#define EXT_DATA_SIZE   8192
 
#define HASH_EXTENHINT_SIZE   563
 
#define HINTDEVICE_DATA_LENGTH   16
 
#define INC_DST_OVERFLOW_CHECK
 
#define MORE(s)   (*candidate_exten_advance(s))
 
#define NEW_MATCHER_CHK_MATCH
 
#define NEW_MATCHER_RECURSE
 
#define SAY_STUBS   /* generate declarations and stubs for say methods */
 
#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_HARDTRAN   3
 
#define VAR_NORMAL   1
 
#define VAR_SOFTTRAN   2
 

Functions

void __ast_context_destroy (struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
 
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 __init_extensionstate_buf (void)
 
static void __init_hintdevice_data (void)
 
static void __init_switch_data (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 action_extensionstatelist (struct mansession *s, const struct message *m)
 
static struct match_charadd_exten_to_pattern_tree (struct ast_context *con, struct ast_exten *e1, int findonly)
 
static int add_hintdevice (struct ast_hint *hint, const char *devicelist)
 add hintdevice structure and link it into the container. More...
 
static struct match_charadd_pattern_node (struct ast_context *con, struct match_char *current, const struct pattern_node *pattern, int is_pattern, int already, struct match_char **nextcharptr)
 
static int add_priority (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. More...
 
static struct ao2_containeralloc_device_state_info (void)
 
static struct match_charalready_in_tree (struct match_char *current, char *pat, int is_pattern)
 
int ast_active_calls (void)
 Retrieve the number of active calls. More...
 
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. More...
 
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, const char *registrar_file, int registrar_line)
 Main interface to add extensions to the list for out context. More...
 
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, const char *registrar_file, int registrar_line, int lock_context)
 Same as ast_add_extension2() but controls the context locking. More...
 
int ast_add_extension2_nolock (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, const char *registrar_file, int registrar_line)
 Same as ast_add_extension2, but assumes you have already locked context. More...
 
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. More...
 
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. More...
 
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. More...
 
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_canmatch_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
 Looks for a valid matching extension. More...
 
static int ast_change_hint (struct ast_exten *oe, struct ast_exten *ne)
 Change hint for an extension. More...
 
int ast_context_add_ignorepat (const char *context, const char *value, const char *registrar)
 Add an ignorepat. More...
 
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. More...
 
int ast_context_add_include2 (struct ast_context *con, const char *value, const char *registrar)
 Add a context include. More...
 
int ast_context_add_switch (const char *context, const char *sw, const char *data, int eval, const char *registrar)
 Add a switch. More...
 
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) More...
 
void ast_context_destroy (struct ast_context *con, const char *registrar)
 Destroy a context (matches the specified context or ANY context if NULL) More...
 
int ast_context_destroy_by_name (const char *context, const char *registrar)
 Destroy a context by name. More...
 
struct ast_contextast_context_find (const char *name)
 Find a context. More...
 
struct ast_contextast_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. More...
 
int ast_context_ignorepats_count (const struct ast_context *con)
 
const struct ast_ignorepatast_context_ignorepats_get (const struct ast_context *con, int idx)
 
int ast_context_includes_count (const struct ast_context *con)
 
const struct ast_includeast_context_includes_get (const struct ast_context *con, int idx)
 
int ast_context_lockmacro (const char *context)
 locks the macrolock in the given context More...
 
int ast_context_remove_extension (const char *context, const char *extension, int priority, const char *registrar)
 Simply remove extension from context. More...
 
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. More...
 
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 ... More...
 
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. More...
 
int ast_context_remove_switch (const char *context, const char *sw, const char *data, const char *registrar)
 Remove a switch. More...
 
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. More...
 
void ast_context_set_autohints (struct ast_context *con, int enabled)
 Enable or disable autohints support on a context. More...
 
int ast_context_switches_count (const struct ast_context *con)
 
const struct ast_swast_context_switches_get (const struct ast_context *con, int idx)
 
int ast_context_unlockmacro (const char *context)
 Unlocks the macrolock in the given context. More...
 
int ast_context_verify_includes (struct ast_context *con)
 Verifies includes in an ast_contect structure. More...
 
enum ast_extension_states ast_devstate_to_extenstate (enum ast_device_state devstate)
 Map devstate to an extension state. More...
 
int ast_exists_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
 Determine whether an extension exists. More...
 
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. More...
 
int ast_extension_match (const char *pattern, const char *data)
 Determine if a given extension matches a given pattern (in NXX format) More...
 
int ast_extension_state (struct ast_channel *c, const char *context, const char *exten)
 Check extension state for an extension by using hint. More...
 
static int ast_extension_state2 (struct ast_exten *e, struct ao2_container *device_state_info)
 Check state of extension by using hints. More...
 
const char * ast_extension_state2str (int extension_state)
 Return extension_state as string. More...
 
static int ast_extension_state3 (struct ast_str *hint_app, struct ao2_container *device_state_info)
 
int ast_extension_state_add (const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
 Add watcher for extension states. More...
 
int ast_extension_state_add_destroy (const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
 Add watcher for extension states with destructor. More...
 
int ast_extension_state_add_destroy_extended (const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
 Add watcher for extended extension states with destructor. More...
 
int ast_extension_state_add_extended (const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
 Add watcher for extended extension states. More...
 
int ast_extension_state_del (int id, ast_state_cb_type change_cb)
 Deletes a state change watcher by ID. More...
 
int ast_extension_state_extended (struct ast_channel *c, const char *context, const char *exten, struct ao2_container **device_state_info)
 Check extended extension state for an extension by using hint. More...
 
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. More...
 
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. More...
 
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_contextast_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)
 
const char * ast_get_extension_registrar_file (struct ast_exten *e)
 Get name of configuration file used by registrar to register this extension. More...
 
int ast_get_extension_registrar_line (struct ast_exten *e)
 Get line number of configuration file used by registrar to register this extension. More...
 
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. More...
 
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 More...
 
unsigned int ast_hashtab_hash_contexts (const void *obj)
 
static struct ast_extenast_hint_extension (struct ast_channel *c, const char *context, const char *exten)
 
static struct ast_extenast_hint_extension_nolock (struct ast_channel *c, const char *context, const char *exten)
 Find hint for given extension in context. More...
 
int ast_hint_presence_state (struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
 Uses hint and presence state callback to get the presence state of an extension. More...
 
int ast_ignore_pattern (const char *context, const char *pattern)
 Checks to see if a number should be ignored. More...
 
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) More...
 
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. More...
 
int ast_parseable_goto (struct ast_channel *chan, const char *goto_string)
 
void ast_pbx_h_exten_run (struct ast_channel *chan, const char *context)
 Run the h exten from the given context. More...
 
int ast_pbx_init (void)
 
int ast_pbx_outgoing_app (const char *type, struct ast_format_cap *cap, const char *addr, 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, const struct ast_assigned_ids *assignedids)
 Synchronously or asynchronously make an outbound call and execute an application on the channel. More...
 
int ast_pbx_outgoing_app_predial (const char *type, struct ast_format_cap *cap, const char *addr, 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, const struct ast_assigned_ids *assignedids, const char *predial_callee)
 
int ast_pbx_outgoing_exten (const char *type, struct ast_format_cap *cap, const char *addr, 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 **locked_channel, int early_media, const struct ast_assigned_ids *assignedids)
 Synchronously or asynchronously make an outbound call and send it to a particular extension. More...
 
int ast_pbx_outgoing_exten_predial (const char *type, struct ast_format_cap *cap, const char *addr, 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 **locked_channel, int early_media, const struct ast_assigned_ids *assignedids, const char *predial_callee)
 
enum ast_pbx_result ast_pbx_run (struct ast_channel *c)
 Execute the PBX in the current thread. More...
 
enum ast_pbx_result ast_pbx_run_args (struct ast_channel *c, struct ast_pbx_args *args)
 Execute the PBX in the current thread. More...
 
enum ast_pbx_result ast_pbx_start (struct ast_channel *c)
 Create a new thread and start the PBX. More...
 
int ast_processed_calls (void)
 Retrieve the total number of calls processed through the PBX since last restart. More...
 
int ast_rdlock_context (struct ast_context *con)
 Read locks a given context. More...
 
int ast_rdlock_contexts (void)
 Read locks the context list. More...
 
static int ast_remove_hint (struct ast_exten *e)
 Remove hint from extension. More...
 
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) More...
 
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. More...
 
int ast_unlock_context (struct ast_context *con)
 
int ast_unlock_contexts (void)
 Unlocks contexts. More...
 
struct ast_extenast_walk_context_extensions (struct ast_context *con, struct ast_exten *exten)
 
const struct ast_ignorepatast_walk_context_ignorepats (const struct ast_context *con, const struct ast_ignorepat *ip)
 
const struct ast_includeast_walk_context_includes (const struct ast_context *con, const struct ast_include *inc)
 
const struct ast_swast_walk_context_switches (const struct ast_context *con, const struct ast_sw *sw)
 
struct ast_contextast_walk_contexts (struct ast_context *con)
 
struct ast_extenast_walk_extension_priorities (struct ast_exten *exten, struct ast_exten *priority)
 
int ast_wrlock_context (struct ast_context *con)
 Write locks a given context. More...
 
int ast_wrlock_contexts (void)
 Write locks the context list. More...
 
static int autohint_cmp (void *obj, void *arg, int flags)
 
static int autohint_hash_cb (const void *obj, const int flags)
 
static const char * candidate_exten_advance (const char *str)
 
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. More...
 
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' More...
 
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 context_table_create_autohints (struct ast_hashtab *table)
 
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_hint (void *obj)
 
static void destroy_pattern_tree (struct match_char *pattern_tree)
 
static void destroy_state_cb (void *doomed)
 
static void device_state_cb (void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void device_state_info_dt (void *obj)
 
static void device_state_notify_callbacks (struct ast_hint *hint, struct ast_str **hint_app)
 
static void exception_store_free (void *data)
 
static int execute_state_callback (ast_state_cb_type cb, const char *context, const char *exten, void *data, enum ast_state_cb_update_reason reason, struct ast_hint *hint, struct ao2_container *device_state_info)
 
static int ext_cmp (const char *left, const char *right)
 
static int ext_cmp_exten (const char *left, const char *right)
 
static int ext_cmp_exten_partial (const char *left, const char *right)
 
static int ext_cmp_exten_strlen (const char *str)
 
static int ext_cmp_pattern (const char *left, const char *right)
 
static int ext_cmp_pattern_pos (const char **p, unsigned char *bitwise)
 helper functions to sort extension patterns in the desired way, so that more specific patterns appear first. More...
 
static int ext_fluff_count (const char *exten)
 
static unsigned int ext_strncpy (char *dst, const char *src, size_t dst_size, int nofluff)
 
static int extension_match_core (const char *pattern, const char *data, enum ext_match_t mode)
 
static int extension_presence_state_helper (struct ast_exten *e, char **subtype, char **message)
 
static int extension_state_add_destroy (const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data, int extended)
 
static struct ast_contextfind_context (const char *context)
 lookup for a context with a given name, More...
 
static struct ast_contextfind_context_locked (const char *context)
 lookup for a context with a given name, More...
 
static int find_hint_by_cb_id (void *obj, void *arg, int flags)
 Find Hint by callback id. More...
 
static struct ast_extenget_canmatch_exten (struct match_char *node)
 
static void get_device_state_causing_channels (struct ao2_container *c)
 
static const char * get_pattern_node (struct pattern_node *node, const char *src, int pattern, const char *extenbuf)
 
static char * handle_debug_dialplan (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Send ack once. More...
 
static int handle_hint_change_message_type (struct stasis_message *msg, enum ast_state_cb_update_reason reason)
 
static char * handle_set_extenpatternmatchnew (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_show_device2extenstate (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_show_dialplan (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
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 More...
 
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 More...
 
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 hint_cmp (void *obj, void *arg, int flags)
 
static int hint_hash (const void *obj, const int flags)
 
static int hint_id_cmp (void *obj, void *arg, int flags)
 
static int hintdevice_cmp_multiple (void *obj, void *arg, int flags)
 
static void hintdevice_destroy (void *obj)
 
static int hintdevice_hash_cb (const void *obj, const int flags)
 
static int hintdevice_remove_cb (void *obj, void *arg, void *data, int flags)
 
static int increase_call_count (const struct ast_channel *c)
 Increase call count for channel. More...
 
static void insert_in_next_chars_alt_char_list (struct match_char **parent_ptr, struct match_char *node)
 
static int internal_extension_state_extended (struct ast_channel *c, const char *context, const char *exten, struct ao2_container *device_state_info)
 
int load_pbx (void)
 
static void manager_dpsendack (struct mansession *s, const struct message *m)
 Send ack once. More...
 
static int manager_show_dialplan (struct mansession *s, const struct message *m)
 Manager listing of dial plan. More...
 
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, const struct ast_include *rinclude, int includecount, const char *includes[])
 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. More...
 
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 char * parse_hint_device (struct ast_str *hint_args)
 
static char * parse_hint_presence (struct ast_str *hint_args)
 
int pbx_checkcondition (const char *condition)
 Evaluate a condition. More...
 
static void pbx_destroy (struct ast_pbx *p)
 
static enum ast_control_frame_type pbx_dial_reason (enum ast_dial_result dial_result, int cause)
 Attempt to convert disconnect cause to old originate reason. More...
 
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: More...
 
struct ast_extenpbx_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)
 
static int pbx_outgoing_attempt (const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, 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, int early_media, const struct ast_assigned_ids *assignedids, const char *predial_callee)
 
static void pbx_outgoing_destroy (void *obj)
 Destructor for outgoing structure. More...
 
static void * pbx_outgoing_exec (void *data)
 Internal function which dials an outgoing leg and sends it to a provided extension or application. More...
 
static void pbx_outgoing_state_callback (struct ast_dial *dial)
 Internal dialing state callback which causes early media to trigger an answer. More...
 
static int pbx_parseable_goto (struct ast_channel *chan, const char *goto_string, int async)
 
int pbx_set_autofallthrough (int newval)
 
int pbx_set_extenpatternmatchnew (int newval)
 
void pbx_set_overrideswitch (const char *newval)
 
static void pbx_shutdown (void)
 
static void * pbx_thread (void *data)
 
static void presence_state_cb (void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void presence_state_notify_callbacks (struct ast_hint *hint, struct ast_str **hint_app, struct ast_presence_state_message *presence_state)
 
static void print_autohint_key (void *v_obj, void *where, ao2_prnt_fn *prnt)
 
static void print_ext (struct ast_exten *e, char *buf, int buflen)
 helper function to print an extension More...
 
static void print_hintdevices_key (void *v_obj, void *where, ao2_prnt_fn *prnt)
 
static void print_hints_key (void *v_obj, void *where, ao2_prnt_fn *prnt)
 
static void print_statecbs_key (void *v_obj, void *where, ao2_prnt_fn *prnt)
 
static int publish_hint_change (struct ast_hint *hint, struct ast_exten *ne)
 Publish a hint changed event. More...
 
static int publish_hint_remove (struct ast_hint *hint)
 Publish a hint removed event. More...
 
int raise_exception (struct ast_channel *chan, const char *reason, int priority)
 
static int remove_hintdevice (struct ast_hint *hint)
 
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, const struct ast_include *rinclude, int includecount, const char *includes[])
 
static void show_dialplan_helper_extension_output (int fd, char *buf1, char *buf2, struct ast_exten *exten)
 Writes CLI output of a single extension for show dialplan. More...
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (hint_change_message_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (hint_remove_message_type)
 
static int statecbs_cmp (void *obj, void *arg, int flags)
 
static int testtime_write (struct ast_channel *chan, const char *cmd, char *var, const char *value)
 
static struct ast_extentrie_find_next_match (struct match_char *node)
 
static void unload_pbx (void)
 
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)
 
void wait_for_hangup (struct ast_channel *chan, const void *data)
 

Variables

static int autofallthrough = 1
 
static struct ao2_containerautohints
 Container for autohint contexts. More...
 
static ast_mutex_t conlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 Lock for the ast_context list. More...
 
static ast_mutex_t context_merge_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 Lock to hold off restructuring of hints by ast_merge_contexts_and_delete. More...
 
static struct ast_contextcontexts
 
static struct ast_hashtabcontexts_table = NULL
 
static int countcalls
 
static struct stasis_subscriptiondevice_state_sub
 Subscription for device state change events. More...
 
static struct ast_custom_function exception_function
 
static const struct ast_datastore_info exception_store_info
 
static int extenpatternmatchnew = 0
 
static const 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 ast_threadstorage hintdevice_data = { .once = PTHREAD_ONCE_INIT , .key_init = __init_hintdevice_data , .custom_init = NULL , }
 
static struct ao2_containerhintdevices
 Container for hint devices. More...
 
static struct ao2_containerhints
 
static ast_mutex_t maxcalllock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 
static char * overrideswitch = NULL
 
static struct ast_cli_entry pbx_cli []
 
static struct stasis_subscriptionpresence_state_sub
 Subscription for presence state change events. More...
 
static struct ao2_containerstatecbs
 
static int stateid = 1
 
static struct ast_threadstorage switch_data = { .once = PTHREAD_ONCE_INIT , .key_init = __init_switch_data , .custom_init = NULL , }
 
static struct ast_custom_function testtime_function
 
static int totalcalls
 

Detailed Description

Core PBX routines.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file pbx.c.

Macro Definition Documentation

◆ ADVANCE

#define ADVANCE (   s)    candidate_exten_advance(s)

Definition at line 1229 of file pbx.c.

◆ BITS_PER

#define BITS_PER   8 /* Number of bits per unit (byte). */

Referenced by ext_cmp_pattern_pos().

◆ EXT_DATA_SIZE

#define EXT_DATA_SIZE   8192
Note
I M P O R T A N T :

The speed of extension handling will likely be among the most important aspects of this PBX. The switching scheme as it exists right now isn't terribly bad (it's O(N+M), where N is the # of extensions and M is the avg # of priorities, but a constant search time here would be great ;-)

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 216 of file pbx.c.

Referenced by pbx_extension_helper().

◆ HASH_EXTENHINT_SIZE

#define HASH_EXTENHINT_SIZE   563

Definition at line 358 of file pbx.c.

Referenced by ast_pbx_init().

◆ HINTDEVICE_DATA_LENGTH

#define HINTDEVICE_DATA_LENGTH   16

Definition at line 351 of file pbx.c.

◆ INC_DST_OVERFLOW_CHECK

#define INC_DST_OVERFLOW_CHECK

Referenced by get_pattern_node().

◆ MORE

#define MORE (   s)    (*candidate_exten_advance(s))

Definition at line 1228 of file pbx.c.

◆ NEW_MATCHER_CHK_MATCH

#define NEW_MATCHER_CHK_MATCH

Referenced by new_find_extension().

◆ NEW_MATCHER_RECURSE

#define NEW_MATCHER_RECURSE

Referenced by new_find_extension().

◆ SAY_STUBS

#define SAY_STUBS   /* generate declarations and stubs for say methods */

Definition at line 57 of file pbx.c.

◆ STATUS_NO_CONTEXT

#define STATUS_NO_CONTEXT   1

Definition at line 2467 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

◆ STATUS_NO_EXTENSION

#define STATUS_NO_EXTENSION   2

Definition at line 2468 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

◆ STATUS_NO_LABEL

#define STATUS_NO_LABEL   4

Definition at line 2470 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

◆ STATUS_NO_PRIORITY

#define STATUS_NO_PRIORITY   3

Definition at line 2469 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

◆ STATUS_SUCCESS

#define STATUS_SUCCESS   5

Definition at line 2471 of file pbx.c.

Referenced by pbx_find_extension().

◆ SWITCH_DATA_LENGTH

#define SWITCH_DATA_LENGTH   256

Definition at line 219 of file pbx.c.

◆ VAR_HARDTRAN

#define VAR_HARDTRAN   3

Definition at line 223 of file pbx.c.

◆ VAR_NORMAL

#define VAR_NORMAL   1

Definition at line 221 of file pbx.c.

◆ VAR_SOFTTRAN

#define VAR_SOFTTRAN   2

Definition at line 222 of file pbx.c.

Function Documentation

◆ __ast_context_destroy()

void __ast_context_destroy ( struct ast_context list,
struct ast_hashtab contexttab,
struct ast_context con,
const char *  registrar 
)

Definition at line 8095 of file pbx.c.

References __ast_internal_context_destroy(), ast_context::alts, ast_context_ignorepats_count(), ast_context_includes_count(), ast_context_remove_extension_callerid2(), ast_context_switches_count(), ast_copy_string(), ast_debug, ast_free, ast_get_ignorepat_registrar(), ast_get_include_registrar(), ast_get_switch_registrar(), ast_hashtab_end_traversal(), ast_hashtab_next(), ast_hashtab_remove_this_object(), ast_hashtab_start_traversal, AST_MAX_EXTENSION, ast_unlock_context(), AST_VECTOR_GET, AST_VECTOR_REMOVE_ORDERED, ast_verb, ast_wrlock_context(), ast_exten::cidmatch, ast_exten::exten, ignorepat_free(), ast_context::ignorepats, include_free(), ast_context::includes, ast_exten::matchcid, ast_exten::name, ast_context::name, ast_exten::next, ast_context::next, NULL, ast_exten::peer_table, ast_exten::priority, ast_context::refcount, ast_exten::registrar, ast_context::registrar, ast_context::root, ast_context::root_table, sw_free(), and tmp().

Referenced by ast_context_destroy(), and ast_context_set_autohints().

8096 {
8097  struct ast_context *tmp, *tmpl=NULL;
8098  struct ast_exten *exten_item, *prio_item;
8099 
8100  for (tmp = list; tmp; ) {
8101  struct ast_context *next = NULL; /* next starting point */
8102  /* The following code used to skip forward to the next
8103  context with matching registrar, but this didn't
8104  make sense; individual priorities registrar'd to
8105  the matching registrar could occur in any context! */
8106  ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
8107  if (con) {
8108  for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
8109  ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
8110  if ( !strcasecmp(tmp->name, con->name) ) {
8111  break; /* found it */
8112  }
8113  }
8114  }
8115 
8116  if (!tmp) /* not found, we are done */
8117  break;
8118  ast_wrlock_context(tmp);
8119 
8120  if (registrar) {
8121  /* then search thru and remove any extens that match registrar. */
8122  struct ast_hashtab_iter *exten_iter;
8123  struct ast_hashtab_iter *prio_iter;
8124  int idx;
8125 
8126  /* remove any ignorepats whose registrar matches */
8127  for (idx = ast_context_ignorepats_count(tmp) - 1; idx >= 0; idx--) {
8128  struct ast_ignorepat *ip = AST_VECTOR_GET(&tmp->ignorepats, idx);
8129 
8130  if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
8131  AST_VECTOR_REMOVE_ORDERED(&tmp->ignorepats, idx);
8132  ignorepat_free(ip);
8133  }
8134  }
8135  /* remove any includes whose registrar matches */
8136  for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) {
8137  struct ast_include *i = AST_VECTOR_GET(&tmp->includes, idx);
8138 
8139  if (!strcmp(ast_get_include_registrar(i), registrar)) {
8140  AST_VECTOR_REMOVE_ORDERED(&tmp->includes, idx);
8141  include_free(i);
8142  }
8143  }
8144  /* remove any switches whose registrar matches */
8145  for (idx = ast_context_switches_count(tmp) - 1; idx >= 0; idx--) {
8146  struct ast_sw *sw = AST_VECTOR_GET(&tmp->alts, idx);
8147 
8148  if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
8149  AST_VECTOR_REMOVE_ORDERED(&tmp->alts, idx);
8150  sw_free(sw);
8151  }
8152  }
8153 
8154  if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
8155  exten_iter = ast_hashtab_start_traversal(tmp->root_table);
8156  while ((exten_item=ast_hashtab_next(exten_iter))) {
8157  int end_traversal = 1;
8158 
8159  /*
8160  * If the extension could not be removed from the root_table due to
8161  * a loaded PBX app, it can exist here but have its peer_table be
8162  * destroyed due to a previous pass through this function.
8163  */
8164  if (!exten_item->peer_table) {
8165  continue;
8166  }
8167 
8168  prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
8169  while ((prio_item=ast_hashtab_next(prio_iter))) {
8171  char cidmatch[AST_MAX_EXTENSION];
8172  if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
8173  continue;
8174  }
8175  ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
8176  tmp->name, prio_item->name, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
8177  ast_copy_string(extension, prio_item->exten, sizeof(extension));
8178  if (prio_item->cidmatch) {
8179  ast_copy_string(cidmatch, prio_item->cidmatch, sizeof(cidmatch));
8180  }
8181  end_traversal &= ast_context_remove_extension_callerid2(tmp, extension, prio_item->priority, cidmatch, prio_item->matchcid, NULL, 1);
8182  }
8183  /* Explanation:
8184  * ast_context_remove_extension_callerid2 will destroy the extension that it comes across. This
8185  * destruction includes destroying the exten's peer_table, which we are currently traversing. If
8186  * ast_context_remove_extension_callerid2 ever should return '0' then this means we have destroyed
8187  * the hashtable which we are traversing, and thus calling ast_hashtab_end_traversal will result
8188  * in reading invalid memory. Thus, if we detect that we destroyed the hashtable, then we will simply
8189  * free the iterator
8190  */
8191  if (end_traversal) {
8192  ast_hashtab_end_traversal(prio_iter);
8193  } else {
8194  ast_free(prio_iter);
8195  }
8196  }
8197  ast_hashtab_end_traversal(exten_iter);
8198  }
8199 
8200  /* delete the context if it's registrar matches, is empty, has refcount of 1, */
8201  /* it's not empty, if it has includes, ignorepats, or switches that are registered from
8202  another registrar. It's not empty if there are any extensions */
8203  if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !ast_context_ignorepats_count(tmp) && !ast_context_includes_count(tmp) && !ast_context_switches_count(tmp)) {
8204  ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
8205  ast_hashtab_remove_this_object(contexttab, tmp);
8206 
8207  next = tmp->next;
8208  if (tmpl)
8209  tmpl->next = next;
8210  else
8211  contexts = next;
8212  /* Okay, now we're safe to let it go -- in a sense, we were
8213  ready to let it go as soon as we locked it. */
8214  ast_unlock_context(tmp);
8216  } else {
8217  ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
8218  tmp->refcount, tmp->root);
8219  ast_unlock_context(tmp);
8220  next = tmp->next;
8221  tmpl = tmp;
8222  }
8223  } else if (con) {
8224  ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
8225  ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
8226  ast_hashtab_remove_this_object(contexttab, tmp);
8227 
8228  next = tmp->next;
8229  if (tmpl)
8230  tmpl->next = next;
8231  else
8232  contexts = next;
8233  /* Okay, now we're safe to let it go -- in a sense, we were
8234  ready to let it go as soon as we locked it. */
8235  ast_unlock_context(tmp);
8237  }
8238 
8239  /* if we have a specific match, we are done, otherwise continue */
8240  tmp = con ? NULL : next;
8241  }
8242 }
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
const char * ast_get_switch_registrar(const struct ast_sw *sw)
Definition: pbx_sw.c:63
int ast_context_switches_count(const struct ast_context *con)
Definition: pbx.c:8652
ast_exten: An extension The dialplan is saved as a linked list with each context having it&#39;s own link...
Definition: pbx.c:237
static void __ast_internal_context_destroy(struct ast_context *con)
Definition: pbx.c:8050
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8530
void include_free(struct ast_include *inc)
Definition: pbx_include.c:106
const char * ast_get_ignorepat_registrar(const struct ast_ignorepat *ip)
Definition: pbx_ignorepat.c:47
char * name
Definition: pbx.c:239
static int tmp()
Definition: bt_open.c:389
void * ast_hashtab_next(struct ast_hashtab_iter *it)
Gets the next object in the list, advances iter one step returns null on end of traversal.
Definition: hashtab.c:683
const char * ast_get_include_registrar(const struct ast_include *i)
Definition: pbx_include.c:60
#define NULL
Definition: resample.c:96
struct ast_hashtab * peer_table
Definition: pbx.c:251
void ignorepat_free(struct ast_ignorepat *ip)
Definition: pbx_ignorepat.c:77
#define ast_verb(level,...)
Definition: logger.h:463
const char * registrar
Definition: pbx.c:253
struct ast_context * next
Definition: pbx.c:289
#define ast_hashtab_start_traversal(tab)
Definition: hashtab.h:355
int matchcid
Definition: pbx.c:240
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
int priority
Definition: pbx.c:243
ast_sw: Switch statement in extensions.conf
Definition: pbx_sw.c:37
char * registrar
Definition: pbx.c:293
#define AST_MAX_EXTENSION
Definition: channel.h:135
structure to hold extensions
#define AST_VECTOR_REMOVE_ORDERED(vec, idx)
Remove an element from a vector by index while maintaining order.
Definition: vector.h:448
void ast_hashtab_end_traversal(struct ast_hashtab_iter *it)
end the traversal, free the iterator, unlock if necc.
Definition: hashtab.c:674
int ast_context_ignorepats_count(const struct ast_context *con)
Definition: pbx.c:8740
char * exten
Definition: pbx.c:238
char name[0]
Definition: pbx.c:297
ast_ignorepat: Ignore patterns in dial plan
Definition: pbx_ignorepat.c:37
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8520
an iterator for traversing the buckets
Definition: hashtab.h:105
static char * registrar
Definition: pbx_ael.c:78
#define ast_free(a)
Definition: astmm.h:182
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: pbx.c:4987
void sw_free(struct ast_sw *sw)
Definition: pbx_sw.c:101
const char * cidmatch
Definition: pbx.c:241
struct ast_sw * next
Definition: pbx_sw.c:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
struct ast_hashtab * root_table
Definition: pbx.c:287
static struct ast_context * contexts
Definition: pbx.c:776
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8697
void * ast_hashtab_remove_this_object(struct ast_hashtab *tab, void *obj)
Hash the object and then compare ptrs in bucket list instead of calling the compare routine...
Definition: hashtab.c:789

◆ __ast_goto_if_exists()

static int __ast_goto_if_exists ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
int  async 
)
static

Definition at line 8772 of file pbx.c.

References ast_async_goto(), ast_channel_caller(), ast_channel_context(), ast_channel_exten(), ast_exists_extension(), ast_explicit_goto(), AST_PBX_GOTO_FAILED, context, ast_exten::exten, NULL, ast_exten::priority, and S_COR.

Referenced by ast_async_goto_if_exists(), and ast_goto_if_exists().

8773 {
8774  int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
8775 
8776  if (!chan)
8777  return -2;
8778 
8779  if (context == NULL)
8780  context = ast_channel_context(chan);
8781  if (exten == NULL)
8782  exten = ast_channel_exten(chan);
8783 
8784  goto_func = (async) ? ast_async_goto : ast_explicit_goto;
8785  if (ast_exists_extension(chan, context, exten, priority,
8786  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)))
8787  return goto_func(chan, context, exten, priority);
8788  else {
8789  return AST_PBX_GOTO_FAILED;
8790  }
8791 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6987
#define NULL
Definition: resample.c:96
static int priority
Number structure.
Definition: app_followme.c:154
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
const char * ast_channel_exten(const struct ast_channel *chan)
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: pbx.c:7011
#define AST_PBX_GOTO_FAILED
Definition: pbx.h:42
const char * ast_channel_context(const struct ast_channel *chan)
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116

◆ __ast_internal_context_destroy()

static void __ast_internal_context_destroy ( struct ast_context con)
static

Definition at line 8050 of file pbx.c.

References ast_context::alts, ast_free, ast_hashtab_destroy(), ast_mutex_destroy, ast_rwlock_destroy, AST_VECTOR_CALLBACK_VOID, AST_VECTOR_FREE, destroy_exten(), destroy_pattern_tree(), el, ignorepat_free(), ast_context::ignorepats, include_free(), ast_context::includes, ast_context::lock, ast_context::macrolock, ast_exten::next, NULL, ast_context::pattern_tree, ast_exten::peer, ast_context::registrar, ast_context::root, ast_context::root_table, sw_free(), and tmp().

Referenced by __ast_context_destroy(), and ast_merge_contexts_and_delete().

8051 {
8052  struct ast_exten *e, *el, *en;
8053  struct ast_context *tmp = con;
8054 
8055  /* Free includes */
8057  AST_VECTOR_FREE(&tmp->includes);
8058 
8059  /* Free ignorepats */
8061  AST_VECTOR_FREE(&tmp->ignorepats);
8062 
8063  /* Free switches */
8065  AST_VECTOR_FREE(&tmp->alts);
8066 
8067  if (tmp->registrar)
8068  ast_free(tmp->registrar);
8069 
8070  /* destroy the hash tabs */
8071  if (tmp->root_table) {
8073  }
8074  /* and destroy the pattern tree */
8075  if (tmp->pattern_tree)
8077 
8078  for (e = tmp->root; e;) {
8079  for (en = e->peer; en;) {
8080  el = en;
8081  en = en->peer;
8082  destroy_exten(el);
8083  }
8084  el = e;
8085  e = e->next;
8086  destroy_exten(el);
8087  }
8088  tmp->root = NULL;
8089  ast_rwlock_destroy(&tmp->lock);
8091  ast_free(tmp);
8092 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
struct ast_ignorepats ignorepats
Definition: pbx.c:291
ast_exten: An extension The dialplan is saved as a linked list with each context having it&#39;s own link...
Definition: pbx.c:237
struct ast_exten * root
Definition: pbx.c:286
void include_free(struct ast_include *inc)
Definition: pbx_include.c:106
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:231
static int tmp()
Definition: bt_open.c:389
static EditLine * el
Definition: asterisk.c:340
#define NULL
Definition: resample.c:96
void ignorepat_free(struct ast_ignorepat *ip)
Definition: pbx_ignorepat.c:77
ast_mutex_t macrolock
Definition: pbx.c:296
struct ast_exten * next
Definition: pbx.c:256
struct ast_exten * peer
Definition: pbx.c:250
char * registrar
Definition: pbx.c:293
struct ast_includes includes
Definition: pbx.c:290
ast_rwlock_t lock
Definition: pbx.c:285
#define ast_free(a)
Definition: astmm.h:182
static void destroy_pattern_tree(struct match_char *pattern_tree)
Definition: pbx.c:1779
void sw_free(struct ast_sw *sw)
Definition: pbx_sw.c:101
struct ast_hashtab * root_table
Definition: pbx.c:287
#define ast_mutex_destroy(a)
Definition: lock.h:186
struct ast_sws alts
Definition: pbx.c:292
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284
struct match_char * pattern_tree
Definition: pbx.c:288
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:865
static void destroy_exten(struct ast_exten *e)
Definition: pbx.c:4678
void ast_hashtab_destroy(struct ast_hashtab *tab, void(*objdestroyfunc)(void *obj))
This func will free the hash table and all its memory.
Definition: hashtab.c:363

◆ __ast_pbx_run()

static enum ast_pbx_result __ast_pbx_run ( struct ast_channel c,
struct ast_pbx_args args 
)
static
Note
We get here on a failure of some kind: non-existing extension or hangup. We have options, here. We can either catch the failure and continue, or we can drop out entirely.
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 4310 of file pbx.c.

References ast_callid_threadassoc_add(), ast_calloc, ast_channel_caller(), ast_channel_callid(), ast_channel_callid_set(), ast_channel_clear_softhangup(), ast_channel_context(), ast_channel_exten(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_pbx(), ast_channel_pbx_set(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_softhangup_internal_flag(), ast_channel_unlock, ast_channel_whentohangup(), ast_check_hangup(), ast_clear_flag, ast_copy_string(), ast_create_callid(), ast_debug, ast_exists_extension(), AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, ast_free, ast_hangup(), ast_log, ast_matchmore_extension(), AST_PBX_ERROR, AST_PBX_FAILED, ast_pbx_h_exten_run(), ast_pbx_hangup_handler_run(), AST_PBX_INCOMPLETE, AST_PBX_SUCCESS, ast_read_threadstorage_callid(), 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, collect_digits(), digit, ast_pbx::dtimeoutms, error(), indicate_busy(), indicate_congestion(), LOG_WARNING, ast_pbx_args::no_hangup_chan, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_destroy(), raise_exception(), ast_pbx::rtimeoutms, S_COR, set_ext_pri(), status, and timeout.

Referenced by ast_pbx_run_args(), and pbx_thread().

4312 {
4313  int found = 0; /* set if we find at least one match */
4314  int res = 0;
4315  int autoloopflag;
4316  int error = 0; /* set an error conditions */
4317  struct ast_pbx *pbx;
4318  ast_callid callid;
4319 
4320  /* A little initial setup here */
4321  if (ast_channel_pbx(c)) {
4322  ast_log(LOG_WARNING, "%s already has PBX structure??\n", ast_channel_name(c));
4323  /* XXX and now what ? */
4325  }
4326  if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
4327  return AST_PBX_FAILED;
4328  }
4329 
4330  callid = ast_read_threadstorage_callid();
4331  /* If the thread isn't already associated with a callid, we should create that association. */
4332  if (!callid) {
4333  /* Associate new PBX thread with the channel call id if it is availble.
4334  * If not, create a new one instead.
4335  */
4336  callid = ast_channel_callid(c);
4337  if (!callid) {
4338  callid = ast_create_callid();
4339  if (callid) {
4340  ast_channel_lock(c);
4341  ast_channel_callid_set(c, callid);
4342  ast_channel_unlock(c);
4343  }
4344  }
4346  callid = 0;
4347  }
4348 
4349  ast_channel_pbx_set(c, pbx);
4350  /* Set reasonable defaults */
4351  ast_channel_pbx(c)->rtimeoutms = 10000;
4352  ast_channel_pbx(c)->dtimeoutms = 5000;
4353 
4354  ast_channel_lock(c);
4355  autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
4357  ast_channel_unlock(c);
4358 
4360  /* If not successful fall back to 's' - but only if there is no given exten */
4361  ast_verb(2, "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
4362  /* XXX the original code used the existing priority in the call to
4363  * ast_exists_extension(), and reset it to 1 afterwards.
4364  * I believe the correct thing is to set it to 1 immediately.
4365  */
4366  set_ext_pri(c, "s", 1);
4367  }
4368 
4369  for (;;) {
4370  char dst_exten[256]; /* buffer to accumulate digits */
4371  int pos = 0; /* XXX should check bounds */
4372  int digit = 0;
4373  int invalid = 0;
4374  int timeout = 0;
4375 
4376  /* No digits pressed yet */
4377  dst_exten[pos] = '\0';
4378 
4379  /* loop on priorities in this context/exten */
4381  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL),
4382  &found, 1))) {
4383 
4384  if (!ast_check_hangup(c)) {
4386  continue;
4387  }
4388 
4389  /* Check softhangup flags. */
4391  ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
4392  continue;
4393  }
4395  if (ast_exists_extension(c, ast_channel_context(c), "T", 1,
4396  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4397  set_ext_pri(c, "T", 1);
4398  /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4399  memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
4400  ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
4401  continue;
4402  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4403  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4404  raise_exception(c, "ABSOLUTETIMEOUT", 1);
4405  /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4406  memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
4407  ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
4408  continue;
4409  }
4410 
4411  /* Call timed out with no special extension to jump to. */
4412  error = 1;
4413  break;
4414  }
4415  ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
4417  error = 1;
4418  break;
4419  } /* end while - from here on we can use 'break' to go out */
4420  if (found && res) {
4421  /* Something bad happened, or a hangup has been requested. */
4422  if (strchr("0123456789ABCDEF*#", res)) {
4423  ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
4424  pos = 0;
4425  dst_exten[pos++] = digit = res;
4426  dst_exten[pos] = '\0';
4427  } else if (res == AST_PBX_INCOMPLETE) {
4428  ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4429  ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4430 
4431  /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
4433  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4434  invalid = 1;
4435  } else {
4436  ast_copy_string(dst_exten, ast_channel_exten(c), sizeof(dst_exten));
4437  digit = 1;
4438  pos = strlen(dst_exten);
4439  }
4440  } else {
4441  ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4442  ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4443 
4444  if ((res == AST_PBX_ERROR)
4445  && ast_exists_extension(c, ast_channel_context(c), "e", 1,
4446  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4447  /* if we are already on the 'e' exten, don't jump to it again */
4448  if (!strcmp(ast_channel_exten(c), "e")) {
4449  ast_verb(2, "Spawn extension (%s, %s, %d) exited ERROR while already on 'e' exten on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4450  error = 1;
4451  } else {
4452  raise_exception(c, "ERROR", 1);
4453  continue;
4454  }
4455  }
4456 
4457  if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
4458  ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
4459  continue;
4460  }
4461  if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
4462  if (ast_exists_extension(c, ast_channel_context(c), "T", 1,
4463  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4464  set_ext_pri(c, "T", 1);
4465  /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4466  memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
4467  ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
4468  continue;
4469  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4470  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4471  raise_exception(c, "ABSOLUTETIMEOUT", 1);
4472  /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4473  memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
4474  ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
4475  continue;
4476  }
4477  /* Call timed out with no special extension to jump to. */
4478  }
4479  error = 1;
4480  break;
4481  }
4482  }
4483  if (error)
4484  break;
4485 
4486  /*!\note
4487  * We get here on a failure of some kind: non-existing extension or
4488  * hangup. We have options, here. We can either catch the failure
4489  * and continue, or we can drop out entirely. */
4490 
4491  if (invalid
4492  || (ast_strlen_zero(dst_exten) &&
4494  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL)))) {
4495  /*!\note
4496  * If there is no match at priority 1, it is not a valid extension anymore.
4497  * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
4498  * neither exist.
4499  */
4500  if (ast_exists_extension(c, ast_channel_context(c), "i", 1,
4501  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4502  ast_verb(3, "Channel '%s' sent to invalid extension: context,exten,priority=%s,%s,%d\n",
4504  pbx_builtin_setvar_helper(c, "INVALID_EXTEN", ast_channel_exten(c));
4505  set_ext_pri(c, "i", 1);
4506  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4507  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4508  raise_exception(c, "INVALID", 1);
4509  } else {
4510  ast_log(LOG_WARNING, "Channel '%s' sent to invalid extension but no invalid handler: context,exten,priority=%s,%s,%d\n",
4512  error = 1; /* we know what to do with it */
4513  break;
4514  }
4515  } else if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
4516  /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
4517  ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
4518  } else { /* keypress received, get more digits for a full extension */
4519  int waittime = 0;
4520  if (digit)
4521  waittime = ast_channel_pbx(c)->dtimeoutms;
4522  else if (!autofallthrough)
4523  waittime = ast_channel_pbx(c)->rtimeoutms;
4524  if (!waittime) {
4525  const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
4526  if (!status)
4527  status = "UNKNOWN";
4528  ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
4529  if (!strcasecmp(status, "CONGESTION"))
4530  res = indicate_congestion(c, "10");
4531  else if (!strcasecmp(status, "CHANUNAVAIL"))
4532  res = indicate_congestion(c, "10");
4533  else if (!strcasecmp(status, "BUSY"))
4534  res = indicate_busy(c, "10");
4535  error = 1; /* XXX disable message */
4536  break; /* exit from the 'for' loop */
4537  }
4538 
4539  if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
4540  break;
4541  if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
4542  timeout = 1;
4543  if (!timeout
4544  && ast_exists_extension(c, ast_channel_context(c), dst_exten, 1,
4545  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) { /* Prepare the next cycle */
4546  set_ext_pri(c, dst_exten, 1);
4547  } else {
4548  /* No such extension */
4549  if (!timeout && !ast_strlen_zero(dst_exten)) {
4550  /* An invalid extension */
4551  if (ast_exists_extension(c, ast_channel_context(c), "i", 1,
4552  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4553  ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, ast_channel_context(c), ast_channel_name(c));
4554  pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
4555  set_ext_pri(c, "i", 1);
4556  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4557  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4558  raise_exception(c, "INVALID", 1);
4559  } else {
4561  "Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
4562  dst_exten, ast_channel_context(c));
4563  found = 1; /* XXX disable message */
4564  break;
4565  }
4566  } else {
4567  /* A simple timeout */
4568  if (ast_exists_extension(c, ast_channel_context(c), "t", 1,
4569  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4570  ast_verb(3, "Timeout on %s\n", ast_channel_name(c));
4571  set_ext_pri(c, "t", 1);
4572  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4573  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4574  raise_exception(c, "RESPONSETIMEOUT", 1);
4575  } else {
4577  "Timeout, but no rule 't' or 'e' in context '%s'\n",
4578  ast_channel_context(c));
4579  found = 1; /* XXX disable message */
4580  break;
4581  }
4582  }
4583  }
4584  }
4585  }
4586 
4587  if (!found && !error) {
4588  ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", ast_channel_name(c));
4589  }
4590 
4591  if (!args || !args->no_hangup_chan) {
4594  && ast_exists_extension(c, ast_channel_context(c), "h", 1,
4595  S_COR(ast_channel_caller(c)->id.number.valid,
4596  ast_channel_caller(c)->id.number.str, NULL))) {
4598  }
4600  }
4601 
4602  ast_channel_lock(c);
4604  ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
4605  ast_channel_unlock(c);
4608 
4609  if (!args || !args->no_hangup_chan) {
4610  ast_hangup(c);
4611  }
4612 
4613  return AST_PBX_SUCCESS;
4614 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
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)
Definition: pbx.c:4204
char digit
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:274
static int autofallthrough
Definition: pbx.c:763
static int timeout
Definition: cdr_mysql.c:86
unsigned int ast_callid
Definition: logger.h:87
#define NULL
Definition: resample.c:96
int ast_channel_priority(const struct ast_channel *chan)
#define ast_verb(level,...)
Definition: logger.h:463
static void pbx_destroy(struct ast_pbx *p)
Definition: pbx.c:985
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:1962
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
Number structure.
Definition: app_followme.c:154
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:1984
int indicate_congestion(struct ast_channel *chan, const char *data)
Definition: pbx_builtins.c:757
Definition: pbx.h:211
#define AST_PBX_ERROR
Definition: pbx.h:50
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
int raise_exception(struct ast_channel *chan, const char *reason, int priority)
Definition: pbx.c:2806
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2437
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2476
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
int indicate_busy(struct ast_channel *chan, const char *data)
Definition: pbx_builtins.c:739
const char * ast_channel_exten(const struct ast_channel *chan)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
#define AST_PBX_INCOMPLETE
Definition: pbx.h:51
void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
Definition: pbx.c:4268
ast_callid ast_create_callid(void)
factory function to create a new uniquely identifying callid.
Definition: logger.c:1957
static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
collect digits from the channel into the buffer.
Definition: pbx.c:4283
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
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) ...
Definition: pbx.c:4199
void ast_channel_pbx_set(struct ast_channel *chan, struct ast_pbx *value)
#define ast_clear_flag(p, flag)
Definition: utils.h:77
void ast_channel_callid_set(struct ast_channel *chan, ast_callid value)
int ast_pbx_hangup_handler_run(struct ast_channel *chan)
Run all hangup handlers on the channel.
int 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 ast_channel_softhangup_internal_flag(struct ast_channel *chan)
int dtimeoutms
Definition: pbx.h:212
void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
Run the h exten from the given context.
Definition: pbx.c:4209
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
int error(const char *format,...)
Definition: utils/frame.c:999
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
void ast_channel_priority_set(struct ast_channel *chan, int value)
unsigned int no_hangup_chan
Definition: pbx.h:398
ast_callid ast_channel_callid(const struct ast_channel *chan)
jack_status_t status
Definition: app_jack.c:146
int rtimeoutms
Definition: pbx.h:213

◆ __init_extensionstate_buf()

static void __init_extensionstate_buf ( void  )
static

Definition at line 229 of file pbx.c.

237 {

◆ __init_hintdevice_data()

static void __init_hintdevice_data ( void  )
static

Definition at line 352 of file pbx.c.

369 {

◆ __init_switch_data()

static void __init_switch_data ( void  )
static

Definition at line 228 of file pbx.c.

237 {

◆ _extension_match_core()

static int _extension_match_core ( const char *  pattern,
const char *  data,
enum ext_match_t  mode 
)
static

Definition at line 2209 of file pbx.c.

References ast_log, ast_exten::data, E_MATCH, E_MATCH_MASK, E_MATCHMORE, end, ext_cmp_exten(), ext_cmp_exten_partial(), ext_cmp_exten_strlen(), ext_cmp_pattern(), LOG_NOTICE, and LOG_WARNING.

Referenced by extension_match_core().

2210 {
2211  mode &= E_MATCH_MASK; /* only consider the relevant bits */
2212 
2213 #ifdef NEED_DEBUG_HERE
2214  ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
2215 #endif
2216 
2217  if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
2218  int lp = ext_cmp_exten_strlen(pattern);
2219  int ld = ext_cmp_exten_strlen(data);
2220 
2221  if (lp < ld) { /* pattern too short, cannot match */
2222 #ifdef NEED_DEBUG_HERE
2223  ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
2224 #endif
2225  return 0;
2226  }
2227  /* depending on the mode, accept full or partial match or both */
2228  if (mode == E_MATCH) {
2229 #ifdef NEED_DEBUG_HERE
2230  ast_log(LOG_NOTICE,"return (!ext_cmp_exten(%s,%s) when mode== E_MATCH)\n", pattern, data);
2231 #endif
2232  return !ext_cmp_exten(pattern, data); /* 1 on match, 0 on fail */
2233  }
2234  if (ld == 0 || !ext_cmp_exten_partial(pattern, data)) { /* partial or full match */
2235 #ifdef NEED_DEBUG_HERE
2236  ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
2237 #endif
2238  return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
2239  } else {
2240 #ifdef NEED_DEBUG_HERE
2241  ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
2242 #endif
2243  return 0;
2244  }
2245  }
2246  if (mode == E_MATCH && data[0] == '_') {
2247  /*
2248  * XXX It is bad design that we don't know if we should be
2249  * comparing data and pattern as patterns or comparing data if
2250  * it conforms to pattern when the function is called. First,
2251  * assume they are both patterns. If they don't match then try
2252  * to see if data conforms to the given pattern.
2253  *
2254  * note: if this test is left out, then _x. will not match _x. !!!
2255  */
2256 #ifdef NEED_DEBUG_HERE
2257  ast_log(LOG_NOTICE, "Comparing as patterns first. pattern:%s data:%s\n", pattern, data);
2258 #endif
2259  if (!ext_cmp_pattern(pattern + 1, data + 1)) {
2260 #ifdef NEED_DEBUG_HERE
2261  ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
2262 #endif
2263  return 1;
2264  }
2265  }
2266 
2267  ++pattern; /* skip leading _ */
2268  /*
2269  * XXX below we stop at '/' which is a separator for the CID info. However we should
2270  * not store '/' in the pattern at all. When we insure it, we can remove the checks.
2271  */
2272  for (;;) {
2273  const char *end;
2274 
2275  /* Ignore '-' chars as eye candy fluff. */
2276  while (*data == '-') {
2277  ++data;
2278  }
2279  while (*pattern == '-') {
2280  ++pattern;
2281  }
2282  if (!*data || !*pattern || *pattern == '/') {
2283  break;
2284  }
2285 
2286  switch (*pattern) {
2287  case '[': /* a range */
2288  ++pattern;
2289  end = strchr(pattern, ']'); /* XXX should deal with escapes ? */
2290  if (!end) {
2291  ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
2292  return 0; /* unconditional failure */
2293  }
2294  if (pattern == end) {
2295  /* Ignore empty character sets. */
2296  ++pattern;
2297  continue;
2298  }
2299  for (; pattern < end; ++pattern) {
2300  if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
2301  if (*data >= pattern[0] && *data <= pattern[2])
2302  break; /* match found */
2303  else {
2304  pattern += 2; /* skip a total of 3 chars */
2305  continue;
2306  }
2307  } else if (*data == pattern[0])
2308  break; /* match found */
2309  }
2310  if (pattern >= end) {
2311 #ifdef NEED_DEBUG_HERE
2312  ast_log(LOG_NOTICE,"return (0) when pattern>=end\n");
2313 #endif
2314  return 0;
2315  }
2316  pattern = end; /* skip and continue */
2317  break;
2318  case 'n':
2319  case 'N':
2320  if (*data < '2' || *data > '9') {
2321 #ifdef NEED_DEBUG_HERE
2322  ast_log(LOG_NOTICE,"return (0) N is not matched\n");
2323 #endif
2324  return 0;
2325  }
2326  break;
2327  case 'x':
2328  case 'X':
2329  if (*data < '0' || *data > '9') {
2330 #ifdef NEED_DEBUG_HERE
2331  ast_log(LOG_NOTICE,"return (0) X is not matched\n");
2332 #endif
2333  return 0;
2334  }
2335  break;
2336  case 'z':
2337  case 'Z':
2338  if (*data < '1' || *data > '9') {
2339 #ifdef NEED_DEBUG_HERE
2340  ast_log(LOG_NOTICE,"return (0) Z is not matched\n");
2341 #endif
2342  return 0;
2343  }
2344  break;
2345  case '.': /* Must match, even with more digits */
2346 #ifdef NEED_DEBUG_HERE
2347  ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
2348 #endif
2349  return 1;
2350  case '!': /* Early match */
2351 #ifdef NEED_DEBUG_HERE
2352  ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
2353 #endif
2354  return 2;
2355  default:
2356  if (*data != *pattern) {
2357 #ifdef NEED_DEBUG_HERE
2358  ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
2359 #endif
2360  return 0;
2361  }
2362  break;
2363  }
2364  ++data;
2365  ++pattern;
2366  }
2367  if (*data) /* data longer than pattern, no match */ {
2368 #ifdef NEED_DEBUG_HERE
2369  ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
2370 #endif
2371  return 0;
2372  }
2373 
2374  /*
2375  * match so far, but ran off the end of data.
2376  * Depending on what is next, determine match or not.
2377  */
2378  if (*pattern == '\0' || *pattern == '/') { /* exact match */
2379 #ifdef NEED_DEBUG_HERE
2380  ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
2381 #endif
2382  return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
2383  } else if (*pattern == '!') { /* early match */
2384 #ifdef NEED_DEBUG_HERE
2385  ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
2386 #endif
2387  return 2;
2388  } else { /* partial match */
2389 #ifdef NEED_DEBUG_HERE
2390  ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
2391 #endif
2392  return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
2393  }
2394 }
#define LOG_WARNING
Definition: logger.h:274
char * end
Definition: eagi_proxy.c:73
#define ast_log
Definition: astobj2.c:42
static int ext_cmp_exten_strlen(const char *str)
Definition: pbx.c:1803
static int ext_cmp_pattern(const char *left, const char *right)
Definition: pbx.c:2078
#define LOG_NOTICE
Definition: logger.h:263
static int ext_cmp_exten_partial(const char *left, const char *right)
Definition: pbx.c:1833
static int ext_cmp_exten(const char *left, const char *right)
Definition: pbx.c:1876

◆ acf_exception_read()

static int acf_exception_read ( struct ast_channel chan,
const char *  name,
char *  data,
char *  buf,
size_t  buflen 
)
static

Definition at line 2832 of file pbx.c.

References ast_channel_datastore_find(), ast_copy_string(), pbx_exception::context, ast_datastore::data, pbx_exception::exten, NULL, pbx_exception::priority, and pbx_exception::reason.

2833 {
2835  struct pbx_exception *exception = NULL;
2836  if (!ds || !ds->data)
2837  return -1;
2838  exception = ds->data;
2839  if (!strcasecmp(data, "REASON"))
2840  ast_copy_string(buf, exception->reason, buflen);
2841  else if (!strcasecmp(data, "CONTEXT"))
2842  ast_copy_string(buf, exception->context, buflen);
2843  else if (!strncasecmp(data, "EXTEN", 5))
2844  ast_copy_string(buf, exception->exten, buflen);
2845  else if (!strcasecmp(data, "PRIORITY"))
2846  snprintf(buf, buflen, "%d", exception->priority);
2847  else
2848  return -1;
2849  return 0;
2850 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
const ast_string_field exten
Definition: pbx.c:625
Structure for a data store object.
Definition: datastore.h:68
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2404
#define NULL
Definition: resample.c:96
const ast_string_field reason
Definition: pbx.c:625
int priority
Definition: pbx.c:627
static const struct ast_datastore_info exception_store_info
Definition: pbx.c:2790
void * data
Definition: datastore.h:70
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const ast_string_field context
Definition: pbx.c:625

◆ action_extensionstatelist()

static int action_extensionstatelist ( struct mansession s,
const struct message m 
)
static

Definition at line 8383 of file pbx.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_exten::app, ast_extension_state2str(), ast_strlen_zero, astman_append(), astman_get_header(), astman_send_error(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_exten::exten, ast_hint::exten, ast_hint::laststate, ast_context::name, and ast_exten::parent.

Referenced by load_pbx().

8384 {
8385  const char *action_id = astman_get_header(m, "ActionID");
8386  struct ast_hint *hint;
8387  struct ao2_iterator it_hints;
8388  int hint_count = 0;
8389 
8390  if (!hints) {
8391  astman_send_error(s, m, "No dialplan hints are available");
8392  return 0;
8393  }
8394 
8395  astman_send_listack(s, m, "Extension Statuses will follow", "start");
8396 
8397  ao2_lock(hints);
8398  it_hints = ao2_iterator_init(hints, 0);
8399  for (; (hint = ao2_iterator_next(&it_hints)); ao2_ref(hint, -1)) {
8400 
8401  ao2_lock(hint);
8402 
8403  /* Ignore pattern matching hints; they are stored in the
8404  * hints container but aren't real from the perspective of
8405  * an AMI user
8406  */
8407  if (hint->exten->exten[0] == '_') {
8408  ao2_unlock(hint);
8409  continue;
8410  }
8411 
8412  ++hint_count;
8413 
8414  astman_append(s, "Event: ExtensionStatus\r\n");
8415  if (!ast_strlen_zero(action_id)) {
8416  astman_append(s, "ActionID: %s\r\n", action_id);
8417  }
8418  astman_append(s,
8419  "Exten: %s\r\n"
8420  "Context: %s\r\n"
8421  "Hint: %s\r\n"
8422  "Status: %d\r\n"
8423  "StatusText: %s\r\n\r\n",
8424  hint->exten->exten,
8425  hint->exten->parent->name,
8426  hint->exten->app,
8427  hint->laststate,
8429  ao2_unlock(hint);
8430  }
8431 
8432  ao2_iterator_destroy(&it_hints);
8433  ao2_unlock(hints);
8434 
8435  astman_send_list_complete_start(s, m, "ExtensionStateListComplete", hint_count);
8437 
8438  return 0;
8439 }
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3237
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
struct ast_exten * exten
Hint extension.
Definition: pbx.c:331
char * exten
Definition: pbx.c:238
int laststate
Definition: pbx.c:335
char name[0]
Definition: pbx.c:297
Structure for dial plan hints.
Definition: pbx.c:324
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
const char * app
Definition: pbx.c:246
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ast_context * parent
Definition: pbx.c:245
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
const char * ast_extension_state2str(int extension_state)
Return extension_state as string.
Definition: pbx.c:3126
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3201

◆ add_exten_to_pattern_tree()

static struct match_char * add_exten_to_pattern_tree ( struct ast_context con,
struct ast_exten e1,
int  findonly 
)
static

Definition at line 1657 of file pbx.c.

References add_pattern_node(), already_in_tree(), ARRAY_LEN, ast_copy_string(), ast_debug, ast_log, buf, pattern_node::buf, ast_exten::cidmatch, match_char::deleted, ast_exten::exten, match_char::exten, get_pattern_node(), LOG_ERROR, LOG_WARNING, ast_exten::matchcid, ast_exten::name, match_char::next_char, NULL, and ast_context::pattern_tree.

Referenced by add_priority(), ast_add_extension2_lockopt(), ast_context_remove_extension_callerid2(), and create_match_char_tree().

1658 {
1659  struct match_char *m1 = NULL;
1660  struct match_char *m2 = NULL;
1661  struct match_char **m0;
1662  const char *pos;
1663  int already;
1664  int pattern = 0;
1665  int idx_cur;
1666  int idx_next;
1667  char extenbuf[512];
1668  struct pattern_node pat_node[2];
1669 
1670  if (e1->matchcid) {
1671  if (sizeof(extenbuf) < strlen(e1->exten) + strlen(e1->cidmatch) + 2) {
1673  "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
1674  e1->exten, e1->cidmatch);
1675  return NULL;
1676  }
1677  sprintf(extenbuf, "%s/%s", e1->exten, e1->cidmatch);/* Safe. We just checked. */
1678  } else {
1679  ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
1680  }
1681 
1682 #ifdef NEED_DEBUG
1683  ast_debug(1, "Adding exten %s to tree\n", extenbuf);
1684 #endif
1685  m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
1686  m0 = &con->pattern_tree;
1687  already = 1;
1688 
1689  pos = extenbuf;
1690  if (*pos == '_') {
1691  pattern = 1;
1692  ++pos;
1693  }
1694  idx_cur = 0;
1695  pos = get_pattern_node(&pat_node[idx_cur], pos, pattern, extenbuf);
1696  for (; pat_node[idx_cur].buf[0]; idx_cur = idx_next) {
1697  idx_next = (idx_cur + 1) % ARRAY_LEN(pat_node);
1698  pos = get_pattern_node(&pat_node[idx_next], pos, pattern, extenbuf);
1699 
1700  /* See about adding node to tree. */
1701  m2 = NULL;
1702  if (already && (m2 = already_in_tree(m1, pat_node[idx_cur].buf, pattern))
1703  && m2->next_char) {
1704  if (!pat_node[idx_next].buf[0]) {
1705  /*
1706  * This is the end of the pattern, but not the end of the tree.
1707  * Mark this node with the exten... a shorter pattern might win
1708  * if the longer one doesn't match.
1709  */
1710  if (findonly) {
1711  return m2;
1712  }
1713  if (m2->exten) {
1714  ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
1715  m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name);
1716  }
1717  m2->exten = e1;
1718  m2->deleted = 0;
1719  }
1720  m1 = m2->next_char; /* m1 points to the node to compare against */
1721  m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
1722  } else { /* not already OR not m2 OR nor m2->next_char */
1723  if (m2) {
1724  if (findonly) {
1725  return m2;
1726  }
1727  m1 = m2; /* while m0 stays the same */
1728  } else {
1729  if (findonly) {
1730  return m1;
1731  }
1732  m1 = add_pattern_node(con, m1, &pat_node[idx_cur], pattern, already, m0);
1733  if (!m1) { /* m1 is the node just added */
1734  return NULL;
1735  }
1736  m0 = &m1->next_char;
1737  }
1738  if (!pat_node[idx_next].buf[0]) {
1739  if (m2 && m2->exten) {
1740  ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
1741  m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name);
1742  }
1743  m1->deleted = 0;
1744  m1->exten = e1;
1745  }
1746 
1747  /* The 'already' variable is a mini-optimization designed to make it so that we
1748  * don't have to call already_in_tree when we know it will return false.
1749  */
1750  already = 0;
1751  }
1752  }
1753  return m1;
1754 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
struct ast_exten * exten
Definition: pbx.c:268
char * name
Definition: pbx.c:239
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
static struct match_char * add_pattern_node(struct ast_context *con, struct match_char *current, const struct pattern_node *pattern, int is_pattern, int already, struct match_char **nextcharptr)
Definition: pbx.c:1459
#define NULL
Definition: resample.c:96
int matchcid
Definition: pbx.c:240
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static struct match_char * already_in_tree(struct match_char *current, char *pat, int is_pattern)
Definition: pbx.c:1397
char * exten
Definition: pbx.c:238
#define LOG_ERROR
Definition: logger.h:285
const char * cidmatch
Definition: pbx.c:241
static const char * get_pattern_node(struct pattern_node *node, const char *src, int pattern, const char *extenbuf)
Definition: pbx.c:1513
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
struct match_char * next_char
Definition: pbx.c:267
struct match_char * pattern_tree
Definition: pbx.c:288
int deleted
Definition: pbx.c:264
match_char: forms a syntax tree for quick matching of extension patterns
Definition: pbx.c:261

◆ add_hintdevice()

static int add_hintdevice ( struct ast_hint hint,
const char *  devicelist 
)
static

add hintdevice structure and link it into the container.

Definition at line 552 of file pbx.c.

References ao2_ref, ao2_t_alloc, ao2_t_link, ao2_t_ref, ast_free, ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strdup, AST_VECTOR_APPEND, ast_hintdevice::hint, ast_hintdevice::hintdevice, hintdevice_data, hintdevice_destroy(), parse(), str, and strsep().

Referenced by ast_add_hint(), and ast_change_hint().

553 {
554  struct ast_str *str;
555  char *parse;
556  char *cur;
557  struct ast_hintdevice *device;
558  int devicelength;
559 
560  if (!hint || !devicelist) {
561  /* Trying to add garbage? Don't bother. */
562  return 0;
563  }
564  if (!(str = ast_str_thread_get(&hintdevice_data, 16))) {
565  return -1;
566  }
567  ast_str_set(&str, 0, "%s", devicelist);
568  parse = ast_str_buffer(str);
569 
570  /* Spit on '&' and ',' to handle presence hints as well */
571  while ((cur = strsep(&parse, "&,"))) {
572  char *device_name;
573 
574  devicelength = strlen(cur);
575  if (!devicelength) {
576  continue;
577  }
578 
579  device_name = ast_strdup(cur);
580  if (!device_name) {
581  return -1;
582  }
583 
584  device = ao2_t_alloc(sizeof(*device) + devicelength, hintdevice_destroy,
585  "allocating a hintdevice structure");
586  if (!device) {
587  ast_free(device_name);
588  return -1;
589  }
590  strcpy(device->hintdevice, cur);
591  ao2_ref(hint, +1);
592  device->hint = hint;
593  if (AST_VECTOR_APPEND(&hint->devices, device_name)) {
594  ast_free(device_name);
595  ao2_ref(device, -1);
596  return -1;
597  }
598  ao2_t_link(hintdevices, device, "Linking device into hintdevice container.");
599  ao2_t_ref(device, -1, "hintdevice is linked so we can unref");
600  }
601 
602  return 0;
603 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
static void hintdevice_destroy(void *obj)
Definition: pbx.c:540
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:409
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
static struct ao2_container * hintdevices
Container for hint devices.
Definition: pbx.c:363
#define ao2_t_link(container, obj, tag)
Add an object to a container.
Definition: astobj2.h:1547
struct ast_hint * hint
Hint this hintdevice belongs to.
Definition: pbx.c:374
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * str
Definition: app_jack.c:147
char hintdevice[1]
Definition: pbx.c:376
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
#define ao2_ref(o, delta)
Definition: astobj2.h:464
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define ast_free(a)
Definition: astmm.h:182
static struct ast_threadstorage hintdevice_data
Definition: pbx.c:352
Structure for dial plan hint devices.
Definition: pbx.c:369
char * strsep(char **str, const char *delims)
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:861

◆ add_pattern_node()

static struct match_char* add_pattern_node ( struct ast_context con,
struct match_char current,
const struct pattern_node pattern,
int  is_pattern,
int  already,
struct match_char **  nextcharptr 
)
static

Definition at line 1459 of file pbx.c.

References ast_calloc, pattern_node::buf, insert_in_next_chars_alt_char_list(), match_char::is_pattern, match_char::next_char, NULL, ast_context::pattern_tree, pattern_node::specif, match_char::specificity, and match_char::x.

Referenced by add_exten_to_pattern_tree().

1460 {
1461  struct match_char *m;
1462 
1463  if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern->buf)))) {
1464  return NULL;
1465  }
1466 
1467  /* strcpy is safe here since we know its size and have allocated
1468  * just enough space for when we allocated m
1469  */
1470  strcpy(m->x, pattern->buf);
1471 
1472  /* the specificity scores are the same as used in the old
1473  pattern matcher. */
1474  m->is_pattern = is_pattern;
1475  if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'N') {
1476  m->specificity = 0x0832;
1477  } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'Z') {
1478  m->specificity = 0x0931;
1479  } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'X') {
1480  m->specificity = 0x0a30;
1481  } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '.') {
1482  m->specificity = 0x18000;
1483  } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '!') {
1484  m->specificity = 0x28000;
1485  } else {
1486  m->specificity = pattern->specif;
1487  }
1488 
1489  if (!con->pattern_tree) {
1491  } else {
1492  if (already) { /* switch to the new regime (traversing vs appending)*/
1493  insert_in_next_chars_alt_char_list(nextcharptr, m);
1494  } else {
1496  }
1497  }
1498 
1499  return m;
1500 }
int specificity
Definition: pbx.c:265
#define NULL
Definition: resample.c:96
char x[1]
Definition: pbx.c:269
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
int is_pattern
Definition: pbx.c:263
struct match_char * next_char
Definition: pbx.c:267
int specif
Definition: pbx.c:1454
char buf[256]
Definition: pbx.c:1456
struct match_char * pattern_tree
Definition: pbx.c:288
match_char: forms a syntax tree for quick matching of extension patterns
Definition: pbx.c:261
static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
Definition: pbx.c:1418

◆ add_priority()

static int add_priority ( 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.

Return values
0on success.
-1on failure.

Definition at line 7109 of file pbx.c.

References add_exten_to_pattern_tree(), ast_add_hint(), ast_change_hint(), ast_free, ast_hashtab_insert_safe, ast_hashtab_remove_object_via_lookup(), ast_log, match_char::exten, ast_exten::label, LOG_ERROR, LOG_WARNING, ast_exten::name, ast_context::name, ast_exten::next, NULL, ast_exten::peer, ast_exten::peer_label_table, ast_exten::peer_table, ast_exten::priority, PRIORITY_HINT, ast_context::root, ast_context::root_table, tmp(), and match_char::x.

Referenced by ast_add_extension2_lockopt().

7111 {
7112  struct ast_exten *ep;
7113  struct ast_exten *eh=e;
7114  int repeated_label = 0; /* Track if this label is a repeat, assume no. */
7115 
7116  for (ep = NULL; e ; ep = e, e = e->peer) {
7117  if (e->label && tmp->label && e->priority != tmp->priority && !strcmp(e->label, tmp->label)) {
7118  if (strcmp(e->name, tmp->name)) {
7120  "Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n",
7121  tmp->name, tmp->priority, con->name, tmp->label, e->name, e->priority);
7122  } else {
7124  "Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n",
7125  tmp->name, tmp->priority, con->name, tmp->label, e->priority);
7126  }
7127  repeated_label = 1;
7128  }
7129  if (e->priority >= tmp->priority) {
7130  break;
7131  }
7132  }
7133 
7134  if (repeated_label) { /* Discard the label since it's a repeat. */
7135  tmp->label = NULL;
7136  }
7137 
7138  if (!e) { /* go at the end, and ep is surely set because the list is not empty */
7140 
7141  if (tmp->label) {
7143  }
7144  ep->peer = tmp;
7145  return 0; /* success */
7146  }
7147  if (e->priority == tmp->priority) {
7148  /* Can't have something exactly the same. Is this a
7149  replacement? If so, replace, otherwise, bonk. */
7150  if (!replace) {
7151  if (strcmp(e->name, tmp->name)) {
7153  "Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n",
7154  tmp->name, tmp->priority, con->name, e->name);
7155  } else {
7157  "Unable to register extension '%s' priority %d in '%s', already in use\n",
7158  tmp->name, tmp->priority, con->name);
7159  }
7160 
7161  return -1;
7162  }
7163  /* we are replacing e, so copy the link fields and then update
7164  * whoever pointed to e to point to us
7165  */
7166  tmp->next = e->next; /* not meaningful if we are not first in the peer list */
7167  tmp->peer = e->peer; /* always meaningful */
7168  if (ep) { /* We're in the peer list, just insert ourselves */
7170 
7171  if (e->label) {
7173  }
7174 
7176  if (tmp->label) {
7178  }
7179 
7180  ep->peer = tmp;
7181  } else if (el) { /* We're the first extension. Take over e's functions */
7182  struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
7183  tmp->peer_table = e->peer_table;
7184  tmp->peer_label_table = e->peer_label_table;
7187  if (e->label) {
7189  }
7190  if (tmp->label) {
7192  }
7193 
7196  el->next = tmp;
7197  /* The pattern trie points to this exten; replace the pointer,
7198  and all will be well */
7199  if (x) { /* if the trie isn't formed yet, don't sweat this */
7200  if (x->exten) { /* this test for safety purposes */
7201  x->exten = tmp; /* replace what would become a bad pointer */
7202  } else {
7203  ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
7204  }
7205  }
7206  } else { /* We're the very first extension. */
7207  struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
7210  tmp->peer_table = e->peer_table;
7211  tmp->peer_label_table = e->peer_label_table;
7214  if (e->label) {
7216  }
7217  if (tmp->label) {
7219  }
7220 
7223  con->root = tmp;
7224  /* The pattern trie points to this exten; replace the pointer,
7225  and all will be well */
7226  if (x) { /* if the trie isn't formed yet; no problem */
7227  if (x->exten) { /* this test for safety purposes */
7228  x->exten = tmp; /* replace what would become a bad pointer */
7229  } else {
7230  ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
7231  }
7232  }
7233  }
7234  if (tmp->priority == PRIORITY_HINT)
7235  ast_change_hint(e,tmp);
7236  /* Destroy the old one */
7237  if (e->datad)
7238  e->datad(e->data);
7239  ast_free(e);
7240  } else { /* Slip ourselves in just before e */
7241  tmp->peer = e;
7242  tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
7243  if (ep) { /* Easy enough, we're just in the peer list */
7244  if (tmp->label) {
7246  }
7248  ep->peer = tmp;
7249  } else { /* we are the first in some peer list, so link in the ext list */
7250  tmp->peer_table = e->peer_table;
7251  tmp->peer_label_table = e->peer_label_table;
7252  e->peer_table = 0;
7253  e->peer_label_table = 0;
7255  if (tmp->label) {
7257  }
7260  if (el)
7261  el->next = tmp; /* in the middle... */
7262  else
7263  con->root = tmp; /* ... or at the head */
7264  e->next = NULL; /* e is no more at the head, so e->next must be reset */
7265  }
7266  /* And immediately return success. */
7267  if (tmp->priority == PRIORITY_HINT) {
7268  ast_add_hint(tmp);
7269  }
7270  }
7271  return 0;
7272 }
const char * label
Definition: pbx.c:244
ast_exten: An extension The dialplan is saved as a linked list with each context having it&#39;s own link...
Definition: pbx.c:237
static int ast_add_hint(struct ast_exten *e)
Add hint to hint list, check initial extension state.
Definition: pbx.c:3982
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
Change hint for an extension.
Definition: pbx.c:4096
struct ast_exten * exten
Definition: pbx.c:268
struct ast_exten * root
Definition: pbx.c:286
char * name
Definition: pbx.c:239
static struct match_char * add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
Definition: pbx.c:1657
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
#define NULL
Definition: resample.c:96
struct ast_hashtab * peer_table
Definition: pbx.c:251
char x[1]
Definition: pbx.c:269
#define ast_hashtab_insert_safe(tab, obj)
Definition: hashtab.h:315
struct ast_exten * next
Definition: pbx.c:256
int priority
Definition: pbx.c:243
#define ast_log
Definition: astobj2.c:42
struct ast_exten * peer
Definition: pbx.c:250
#define PRIORITY_HINT
Definition: pbx.h:54
struct ast_hashtab * peer_label_table
Definition: pbx.c:252
#define LOG_ERROR
Definition: logger.h:285
void * ast_hashtab_remove_object_via_lookup(struct ast_hashtab *tab, void *obj)
Looks up the object, removes the corresponding bucket.
Definition: hashtab.c:746
char name[0]
Definition: pbx.c:297
#define ast_free(a)
Definition: astmm.h:182
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:790
struct ast_hashtab * root_table
Definition: pbx.c:287
match_char: forms a syntax tree for quick matching of extension patterns
Definition: pbx.c:261

◆ alloc_device_state_info()

static struct ao2_container* alloc_device_state_info ( void  )
static

Definition at line 3076 of file pbx.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_container_alloc_list, and NULL.

Referenced by ast_extension_state_extended(), and device_state_notify_callbacks().

3077 {
3079 }
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
#define NULL
Definition: resample.c:96

◆ already_in_tree()

static struct match_char * already_in_tree ( struct match_char current,
char *  pat,
int  is_pattern 
)
static

Definition at line 1397 of file pbx.c.

References match_char::alt_char, match_char::is_pattern, and match_char::x.

Referenced by add_exten_to_pattern_tree().

1398 {
1399  struct match_char *t;
1400 
1401  if (!current) {
1402  return 0;
1403  }
1404 
1405  for (t = current; t; t = t->alt_char) {
1406  if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {/* uh, we may want to sort exploded [] contents to make matching easy */
1407  return t;
1408  }
1409  }
1410 
1411  return 0;
1412 }
struct match_char * alt_char
Definition: pbx.c:266
char x[1]
Definition: pbx.c:269
int is_pattern
Definition: pbx.c:263
match_char: forms a syntax tree for quick matching of extension patterns
Definition: pbx.c:261

◆ ast_active_calls()

int ast_active_calls ( void  )

Retrieve the number of active calls.

Definition at line 4764 of file pbx.c.

References countcalls.

Referenced by ast_var_Config(), get_current_call_count(), handle_chanlist(), handle_showcalls(), and sysinfo_helper().

4765 {
4766  return countcalls;
4767 }
static int countcalls
Definition: pbx.c:773

◆ ast_add_extension()

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.

Parameters
contextcontext to add the extension to
replace
extensionextension to add
prioritypriority level of extension addition
labelextension label
calleridpattern to match CallerID, or NULL to match any CallerID
applicationapplication to run on the extension with that priority level
datadata to pass to the application
datada pointer to a function that will deallocate data when needed or NULL if data does not need to be freed.
registrarwho registered the extension
Note
On any failure, the function pointed to by datap will be called and passed the data pointer.
Return values
0success
-1failure

Definition at line 6970 of file pbx.c.

References ast_add_extension2(), ast_unlock_contexts(), c, ast_exten::datad, find_context_locked(), and NULL.

Referenced by add_to_regcontext(), app_create(), ast_hint_presence_state(), ast_sip_persistent_endpoint_update_state(), AST_TEST_DEFINE(), create_test_dialplan(), device_state_cb(), extension_state_add_destroy(), handle_cli_dialplan_add_extension(), internal_extension_state_extended(), join_conference_bridge(), load_module(), register_exten(), register_extension(), register_peer_exten(), sla_build_station(), and sla_build_trunk().

6973 {
6974  int ret = -1;
6975  struct ast_context *c;
6976 
6978  if (c) {
6979  ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
6980  application, data, datad, registrar, NULL, 0);
6982  }
6983 
6984  return ret;
6985 }
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, const char *registrar_file, int registrar_line)
Main interface to add extensions to the list for out context.
Definition: pbx.c:7299
static struct test_val c
#define NULL
Definition: resample.c:96
static int priority
structure to hold extensions
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
static char * registrar
Definition: pbx_ael.c:78
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4818
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:790
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284

◆ ast_add_extension2()

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,
const char *  registrar_file,
int  registrar_line 
)

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 7299 of file pbx.c.

References ast_add_extension2_lockopt(), and ast_exten::datad.

Referenced by ast_add_extension(), and context_merge().

7303 {
7304  return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
7305  application, data, datad, registrar, registrar_file, registrar_line, 1);
7306 }
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, const char *registrar_file, int registrar_line, int lock_context)
Same as ast_add_extension2() but controls the context locking.
Definition: pbx.c:7325
static int priority
structure to hold extensions
static char * registrar
Definition: pbx_ael.c:78
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:790

◆ ast_add_extension2_lockopt()

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,
const char *  registrar_file,
int  registrar_line,
int  lock_context 
)
static

Same as ast_add_extension2() but controls the context locking.

Does all the work of ast_add_extension2, but adds an arg to determine if context locking should be done.

Definition at line 7325 of file pbx.c.

References add_exten_to_pattern_tree(), add_priority(), ast_exten::app, ast_add_hint(), ast_calloc, ast_channel_context_set(), ast_channel_exten_set(), ast_channel_unref, ast_dummy_channel_alloc, AST_EXT_MATCHCID_OFF, AST_EXT_MATCHCID_ON, ast_free, ast_hashtab_create, ast_hashtab_insert_safe, ast_hashtab_lookup(), ast_hashtab_newsize_java(), ast_hashtab_remove_this_object(), ast_hashtab_resize_java(), ast_log, ast_strlen_zero, ast_thread_inhibit_escalations(), ast_thread_inhibit_escalations_swap(), ast_unlock_context(), ast_wrlock_context(), c, ast_exten::cidmatch, ast_exten::cidmatch_display, ast_exten::data, ast_exten::datad, DEBUG_ATLEAST, match_char::deleted, el, errno, ext_cmp(), ext_fluff_count(), ext_strncpy(), ast_exten::exten, match_char::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_DEBUG, LOG_ERROR, ast_exten::matchcid, ast_exten::name, ast_context::name, ast_exten::next, NULL, 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_exten::registrar_file, ast_exten::registrar_line, ast_context::root, ast_context::root_table, ast_exten::stuff, tmp(), VAR_BUF_SIZE, and match_char::x.

Referenced by ast_add_extension2(), ast_add_extension2_nolock(), and ast_add_extension_nolock().

7329 {
7330  /*
7331  * Sort extensions (or patterns) according to the rules indicated above.
7332  * These are implemented by the function ext_cmp()).
7333  * All priorities for the same ext/pattern/cid are kept in a list,
7334  * using the 'peer' field as a link field..
7335  */
7336  struct ast_exten *tmp, *tmp2, *e, *el = NULL;
7337  int res;
7338  int length;
7339  char *p;
7340  char expand_buf[VAR_BUF_SIZE];
7341  struct ast_exten dummy_exten = {0};
7342  char dummy_name[1024];
7343  int exten_fluff;
7344  int callerid_fluff;
7345 
7346  if (ast_strlen_zero(extension)) {
7347  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",
7348  con->name);
7349  /* We always need to deallocate 'data' on failure */
7350  if (datad) {
7351  datad(data);
7352  }
7353  return -1;
7354  }
7355 
7356  /* If we are adding a hint evalulate in variables and global variables */
7357  if (priority == PRIORITY_HINT && strstr(application, "${") && extension[0] != '_') {
7358  int inhibited;
7360 
7361  if (c) {
7363  ast_channel_context_set(c, con->name);
7364  }
7365 
7366  /*
7367  * We can allow dangerous functions when adding a hint since
7368  * altering dialplan is itself a privileged activity. Otherwise,
7369  * we could never execute dangerous functions.
7370  */
7371  inhibited = ast_thread_inhibit_escalations_swap(0);
7372  pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
7373  if (0 < inhibited) {
7375  }
7376 
7377  application = expand_buf;
7378  if (c) {
7379  ast_channel_unref(c);
7380  }
7381  }
7382 
7383  exten_fluff = ext_fluff_count(extension);
7384  callerid_fluff = callerid ? ext_fluff_count(callerid) : 0;
7385 
7386  length = sizeof(struct ast_exten);
7387  length += strlen(extension) + 1;
7388  if (exten_fluff) {
7389  length += strlen(extension) + 1 - exten_fluff;
7390  }
7391  length += strlen(application) + 1;
7392  if (label) {
7393  length += strlen(label) + 1;
7394  }
7395  if (callerid) {
7396  length += strlen(callerid) + 1;
7397  if (callerid_fluff) {
7398  length += strlen(callerid) + 1 - callerid_fluff;
7399  }
7400  } else {
7401  length ++; /* just the '\0' */
7402  }
7403  if (registrar_file) {
7404  length += strlen(registrar_file) + 1;
7405  }
7406 
7407  /* Be optimistic: Build the extension structure first */
7408  tmp = ast_calloc(1, length);
7409  if (!tmp) {
7410  /* We always need to deallocate 'data' on failure */
7411  if (datad) {
7412  datad(data);
7413  }
7414  return -1;
7415  }
7416 
7417  if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
7418  label = 0;
7419 
7420  /* use p as dst in assignments, as the fields are const char * */
7421  p = tmp->stuff;
7422  if (label) {
7423  tmp->label = p;
7424  strcpy(p, label);
7425  p += strlen(label) + 1;
7426  }
7427  tmp->name = p;
7428  p += ext_strncpy(p, extension, strlen(extension) + 1, 0);
7429  if (exten_fluff) {
7430  tmp->exten = p;
7431  p += ext_strncpy(p, extension, strlen(extension) + 1 - exten_fluff, 1);
7432  } else {
7433  /* no fluff, we don't need a copy. */
7434  tmp->exten = tmp->name;
7435  }
7436  tmp->priority = priority;
7437  tmp->cidmatch_display = tmp->cidmatch = p; /* but use p for assignments below */
7438 
7439  /* Blank callerid and NULL callerid are two SEPARATE things. Do NOT confuse the two!!! */
7440  if (callerid) {
7441  p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0);
7442  if (callerid_fluff) {
7443  tmp->cidmatch = p;
7444  p += ext_strncpy(p, callerid, strlen(callerid) + 1 - callerid_fluff, 1);
7445  }
7447  } else {
7448  *p++ = '\0';
7450  }
7451 
7452  if (registrar_file) {
7453  tmp->registrar_file = p;
7454  strcpy(p, registrar_file);
7455  p += strlen(registrar_file) + 1;
7456  } else {
7457  tmp->registrar_file = NULL;
7458  }
7459 
7460  tmp->app = p;
7461  strcpy(p, application);
7462  tmp->parent = con;
7463  tmp->data = data;
7464  tmp->datad = datad;
7465  tmp->registrar = registrar;
7467 
7468  if (lock_context) {
7469  ast_wrlock_context(con);
7470  }
7471 
7472  if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
7473  an extension, and the trie exists, then we need to incrementally add this pattern to it. */
7474  ext_strncpy(dummy_name, tmp->exten, sizeof(dummy_name), 1);
7475  dummy_exten.exten = dummy_name;
7476  dummy_exten.matchcid = AST_EXT_MATCHCID_OFF;
7477  dummy_exten.cidmatch = 0;
7478  tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
7479  if (!tmp2) {
7480  /* hmmm, not in the trie; */
7481  add_exten_to_pattern_tree(con, tmp, 0);
7482  ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
7483  }
7484  }
7485  res = 0; /* some compilers will think it is uninitialized otherwise */
7486  for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
7487  res = ext_cmp(e->exten, tmp->exten);
7488  if (res == 0) { /* extension match, now look at cidmatch */
7490  res = 0;
7491  else if (tmp->matchcid == AST_EXT_MATCHCID_ON && e->matchcid == AST_EXT_MATCHCID_OFF)
7492  res = 1;
7493  else if (e->matchcid == AST_EXT_MATCHCID_ON && tmp->matchcid == AST_EXT_MATCHCID_OFF)
7494  res = -1;
7495  else
7496  res = ext_cmp(e->cidmatch, tmp->cidmatch);
7497  }
7498  if (res >= 0)
7499  break;
7500  }
7501  if (e && res == 0) { /* exact match, insert in the priority chain */
7502  res = add_priority(con, tmp, el, e, replace);
7503  if (res < 0) {
7504  if (con->pattern_tree) {
7505  struct match_char *x = add_exten_to_pattern_tree(con, tmp, 1);
7506 
7507  if (x->exten) {
7508  x->deleted = 1;
7509  x->exten = 0;
7510  }
7511 
7513  }
7514 
7515  if (tmp->datad) {
7516  tmp->datad(tmp->data);
7517  /* if you free this, null it out */
7518  tmp->data = NULL;
7519  }
7520 
7521  ast_free(tmp);
7522  }
7523  if (lock_context) {
7524  ast_unlock_context(con);
7525  }
7526  if (res < 0) {
7527  errno = EEXIST;
7528  return -1;
7529  }
7530  } else {
7531  /*
7532  * not an exact match, this is the first entry with this pattern,
7533  * so insert in the main list right before 'e' (if any)
7534  */
7535  tmp->next = e;
7536  tmp->peer_table = ast_hashtab_create(13,
7541  0);
7547  0);
7548 
7549  if (el) { /* there is another exten already in this context */
7550  el->next = tmp;
7551  } else { /* this is the first exten in this context */
7552  if (!con->root_table) {
7553  con->root_table = ast_hashtab_create(27,
7558  0);
7559  }
7560  con->root = tmp;
7561  }
7562  if (label) {
7564  }
7567 
7568  if (lock_context) {
7569  ast_unlock_context(con);
7570  }
7571  if (tmp->priority == PRIORITY_HINT) {
7572  ast_add_hint(tmp);
7573  }
7574  }
7575  if (DEBUG_ATLEAST(1)) {
7576  if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
7577  ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
7578  tmp->name, tmp->priority, tmp->cidmatch_display, con->name, con);
7579  } else {
7580  ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s (%p)\n",
7581  tmp->name, tmp->priority, con->name, con);
7582  }
7583  }
7584 
7585  return 0;
7586 }
const char * label
Definition: pbx.c:244
Main Channel structure associated with a channel.
ast_exten: An extension The dialplan is saved as a linked list with each context having it&#39;s own link...
Definition: pbx.c:237
void * ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
Lookup this object in the hash table.
Definition: hashtab.c:486
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
Definition: hashtab.c:127
static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff)
Definition: pbx.c:7068
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8530
static int ast_add_hint(struct ast_exten *e)
Add hint to hint list, check initial extension state.
Definition: pbx.c:3982
struct ast_exten * exten
Definition: pbx.c:268
struct ast_exten * root
Definition: pbx.c:286
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
char * name
Definition: pbx.c:239
static struct match_char * add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
Definition: pbx.c:1657
int registrar_line
Definition: pbx.c:255
static int tmp()
Definition: bt_open.c:389
static int hashtab_compare_extens(const void *ha_a, const void *ah_b)
Definition: pbx.c:693
static EditLine * el
Definition: asterisk.c:340
static struct test_val c
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
Definition: pbx.c:728
#define NULL
Definition: resample.c:96
static unsigned int hashtab_hash_labels(const void *obj)
Definition: pbx.c:757
char stuff[0]
Definition: pbx.c:257
#define LOG_DEBUG
Definition: logger.h:241
struct ast_hashtab * peer_table
Definition: pbx.c:251
static int priority
char x[1]
Definition: pbx.c:269
const char * registrar
Definition: pbx.c:253
int ast_hashtab_resize_java(struct ast_hashtab *tab)
Determines if a table resize should occur using the Java algorithm (if the table load factor is 75% o...
Definition: hashtab.c:84
#define ast_hashtab_insert_safe(tab, obj)
Definition: hashtab.h:315
#define ast_strlen_zero(foo)
Definition: strings.h:52
int matchcid
Definition: pbx.c:240
struct ast_exten * next
Definition: pbx.c:256
const char * registrar_file
Definition: pbx.c:254
int priority
Definition: pbx.c:243
#define ast_log
Definition: astobj2.c:42
static int ext_cmp(const char *left, const char *right)
Definition: pbx.c:2126
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
structure to hold extensions
void(* datad)(void *)
Definition: pbx.c:249
#define PRIORITY_HINT
Definition: pbx.h:54
struct ast_hashtab * peer_label_table
Definition: pbx.c:252
static int ext_fluff_count(const char *exten)
Definition: pbx.c:2148
static unsigned int hashtab_hash_priority(const void *obj)
Definition: pbx.c:751
char * exten
Definition: pbx.c:238
#define LOG_ERROR
Definition: logger.h:285
char name[0]
Definition: pbx.c:297
int errno
int ast_thread_inhibit_escalations_swap(int inhibit)
Swap the current thread escalation inhibit setting.
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8520
static char * registrar
Definition: pbx_ael.c:78
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
Definition: pbx.c:721
#define VAR_BUF_SIZE
Definition: pbx_private.h:68
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:790
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
const char * cidmatch
Definition: pbx.c:241
const char * app
Definition: pbx.c:246
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
int ast_thread_inhibit_escalations(void)
Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations...
static unsigned int hashtab_hash_extens(const void *obj)
Definition: pbx.c:741
static int add_priority(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.
Definition: pbx.c:7109
const char * cidmatch_display
Definition: pbx.c:242
struct ast_hashtab * root_table
Definition: pbx.c:287
#define ast_hashtab_create(initial_buckets, compare, resize, newsize, hash, do_locking)
Definition: hashtab.h:261
struct ast_context * parent
Definition: pbx.c:245
void * data
Definition: pbx.c:248
#define DEBUG_ATLEAST(level)
Definition: logger.h:441
struct match_char * pattern_tree
Definition: pbx.c:288
int deleted
Definition: pbx.c:264
match_char: forms a syntax tree for quick matching of extension patterns
Definition: pbx.c:261
void * ast_hashtab_remove_this_object(struct ast_hashtab *tab, void *obj)
Hash the object and then compare ptrs in bucket list instead of calling the compare routine...
Definition: hashtab.c:789

◆ ast_add_extension2_nolock()

int ast_add_extension2_nolock ( 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,
const char *  registrar_file,
int  registrar_line 
)

Same as ast_add_extension2, but assumes you have already locked context.

Since
12.0.0
Note
con must be write locked prior to calling. For details about the arguments, check ast_add_extension()

Definition at line 7308 of file pbx.c.

References ast_add_extension2_lockopt(), and ast_exten::datad.

Referenced by add_extension(), parking_add_extension(), and parking_duration_callback().

7312 {
7313  return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
7314  application, data, datad, registrar, registrar_file, registrar_line, 0);
7315 }
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, const char *registrar_file, int registrar_line, int lock_context)
Same as ast_add_extension2() but controls the context locking.
Definition: pbx.c:7325
static int priority
structure to hold extensions
static char * registrar
Definition: pbx_ael.c:78
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:790

◆ ast_add_extension_nolock()

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 6950 of file pbx.c.

References ast_add_extension2_lockopt(), c, ast_exten::datad, find_context(), and NULL.

Referenced by ast_merge_contexts_and_delete().

6953 {
6954  int ret = -1;
6955  struct ast_context *c;
6956 
6957  c = find_context(context);
6958  if (c) {
6959  ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
6960  application, data, datad, registrar, NULL, 0, 1);
6961  }
6962 
6963  return ret;
6964 }
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, const char *registrar_file, int registrar_line, int lock_context)
Same as ast_add_extension2() but controls the context locking.
Definition: pbx.c:7325
static struct test_val c
#define NULL
Definition: resample.c:96
static int priority
structure to hold extensions
static char * registrar
Definition: pbx_ael.c:78
static struct ast_context * find_context(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4804
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:790
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284

◆ ast_add_hint()

static int ast_add_hint ( struct ast_exten e)
static

Add hint to hint list, check initial extension state.

Definition at line 3982 of file pbx.c.

References add_hintdevice(), ao2_alloc, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_list, ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_lock, ao2_ref, ao2_unlock, ast_exten::app, ast_debug, AST_DEVICE_INVALID, ast_extension_state2(), ast_get_context_name(), ast_get_extension_app(), ast_get_extension_context(), ast_get_extension_name(), AST_HINT_UPDATE_DEVICE, ast_log, AST_PRESENCE_INVALID, AST_VECTOR_INIT, ast_hint::callbacks, ast_state_cb::change_cb, ast_state_cb::data, destroy_hint(), execute_state_callback(), ast_exten::exten, ast_hint::exten, extension_presence_state_helper(), hint_id_cmp(), ast_hint::last_presence_message, ast_hint::last_presence_state, ast_hint::last_presence_subtype, ast_hint::laststate, LOG_WARNING, and NULL.

Referenced by add_priority(), and ast_add_extension2_lockopt().

3983 {
3984  struct ast_hint *hint_new;
3985  struct ast_hint *hint_found;
3986  char *message = NULL;
3987  char *subtype = NULL;
3988  int presence_state;
3989 
3990  if (!e) {
3991  return -1;
3992  }
3993 
3994  /*
3995  * We must create the hint we wish to add before determining if
3996  * it is already in the hints container to avoid possible
3997  * deadlock when getting the current extension state.
3998  */
3999  hint_new = ao2_alloc(sizeof(*hint_new), destroy_hint);
4000  if (!hint_new) {
4001  return -1;
4002  }
4003  AST_VECTOR_INIT(&hint_new->devices, 8);
4004 
4005  /* Initialize new hint. */
4007  if (!hint_new->callbacks) {
4008  ao2_ref(hint_new, -1);
4009  return -1;
4010  }
4011  hint_new->exten = e;
4012  if (strstr(e->app, "${") && e->exten[0] == '_') {
4013  /* The hint is dynamic and hasn't been evaluted yet */
4014  hint_new->laststate = AST_DEVICE_INVALID;
4016  } else {
4017  hint_new->laststate = ast_extension_state2(e, NULL);
4018  if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
4019  hint_new->last_presence_state = presence_state;
4020  hint_new->last_presence_subtype = subtype;
4021  hint_new->last_presence_message = message;
4022  }
4023  }
4024 
4025  /* Prevent multiple add hints from adding the same hint at the same time. */
4026  ao2_lock(hints);
4027 
4028  /* Search if hint exists, do nothing */
4029  hint_found = ao2_find(hints, e, 0);
4030  if (hint_found) {
4031  ao2_ref(hint_found, -1);
4032  ao2_unlock(hints);
4033  ao2_ref(hint_new, -1);
4034  ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n",
4036  return -1;
4037  }
4038 
4039  /* Add new hint to the hints container */
4040  ast_debug(2, "HINTS: Adding hint %s: %s\n",
4042  ao2_link(hints, hint_new);
4043  if (add_hintdevice(hint_new, ast_get_extension_app(e))) {
4044  ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
4047  }
4048 
4049  /* if not dynamic */
4050  if (!(strstr(e->app, "${") && e->exten[0] == '_')) {
4051  struct ast_state_cb *state_cb;
4052  struct ao2_iterator cb_iter;
4053 
4054  /* For general callbacks */
4055  cb_iter = ao2_iterator_init(statecbs, 0);
4056  for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
4060  state_cb->data,
4062  hint_new,
4063  NULL);
4064  }
4065  ao2_iterator_destroy(&cb_iter);
4066  }
4067  ao2_unlock(hints);
4068  ao2_ref(hint_new, -1);
4069 
4070  return 0;
4071 }
struct ast_context * ast_get_extension_context(struct ast_exten *exten)
Definition: pbx.c:8543
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8548
void * data
Definition: pbx.c:305
static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
Definition: pbx.c:3200
#define LOG_WARNING
Definition: logger.h:274
static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
add hintdevice structure and link it into the container.
Definition: pbx.c:552
ast_state_cb: An extension state notify register item
Definition: pbx.c:301
static void destroy_hint(void *obj)
Definition: pbx.c:3907
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
ast_state_cb_type change_cb
Definition: pbx.c:309
int last_presence_state
Definition: pbx.c:338
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
static int ast_extension_state2(struct ast_exten *e, struct ao2_container *device_state_info)
Check state of extension by using hints.
Definition: pbx.c:3113
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
struct ast_exten * exten
Hint extension.
Definition: pbx.c:331
char * exten
Definition: pbx.c:238
int laststate
Definition: pbx.c:335
Structure for dial plan hints.
Definition: pbx.c:324
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
struct ao2_container * callbacks
Definition: pbx.c:332
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
const char * app
Definition: pbx.c:246
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8596
static struct ao2_container * statecbs
Definition: pbx.c:803
const char * ast_get_context_name(struct ast_context *con)
Definition: pbx.c:8538
char * last_presence_message
Definition: pbx.c:340
static int execute_state_callback(ast_state_cb_type cb, const char *context, const char *exten, void *data, enum ast_state_cb_update_reason reason, struct ast_hint *hint, struct ao2_container *device_state_info)
Definition: pbx.c:3250
char * last_presence_subtype
Definition: pbx.c:339
static int hint_id_cmp(void *obj, void *arg, int flags)
Definition: pbx.c:3891
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ ast_async_goto()

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.

See also
ast_async_parseable_goto, ast_async_goto_if_exists
Note
Do NOT hold any channel locks when calling this function.

Definition at line 7011 of file pbx.c.

References ast_channel_flags(), ast_channel_is_bridged(), ast_channel_lock, ast_channel_name(), ast_channel_pbx(), ast_channel_unlock, ast_channel_yank(), ast_explicit_goto(), AST_FLAG_IN_AUTOLOOP, ast_hangup(), ast_log, ast_pbx_start(), AST_SOFTHANGUP_ASYNCGOTO, ast_softhangup_nolock(), ast_test_flag, and LOG_WARNING.

Referenced by __ast_goto_if_exists(), action_redirect(), ast_async_goto_by_name(), bridge_channel_blind_transfer(), chan_pjsip_cng_tone_detected(), comeback_goto(), dahdi_handle_dtmf(), fax_detect_framehook(), handle_request_bye(), my_handle_dtmf(), onModeChanged(), ooh323_rtp_read(), pbx_parseable_goto(), process_ast_dsp(), process_sdp(), and sip_read().

7012 {
7013  struct ast_channel *newchan;
7014 
7015  ast_channel_lock(chan);
7016  /* Channels in a bridge or running a PBX can be sent directly to the specified destination */
7017  if (ast_channel_is_bridged(chan) || ast_channel_pbx(chan)) {
7019  priority += 1;
7020  }
7023  ast_channel_unlock(chan);
7024  return 0;
7025  }
7026  ast_channel_unlock(chan);
7027 
7028  /* Otherwise, we need to gain control of the channel first */
7029  newchan = ast_channel_yank(chan);
7030  if (!newchan) {
7031  ast_log(LOG_WARNING, "Unable to gain control of channel %s\n", ast_channel_name(chan));
7032  return -1;
7033  }
7035  if (ast_pbx_start(newchan)) {
7036  ast_hangup(newchan);
7037  ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(newchan));
7038  return -1;
7039  }
7040 
7041  return 0;
7042 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6987
#define LOG_WARNING
Definition: logger.h:274
struct ast_channel * ast_channel_yank(struct ast_channel *yankee)
Gain control of a channel in the system.
Definition: channel.c:10794
static int priority
#define ast_log
Definition: astobj2.c:42
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4712
int ast_softhangup_nolock(struct ast_channel *chan, int reason)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2463
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10746
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
const char * ast_channel_name(const struct ast_channel *chan)
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
struct ast_flags * ast_channel_flags(struct ast_channel *chan)

◆ ast_async_goto_by_name()

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 7044 of file pbx.c.

References ast_async_goto(), ast_channel_get_by_name(), and ast_channel_unref.

7045 {
7046  struct ast_channel *chan;
7047  int res = -1;
7048 
7049  if ((chan = ast_channel_get_by_name(channame))) {
7050  res = ast_async_goto(chan, context, exten, priority);
7051  chan = ast_channel_unref(chan);
7052  }
7053 
7054  return res;
7055 }
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
static int priority
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: pbx.c:7011
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454

◆ ast_async_goto_if_exists()

int ast_async_goto_if_exists ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority 
)
Note
This function will handle locking the channel as needed.

Definition at line 8798 of file pbx.c.

References __ast_goto_if_exists().

8799 {
8800  return __ast_goto_if_exists(chan, context, exten, priority, 1);
8801 }
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
Definition: pbx.c:8772
static int priority
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116

◆ ast_async_parseable_goto()

int ast_async_parseable_goto ( struct ast_channel chan,
const char *  goto_string 
)
Note
This function will handle locking the channel as needed.

Definition at line 8864 of file pbx.c.

References pbx_parseable_goto().

Referenced by asyncgoto_exec(), detect_callback(), handle_redirect(), and parking_duration_callback().

8865 {
8866  return pbx_parseable_goto(chan, goto_string, 1);
8867 }
static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
Definition: pbx.c:8803

◆ ast_canmatch_extension()

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.

Parameters
cnot really important
contextcontext to serach within
extenextension to check
prioritypriority of extension path
calleridcallerid of extension being searched for
Note
It is possible for autoservice to be started and stopped on c during this function call, it is important that c is not locked prior to calling this. Otherwise a deadlock may occur
Returns
If "exten" could be a valid extension in this context with or without some more digits, return non-zero. Basically, when this returns 0, no matter what you add to exten, it's not going to be a valid extension anymore

Definition at line 4194 of file pbx.c.

References E_CANMATCH, NULL, 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(), leave_voicemail(), loopback_canmatch(), mgcp_ss(), pbx_builtin_background(), phone_check_exception(), test_exten(), and valid_exit().

4195 {
4196  return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
4197 }
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
#define NULL
Definition: resample.c:96
static int priority
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
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:
Definition: pbx.c:2875

◆ ast_change_hint()

static int ast_change_hint ( struct ast_exten oe,
struct ast_exten ne 
)
static

Change hint for an extension.

Definition at line 4096 of file pbx.c.

References add_hintdevice(), ao2_find, ao2_link, ao2_lock, ao2_ref, ao2_unlock, ast_get_context_name(), ast_get_extension_app(), ast_get_extension_context(), ast_get_extension_name(), ast_log, ast_mutex_unlock, context_merge_lock, ast_hint::exten, LOG_WARNING, OBJ_UNLINK, publish_hint_change(), and remove_hintdevice().

Referenced by add_priority().

4097 {
4098  struct ast_hint *hint;
4099 
4100  if (!oe || !ne) {
4101  return -1;
4102  }
4103 
4104  ao2_lock(hints);/* Locked to hold off others while we move the hint around. */
4105 
4106  /*
4107  * Unlink the hint from the hints container as the extension
4108  * name (which is the hash value) could change.
4109  */
4110  hint = ao2_find(hints, oe, OBJ_UNLINK);
4111  if (!hint) {
4112  ao2_unlock(hints);
4114  return -1;
4115  }
4116 
4117  remove_hintdevice(hint);
4118 
4119  /* Update the hint and put it back in the hints container. */
4120  ao2_lock(hint);
4121  hint->exten = ne;
4122 
4123  ao2_unlock(hint);
4124 
4125  ao2_link(hints, hint);
4126  if (add_hintdevice(hint, ast_get_extension_app(ne))) {
4127  ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
4130  }
4131  ao2_unlock(hints);
4132 
4133  publish_hint_change(hint, ne);
4134 
4135  ao2_ref(hint, -1);
4136 
4137  return 0;
4138 }
struct ast_context * ast_get_extension_context(struct ast_exten *exten)
Definition: pbx.c:8543
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8548
#define LOG_WARNING
Definition: logger.h:274
static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
add hintdevice structure and link it into the container.
Definition: pbx.c:552
static ast_mutex_t context_merge_lock
Lock to hold off restructuring of hints by ast_merge_contexts_and_delete.
Definition: pbx.c:790
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
struct ast_exten * exten
Hint extension.
Definition: pbx.c:331
Structure for dial plan hints.
Definition: pbx.c:324
static int remove_hintdevice(struct ast_hint *hint)
Definition: pbx.c:517
static int publish_hint_change(struct ast_hint *hint, struct ast_exten *ne)
Publish a hint changed event.
Definition: pbx.c:4074
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8596
const char * ast_get_context_name(struct ast_context *con)
Definition: pbx.c:8538
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ ast_context_add_ignorepat()

int ast_context_add_ignorepat ( const char *  context,
const char *  ignorepat,
const char *  registrar 
)

Add an ignorepat.

Parameters
contextwhich context to add the ignorpattern to
ignorepatignorepattern to set up for the extension
registrarregistrar of the ignore pattern

Adds an ignore pattern to a particular context.

Return values
0on success
-1on failure

Definition at line 6877 of file pbx.c.

References ast_context_add_ignorepat2(), ast_unlock_contexts(), c, and find_context_locked().

Referenced by handle_cli_dialplan_add_ignorepat().

6878 {
6879  int ret = -1;
6880  struct ast_context *c;
6881 
6883  if (c) {
6886  }
6887  return ret;
6888 }
static struct test_val c
int value
Definition: syslog.c:37
int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
Definition: pbx.c:6890
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
static char * registrar
Definition: pbx_ael.c:78
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4818
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284

◆ ast_context_add_ignorepat2()

int ast_context_add_ignorepat2 ( struct ast_context con,
const char *  value,
const char *  registrar 
)

Definition at line 6890 of file pbx.c.

References ast_context_ignorepats_count(), ast_context_ignorepats_get(), ast_get_ignorepat_name(), ast_unlock_context(), AST_VECTOR_APPEND, ast_wrlock_context(), errno, ignorepat_alloc(), ignorepat_free(), and ast_context::ignorepats.

Referenced by ast_context_add_ignorepat(), and context_merge_incls_swits_igps_other_registrars().

6891 {
6892  struct ast_ignorepat *ignorepat = ignorepat_alloc(value, registrar);
6893  int idx;
6894 
6895  if (!ignorepat) {
6896  return -1;
6897  }
6898 
6899  ast_wrlock_context(con);
6900  for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6901  const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
6902 
6903  if (!strcasecmp(ast_get_ignorepat_name(i), value)) {
6904  /* Already there */
6905  ast_unlock_context(con);
6906  ignorepat_free(ignorepat);
6907  errno = EEXIST;
6908  return -1;
6909  }
6910  }
6911  if (AST_VECTOR_APPEND(&con->ignorepats, ignorepat)) {
6912  ignorepat_free(ignorepat);
6913  ast_unlock_context(con);
6914  return -1;
6915  }
6916  ast_unlock_context(con);
6917 
6918  return 0;
6919 }
struct ast_ignorepats ignorepats
Definition: pbx.c:291
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8530
const struct ast_ignorepat * ast_context_ignorepats_get(const struct ast_context *con, int idx)
Definition: pbx.c:8745
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
int value
Definition: syslog.c:37
void ignorepat_free(struct ast_ignorepat *ip)
Definition: pbx_ignorepat.c:77
const char * ast_get_ignorepat_name(const struct ast_ignorepat *ip)
Definition: pbx_ignorepat.c:42
int ast_context_ignorepats_count(const struct ast_context *con)
Definition: pbx.c:8740
struct ast_ignorepat * ignorepat_alloc(const char *value, const char *registrar)
Definition: pbx_ignorepat.c:52
ast_ignorepat: Ignore patterns in dial plan
Definition: pbx_ignorepat.c:37
int errno
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8520
static char * registrar
Definition: pbx_ael.c:78

◆ ast_context_add_include()

int ast_context_add_include ( const char *  context,
const char *  include,
const char *  registrar 
)

Add a context include.

Parameters
contextcontext to add include to
includenew include to add
registrarwho's registering it

Adds an include taking a char * string as the context parameter

Return values
0on success
-1on error

Definition at line 6706 of file pbx.c.

References ast_context_add_include2(), ast_unlock_contexts(), c, and find_context_locked().

Referenced by AST_TEST_DEFINE(), and handle_cli_dialplan_add_include().

6707 {
6708  int ret = -1;
6709  struct ast_context *c;
6710 
6712  if (c) {
6713  ret = ast_context_add_include2(c, include, registrar);
6715  }
6716  return ret;
6717 }
int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Add a context include.
Definition: pbx.c:6726
static struct test_val c
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
static char * registrar
Definition: pbx_ael.c:78
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4818
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284

◆ ast_context_add_include2()

int ast_context_add_include2 ( struct ast_context con,
const char *  value,
const char *  registrar 
)

Add a context include.

Parameters
concontext to add the include to
valueinclude value to add
registrarwho registered the context

Adds an include taking a struct ast_context as the first parameter

Return values
0on success
-1on failure

Definition at line 6726 of file pbx.c.

References ast_context_includes_count(), ast_context_includes_get(), ast_debug, ast_get_context_name(), ast_get_include_name(), ast_unlock_context(), AST_VECTOR_APPEND, ast_wrlock_context(), errno, include_alloc(), include_free(), and ast_context::includes.

Referenced by ast_context_add_include(), and context_merge_incls_swits_igps_other_registrars().

6728 {
6729  struct ast_include *new_include;
6730  int idx;
6731 
6732  /* allocate new include structure ... */
6733  new_include = include_alloc(value, registrar);
6734  if (!new_include) {
6735  return -1;
6736  }
6737 
6738  ast_wrlock_context(con);
6739 
6740  /* ... go to last include and check if context is already included too... */
6741  for (idx = 0; idx < ast_context_includes_count(con); idx++) {
6742  const struct ast_include *i = ast_context_includes_get(con, idx);
6743 
6744  if (!strcasecmp(ast_get_include_name(i), ast_get_include_name(new_include))) {
6745  include_free(new_include);
6746  ast_unlock_context(con);
6747  errno = EEXIST;
6748  return -1;
6749  }
6750  }
6751 
6752  /* ... include new context into context list, unlock, return */
6753  if (AST_VECTOR_APPEND(&con->includes, new_include)) {
6754  include_free(new_include);
6755  ast_unlock_context(con);
6756  return -1;
6757  }
6758  ast_debug(1, "Including context '%s' in context '%s'\n",
6759  ast_get_include_name(new_include), ast_get_context_name(con));
6760 
6761  ast_unlock_context(con);
6762 
6763  return 0;
6764 }
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8530
struct ast_include * include_alloc(const char *value, const char *registrar)
Definition: pbx_include.c:74
void include_free(struct ast_include *inc)
Definition: pbx_include.c:106
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
int value
Definition: syslog.c:37
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct ast_includes includes
Definition: pbx.c:290
int errno
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8520
static char * registrar
Definition: pbx_ael.c:78
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
Definition: pbx.c:8702
const char * ast_get_context_name(struct ast_context *con)
Definition: pbx.c:8538
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8697

◆ ast_context_add_switch()

int ast_context_add_switch ( const char *  context,
const char *  sw,
const char *  data,
int  eval,
const char *  registrar 
)

Add a switch.

Parameters
contextcontext to which to add the switch
swswitch to add
datadata to pass to switch
evalwhether to evaluate variables when running switch
registrarwhoever registered the switch

This function registers a switch with the asterisk switch architecture

Return values
0on success
-1on failure

Definition at line 6771 of file pbx.c.

References ast_context_add_switch2(), ast_unlock_contexts(), c, and find_context_locked().

6772 {
6773  int ret = -1;
6774  struct ast_context *c;
6775 
6777  if (c) { /* found, add switch to this context */
6778  ret = ast_context_add_switch2(c, sw, data, eval, registrar);
6780  }
6781  return ret;
6782 }
static struct test_val c
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
static char * registrar
Definition: pbx_ael.c:78
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4818
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)
Definition: pbx.c:6791
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284

◆ ast_context_add_switch2()

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)

Note
See ast_context_add_switch() for argument information, with the exception of the first argument. In this case, it's a pointer to an ast_context structure as opposed to the name.

Definition at line 6791 of file pbx.c.

References ast_context::alts, ast_context_switches_count(), ast_context_switches_get(), ast_get_context_name(), ast_get_switch_data(), ast_get_switch_name(), ast_unlock_context(), AST_VECTOR_APPEND, ast_verb, ast_wrlock_context(), errno, sw_alloc(), and sw_free().

Referenced by ast_context_add_switch(), and context_merge_incls_swits_igps_other_registrars().

6793 {
6794  int idx;
6795  struct ast_sw *new_sw;
6796 
6797  /* allocate new sw structure ... */
6798  if (!(new_sw = sw_alloc(value, data, eval, registrar))) {
6799  return -1;
6800  }
6801 
6802  /* ... try to lock this context ... */
6803  ast_wrlock_context(con);
6804 
6805  /* ... go to last sw and check if context is already swd too... */
6806  for (idx = 0; idx < ast_context_switches_count(con); idx++) {
6807  const struct ast_sw *i = ast_context_switches_get(con, idx);
6808 
6809  if (!strcasecmp(ast_get_switch_name(i), ast_get_switch_name(new_sw)) &&
6810  !strcasecmp(ast_get_switch_data(i), ast_get_switch_data(new_sw))) {
6811  sw_free(new_sw);
6812  ast_unlock_context(con);
6813  errno = EEXIST;
6814  return -1;
6815  }
6816  }
6817 
6818  /* ... sw new context into context list, unlock, return */
6819  if (AST_VECTOR_APPEND(&con->alts, new_sw)) {
6820  sw_free(new_sw);
6821  ast_unlock_context(con);
6822  return -1;
6823  }
6824 
6825  ast_verb(3, "Including switch '%s/%s' in context '%s'\n",
6827 
6828  ast_unlock_context(con);
6829 
6830  return 0;
6831 }
const char * ast_get_switch_name(const struct ast_sw *sw)
Definition: pbx_sw.c:48
int ast_context_switches_count(const struct ast_context *con)
Definition: pbx.c:8652
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8530
const struct ast_sw * ast_context_switches_get(const struct ast_context *con, int idx)
Definition: pbx.c:8657
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
int value
Definition: syslog.c:37
#define ast_verb(level,...)
Definition: logger.h:463
ast_sw: Switch statement in extensions.conf
Definition: pbx_sw.c:37
const char * data
Definition: pbx_sw.c:42
struct ast_sw * sw_alloc(const char *value, const char *data, int eval, const char *registrar)
Definition: pbx_sw.c:68
int eval
Definition: pbx_sw.c:43
int errno
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8520
static char * registrar
Definition: pbx_ael.c:78
const char * ast_get_switch_data(const struct ast_sw *sw)
Definition: pbx_sw.c:53
void sw_free(struct ast_sw *sw)
Definition: pbx_sw.c:101
const char * ast_get_context_name(struct ast_context *con)
Definition: pbx.c:8538
struct ast_sws alts
Definition: pbx.c:292

◆ ast_context_destroy()

void ast_context_destroy ( struct ast_context con,
const char *  registrar 
)

Destroy a context (matches the specified context or ANY context if NULL)

Parameters
concontext to destroy
registrarwho registered it

You can optionally leave out either parameter. It will find it based on either the ast_context or the registrar name.

Returns
nothing

Definition at line 8260 of file pbx.c.

References __ast_context_destroy(), ast_unlock_contexts(), and ast_wrlock_contexts().

Referenced by ast_context_destroy_by_name().

8261 {
8265 }
void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
Definition: pbx.c:8095
static struct ast_hashtab * contexts_table
Definition: pbx.c:777
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8502
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
static char * registrar
Definition: pbx_ael.c:78
static struct ast_context * contexts
Definition: pbx.c:776

◆ ast_context_destroy_by_name()

int ast_context_destroy_by_name ( const char *  context,
const char *  registrar 
)

Destroy a context by name.

Parameters
contextName of the context to destroy
registrarwho registered it

You can optionally leave out the registrar parameter. It will find it based on the context name.

Return values
-1context not found
0Success

Definition at line 8244 of file pbx.c.

References ast_context_destroy(), ast_context_find(), ast_unlock_contexts(), and ast_wrlock_contexts().

Referenced by __unload_module(), app_dtor(), ast_sip_destroy_sorcery_global(), check_regcontext(), cleanup_stale_contexts(), handle_cli_dialplan_remove_context(), and unload_module().

8245 {
8246  struct ast_context *con;
8247  int ret = -1;
8248 
8250  con = ast_context_find(context);
8251  if (con) {
8253  ret = 0;
8254  }
8256 
8257  return ret;
8258 }
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: pbx.c:2443
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: pbx.c:8260
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8502
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
static char * registrar
Definition: pbx_ael.c:78
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284

◆ ast_context_find()

struct ast_context* ast_context_find ( const char *  name)

Find a context.

Parameters
namename of the context to find

Will search for the context with the given name.

Returns
the ast_context on success, NULL on failure.

Definition at line 2443 of file pbx.c.

References ast_copy_string(), ast_hashtab_lookup(), ast_rdlock_contexts(), ast_unlock_contexts(), ast_walk_contexts(), ast_context::name, fake_context::name, NULL, and tmp().

Referenced by _macro_exec(), app_create(), ast_context_destroy_by_name(), ast_context_verify_includes(), ast_ignore_pattern(), handle_cli_dialplan_add_extension(), handle_cli_dialplan_add_include(), isexten_function_read(), register_exten(), register_peer_exten(), and unregister_exten().

2444 {
2445  struct ast_context *tmp;
2446  struct fake_context item;
2447 
2448  if (!name) {
2449  return NULL;
2450  }
2452  if (contexts_table) {
2453  ast_copy_string(item.name, name, sizeof(item.name));
2455  } else {
2456  tmp = NULL;
2457  while ((tmp = ast_walk_contexts(tmp))) {
2458  if (!strcasecmp(name, tmp->name)) {
2459  break;
2460  }
2461  }
2462  }
2464  return tmp;
2465 }
void * ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
Lookup this object in the hash table.
Definition: hashtab.c:486
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: pbx.c:8609
static struct ast_hashtab * contexts_table
Definition: pbx.c:777
static int tmp()
Definition: bt_open.c:389
static struct aco_type item
Definition: test_config.c:1463
#define NULL
Definition: resample.c:96
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:8507
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
char name[0]
Definition: pbx.c:297
static const char name[]
Definition: cdr_mysql.c:74
const char * name
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284

◆ ast_context_find_or_create()

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.

Parameters
extcontextspointer to the ast_context structure pointer
exttablepointer to the hashtable that contains all the elements in extcontexts
namename of the new context
registrarregistrar of the context

This function allows you to play in two environments: the global contexts (active dialplan) or an external context set of your choosing. To act on the external set, make sure extcontexts and exttable are set; for the globals, make sure both extcontexts and exttable are NULL.

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.

Returns
NULL on failure, and an ast_context structure on success

Definition at line 6198 of file pbx.c.

References ast_context::alts, 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_VECTOR_INIT, ast_wrlock_contexts(), contexts, 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, NULL, ast_context::refcount, ast_context::registrar, ast_context::root, ast_context::root_table, and tmp().

Referenced by context_merge().

6199 {
6200  struct ast_context *tmp, **local_contexts;
6201  struct fake_context search;
6202  int length = sizeof(struct ast_context) + strlen(name) + 1;
6203 
6204  if (!contexts_table) {
6205  /* Protect creation of contexts_table from reentrancy. */
6207  if (!contexts_table) {
6213  0);
6214  }
6216  }
6217 
6218  ast_copy_string(search.name, name, sizeof(search.name));
6219  if (!extcontexts) {
6221  local_contexts = &contexts;
6222  tmp = ast_hashtab_lookup(contexts_table, &search);
6223  if (tmp) {
6224  tmp->refcount++;
6226  return tmp;
6227  }
6228  } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
6229  local_contexts = extcontexts;
6230  tmp = ast_hashtab_lookup(exttable, &search);
6231  if (tmp) {
6232  tmp->refcount++;
6233  return tmp;
6234  }
6235  }
6236 
6237  if ((tmp = ast_calloc(1, length))) {
6238  ast_rwlock_init(&tmp->lock);
6239  ast_mutex_init(&tmp->macrolock);
6240  strcpy(tmp->name, name);
6241  tmp->root = NULL;
6242  tmp->root_table = NULL;
6243  tmp->registrar = ast_strdup(registrar);
6244  AST_VECTOR_INIT(&tmp->includes, 0);
6245  AST_VECTOR_INIT(&tmp->ignorepats, 0);
6246  AST_VECTOR_INIT(&tmp->alts, 0);
6247  tmp->refcount = 1;
6248  } else {
6249  ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
6250  if (!extcontexts) {
6252  }
6253  return NULL;
6254  }
6255 
6256  if (!extcontexts) {
6257  tmp->next = *local_contexts;
6258  *local_contexts = tmp;
6259  ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
6261  } else {
6262  tmp->next = *local_contexts;
6263  if (exttable)
6264  ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
6265 
6266  *local_contexts = tmp;
6267  }
6268  ast_debug(1, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
6269  return tmp;
6270 }
struct ast_ignorepats ignorepats
Definition: pbx.c:291
void * ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
Lookup this object in the hash table.
Definition: hashtab.c:486
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
Definition: hashtab.c:127
struct ast_exten * root
Definition: pbx.c:286
static struct ast_hashtab * contexts_table
Definition: pbx.c:777
static int tmp()
Definition: bt_open.c:389
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
struct ast_context * local_contexts
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:8507
int ast_hashtab_resize_java(struct ast_hashtab *tab)
Determines if a table resize should occur using the Java algorithm (if the table load factor is 75% o...
Definition: hashtab.c:84
#define ast_hashtab_insert_safe(tab, obj)
Definition: hashtab.h:315
struct ast_context * next
Definition: pbx.c:289
ast_mutex_t macrolock
Definition: pbx.c:296
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8502
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_hashtab_insert_immediate(tab, obj)
Definition: hashtab.h:291
#define ast_log
Definition: astobj2.c:42
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
char * registrar
Definition: pbx.c:293
struct ast_includes includes
Definition: pbx.c:290
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
ast_rwlock_t lock
Definition: pbx.c:285
#define LOG_ERROR
Definition: logger.h:285
char name[0]
Definition: pbx.c:297
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:222
static char * registrar
Definition: pbx_ael.c:78
static const char name[]
Definition: cdr_mysql.c:74
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
unsigned int ast_hashtab_hash_contexts(const void *obj)
Definition: pbx.c:735
int refcount
Definition: pbx.c:294
struct ast_hashtab * root_table
Definition: pbx.c:287
static struct ast_context * contexts
Definition: pbx.c:776
#define ast_hashtab_create(initial_buckets, compare, resize, newsize, hash, do_locking)
Definition: hashtab.h:261
#define ast_mutex_init(pmutex)
Definition: lock.h:184
struct ast_sws alts
Definition: pbx.c:292
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
Definition: pbx.c:683

◆ ast_context_ignorepats_count()

int ast_context_ignorepats_count ( const struct ast_context con)

◆ ast_context_ignorepats_get()

const struct ast_ignorepat* ast_context_ignorepats_get ( const struct ast_context con,
int  idx 
)

◆ ast_context_includes_count()

int ast_context_includes_count ( const struct ast_context con)

◆ ast_context_includes_get()

const struct ast_include* ast_context_includes_get ( const struct ast_context con,
int  idx 
)

◆ ast_context_lockmacro()

int ast_context_lockmacro ( const char *  context)

locks the macrolock in the given context

Note
This function locks contexts list by &conlist, searches for the right context structure, and locks the macrolock mutex in that context. macrolock is used to limit a macro to be executed by one call at a time.
Parameters
contextThe context

Definition at line 5162 of file pbx.c.

References ast_mutex_lock, ast_unlock_contexts(), c, find_context_locked(), and ast_context::macrolock.

Referenced by _macro_exec().

5163 {
5164  struct ast_context *c;
5165  int ret = -1;
5166 
5168  if (c) {
5170 
5171  /* if we found context, lock macrolock */
5172  ret = ast_mutex_lock(&c->macrolock);
5173  }
5174 
5175  return ret;
5176 }
#define ast_mutex_lock(a)
Definition: lock.h:187
static struct test_val c
ast_mutex_t macrolock
Definition: pbx.c:296
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4818
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284

◆ ast_context_remove_extension()

int ast_context_remove_extension ( const char *  context,
const char *  extension,
int  priority,
const char *  registrar 
)

Simply remove extension from context.

Note
This function will lock conlock.

Definition at line 4952 of file pbx.c.

References ast_context_remove_extension_callerid(), AST_EXT_MATCHCID_ANY, and NULL.

Referenced by ast_sip_persistent_endpoint_update_state(), AST_TEST_DEFINE(), conf_ended(), delete_extens(), register_peer_exten(), sla_station_destructor(), sla_trunk_destructor(), unregister_exten(), and unregister_extension().

4953 {
4955 }
#define NULL
Definition: resample.c:96
static int priority
structure to hold extensions
static char * registrar
Definition: pbx_ael.c:78
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
Definition: pbx.c:4957

◆ ast_context_remove_extension2()

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.

Note
When do you want to call this function, make sure that &conlock is locked, because some process can handle with your *con context before you lock it.

Definition at line 4982 of file pbx.c.

References ast_context_remove_extension_callerid2(), AST_EXT_MATCHCID_ANY, and NULL.

Referenced by add_extension(), and add_hints().

4983 {
4985 }
#define NULL
Definition: resample.c:96
static int priority
structure to hold extensions
static char * registrar
Definition: pbx_ael.c:78
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: pbx.c:4987

◆ ast_context_remove_extension_callerid()

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 4957 of file pbx.c.

References ast_context_remove_extension_callerid2(), ast_unlock_contexts(), c, and find_context_locked().

Referenced by ast_context_remove_extension(), handle_cli_dialplan_remove_extension(), and manager_dialplan_extension_remove().

4958 {
4959  int ret = -1; /* default error return */
4960  struct ast_context *c;
4961 
4963  if (c) { /* ... remove extension ... */
4965  matchcallerid, registrar, 0);
4967  }
4968 
4969  return ret;
4970 }
static struct test_val c
static int priority
structure to hold extensions
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
static char * registrar
Definition: pbx_ael.c:78
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4818
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: pbx.c:4987
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284

◆ ast_context_remove_extension_callerid2()

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 4987 of file pbx.c.

References add_exten_to_pattern_tree(), 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(), ext_strncpy(), ast_exten::exten, match_char::exten, ast_exten::label, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_exten::matchcid, ast_exten::name, ast_context::name, ast_exten::next, NULL, 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().

4988 {
4989  struct ast_exten *exten, *prev_exten = NULL;
4990  struct ast_exten *peer;
4991  struct ast_exten ex, *exten2, *exten3;
4992  char dummy_name[1024];
4993  char dummy_cid[1024];
4994  struct ast_exten *previous_peer = NULL;
4995  struct ast_exten *next_peer = NULL;
4996  int found = 0;
4997 
4998  if (!already_locked)
4999  ast_wrlock_context(con);
5000 
5001 #ifdef NEED_DEBUG
5002  ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
5003 #endif
5004 #ifdef CONTEXT_DEBUG
5005  check_contexts(__FILE__, __LINE__);
5006 #endif
5007  /* find this particular extension */
5008  ex.exten = dummy_name;
5009  ext_strncpy(dummy_name, extension, sizeof(dummy_name), 1);
5010  ex.matchcid = matchcallerid;
5011  if (callerid) {
5012  ex.cidmatch = dummy_cid;
5013  ext_strncpy(dummy_cid, callerid, sizeof(dummy_cid), 1);
5014  } else {
5015  ex.cidmatch = NULL;
5016  }
5017  exten = ast_hashtab_lookup(con->root_table, &ex);
5018  if (exten) {
5019  if (priority == 0) {
5020  exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
5021  if (!exten2)
5022  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);
5023  if (con->pattern_tree) {
5024  struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5025 
5026  if (x->exten) { /* this test for safety purposes */
5027  x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
5028  x->exten = 0; /* get rid of what will become a bad pointer */
5029  } else {
5030  ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
5031  }
5032  }
5033  } else {
5034  ex.priority = priority;
5035  exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
5036  if (exten2) {
5037  if (exten2->label) { /* if this exten has a label, remove that, too */
5038  exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
5039  if (!exten3) {
5040  ast_log(LOG_ERROR, "Did not remove this priority label (%d/%s) "
5041  "from the peer_label_table of context %s, extension %s!\n",
5042  priority, exten2->label, con->name, exten2->name);
5043  }
5044  }
5045 
5046  exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
5047  if (!exten3) {
5048  ast_log(LOG_ERROR, "Did not remove this priority (%d) from the "
5049  "peer_table of context %s, extension %s!\n",
5050  priority, con->name, exten2->name);
5051  }
5052  if (exten2 == exten && exten2->peer) {
5053  exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
5055  }
5056  if (ast_hashtab_size(exten->peer_table) == 0) {
5057  /* well, if the last priority of an exten is to be removed,
5058  then, the extension is removed, too! */
5059  exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
5060  if (!exten3) {
5061  ast_log(LOG_ERROR, "Did not remove this exten (%s) from the "
5062  "context root_table (%s) (priority %d)\n",
5063  exten->name, con->name, priority);
5064  }
5065  if (con->pattern_tree) {
5066  struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5067  if (x->exten) { /* this test for safety purposes */
5068  x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
5069  x->exten = 0; /* get rid of what will become a bad pointer */
5070  }
5071  }
5072  }
5073  } else {
5074  ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
5075  priority, exten->name, con->name);
5076  }
5077  }
5078  } else {
5079  /* hmmm? this exten is not in this pattern tree? */
5080  ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
5081  extension, con->name);
5082  }
5083 #ifdef NEED_DEBUG
5084  if (con->pattern_tree) {
5085  ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
5086  log_match_char_tree(con->pattern_tree, " ");
5087  }
5088 #endif
5089 
5090  /* scan the extension list to find first matching extension-registrar */
5091  for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
5092  if (!strcmp(exten->exten, ex.exten) &&
5093  (!matchcallerid ||
5094  (!ast_strlen_zero(ex.cidmatch) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, ex.cidmatch)) ||
5095  (ast_strlen_zero(ex.cidmatch) && ast_strlen_zero(exten->cidmatch)))) {
5096  break;
5097  }
5098  }
5099  if (!exten) {
5100  /* we can't find right extension */
5101  if (!already_locked)
5102  ast_unlock_context(con);
5103  return -1;
5104  }
5105 
5106  /* scan the priority list to remove extension with exten->priority == priority */
5107  for (peer = exten, next_peer = exten->