Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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  scoreboard
 

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 MAX_EXTENBUF_SIZE   512
 
#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

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 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 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...
 
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)
 
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_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...
 
struct ast_contextast_context_find (const char *name)
 Find a context. More...
 
int ast_context_lockmacro (const char *macrocontext)
 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_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...
 
int ast_context_unlockmacro (const char *macrocontext)
 Unlocks the macrolock in the given context. 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_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 *extension)
 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...
 
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_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_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_pbx_h_exten_run (struct ast_channel *chan, const char *context)
 Run the h exten from the given context. More...
 
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...
 
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...
 
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 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 int handle_hint_change_message_type (struct stasis_message *msg, enum ast_state_cb_update_reason reason)
 
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 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_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)
 
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)
 
static void pbx_destroy (struct ast_pbx *p)
 
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)
 
int pbx_set_autofallthrough (int newval)
 
int pbx_set_extenpatternmatchnew (int newval)
 
void pbx_set_overrideswitch (const char *newval)
 
static void * pbx_thread (void *data)
 
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_ext (struct ast_exten *e, char *buf, int buflen)
 helper function to print an extension More...
 
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 struct ast_extentrie_find_next_match (struct match_char *node)
 
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)
 

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

◆ BITS_PER

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

◆ 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.

◆ HASH_EXTENHINT_SIZE

#define HASH_EXTENHINT_SIZE   563

Definition at line 358 of file pbx.c.

◆ 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

◆ MAX_EXTENBUF_SIZE

#define MAX_EXTENBUF_SIZE   512

Definition at line 1655 of file pbx.c.

◆ MORE

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

Definition at line 1226 of file pbx.c.

◆ NEW_MATCHER_CHK_MATCH

#define NEW_MATCHER_CHK_MATCH

◆ NEW_MATCHER_RECURSE

#define NEW_MATCHER_RECURSE

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

◆ STATUS_NO_EXTENSION

#define STATUS_NO_EXTENSION   2

Definition at line 2475 of file pbx.c.

◆ STATUS_NO_LABEL

#define STATUS_NO_LABEL   4

Definition at line 2477 of file pbx.c.

◆ STATUS_NO_PRIORITY

#define STATUS_NO_PRIORITY   3

Definition at line 2476 of file pbx.c.

◆ STATUS_SUCCESS

#define STATUS_SUCCESS   5

Definition at line 2478 of file pbx.c.

◆ 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_internal_context_destroy()

static void __ast_internal_context_destroy ( struct ast_context con)
static

◆ __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 4286 of file pbx.c.

4315 {
4316  int found = 0; /* set if we find at least one match */
4317  int res = 0;
4318  int autoloopflag;
4319  int error = 0; /* set an error conditions */
4320  struct ast_pbx *pbx;
4321  ast_callid callid;
4322 
4323  /* A little initial setup here */
4324  if (ast_channel_pbx(c)) {
4325  ast_log(LOG_WARNING, "%s already has PBX structure??\n", ast_channel_name(c));
4326  /* XXX and now what ? */
4328  }
4329  if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
4330  return AST_PBX_FAILED;
4331  }
4332 
4333  callid = ast_read_threadstorage_callid();
4334  /* If the thread isn't already associated with a callid, we should create that association. */
4335  if (!callid) {
4336  /* Associate new PBX thread with the channel call id if it is availble.
4337  * If not, create a new one instead.
4338  */
4339  callid = ast_channel_callid(c);
4340  if (!callid) {
4341  callid = ast_create_callid();
4342  if (callid) {
4344  ast_channel_callid_set(c, callid);
4346  }
4347  }
4349  callid = 0;
4350  }
4351 
4352  ast_channel_pbx_set(c, pbx);
4353  /* Set reasonable defaults */
4354  ast_channel_pbx(c)->rtimeoutms = 10000;
4355  ast_channel_pbx(c)->dtimeoutms = 5000;
4356 
4358  autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
4361 
4363  /* If not successful fall back to 's' - but only if there is no given exten */
4364  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));
4365  /* XXX the original code used the existing priority in the call to
4366  * ast_exists_extension(), and reset it to 1 afterwards.
4367  * I believe the correct thing is to set it to 1 immediately.
4368  */
4369  set_ext_pri(c, "s", 1);
4370  }
4371 
4372  for (;;) {
4373  char dst_exten[256]; /* buffer to accumulate digits */
4374  int pos = 0; /* XXX should check bounds */
4375  int digit = 0;
4376  int invalid = 0;
4377  int timeout = 0;
4378 
4379  /* No digits pressed yet */
4380  dst_exten[pos] = '\0';
4381 
4382  /* loop on priorities in this context/exten */
4385  &found, 1))) {
4386 
4387  if (!ast_check_hangup(c)) {
4389  continue;
4390  }
4391 
4392  /* Check softhangup flags. */
4395  continue;
4396  }
4399  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4400  set_ext_pri(c, "T", 1);
4401  /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4402  memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
4404  continue;
4405  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4406  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4407  raise_exception(c, "ABSOLUTETIMEOUT", 1);
4408  /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4409  memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
4411  continue;
4412  }
4413 
4414  /* Call timed out with no special extension to jump to. */
4415  error = 1;
4416  break;
4417  }
4418  ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
4420  error = 1;
4421  break;
4422  } /* end while - from here on we can use 'break' to go out */
4423  if (found && res) {
4424  /* Something bad happened, or a hangup has been requested. */
4425  if (strchr("0123456789ABCDEF*#", res)) {
4426  ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
4427  pos = 0;
4428  dst_exten[pos++] = digit = res;
4429  dst_exten[pos] = '\0';
4430  } else if (res == AST_PBX_INCOMPLETE) {
4431  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));
4432  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));
4433 
4434  /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
4436  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4437  invalid = 1;
4438  } else {
4439  ast_copy_string(dst_exten, ast_channel_exten(c), sizeof(dst_exten));
4440  digit = 1;
4441  pos = strlen(dst_exten);
4442  }
4443  } else {
4444  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));
4445  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));
4446 
4447  if ((res == AST_PBX_ERROR)
4449  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4450  /* if we are already on the 'e' exten, don't jump to it again */
4451  if (!strcmp(ast_channel_exten(c), "e")) {
4452  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));
4453  error = 1;
4454  } else {
4455  raise_exception(c, "ERROR", 1);
4456  continue;
4457  }
4458  }
4459 
4462  continue;
4463  }
4466  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4467  set_ext_pri(c, "T", 1);
4468  /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4469  memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
4471  continue;
4472  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4473  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4474  raise_exception(c, "ABSOLUTETIMEOUT", 1);
4475  /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4476  memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
4478  continue;
4479  }
4480  /* Call timed out with no special extension to jump to. */
4481  }
4482  error = 1;
4483  break;
4484  }
4485  }
4486  if (error)
4487  break;
4488 
4489  /*!\note
4490  * We get here on a failure of some kind: non-existing extension or
4491  * hangup. We have options, here. We can either catch the failure
4492  * and continue, or we can drop out entirely. */
4493 
4494  if (invalid
4495  || (ast_strlen_zero(dst_exten) &&
4497  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL)))) {
4498  /*!\note
4499  * If there is no match at priority 1, it is not a valid extension anymore.
4500  * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
4501  * neither exist.
4502  */
4504  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4505  ast_verb(3, "Channel '%s' sent to invalid extension: context,exten,priority=%s,%s,%d\n",
4507  pbx_builtin_setvar_helper(c, "INVALID_EXTEN", ast_channel_exten(c));
4508  set_ext_pri(c, "i", 1);
4509  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4510  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4511  raise_exception(c, "INVALID", 1);
4512  } else {
4513  ast_log(LOG_WARNING, "Channel '%s' sent to invalid extension but no invalid handler: context,exten,priority=%s,%s,%d\n",
4515  error = 1; /* we know what to do with it */
4516  break;
4517  }
4519  /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
4521  } else { /* keypress received, get more digits for a full extension */
4522  int waittime = 0;
4523  if (digit)
4524  waittime = ast_channel_pbx(c)->dtimeoutms;
4525  else if (!autofallthrough)
4526  waittime = ast_channel_pbx(c)->rtimeoutms;
4527  if (!waittime) {
4528  const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
4529  if (!status)
4530  status = "UNKNOWN";
4531  ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
4532  if (!strcasecmp(status, "CONGESTION"))
4533  res = indicate_congestion(c, "10");
4534  else if (!strcasecmp(status, "CHANUNAVAIL"))
4535  res = indicate_congestion(c, "10");
4536  else if (!strcasecmp(status, "BUSY"))
4537  res = indicate_busy(c, "10");
4538  error = 1; /* XXX disable message */
4539  break; /* exit from the 'for' loop */
4540  }
4541 
4542  if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
4543  break;
4544  if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
4545  timeout = 1;
4546  if (!timeout
4547  && ast_exists_extension(c, ast_channel_context(c), dst_exten, 1,
4548  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) { /* Prepare the next cycle */
4549  set_ext_pri(c, dst_exten, 1);
4550  } else {
4551  /* No such extension */
4552  if (!timeout && !ast_strlen_zero(dst_exten)) {
4553  /* An invalid extension */
4555  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4556  ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, ast_channel_context(c), ast_channel_name(c));
4557  pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
4558  set_ext_pri(c, "i", 1);
4559  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4560  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4561  raise_exception(c, "INVALID", 1);
4562  } else {
4564  "Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
4565  dst_exten, ast_channel_context(c));
4566  found = 1; /* XXX disable message */
4567  break;
4568  }
4569  } else {
4570  /* A simple timeout */
4572  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4573  ast_verb(3, "Timeout on %s\n", ast_channel_name(c));
4574  set_ext_pri(c, "t", 1);
4575  } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4576  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4577  raise_exception(c, "RESPONSETIMEOUT", 1);
4578  } else {
4580  "Timeout, but no rule 't' or 'e' in context '%s'\n",
4582  found = 1; /* XXX disable message */
4583  break;
4584  }
4585  }
4586  }
4587  }
4588  }
4589 
4590  if (!found && !error) {
4591  ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", ast_channel_name(c));
4592  }
4593 
4594  if (!args || !args->no_hangup_chan) {
4598  S_COR(ast_channel_caller(c)->id.number.valid,
4599  ast_channel_caller(c)->id.number.str, NULL))) {
4601  }
4603  }
4604 
4607  ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
4611 
4612  if (!args || !args->no_hangup_chan) {
4613  ast_hangup(c);
4614  }
4615 
4616  return AST_PBX_SUCCESS;
4617 }
char digit
jack_status_t status
Definition: app_jack.c:146
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2431
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2542
@ AST_SOFTHANGUP_ASYNCGOTO
Definition: channel.h:1126
@ AST_SOFTHANGUP_TIMEOUT
Definition: channel.h:1138
@ AST_SOFTHANGUP_APPUNLOAD
Definition: channel.h:1143
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2922
const char * ast_channel_context(const struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
ast_callid ast_channel_callid(const struct ast_channel *chan)
const char * ast_channel_name(const struct ast_channel *chan)
@ AST_FLAG_BRIDGE_HANGUP_RUN
Definition: channel.h:1018
@ AST_FLAG_IN_AUTOLOOP
Definition: channel.h:997
struct ast_flags * ast_channel_flags(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
const char * ast_channel_exten(const struct ast_channel *chan)
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2470
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
void ast_channel_callid_set(struct ast_channel *chan, ast_callid value)
void ast_channel_priority_set(struct ast_channel *chan, int value)
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
void ast_channel_pbx_set(struct ast_channel *chan, struct ast_pbx *value)
int indicate_busy(struct ast_channel *chan, const char *data)
Definition: pbx_builtins.c:779
int indicate_congestion(struct ast_channel *chan, const char *data)
Definition: pbx_builtins.c:797
#define ast_debug(level,...)
Log a DEBUG message.
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:2048
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:2070
ast_callid ast_create_callid(void)
factory function to create a new uniquely identifying callid.
Definition: logger.c:2043
unsigned int ast_callid
#define ast_verb(level,...)
#define LOG_WARNING
static void pbx_destroy(struct ast_pbx *p)
Definition: pbx.c:983
static int autofallthrough
Definition: pbx.c:761
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:4182
int raise_exception(struct ast_channel *chan, const char *reason, int priority)
Definition: pbx.c:2813
void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
Run the h exten from the given context.
Definition: pbx.c:4212
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:4207
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:4202
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:4286
void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
Definition: pbx.c:4271
@ AST_PBX_FAILED
Definition: pbx.h:355
@ AST_PBX_SUCCESS
Definition: pbx.h:354
#define AST_PBX_INCOMPLETE
Definition: pbx.h:51
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.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define AST_PBX_ERROR
Definition: pbx.h:50
int ast_pbx_hangup_handler_run(struct ast_channel *chan)
Run all hangup handlers on the channel.
#define NULL
Definition: resample.c:96
#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:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406
Definition: pbx.h:214
int rtimeoutms
Definition: pbx.h:216
int dtimeoutms
Definition: pbx.h:215
Number structure.
Definition: app_followme.c:154
const char * args
static struct test_val c
int error(const char *format,...)
Definition: utils/frame.c:999
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70

References ast_channel_caller(), ast_channel_clear_softhangup(), ast_channel_context(), ast_channel_pbx(), ast_channel_softhangup_internal_flag(), ast_matchmore_extension(), AST_SOFTHANGUP_ASYNCGOTO, ast_waitfordigit(), buf, c, digit, ast_pbx::dtimeoutms, NULL, and S_COR.

Referenced by ast_pbx_run().

◆ __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 2216 of file pbx.c.

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

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().

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

2840 {
2842  struct pbx_exception *exception = NULL;
2843  if (!ds || !ds->data)
2844  return -1;
2845  exception = ds->data;
2846  if (!strcasecmp(data, "REASON"))
2847  ast_copy_string(buf, exception->reason, buflen);
2848  else if (!strcasecmp(data, "CONTEXT"))
2849  ast_copy_string(buf, exception->context, buflen);
2850  else if (!strncasecmp(data, "EXTEN", 5))
2851  ast_copy_string(buf, exception->exten, buflen);
2852  else if (!strcasecmp(data, "PRIORITY"))
2853  snprintf(buf, buflen, "%d", exception->priority);
2854  else
2855  return -1;
2856  return 0;
2857 }
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:2398
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const struct ast_datastore_info exception_store_info
Definition: pbx.c:2797
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
const ast_string_field context
Definition: pbx.c:623
const ast_string_field exten
Definition: pbx.c:623
int priority
Definition: pbx.c:625
const ast_string_field reason
Definition: pbx.c:623

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

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

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

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

Referenced by ast_context_remove_extension_callerid2(), and create_match_char_tree().

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

551 {
552  struct ast_str *str;
553  char *parse;
554  char *cur;
555  struct ast_hintdevice *device;
556  int devicelength;
557 
558  if (!hint || !devicelist) {
559  /* Trying to add garbage? Don't bother. */
560  return 0;
561  }
562  if (!(str = ast_str_thread_get(&hintdevice_data, 16))) {
563  return -1;
564  }
565  ast_str_set(&str, 0, "%s", devicelist);
567 
568  /* Spit on '&' and ',' to handle presence hints as well */
569  while ((cur = strsep(&parse, "&,"))) {
570  char *device_name;
571 
572  devicelength = strlen(cur);
573  if (!devicelength) {
574  continue;
575  }
576 
577  device_name = ast_strdup(cur);
578  if (!device_name) {
579  return -1;
580  }
581 
582  device = ao2_t_alloc(sizeof(*device) + devicelength, hintdevice_destroy,
583  "allocating a hintdevice structure");
584  if (!device) {
585  ast_free(device_name);
586  return -1;
587  }
588  strcpy(device->hintdevice, cur);
589  ao2_ref(hint, +1);
590  device->hint = hint;
591  if (AST_VECTOR_APPEND(&hint->devices, device_name)) {
592  ast_free(device_name);
593  ao2_ref(device, -1);
594  return -1;
595  }
596  ao2_t_link(hintdevices, device, "Linking device into hintdevice container.");
597  ao2_t_ref(device, -1, "hintdevice is linked so we can unref");
598  }
599 
600  return 0;
601 }
const char * str
Definition: app_jack.c:147
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ao2_t_ref(o, delta, tag)
Definition: astobj2.h:460
#define ao2_t_link(container, obj, tag)
Definition: astobj2.h:1534
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:407
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1844
char * strsep(char **str, const char *delims)
static void hintdevice_destroy(void *obj)
Definition: pbx.c:538
static struct ao2_container * hintdevices
Container for hint devices.
Definition: pbx.c:363
static struct ast_threadstorage hintdevice_data
Definition: pbx.c:352
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
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:1091
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:887
struct ast_hint::@406 devices
Structure for dial plan hint devices.
Definition: pbx.c:369
char hintdevice[1]
Definition: pbx.c:376
struct ast_hint * hint
Hint this hintdevice belongs to.
Definition: pbx.c:374
Support for dynamic strings.
Definition: strings.h:604
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256

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_hint::devices, ast_hintdevice::hint, ast_hintdevice::hintdevice, hintdevice_data, hintdevice_destroy(), hintdevices, parse(), str, and strsep().

Referenced by ast_add_hint(), and ast_change_hint().

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

1458 {
1459  struct match_char *m;
1460 
1461  if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern->buf)))) {
1462  return NULL;
1463  }
1464 
1465  /* strcpy is safe here since we know its size and have allocated
1466  * just enough space for when we allocated m
1467  */
1468  strcpy(m->x, pattern->buf);
1469 
1470  /* the specificity scores are the same as used in the old
1471  pattern matcher. */
1472  m->is_pattern = is_pattern;
1473  if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'N') {
1474  m->specificity = 0x0832;
1475  } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'Z') {
1476  m->specificity = 0x0931;
1477  } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'X') {
1478  m->specificity = 0x0a30;
1479  } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '.') {
1480  m->specificity = 0x18000;
1481  } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '!') {
1482  m->specificity = 0x28000;
1483  } else {
1484  m->specificity = pattern->specif;
1485  }
1486 
1487  if (!con->pattern_tree) {
1489  } else {
1490  if (already) { /* switch to the new regime (traversing vs appending)*/
1491  insert_in_next_chars_alt_char_list(nextcharptr, m);
1492  } else {
1494  }
1495  }
1496 
1497  return m;
1498 }
size_t current
Definition: main/cli.c:113
static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
Definition: pbx.c:1416
int is_pattern
Definition: pbx.c:263
int specificity
Definition: pbx.c:265
char x[1]
Definition: pbx.c:269
char buf[256]
Definition: pbx.c:1454
int specif
Definition: pbx.c:1452

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

Referenced by add_exten_to_pattern_tree().

◆ alloc_device_state_info()

static struct ao2_container* alloc_device_state_info ( void  )
static

Definition at line 3083 of file pbx.c.

3084 {
3086 }
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_container_alloc_list, and NULL.

Referenced by ast_extension_state_extended(), and device_state_notify_callbacks().

◆ already_in_tree()

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

Definition at line 1395 of file pbx.c.

1396 {
1397  struct match_char *t;
1398 
1399  if (!current) {
1400  return 0;
1401  }
1402 
1403  for (t = current; t; t = t->alt_char) {
1404  if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {/* uh, we may want to sort exploded [] contents to make matching easy */
1405  return t;
1406  }
1407  }
1408 
1409  return 0;
1410 }
struct match_char * alt_char
Definition: pbx.c:266

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

Referenced by add_exten_to_pattern_tree().

◆ ast_active_calls()

int ast_active_calls ( void  )

Retrieve the number of active calls.

Definition at line 4767 of file pbx.c.

4768 {
4769  return countcalls;
4770 }
static int countcalls
Definition: pbx.c:771

References countcalls.

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

◆ 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

◆ 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

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

3986 {
3987  struct ast_hint *hint_new;
3988  struct ast_hint *hint_found;
3989  char *message = NULL;
3990  char *subtype = NULL;
3991  int presence_state;
3992 
3993  if (!e) {
3994  return -1;
3995  }
3996 
3997  /*
3998  * We must create the hint we wish to add before determining if
3999  * it is already in the hints container to avoid possible
4000  * deadlock when getting the current extension state.
4001  */
4002  hint_new = ao2_alloc(sizeof(*hint_new), destroy_hint);
4003  if (!hint_new) {
4004  return -1;
4005  }
4006  AST_VECTOR_INIT(&hint_new->devices, 8);
4007 
4008  /* Initialize new hint. */
4010  if (!hint_new->callbacks) {
4011  ao2_ref(hint_new, -1);
4012  return -1;
4013  }
4014  hint_new->exten = e;
4015  if (strstr(e->app, "${") && e->exten[0] == '_') {
4016  /* The hint is dynamic and hasn't been evaluated yet */
4017  hint_new->laststate = AST_DEVICE_INVALID;
4019  } else {
4020  hint_new->laststate = ast_extension_state2(e, NULL);
4021  if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
4022  hint_new->last_presence_state = presence_state;
4023  hint_new->last_presence_subtype = subtype;
4024  hint_new->last_presence_message = message;
4025  }
4026  }
4027 
4028  /* Prevent multiple add hints from adding the same hint at the same time. */
4029  ao2_lock(hints);
4030 
4031  /* Search if hint exists, do nothing */
4032  hint_found = ao2_find(hints, e, 0);
4033  if (hint_found) {
4034  ao2_ref(hint_found, -1);
4035  ao2_unlock(hints);
4036  ao2_ref(hint_new, -1);
4037  ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n",
4039  return -1;
4040  }
4041 
4042  /* Add new hint to the hints container */
4043  ast_debug(2, "HINTS: Adding hint %s: %s\n",
4045  ao2_link(hints, hint_new);
4046  if (add_hintdevice(hint_new, ast_get_extension_app(e))) {
4047  ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
4050  }
4051 
4052  /* if not dynamic */
4053  if (!(strstr(e->app, "${") && e->exten[0] == '_')) {
4054  struct ast_state_cb *state_cb;
4055  struct ao2_iterator cb_iter;
4056 
4057  /* For general callbacks */
4058  cb_iter = ao2_iterator_init(statecbs, 0);
4059  for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
4063  state_cb->data,
4065  hint_new,
4066  NULL);
4067  }
4068  ao2_iterator_destroy(&cb_iter);
4069  }
4070  ao2_unlock(hints);
4071  ao2_ref(hint_new, -1);
4072 
4073  return 0;
4074 }
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
static struct ao2_container * statecbs
Definition: pbx.c:801
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:3257
static void destroy_hint(void *obj)
Definition: pbx.c:3910
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:3120
static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
Definition: pbx.c:3207
static int hint_id_cmp(void *obj, void *arg, int flags)
Definition: pbx.c:3896
static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
add hintdevice structure and link it into the container.
Definition: pbx.c:550
const char * ast_get_extension_app(struct ast_exten *e)
struct ast_context * ast_get_extension_context(struct ast_exten *exten)
const char * ast_get_extension_name(struct ast_exten *exten)
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
@ AST_HINT_UPDATE_DEVICE
Definition: pbx.h:91
@ AST_PRESENCE_INVALID
Definition: presencestate.h:39
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
const char * app
Definition: pbx.c:246
Structure for dial plan hints.
Definition: pbx.c:324
int laststate
Definition: pbx.c:335
struct ao2_container * callbacks
Definition: pbx.c:332
struct ast_exten * exten
Hint extension.
Definition: pbx.c:331
int last_presence_state
Definition: pbx.c:338
char * last_presence_subtype
Definition: pbx.c:339
char * last_presence_message
Definition: pbx.c:340
ast_state_cb: An extension state notify register item
Definition: pbx.c:301
ast_state_cb_type change_cb
Definition: pbx.c:309
void * data
Definition: pbx.c:305
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

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(), ast_hint::devices, 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, NULL, and statecbs.

◆ 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 search 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 4197 of file pbx.c.

4198 {
4199  return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
4200 }
static int priority
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
@ E_CANMATCH
Definition: extconf.h:217
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:2882

References c, context, E_CANMATCH, exten, NULL, pbx_extension_helper(), and priority.

Referenced by __analog_ss_thread(), analog_ss_thread(), background_detect_exec(), dp_lookup(), dundi_lookup_local(), get_also_info(), leave_voicemail(), loopback_canmatch(), mgcp_ss(), pbx_builtin_background(), test_exten(), and valid_exit().

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

4100 {
4101  struct ast_hint *hint;
4102 
4103  if (!oe || !ne) {
4104  return -1;
4105  }
4106 
4107  ao2_lock(hints);/* Locked to hold off others while we move the hint around. */
4108 
4109  /*
4110  * Unlink the hint from the hints container as the extension
4111  * name (which is the hash value) could change.
4112  */
4113  hint = ao2_find(hints, oe, OBJ_UNLINK);
4114  if (!hint) {
4115  ao2_unlock(hints);
4117  return -1;
4118  }
4119 
4120  remove_hintdevice(hint);
4121 
4122  /* Update the hint and put it back in the hints container. */
4123  ao2_lock(hint);
4124  hint->exten = ne;
4125 
4126  ao2_unlock(hint);
4127 
4128  ao2_link(hints, hint);
4129  if (add_hintdevice(hint, ast_get_extension_app(ne))) {
4130  ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
4133  }
4134  ao2_unlock(hints);
4135 
4136  publish_hint_change(hint, ne);
4137 
4138  ao2_ref(hint, -1);
4139 
4140  return 0;
4141 }
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ast_mutex_unlock(a)
Definition: lock.h:188
static int publish_hint_change(struct ast_hint *hint, struct ast_exten *ne)
Publish a hint changed event
Definition: pbx.c:4077
static int remove_hintdevice(struct ast_hint *hint)
Definition: pbx.c:517
static ast_mutex_t context_merge_lock
Lock to hold off restructuring of hints by ast_merge_contexts_and_delete.
Definition: pbx.c:788

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().

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

2451 {
2452  struct ast_context *tmp;
2453  struct fake_context item;
2454 
2455  if (!name) {
2456  return NULL;
2457  }
2459  if (contexts_table) {
2460  ast_copy_string(item.name, name, sizeof(item.name));
2462  } else {
2463  tmp = NULL;
2464  while ((tmp = ast_walk_contexts(tmp))) {
2465  if (!strcasecmp(name, tmp->name)) {
2466  break;
2467  }
2468  }
2469  }
2471  return tmp;
2472 }
static int tmp()
Definition: bt_open.c:389
static const char name[]
Definition: format_mp3.c:68
void * ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
Lookup this object in the hash table.
Definition: hashtab.c:486
static struct ast_hashtab * contexts_table
Definition: pbx.c:775
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: extconf.c:4025
int ast_rdlock_contexts(void)
Read locks the context list.
int ast_unlock_contexts(void)
Unlocks contexts.
const char * name
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284
static struct aco_type item
Definition: test_config.c:1463

References ast_copy_string(), ast_hashtab_lookup(), ast_rdlock_contexts(), ast_unlock_contexts(), ast_walk_contexts(), contexts_table, item, name, aco_type::name, NULL, and tmp().

Referenced by _macro_exec(), app_create(), context_included(), handle_cli_dialplan_add_extension(), handle_cli_dialplan_add_include(), isexten_function_read(), register_exten(), register_peer_exten(), and unregister_exten().

◆ ast_context_lockmacro()

int ast_context_lockmacro ( const char *  macrocontext)

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.

Definition at line 5164 of file pbx.c.

5165 {
5166  struct ast_context *c;
5167  int ret = -1;
5168 
5169  c = find_context_locked(macrocontext);
5170  if (c) {
5172 
5173  /* if we found context, lock macrolock */
5174  ret = ast_mutex_lock(&c->macrolock);
5175  }
5176 
5177  return ret;
5178 }
#define ast_mutex_lock(a)
Definition: lock.h:187
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4821

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

Referenced by _macro_exec().

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

4956 {
4958 }
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:4960
@ AST_EXT_MATCHCID_ANY
Definition: pbx.h:80
static char * registrar
Definition: pbx_ael.c:78
structure to hold extensions

References ast_context_remove_extension_callerid(), AST_EXT_MATCHCID_ANY, context, NULL, priority, and registrar.

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().

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

4986 {
4988 }
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:4990

References ast_context_remove_extension_callerid2(), AST_EXT_MATCHCID_ANY, NULL, priority, and registrar.

Referenced by add_extension(), and add_hints().

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

4961 {
4962  int ret = -1; /* default error return */
4963  struct ast_context *c;
4964 
4966  if (c) { /* ... remove extension ... */
4968  matchcallerid, registrar, 0);
4970  }
4971 
4972  return ret;
4973 }

References ast_context_remove_extension_callerid2(), ast_unlock_contexts(), c, context, find_context_locked(), priority, and registrar.

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

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

4991 {
4992  struct ast_exten *exten, *prev_exten = NULL;
4993  struct ast_exten *peer;
4994  struct ast_exten ex, *exten2, *exten3;
4995  char dummy_name[1024];
4996  char dummy_cid[1024];
4997  struct ast_exten *previous_peer = NULL;
4998  struct ast_exten *next_peer = NULL;
4999  int found = 0;
5000 
5001  if (!already_locked)
5002  ast_wrlock_context(con);
5003 
5004 #ifdef NEED_DEBUG
5005  ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
5006 #endif
5007 #ifdef CONTEXT_DEBUG
5008  check_contexts(__FILE__, __LINE__);
5009 #endif
5010  /* find this particular extension */
5011  ex.exten = dummy_name;
5012  ext_strncpy(dummy_name, extension, sizeof(dummy_name), 1);
5013  ex.matchcid = matchcallerid;
5014  if (callerid) {
5015  ex.cidmatch = dummy_cid;
5016  ext_strncpy(dummy_cid, callerid, sizeof(dummy_cid), 1);
5017  } else {
5018  ex.cidmatch = NULL;
5019  }
5020  exten = ast_hashtab_lookup(con->root_table, &ex);
5021  if (exten) {
5022  if (priority == 0) {
5024  if (!exten2)
5025  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);
5026  if (con->pattern_tree) {
5027  struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5028 
5029  if (x->exten) { /* this test for safety purposes */
5030  x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
5031  x->exten = 0; /* get rid of what will become a bad pointer */
5032  } else {
5033  ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
5034  }
5035  }
5036  } else {
5037  ex.priority = priority;
5038  exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
5039  if (exten2) {
5040  if (exten2->label) { /* if this exten has a label, remove that, too */
5041  exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
5042  if (!exten3) {
5043  ast_log(LOG_ERROR, "Did not remove this priority label (%d/%s) "
5044  "from the peer_label_table of context %s, extension %s!\n",
5045  priority, exten2->label, con->name, exten2->name);
5046  }
5047  }
5048 
5049  exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
5050  if (!exten3) {
5051  ast_log(LOG_ERROR, "Did not remove this priority (%d) from the "
5052  "peer_table of context %s, extension %s!\n",
5053  priority, con->name, exten2->name);
5054  }
5055  if (exten2 == exten && exten2->peer) {
5058  }
5059  if (ast_hashtab_size(exten->peer_table) == 0) {
5060  /* well, if the last priority of an exten is to be removed,
5061  then, the extension is removed, too! */
5063  if (!exten3) {
5064  ast_log(LOG_ERROR, "Did not remove this exten (%s) from the "
5065  "context root_table (%s) (priority %d)\n",
5066  exten->name, con->name, priority);
5067  }
5068  if (con->pattern_tree) {
5069  struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5070  if (x->exten) { /* this test for safety purposes */
5071  x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
5072  x->exten = 0; /* get rid of what will become a bad pointer */
5073  }
5074  }
5075  }
5076  } else {
5077  ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
5078  priority, exten->name, con->name);
5079  }
5080  }
5081  } else {
5082  /* hmmm? this exten is not in this pattern tree? */
5083  ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
5084  extension, con->name);
5085  }
5086 #ifdef NEED_DEBUG
5087  if (con->pattern_tree) {
5088  ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
5089  log_match_char_tree(con->pattern_tree, " ");
5090  }
5091 #endif
5092 
5093  /* scan the extension list to find first matching extension-registrar */
5094  for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
5095  if (!strcmp(exten->exten, ex.exten) &&
5096  (!matchcallerid ||
5097  (!ast_strlen_zero(ex.cidmatch) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, ex.cidmatch)) ||
5098  (ast_strlen_zero(ex.cidmatch) && ast_strlen_zero(exten->cidmatch)))) {
5099  break;
5100  }
5101  }
5102  if (!exten) {
5103  /* we can't find right extension */
5104  if (!already_locked)
5105  ast_unlock_context(con);
5106  return -1;
5107  }
5108 
5109  /* scan the priority list to remove extension with exten->priority == priority */
5110  for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
5111  peer && !strcmp(peer->exten, ex.exten) &&
5112  (!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, ex.cidmatch))) ;
5113  peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
5114 
5115  if ((priority == 0 || peer->priority == priority) &&
5116  (!registrar || !strcmp(peer->registrar, registrar) )) {
5117  found = 1;
5118 
5119  /* we are first priority extension? */
5120  if (!previous_peer) {
5121  /*
5122  * We are first in the priority chain, so must update the extension chain.
5123  * The next node is either the next priority or the next extension
5124  */
5125  struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
5126  if (peer->peer) {
5127  /* move the peer_table and peer_label_table down to the next peer, if
5128  it is there */
5131  peer->peer_table = NULL;
5133  }
5134  if (!prev_exten) { /* change the root... */
5135  con->root = next_node;
5136  } else {
5137  prev_exten->next = next_node; /* unlink */
5138  }
5139  if (peer->peer) { /* update the new head of the pri list */
5140  peer->peer->next = peer->next;
5141  }
5142  } else { /* easy, we are not first priority in extension */
5143  previous_peer->peer = peer->peer;
5144  }
5145 
5146 
5147  /* now, free whole priority extension */
5149  } else {
5150  previous_peer = peer;
5151  }
5152  }
5153  if (!already_locked)
5154  ast_unlock_context(con);
5155  return found ? 0 : -1;
5156 }
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
#define ast_hashtab_insert_immediate(tab, obj)
Insert without checking.
Definition: hashtab.h:290
int ast_hashtab_size(struct ast_hashtab *tab)
Returns the number of elements stored in the hashtab.
Definition: hashtab.c:577
static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff)
static struct match_char * add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
Definition: pbx.c:1656
static void destroy_exten(struct ast_exten *e)
Definition: pbx.c:4681
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
int ast_unlock_context(struct ast_context *con)
struct ast_exten * root
Definition: pbx.c:286
char name[0]
Definition: pbx.c:297
struct ast_hashtab * root_table
Definition: pbx.c:287
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition: pbx.c:237
struct ast_hashtab * peer_label_table
Definition: pbx.c:252
struct ast_hashtab * peer_table
Definition: pbx.c:251
const char * registrar
Definition: pbx.c:253
struct ast_exten * peer
Definition: pbx.c:250
struct ast_exten * next
Definition: pbx.c:256
int priority
Definition: pbx.c:243
const char * label
Definition: pbx.c:244

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, destroy_exten(), ext_strncpy(), exten, ast_exten::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, priority, ast_exten::priority, ast_exten::registrar, registrar, ast_context::root, ast_context::root_table, and match_char::x.

Referenced by ast_context_remove_extension2(), and ast_context_remove_extension_callerid().

◆ ast_context_remove_include()

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

Remove included contexts. This function locks contexts list by &conlist, search for the right context structure, leave context list locked and call ast_context_remove_include2 which removes include, unlock contexts list and return ...

Remove a context include.

Definition at line 4843 of file pbx.c.

4844 {
4845  int ret = -1;
4846  struct ast_context *c;
4847 
4849  if (c) {
4850  /* found, remove include from this context ... */
4851  ret = ast_context_remove_include2(c, include, registrar);
4853  }
4854  return ret;
4855 }
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,...
Definition: pbx.c:4866

References ast_context_remove_include2(), ast_unlock_contexts(), c, context, find_context_locked(), and registrar.

Referenced by handle_cli_dialplan_remove_include().

◆ ast_context_remove_include2()

int ast_context_remove_include2 ( struct ast_context con,
const char *  include,
const char *  registrar 
)

Locks context, remove included contexts, unlocks context. When we call this function, &conlock lock must be locked, because when we giving *con argument, some process can remove/change this context and after that there can be segfault.

Removes an include by an ast_context structure.

Return values
0on success.
-1on failure.

Definition at line 4866 of file pbx.c.

4867 {
4868  int ret = -1;
4869  int idx;
4870 
4871  ast_wrlock_context(con);
4872 
4873  /* find our include */
4874  for (idx = 0; idx < ast_context_includes_count(con); idx++) {
4875  struct ast_include *i = AST_VECTOR_GET(&con->includes, idx);
4876 
4877  if (!strcmp(ast_get_include_name(i), include) &&
4878  (!registrar || !strcmp(ast_get_include_registrar(i), registrar))) {
4879 
4880  /* remove from list */
4881  ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
4882  AST_VECTOR_REMOVE_ORDERED(&con->includes, idx);
4883 
4884  /* free include and return */
4885  include_free(i);
4886  ret = 0;
4887  break;
4888  }
4889  }
4890 
4891  ast_unlock_context(con);
4892 
4893  return ret;
4894 }
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
const char * ast_get_include_registrar(const struct ast_include *i)
Definition: pbx_include.c:60
int ast_context_includes_count(const struct ast_context *con)
void include_free(struct ast_include *inc)
Definition: pbx_include.c:106
struct ast_includes includes
Definition: pbx.c:290
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
#define AST_VECTOR_REMOVE_ORDERED(vec, idx)
Remove an element from a vector by index while maintaining order.
Definition: vector.h:448
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References ast_context_includes_count(), ast_get_context_name(), ast_get_include_name(), ast_get_include_registrar(), ast_unlock_context(), AST_VECTOR_GET, AST_VECTOR_REMOVE_ORDERED, ast_verb, ast_wrlock_context(), include_free(), ast_context::includes, and registrar.

Referenced by ast_context_remove_include().

◆ ast_context_remove_switch()

int ast_context_remove_switch ( const char *  context,
const char *  sw,
const char *  data,
const char *  registrar 
)

Remove a switch.

Note
This function locks contexts list by &conlist, search for the right context structure, leave context list locked and call ast_context_remove_switch2 which removes switch, unlock contexts list and return ...

Definition at line 4901 of file pbx.c.

4902 {
4903  int ret = -1; /* default error return */
4904  struct ast_context *c;
4905 
4907  if (c) {
4908  /* remove switch from this context ... */
4909  ret = ast_context_remove_switch2(c, sw, data, registrar);
4911  }
4912  return ret;
4913 }
int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
This function locks given context, removes switch, unlock context and return.
Definition: pbx.c:4923

References ast_context_remove_switch2(), ast_unlock_contexts(), c, context, find_context_locked(), and registrar.

◆ ast_context_remove_switch2()

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.

Note
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.

Definition at line 4923 of file pbx.c.

4924 {
4925  int idx;
4926  int ret = -1;
4927 
4928  ast_wrlock_context(con);
4929 
4930  /* walk switches */
4931  for (idx = 0; idx < ast_context_switches_count(con); idx++) {
4932  struct ast_sw *i = AST_VECTOR_GET(&con->alts, idx);
4933 
4934  if (!strcmp(ast_get_switch_name(i), sw) &&
4935  !strcmp(ast_get_switch_data(i), data) &&
4936  (!registrar || !strcmp(ast_get_switch_registrar(i), registrar))) {
4937 
4938  /* found, remove from list */
4939  ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
4940  AST_VECTOR_REMOVE_ORDERED(&con->alts, idx);
4941 
4942  /* free switch and return */
4943  sw_free(i);
4944  ret = 0;
4945  break;
4946  }
4947  }
4948 
4949  ast_unlock_context(con);
4950 
4951  return ret;
4952 }
const char * ast_get_switch_registrar(const struct ast_sw *sw)
Definition: pbx_sw.c:63
const char * ast_get_switch_name(const struct ast_sw *sw)
Definition: pbx_sw.c:48
const char * ast_get_switch_data(const struct ast_sw *sw)
Definition: pbx_sw.c:53
int ast_context_switches_count(const struct ast_context *con)
void sw_free(struct ast_sw *sw)
Definition: pbx_sw.c:101
struct ast_sws alts
Definition: pbx.c:292
ast_sw: Switch statement in extensions.conf
Definition: pbx_sw.c:37
const char * data
Definition: pbx_sw.c:42

References ast_context::alts, ast_context_switches_count(), ast_get_context_name(), ast_get_switch_data(), ast_get_switch_name(), ast_get_switch_registrar(), ast_unlock_context(), AST_VECTOR_GET, AST_VECTOR_REMOVE_ORDERED, ast_verb, ast_wrlock_context(), ast_sw::data, registrar, and sw_free().

Referenced by ast_context_remove_switch().

◆ ast_context_unlockmacro()

int ast_context_unlockmacro ( const char *  macrocontext)

Unlocks the macrolock in the given context.

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

Definition at line 5185 of file pbx.c.

5186 {
5187  struct ast_context *c;
5188  int ret = -1;
5189 
5190  c = find_context_locked(macrocontext);
5191  if (c) {
5193 
5194  /* if we found context, unlock macrolock */
5195  ret = ast_mutex_unlock(&c->macrolock);
5196  }
5197 
5198  return ret;
5199 }

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

Referenced by _macro_exec().

◆ ast_devstate_to_extenstate()

enum ast_extension_states ast_devstate_to_extenstate ( enum ast_device_state  devstate)

Map devstate to an extension state.

Parameters
[in]devstatedevice state
Returns
the extension state mapping.

Definition at line 3004 of file pbx.c.

3014 {
3015  switch (devstate) {
3016  case AST_DEVICE_ONHOLD:
3017  return AST_EXTENSION_ONHOLD;
3018  case AST_DEVICE_BUSY:
3019  return AST_EXTENSION_BUSY;
3020  case AST_DEVICE_UNKNOWN:
3021  return AST_EXTENSION_NOT_INUSE;
3023  case AST_DEVICE_INVALID:
3025  case AST_DEVICE_RINGINUSE:
3027  case AST_DEVICE_RINGING:
3028  return AST_EXTENSION_RINGING;
3029  case AST_DEVICE_INUSE:
3030  return AST_EXTENSION_INUSE;
3031  case AST_DEVICE_NOT_INUSE:
3032  return AST_EXTENSION_NOT_INUSE;
3033  case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
3034  break;
3035  }
3036 
3037  return AST_EXTENSION_NOT_INUSE;
3038 }
@ AST_DEVICE_RINGINUSE
Definition: devicestate.h:60
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_UNKNOWN
Definition: devicestate.h:53
@ AST_DEVICE_ONHOLD
Definition: devicestate.h:61
@ AST_DEVICE_RINGING
Definition: devicestate.h:59
@ AST_DEVICE_BUSY
Definition: devicestate.h:56
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
@ AST_DEVICE_TOTAL
Definition: devicestate.h:62
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
@ AST_EXTENSION_RINGING
Definition: pbx.h:68
@ AST_EXTENSION_NOT_INUSE
Definition: pbx.h:64
@ AST_EXTENSION_INUSE
Definition: pbx.h:65
@ AST_EXTENSION_UNAVAILABLE
Definition: pbx.h:67
@ AST_EXTENSION_ONHOLD
Definition: pbx.h:69
@ AST_EXTENSION_BUSY
Definition: pbx.h:66

References ast_hint_extension_nolock(), ast_rdlock_contexts(), ast_unlock_contexts(), c, context, and exten.

Referenced by ast_extension_state3(), and AST_TEST_DEFINE().

◆ ast_exists_extension()

int ast_exists_extension ( struct ast_channel c,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid 
)

Determine whether an extension exists.

Parameters
cthis is not important
contextwhich context to look in
extenwhich extension to search for
prioritypriority of the action within the extension
calleridcallerid to search 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 an extension within the given context(or callerid) with the given priority is found a non zero value will be returned. Otherwise, 0 is returned.

Definition at line 4182 of file pbx.c.

4183 {
4184  return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
4185 }

References c, context, E_MATCH, exten, NULL, pbx_extension_helper(), and priority.

Referenced by __analog_ss_thread(), _macro_exec(), action_originate(), add_to_regcontext(), analog_ss_thread(), ast_app_dtget(), ast_bridge_setup_after_goto(), ast_sip_persistent_endpoint_update_state(), chan_pjsip_cng_tone_detected(), cli_console_dial(), comeback_goto(), conf_run(), console_dial(), dahdi_handle_dtmf(), dial_exec_full(), dialplan_has_destination_cb(), disa_exec(), dp_lookup(), dundi_lookup_local(), fax_detect_framehook(), findmeexec(), get_also_info(), get_refer_info(), gosub_exec(), isexten_function_read(), jingle_new(), join_conference_bridge(), key_dial_page(), leave_voicemail(), local_call(), local_devicestate(), loopback_exists(), mgcp_ss(), minivm_greet_exec(), my_handle_dtmf(), new_subscribe(), onModeChanged(), ooh323_rtp_read(), options_on_rx_request(), pbx_builtin_waitexten(), privacy_exec(), process_sdp(), readexten_exec(), refer_incoming_attended_request(), refer_incoming_blind_request(), register_peer_exten(), setsubstate(), show_debug_helper(), sip_new(), sip_read(), skinny_dialer(), socket_process_helper(), try_calling(), vm_authenticate(), and waitstream_core().

◆ ast_extension_close()

int ast_extension_close ( const char *  pattern,
const char *  data,
int  needmore 
)

Definition at line 2425 of file pbx.c.

2426 {
2427  if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
2428  ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
2429  return extension_match_core(pattern, data, needmore);
2430 }
static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
Definition: pbx.c:2407

References ast_log, ast_exten::data, E_CANMATCH, E_MATCHMORE, extension_match_core(), and LOG_WARNING.

Referenced by lua_find_extension(), and realtime_switch_common().

◆ ast_extension_cmp()

int ast_extension_cmp ( const char *  a,
const char *  b 
)

Determine if one extension should match before another.

Parameters
aextension to compare with b
bextension to compare with a

Checks whether or extension a should match before extension b

Return values
0if the two extensions have equal matching priority
1on a > b
-1on a < b

Definition at line 2190 of file pbx.c.

2191 {
2192  int cmp;
2193 
2194  cmp = ext_cmp(a, b);
2195  if (cmp < 0) {
2196  return -1;
2197  }
2198  if (cmp > 0) {
2199  return 1;
2200  }
2201  return 0;
2202 }
static int ext_cmp(const char *left, const char *right)
Definition: pbx.c:2133
static struct test_val b
static struct test_val a

References a, b, and ext_cmp().

Referenced by lua_extension_cmp().

◆ ast_extension_match()

int ast_extension_match ( const char *  pattern,
const char *  extension 
)

Determine if a given extension matches a given pattern (in NXX format)

Parameters
patternpattern to match
extensionextension to check against the pattern.

Checks whether or not the given extension matches the given pattern.

Return values
1on match
0on failure

Definition at line 2420 of file pbx.c.

2421 {
2422  return extension_match_core(pattern, extension, E_MATCH);
2423 }

References E_MATCH, and extension_match_core().

Referenced by do_say(), find_matching_priority(), loopback_canmatch(), loopback_exists(), loopback_matchmore(), lua_find_extension(), matchcid(), realtime_switch_common(), reload(), and show_dialplan_helper().

◆ ast_extension_state()

int ast_extension_state ( struct ast_channel c,
const char *  context,
const char *  exten 
)

Check extension state for an extension by using hint.

Uses hint and devicestate callback to get the state of an extension.

Definition at line 3177 of file pbx.c.

3178 {
3180 }
static int internal_extension_state_extended(struct ast_channel *c, const char *context, const char *exten, struct ao2_container *device_state_info)
Definition: pbx.c:3148

References c, context, exten, internal_extension_state_extended(), and NULL.

Referenced by action_extensionstate(), and get_queue_member_status().

◆ ast_extension_state2()

static int ast_extension_state2 ( struct ast_exten e,
struct ao2_container device_state_info 
)
static

Check state of extension by using hints.

Definition at line 3120 of file pbx.c.

3121 {
3122  struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
3123 
3124  if (!e || !hint_app) {
3125  return -1;
3126  }
3127 
3128  ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(e));
3129  return ast_extension_state3(hint_app, device_state_info);
3130 }
static int ast_extension_state3(struct ast_str *hint_app, struct ao2_container *device_state_info)
Definition: pbx.c:3088
static struct ast_threadstorage extensionstate_buf
Definition: pbx.c:229

References ast_extension_state3(), ast_get_extension_app(), ast_str_set(), ast_str_thread_get(), and extensionstate_buf.

Referenced by ast_add_hint(), and internal_extension_state_extended().

◆ ast_extension_state2str()

const char* ast_extension_state2str ( int  extension_state)

Return extension_state as string.

Return string representation of the state of an extension.

Definition at line 3133 of file pbx.c.

3134 {
3135  int i;
3136 
3137  for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
3138  if (extension_states[i].extension_state == extension_state)
3139  return extension_states[i].text;
3140  }
3141  return "Unknown";
3142 }
static const struct cfextension_states extension_states[]
const char *const text
Definition: pbx.c:606

References ARRAY_LEN, extension_states, and cfextension_states::text.

Referenced by action_extensionstate(), AST_TEST_DEFINE(), exten_state_publisher_state_cb(), extensionstate_update(), handle_request_subscribe(), handle_show_hint(), handle_show_hints(), manager_state_cb(), show_channels_cb(), skinny_extensionstate_cb(), and to_ami().

◆ ast_extension_state3()

static int ast_extension_state3 ( struct ast_str hint_app,
struct ao2_container device_state_info 
)
static

Definition at line 3088 of file pbx.c.

3089 {
3090  char *cur;
3091  char *rest;
3092  struct ast_devstate_aggregate agg;
3093 
3094  /* One or more devices separated with a & character */
3095  rest = parse_hint_device(hint_app);
3096 
3098  while ((cur = strsep(&rest, "&"))) {
3100 
3102  if (device_state_info) {
3103  struct ast_device_state_info *obj;
3104 
3105  obj = ao2_alloc_options(sizeof(*obj) + strlen(cur), device_state_info_dt, AO2_ALLOC_OPT_LOCK_NOLOCK);
3106  /* if failed we cannot add this device */
3107  if (obj) {
3108  obj->device_state = state;
3109  strcpy(obj->device_name, cur);
3110  ao2_link(device_state_info, obj);
3111  ao2_ref(obj, -1);
3112  }
3113  }
3114  }
3115 
3117 }
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
enum sip_cc_notify_state state
Definition: chan_sip.c:966
void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
Add a device state to the aggregate device state.
Definition: devicestate.c:636
void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
Initialize aggregate device state.
Definition: devicestate.c:630
enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
Get the aggregate device state result.
Definition: devicestate.c:663
ast_device_state
Device States.
Definition: devicestate.h:52
enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
Map devstate to an extension state.
Definition: pbx.c:3013
static char * parse_hint_device(struct ast_str *hint_args)
Definition: pbx.c:3063
static void device_state_info_dt(void *obj)
Definition: pbx.c:3076
char device_name[1]
Definition: pbx.h:99
enum ast_device_state device_state
Definition: pbx.h:97
You shouldn't care about the contents of this struct.
Definition: devicestate.h:228

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_link, ao2_ref, ast_devstate_aggregate_add(), ast_devstate_aggregate_init(), ast_devstate_aggregate_result(), ast_devstate_to_extenstate(), ast_device_state_info::device_name, ast_device_state_info::device_state, device_state_info_dt(), parse_hint_device(), state, and strsep().

Referenced by ast_extension_state2(), and device_state_notify_callbacks().

◆ ast_extension_state_add()

int ast_extension_state_add ( const char *  context,
const char *  exten,
ast_state_cb_type  change_cb,
void *  data 
)

Add watcher for extension states.

Parameters
contextwhich context to look in
extenwhich extension to get state
change_cbcallback to call if state changed
datato pass to callback
Note
If context and exten are NULL then the added watcher is global. The change_cb is called for every extension's state change.
The change_cb is called if the state of an extension is changed.
Return values
-1on failure
0Global watcher added successfully
IDon success

Definition at line 3830 of file pbx.c.

3832 {
3833  return extension_state_add_destroy(context, exten, change_cb, NULL, data, 0);
3834 }
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)
Definition: pbx.c:3734

References context, ast_exten::data, exten, extension_state_add_destroy(), and NULL.

Referenced by __init_manager(), create_queue_member(), publisher_start(), and skinny_register().

◆ ast_extension_state_add_destroy()

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.

Since
1.8.9
10.1.0
Parameters
contextwhich context to look in
extenwhich extension to get state
change_cbcallback to call if state changed
destroy_cbcallback to call when the watcher is destroyed.
datato pass to callbacks
Note
If context and exten are NULL then the added watcher is global. The change_cb is called for every extension's state change.
The change_cb is called if the state of an extension is changed.
The destroy_cb is called when the watcher is deleted so the watcher can release any associated resources.
Return values
-1on failure
0Global watcher added successfully
IDon success

Definition at line 3824 of file pbx.c.

3826 {
3827  return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 0);
3828 }

References context, ast_exten::data, exten, and extension_state_add_destroy().

◆ ast_extension_state_add_destroy_extended()

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.

Since
11
Parameters
contextwhich context to look in
extenwhich extension to get state
change_cbcallback to call if state changed
destroy_cbcallback to call when the watcher is destroyed.
datato pass to callbacks
Note
If context and exten are NULL then the added watcher is global. The change_cb is called for every extension's state change.
The change_cb is called if the state of an extension is changed. The extended state is passed to the callback in the device_state_info member of ast_state_cb_info.
The destroy_cb is called when the watcher is deleted so the watcher can release any associated resources.
Return values
-1on failure
0Global watcher added successfully
IDon success

Definition at line 3836 of file pbx.c.

3838 {
3839  return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 1);
3840 }

References context, ast_exten::data, exten, and extension_state_add_destroy().

Referenced by handle_request_subscribe(), and subscription_established().

◆ ast_extension_state_add_extended()

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.

Since
11
Parameters
contextwhich context to look in
extenwhich extension to get state
change_cbcallback to call if state changed
datato pass to callback
Note
If context and exten are NULL then the added watcher is global. The change_cb is called for every extension's state change.
The change_cb is called if the state of an extension is changed. The extended state is passed to the callback in the device_state_info member of ast_state_cb_info.
Return values
-1on failure
0Global watcher added successfully
IDon success

Definition at line 3842 of file pbx.c.

3844 {
3845  return extension_state_add_destroy(context, exten, change_cb, NULL, data, 1);
3846 }

References context, ast_exten::data, exten, extension_state_add_destroy(), and NULL.

◆ ast_extension_state_del()

int ast_extension_state_del ( int  id,
ast_state_cb_type  change_cb 
)

Deletes a state change watcher by ID.

Parameters
idof the state watcher to delete (0 for global watcher)
change_cbcallback to call if state changed (Used if id == 0 (global))
Return values
0success
-1failure

Definition at line 3863 of file pbx.c.

3864 {
3865  struct ast_state_cb *p_cur;
3866  int ret = -1;
3867 
3868  if (!id) { /* id == 0 is a callback without extension */
3869  if (!change_cb) {
3870  return ret;
3871  }
3873  if (p_cur) {
3874  ret = 0;
3875  ao2_ref(p_cur, -1);
3876  }
3877  } else { /* callback with extension, find the callback based on ID */
3878  struct ast_hint *hint;
3879 
3880  ao2_lock(hints);/* Locked to hold off ast_merge_contexts_and_delete */
3881  hint = ao2_callback(hints, 0, find_hint_by_cb_id, &id);
3882  if (hint) {
3883  p_cur = ao2_find(hint->callbacks, &id, OBJ_UNLINK);
3884  if (p_cur) {
3885  ret = 0;
3886  ao2_ref(p_cur, -1);
3887  }
3888  ao2_ref(hint, -1);
3889  }
3890  ao2_unlock(hints);
3891  }
3892 
3893  return ret;
3894 }
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
static int find_hint_by_cb_id(void *obj, void *arg, int flags)
Find Hint by callback id.
Definition: pbx.c:3849

References ao2_callback, ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_hint::callbacks, ast_state_cb::change_cb, find_hint_by_cb_id(), OBJ_UNLINK, and statecbs.

Referenced by destroy_queue_member_cb(), dialog_unlink_all(), handle_request_subscribe(), skinny_session_cleanup(), subscription_shutdown(), and unload_module().

◆ ast_extension_state_extended()

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.

Uses hint and devicestate callback to get the extended state of an extension.

Definition at line 3183 of file pbx.c.

3185 {
3186  struct ao2_container *container = NULL;
3187  int ret;
3188 
3189  if (device_state_info) {
3191  }
3192 
3194  if (ret < 0 && container) {
3195  ao2_ref(container, -1);
3196  container = NULL;
3197  }
3198 
3199  if (device_state_info) {
3201  *device_state_info = container;
3202  }
3203 
3204  return ret;
3205 }
static void get_device_state_causing_channels(struct ao2_container *c)
Definition: pbx.c:3303
static struct ao2_container * alloc_device_state_info(void)
Definition: pbx.c:3083
struct ao2_container * container
Definition: res_fax.c:501
Generic container type.

References alloc_device_state_info(), ao2_ref, c, container, context, exten, get_device_state_causing_channels(), internal_extension_state_extended(), and NULL.

Referenced by exten_state_data_alloc(), and handle_request_subscribe().

◆ ast_findlabel_extension()

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.

Parameters
cthis is not important
contextwhich context to look in
extenwhich extension to search for
labellabel of the action within the extension to match to priority
calleridcallerid to search 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
Return values
thepriority which matches the given label in the extension
-1if not found.

Definition at line 4187 of file pbx.c.

4188 {
4189  return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
4190 }
@ E_FINDLABEL
Definition: extconf.h:221

References c, context, E_FINDLABEL, exten, ast_exten::label, NULL, and pbx_extension_helper().

Referenced by action_originate(), action_redirect(), ari_channels_handle_originate_with_id(), ast_ari_channels_continue_in_dialplan(), handle_setpriority(), and isexten_function_read().

◆ ast_findlabel_extension2()

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.

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
This function is the same as ast_findlabel_extension, except that it accepts a pointer to an ast_context structure to specify the context instead of the name of the context. Otherwise, the functions behave the same.

Definition at line 4192 of file pbx.c.

4193 {
4194  return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
4195 }

References c, E_FINDLABEL, exten, ast_exten::label, NULL, and pbx_extension_helper().

Referenced by pbx_load_config().

◆ ast_get_hint()

int ast_get_hint ( char *  hint,
int  hintsize,
char *  name,
int  namesize,
struct ast_channel c,
const char *  context,
const char *  exten 
)

Get hint for channel.

If an extension hint exists, return non-zero.

Definition at line 4144 of file pbx.c.

4145 {
4146  struct ast_exten *e = ast_hint_extension(c, context, exten);
4147 
4148  if (e) {
4149  if (hint)
4150  ast_copy_string(hint, ast_get_extension_app(e), hintsize);
4151  if (name) {
4152  const char *tmp = ast_get_extension_app_data(e);
4153  if (tmp)
4154  ast_copy_string(name, tmp, namesize);
4155  }
4156  return -1;
4157  }
4158  return 0;
4159 }
static struct ast_exten * ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
Definition: pbx.c:3004
void * ast_get_extension_app_data(struct ast_exten *e)

References ast_copy_string(), ast_get_extension_app(), ast_get_extension_app_data(), ast_hint_extension(), c, context, exten, name, and tmp().

Referenced by action_extensionstate(), custom_devstate_callback(), device_state_cb(), get_cid_name(), get_resource_display_name(), manager_state_cb(), skinny_extensionstate_cb(), and state_notify_build_xml().

◆ ast_hashtab_compare_contexts()

int ast_hashtab_compare_contexts ( const void *  ah_a,
const void *  ah_b 
)

hashtable functions for contexts

Definition at line 681 of file pbx.c.

682 {
683  const struct ast_context *ac = ah_a;
684  const struct ast_context *bc = ah_b;
685  if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
686  return 1;
687  /* assume context names are registered in a string table! */
688  return strcmp(ac->name, bc->name);
689 }
#define bc

References bc, and ast_context::name.

◆ ast_hashtab_hash_contexts()

unsigned int ast_hashtab_hash_contexts ( const void *  obj)

Definition at line 733 of file pbx.c.

734 {
735  const struct ast_context *ac = obj;
736  return ast_hashtab_hash_string(ac->name);
737 }
unsigned int ast_hashtab_hash_string(const void *obj)
Hashes a string to a number.
Definition: hashtab.c:153

References ast_hashtab_hash_string(), and ast_context::name.

◆ ast_hint_extension()

static struct ast_exten* ast_hint_extension ( struct ast_channel c,
const char *  context,
const char *  exten 
)
static

Definition at line 3004 of file pbx.c.

3005 {
3006  struct ast_exten *e;
3010  return e;
3011 }
static struct ast_exten * ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
Find hint for given extension in context.
Definition: pbx.c:2998

Referenced by ast_get_hint(), ast_hint_presence_state(), ast_str_get_hint(), extension_state_add_destroy(), and internal_extension_state_extended().

◆ ast_hint_extension_nolock()

static struct ast_exten* ast_hint_extension_nolock ( struct ast_channel c,
const char *  context,
const char *  exten 
)
static

Find hint for given extension in context.

Definition at line 2998 of file pbx.c.

2999 {
3000  struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
3002 }
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition: pbx.c:2492
#define PRIORITY_HINT
Definition: pbx.h:54
int stacklen
Definition: extconf.h:238

References c, context, E_MATCH, exten, NULL, pbx_find_extension(), PRIORITY_HINT, and pbx_find_info::stacklen.

Referenced by ast_devstate_to_extenstate().

◆ ast_hint_presence_state()

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.

Parameters
cthis is not important
contextwhich context to look in
extenwhich extension to get state
[out]subtypeFurther information regarding the presence returned
[out]messageCustom message further describing current presence
Note
The subtype and message are dynamically allocated and must be freed by the caller of this function.
Returns
returns the presence state value.

Definition at line 3233 of file pbx.c.

3234 {
3235  struct ast_exten *e;
3236 
3237  if (!(e = ast_hint_extension(c, context, exten))) { /* Do we have a hint for this extension ? */
3238  return -1; /* No hint, return -1 */
3239  }
3240 
3241  if (e->exten[0] == '_') {
3242  /* Create this hint on-the-fly */
3243  ao2_lock(hints);
3244  ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
3245  e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
3246  e->registrar);
3247  ao2_unlock(hints);
3248  if (!(e = ast_hint_extension(c, context, exten))) {
3249  /* Improbable, but not impossible */
3250  return -1;
3251  }
3252  }
3253 
3254  return extension_presence_state_helper(e, subtype, message);
3255 }
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
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.
struct ast_context * parent
Definition: pbx.c:245
void * data
Definition: pbx.c:248

References ao2_lock, ao2_unlock, ast_exten::app, ast_add_extension(), ast_free_ptr(), ast_hint_extension(), ast_strdup, c, ast_exten::cidmatch, context, ast_exten::data, exten, ast_exten::exten, extension_presence_state_helper(), ast_exten::label, ast_exten::matchcid, ast_context::name, NULL, ast_exten::parent, ast_exten::priority, and ast_exten::registrar.

Referenced by exten_state_data_alloc(), and handle_request_subscribe().

◆ ast_matchmore_extension()

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)

Parameters
cnot really important XXX
contextcontext to search 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 match a valid extension in this context with some more digits, return non-zero. Does NOT return non-zero if this is an exact-match only. 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 4202 of file pbx.c.

4203 {
4204  return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
4205 }

References c, context, E_MATCHMORE, exten, NULL, pbx_extension_helper(), and priority.

Referenced by __analog_ss_thread(), __ast_pbx_run(), analog_ss_thread(), ast_app_dtget(), disa_exec(), dp_lookup(), dundi_lookup_local(), key_dial_page(), loopback_matchmore(), mgcp_ss(), pbx_builtin_background(), readexten_exec(), and skinny_dialer().

◆ ast_pbx_h_exten_run()

void ast_pbx_h_exten_run ( struct ast_channel chan,
const char *  context 
)

Run the h exten from the given context.

Since
11.0
Parameters
chanChannel to run the h exten on.
contextContext the h exten is in.

Definition at line 4212 of file pbx.c.

4213 {
4214  int autoloopflag;
4215  int found;
4216  int spawn_error;
4217 
4218  ast_channel_lock(chan);
4219 
4220  /*
4221  * Make sure that the channel is marked as hungup since we are
4222  * going to run the h exten on it.
4223  */
4225 
4226  /* Set h exten location */
4227  if (context != ast_channel_context(chan)) {
4229  }
4230  ast_channel_exten_set(chan, "h");
4231  ast_channel_priority_set(chan, 1);
4232 
4233  /* Save autoloop flag */
4234  autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
4236  ast_channel_unlock(chan);
4237 
4238  for (;;) {
4239  spawn_error = ast_spawn_extension(chan, ast_channel_context(chan),
4241  S_COR(ast_channel_caller(chan)->id.number.valid,
4242  ast_channel_caller(chan)->id.number.str, NULL), &found, 1);
4243 
4244  ast_channel_lock(chan);
4245  if (spawn_error) {
4246  /* The code after the loop needs the channel locked. */
4247  break;
4248  }
4250  ast_channel_unlock(chan);
4251  }
4252  if (found && spawn_error) {
4253  /* Something bad happened, or a hangup has been requested. */
4254  ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n",
4256  ast_channel_priority(chan), ast_channel_name(chan));
4257  ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
4259  ast_channel_priority(chan), ast_channel_name(chan));
4260  }
4261 
4262  /* An "h" exten has been run, so indicate that one has been run. */
4264 
4265  /* Restore autoloop flag */
4267  ast_channel_unlock(chan);
4268 }
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
@ AST_SOFTHANGUP_HANGUP_EXEC
Definition: channel.h:1154
void ast_channel_context_set(struct ast_channel *chan, const char *value)
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2457

References ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_unlock, ast_debug, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, ast_set2_flag, ast_set_flag, AST_SOFTHANGUP_HANGUP_EXEC, ast_softhangup_nolock(), ast_spawn_extension(), ast_test_flag, ast_verb, context, NULL, and S_COR.

Referenced by ast_bridge_setup_after_goto().

◆ ast_pbx_run()

enum ast_pbx_result ast_pbx_run ( struct ast_channel c)

Execute the PBX in the current thread.

Parameters
cchannel to run the pbx on

This executes the PBX on a given channel. It allocates a new PBX structure for the channel, and provides all PBX functionality. See ast_pbx_start for an asynchronous function to run the PBX in a new thread as opposed to the current one.

Return values
Zeroon success
non-zeroon failure

Definition at line 4695 of file pbx.c.

4763 {
4764  return ast_pbx_run_args(c, NULL);
4765 }
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
Definition: pbx.c:4742

References __ast_pbx_run(), c, ast_channel::data, decrease_call_count(), and NULL.

Referenced by __analog_ss_thread(), analog_ss_thread(), ari_originate_dial(), ast_bridge_run_after_goto(), do_notify(), mgcp_ss(), skinny_newcall(), and unistim_ss().

◆ ast_pbx_run_args()

enum ast_pbx_result ast_pbx_run_args ( struct ast_channel c,
struct ast_pbx_args args 
)

Execute the PBX in the current thread.

Parameters
cchannel to run the pbx on
argsoptions for the pbx

This executes the PBX on a given channel. It allocates a new PBX structure for the channel, and provides all PBX functionality. See ast_pbx_start for an asynchronous function to run the PBX in a new thread as opposed to the current one.

Return values
Zeroon success
non-zeroon failure

Definition at line 4695 of file pbx.c.

4743 {
4744  enum ast_pbx_result res = AST_PBX_SUCCESS;
4745 
4747  ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
4748  return AST_PBX_FAILED;
4749  }
4750 
4751  if (increase_call_count(c)) {
4752  return AST_PBX_CALL_LIMIT;
4753  }
4754 
4755  res = __ast_pbx_run(c, args);
4756 
4758 
4759  return res;
4760 }
struct ast_flags ast_options
Definition: options.c:61
@ AST_OPT_FLAG_FULLY_BOOTED
Definition: options.h:58
static void decrease_call_count(void)
Definition: pbx.c:4673
static int increase_call_count(const struct ast_channel *c)
Increase call count for channel.
Definition: pbx.c:4624
static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, struct ast_pbx_args *args)
Definition: pbx.c:4313
ast_pbx_result
The result codes when starting the PBX on a channel with ast_pbx_start.
Definition: pbx.h:353
@ AST_PBX_CALL_LIMIT
Definition: pbx.h:356

Referenced by action_dialplan_exec(), msg_route(), and stasis_app_exec().

◆ ast_pbx_start()

enum ast_pbx_result ast_pbx_start ( struct ast_channel c)

Create a new thread and start the PBX.

Parameters
cchannel to start the pbx on
See also
ast_pbx_run for a synchronous function to run the PBX in the current thread, as opposed to starting a new one.
Return values
Zeroon success
non-zeroon failure

Definition at line 4695 of file pbx.c.

4716 {
4717  pthread_t t;
4718 
4719  if (!c) {
4720  ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
4721  return AST_PBX_FAILED;
4722  }
4723 
4725  ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
4726  return AST_PBX_FAILED;
4727  }
4728 
4729  if (increase_call_count(c))
4730  return AST_PBX_CALL_LIMIT;
4731 
4732  /* Start a new thread, and get something handling this channel. */
4734  ast_log(LOG_WARNING, "Failed to create new channel thread\n");
4736  return AST_PBX_FAILED;
4737  }
4738 
4739  return AST_PBX_SUCCESS;
4740 }
static void * pbx_thread(void *data)
Definition: pbx.c:4695
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:583

Referenced by alsa_new(), ast_iax2_new(), bridge_failed_peer_goto(), console_new(), dahdi_new(), dial_exec_full(), do_monitor_headset(), generic_recall(), handle_request_invite(), handle_response_clip(), handle_response_cmgr(), jingle_action_session_initiate(), local_call(), mgcp_new(), ooh323_new(), pbx_start_incoming_request(), skinny_new(), and unistim_new().

◆ ast_processed_calls()

int ast_processed_calls ( void  )

Retrieve the total number of calls processed through the PBX since last restart.

Definition at line 4772 of file pbx.c.

4773 {
4774  return totalcalls;
4775 }
static int totalcalls
Definition: pbx.c:772

References totalcalls.

Referenced by ast_var_Config(), get_total_call_count(), handle_chanlist(), and handle_showcalls().

◆ ast_remove_hint()

static int ast_remove_hint ( struct ast_exten e)
static

Remove hint from extension.

Definition at line 3948 of file pbx.c.

3949 {
3950  /* Cleanup the Notifys if hint is removed */
3951  struct ast_hint *hint;
3952 
3953  if (!e) {
3954  return -1;
3955  }
3956 
3957  hint = ao2_find(hints, e, OBJ_UNLINK);
3958  if (!hint) {
3959  return -1;
3960  }
3961 
3962  remove_hintdevice(hint);
3963 
3964  /*
3965  * The extension is being destroyed so we must save some
3966  * information to notify that the extension is deactivated.
3967  */
3968  ao2_lock(hint);
3971  sizeof(hint->context_name));
3973  sizeof(hint->exten_name));
3974  hint->exten = NULL;
3975  ao2_unlock(hint);
3976 
3977  publish_hint_remove(hint);
3978 
3979  ao2_ref(hint, -1);
3980 
3981  return 0;
3982 }
static int publish_hint_remove(struct ast_hint *hint)
Publish a hint removed event
Definition: pbx.c:3927
char exten_name[AST_MAX_EXTENSION]
Definition: pbx.c:343
char context_name[AST_MAX_CONTEXT]
Definition: pbx.c:342

References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_copy_string(), ast_get_context_name(), ast_get_extension_context(), ast_get_extension_name(), ast_hint::context_name, ast_hint::exten, ast_hint::exten_name, NULL, OBJ_UNLINK, publish_hint_remove(), and remove_hintdevice().

Referenced by destroy_exten().

◆ ast_spawn_extension()

int ast_spawn_extension ( struct ast_channel c,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid,
int *  found,
int  combined_find_spawn 
)

Launch a new extension (i.e. new stack)

Parameters
cnot important
contextwhich context to generate the extension within
extennew extension to add
prioritypriority of new extension
calleridcallerid of extension
found
combined_find_spawnThis adds a new extension to the asterisk extension list.
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
Return values
0on success
-1on failure.

Definition at line 4207 of file pbx.c.

4208 {
4209  return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
4210 }
@ E_SPAWN
Definition: extconf.h:220

References c, context, E_SPAWN, exten, NULL, pbx_extension_helper(), and priority.

Referenced by _macro_exec(), ast_pbx_h_exten_run(), and loopback_exec().

◆ ast_str_get_hint()

int ast_str_get_hint ( struct ast_str **  hint,
ssize_t  hintsize,
struct ast_str **  name,
ssize_t  namesize,
struct ast_channel c,
const char *  context,
const char *  exten 
)

Get hint for channel.

If an extension hint exists, return non-zero.

Definition at line 4162 of file pbx.c.

4163 {
4164  struct ast_exten *e = ast_hint_extension(c, context, exten);
4165 
4166  if (!e) {
4167  return 0;
4168  }
4169 
4170  if (hint) {
4171  ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
4172  }
4173  if (name) {
4174  const char *tmp = ast_get_extension_app_data(e);
4175  if (tmp) {
4176  ast_str_set(name, namesize, "%s", tmp);
4177  }
4178  }
4179  return -1;
4180 }

References ast_get_extension_app(), ast_get_extension_app_data(), ast_hint_extension(), ast_str_set(), c, context, exten, name, and tmp().

Referenced by ast_str_retrieve_variable().

◆ autohint_cmp()

static int autohint_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 474 of file pbx.c.

475 {
476  struct ast_autohint *left = obj;
477  struct ast_autohint *right = arg;
478  const char *right_key = arg;
479  int cmp;
480 
481  switch (flags & OBJ_SEARCH_MASK) {
482  case OBJ_SEARCH_OBJECT:
483  right_key = right->context;
484  /* Fall through */
485  case OBJ_SEARCH_KEY:
486  cmp = strcasecmp(left->context, right_key);
487  break;
489  /*
490  * We could also use a partial key struct containing a length
491  * so strlen() does not get called for every comparison instead.
492  */
493  cmp = strncmp(left->context, right_key, strlen(right_key));
494  break;
495  default:
496  ast_assert(0);
497  cmp = 0;
498  break;
499  }
500  return cmp ? 0 : CMP_MATCH | CMP_STOP;
501 }
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
Structure for dial plan autohints.
Definition: pbx.c:385
char context[1]
Name of the context.
Definition: pbx.c:389
#define ast_assert(a)
Definition: utils.h:734

References ast_assert, CMP_MATCH, CMP_STOP, ast_autohint::context, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and OBJ_SEARCH_PARTIAL_KEY.

◆ autohint_hash_cb()

static int autohint_hash_cb ( const void *  obj,
const int  flags 
)
static
Note
Using the context name for hash

Definition at line 453 of file pbx.c.

454 {
455  const struct ast_autohint *autohint;
456  const char *key;
457 
458  switch (flags & OBJ_SEARCH_MASK) {
459  case OBJ_SEARCH_KEY:
460  key = obj;
461  break;
462  case OBJ_SEARCH_OBJECT:
463  autohint = obj;
464  key = autohint->context;
465  break;
466  default:
467  ast_assert(0);
468  return 0;
469  }
470 
471  return ast_str_case_hash(key);
472 }
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1281

References ast_assert, ast_str_case_hash(), ast_autohint::context, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, and OBJ_SEARCH_OBJECT.

◆ candidate_exten_advance()

static const char* candidate_exten_advance ( const char *  str)
static

Definition at line 1217 of file pbx.c.

1218 {
1219  str++;
1220  while (*str == '-') {
1221  str++;
1222  }
1223  return str;
1224 }

References str.

◆ cli_match_char_tree()

static void cli_match_char_tree ( struct match_char node,
char *  prefix,
int  fd 
)
static

Definition at line 1109 of file pbx.c.

1110 {
1111  char extenstr[40];
1112  struct ast_str *my_prefix = ast_str_alloca(1024);
1113 
1114  extenstr[0] = '\0';
1115 
1116  if (node->exten) {
1117  snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
1118  }
1119 
1120  if (strlen(node->x) > 1) {
1121  ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
1122  node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
1123  node->exten ? node->exten->name : "", extenstr);
1124  } else {
1125  ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
1126  node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
1127  node->exten ? node->exten->name : "", extenstr);
1128  }
1129 
1130  ast_str_set(&my_prefix, 0, "%s+ ", prefix);
1131 
1132  if (node->next_char)
1133  cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
1134 
1135  if (node->alt_char)
1136  cli_match_char_tree(node->alt_char, prefix, fd);
1137 }
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static char prefix[MAX_PREFIX]
Definition: http.c:144
static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
Definition: pbx.c:1109
#define ast_str_alloca(init_len)
Definition: strings.h:826
Definition: test_heap.c:38

References ast_cli(), ast_str_alloca, ast_str_buffer(), ast_str_set(), and prefix.

Referenced by show_debug_helper().

◆ collect_digits()

static int collect_digits ( struct ast_channel c,
int  waittime,
char *  buf,
int  buflen,
int  pos 
)
static

collect digits from the channel into the buffer.

Parameters
c,buf,buflen,pos
waittimeis in milliseconds
Return values
0on timeout or done.
-1on error.

Definition at line 4286 of file pbx.c.

4287 {
4288  int digit;
4289 
4290  buf[pos] = '\0'; /* make sure it is properly terminated */
4292  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4293  /* As long as we're willing to wait, and as long as it's not defined,
4294  keep reading digits until we can't possibly get a right answer anymore. */
4295  digit = ast_waitfordigit(c, waittime);
4298  } else {
4299  if (!digit) /* No entry */
4300  break;
4301  if (digit < 0) /* Error, maybe a hangup */
4302  return -1;
4303  if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
4304  buf[pos++] = digit;
4305  buf[pos] = '\0';
4306  }
4307  waittime = ast_channel_pbx(c)->dtimeoutms;
4308  }
4309  }
4310  return 0;
4311 }
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3176

◆ compare_char()

static int compare_char ( const void *  a,
const void *  b 
)
static

Definition at line 672 of file pbx.c.

673 {
674  const unsigned char *ac = a;
675  const unsigned char *bc = b;
676 
677  return *ac - *bc;
678 }

References a, b, and bc.

Referenced by get_pattern_node().

◆ complete_core_show_hint()

static char* complete_core_show_hint ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

autocomplete for CLI command 'core show hint'

Definition at line 5269 of file pbx.c.

5270 {
5271  struct ast_hint *hint;
5272  char *ret = NULL;
5273  int which = 0;
5274  int wordlen;
5275  struct ao2_iterator i;
5276 
5277  if (pos != 3)
5278  return NULL;
5279 
5280  wordlen = strlen(word);
5281 
5282  /* walk through all hints */
5283  i = ao2_iterator_init(hints, 0);
5284  for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
5285  ao2_lock(hint);
5286  if (!hint->exten) {
5287  /* The extension has already been destroyed */
5288  ao2_unlock(hint);
5289  continue;
5290  }
5291  if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
5292  ret = ast_strdup(ast_get_extension_name(hint->exten));
5293  ao2_unlock(hint);
5294  ao2_ref(hint, -1);
5295  break;
5296  }
5297  ao2_unlock(hint);
5298  }
5300 
5301  return ret;
5302 }
short word

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_get_extension_name(), ast_strdup, ast_hint::exten, and NULL.

Referenced by handle_show_hint().

◆ complete_show_dialplan_context()

static char* complete_show_dialplan_context ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 5448 of file pbx.c.

5450 {
5451  struct ast_context *c = NULL;
5452  char *ret = NULL;
5453  int which = 0;
5454  int wordlen;
5455 
5456  /* we are do completion of [exten@]context on second position only */
5457  if (pos != 2)
5458  return NULL;
5459 
5461 
5462  wordlen = strlen(word);
5463 
5464  /* walk through all contexts and return the n-th match */
5465  while ( (c = ast_walk_contexts(c)) ) {
5466  if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
5468  break;
5469  }
5470  }
5471 
5473 
5474  return ret;
5475 }

References ast_get_context_name(), ast_rdlock_contexts(), ast_strdup, ast_unlock_contexts(), ast_walk_contexts(), c, and NULL.

Referenced by handle_show_dialplan().

◆ create_match_char_tree()

static void create_match_char_tree ( struct ast_context con)
static

Definition at line 1763 of file pbx.c.

1764 {
1765  struct ast_hashtab_iter *t1;
1766  struct ast_exten *e1;
1767 #ifdef NEED_DEBUG
1768  int biggest_bucket, resizes, numobjs, numbucks;
1769 
1770  ast_debug(1, "Creating Extension Trie for context %s(%p)\n", con->name, con);
1771  ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
1772  ast_debug(1, "This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
1773  numobjs, numbucks, biggest_bucket, resizes);
1774 #endif
1776  while ((e1 = ast_hashtab_next(t1))) {
1777  if (e1->exten) {
1778  add_exten_to_pattern_tree(con, e1, 0);
1779  } else {
1780  ast_log(LOG_ERROR, "Attempt to create extension with no extension name.\n");
1781  }
1782  }
1784 }
#define ast_hashtab_start_traversal(tab)
Definition: hashtab.h:356
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
void ast_hashtab_end_traversal(struct ast_hashtab_iter *it)
end the traversal, free the iterator, unlock if necc.
Definition: hashtab.c:674
void ast_hashtab_get_stats(struct ast_hashtab *tab, int *biggest_bucket_size, int *resize_count, int *num_objects, int *num_buckets)
Returns key stats for the table.
Definition: hashtab.c:563
static uint16_t t1
Definition: res_pktccops.c:159
an iterator for traversing the buckets
Definition: hashtab.h:106

References add_exten_to_pattern_tree(), ast_debug, ast_hashtab_end_traversal(), ast_hashtab_get_stats(), ast_hashtab_next(), ast_hashtab_start_traversal, ast_log, ast_exten::exten, LOG_ERROR, ast_context::name, ast_context::root_table, and t1.

Referenced by pbx_find_extension().

◆ decrease_call_count()

static void decrease_call_count ( void  )
static

Definition at line 4673 of file pbx.c.

4674 {
4676  if (countcalls > 0)
4677  countcalls--;
4679 }
static ast_mutex_t maxcalllock
Definition: pbx.c:770

References ast_mutex_lock, ast_mutex_unlock, countcalls, and maxcalllock.

Referenced by ast_pbx_run().

◆ destroy_exten()

static void destroy_exten ( struct ast_exten e)
static

Definition at line 4681 of file pbx.c.

4682 {
4683  if (e->priority == PRIORITY_HINT)
4684  ast_remove_hint(e);
4685 
4686  if (e->peer_table)
4688  if (e->peer_label_table)
4690  if (e->datad)
4691  e->datad(e->data);
4692  ast_free(e);
4693 }
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
static int ast_remove_hint(struct ast_exten *e)
Remove hint from extension.
Definition: pbx.c:3948
void(* datad)(void *)
Definition: pbx.c:249

References ast_free, ast_hashtab_destroy(), ast_remove_hint(), ast_exten::data, ast_exten::datad, ast_exten::peer_label_table, ast_exten::peer_table, ast_exten::priority, and PRIORITY_HINT.

Referenced by ast_context_remove_extension_callerid2().

◆ destroy_hint()

static void destroy_hint ( void *  obj)
static

Definition at line 3910 of file pbx.c.

3911 {
3912  struct ast_hint *hint = obj;
3913  int i;
3914 
3915  ao2_cleanup(hint->callbacks);
3916 
3917  for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
3918  char *device = AST_VECTOR_GET(&hint->devices, i);
3919  ast_free(device);
3920  }
3921  AST_VECTOR_FREE(&hint->devices);
3924 }
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174

References ao2_cleanup, ast_free, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_SIZE, ast_hint::callbacks, ast_hint::devices, ast_hint::last_presence_message, and ast_hint::last_presence_subtype.

Referenced by ast_add_hint().

◆ destroy_pattern_tree()

static void destroy_pattern_tree ( struct match_char pattern_tree)
static

Definition at line 1786 of file pbx.c.

1787 {
1788  /* destroy all the alternates */
1789  if (pattern_tree->alt_char) {
1790  destroy_pattern_tree(pattern_tree->alt_char);
1791  pattern_tree->alt_char = 0;
1792  }
1793  /* destroy all the nexts */
1794  if (pattern_tree->next_char) {
1795  destroy_pattern_tree(pattern_tree->next_char);
1796  pattern_tree->next_char = 0;
1797  }
1798  pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
1799  ast_free(pattern_tree);
1800 }
static void destroy_pattern_tree(struct match_char *pattern_tree)
Definition: pbx.c:1786

References match_char::alt_char, ast_free, match_char::exten, and match_char::next_char.

◆ destroy_state_cb()

static void destroy_state_cb ( void *  doomed)
static

Definition at line 3721 of file pbx.c.

3722 {
3723  struct ast_state_cb *state_cb = doomed;
3724 
3725  if (state_cb->destroy_cb) {
3726  state_cb->destroy_cb(state_cb->id, state_cb->data);
3727  }
3728 }
int id
Definition: pbx.c:303
ast_state_cb_destroy_type destroy_cb
Definition: pbx.c:311

References ast_state_cb::data, ast_state_cb::destroy_cb, and ast_state_cb::id.

Referenced by extension_state_add_destroy().

◆ device_state_cb()

static void device_state_cb ( void *  unused,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 3591 of file pbx.c.

3592 {
3593  struct ast_device_state_message *dev_state;
3594  struct ast_str *hint_app;
3595  struct ast_hintdevice *device;
3596  struct ast_hintdevice *cmpdevice;
3597  struct ao2_iterator *dev_iter;
3598  struct ao2_iterator auto_iter;
3599  struct ast_autohint *autohint;
3600  char *virtual_device;
3601  char *type;
3602  char *device_name;
3603 
3605  return;
3606  }
3607 
3608  if (hint_remove_message_type() == stasis_message_type(msg)) {
3609  /* The extension has already been destroyed */
3610  struct ast_state_cb *state_cb;
3611  struct ao2_iterator cb_iter;
3612  struct ast_hint *hint = stasis_message_data(msg);
3613 
3614  ao2_lock(hint);
3616  ao2_unlock(hint);
3617 
3618  cb_iter = ao2_iterator_init(hint->callbacks, 0);
3619  for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3621  hint->context_name,
3622  hint->exten_name,
3623  state_cb->data,
3625  hint,
3626  NULL);
3627  }
3628  ao2_iterator_destroy(&cb_iter);
3629  return;
3630  }
3631 
3633  return;
3634  }
3635 
3636  dev_state = stasis_message_data(msg);
3637  if (dev_state->eid) {
3638  /* ignore non-aggregate states */
3639  return;
3640  }
3641 
3643  /* There are no hints monitoring devices. */
3644  return;
3645  }
3646 
3647  hint_app = ast_str_create(1024);
3648  if (!hint_app) {
3649  return;
3650  }
3651 
3652  cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(dev_state->device));
3653  strcpy(cmpdevice->hintdevice, dev_state->device);
3654 
3655  ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
3656 
3657  /* Initially we find all hints for the device and notify them */
3658  dev_iter = ao2_t_callback(hintdevices,
3661  cmpdevice,
3662  "find devices in container");
3663  if (dev_iter) {
3664  for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
3665  if (device->hint) {
3666  device_state_notify_callbacks(device->hint, &hint_app);
3667  }
3668  }
3669  ao2_iterator_destroy(dev_iter);
3670  }
3671 
3672  /* Second stage we look for any autohint contexts and if the device is not already in the hints
3673  * we create it.
3674  */
3675  type = ast_strdupa(dev_state->device);
3676  if (ast_strlen_zero(type)) {
3677  goto end;
3678  }
3679 
3680  /* Determine if this is a virtual/custom device or a real device */
3681  virtual_device = strchr(type, ':');
3682  device_name = strchr(type, '/');
3683  if (virtual_device && (!device_name || (virtual_device < device_name))) {
3684  device_name = virtual_device;
3685  }
3686 
3687  /* Invalid device state name - not a virtual/custom device and not a real device */
3688  if (ast_strlen_zero(device_name)) {
3689  goto end;
3690  }
3691 
3692  *device_name++ = '\0';
3693 
3694  auto_iter = ao2_iterator_init(autohints, 0);
3695  for (; (autohint = ao2_iterator_next(&auto_iter)); ao2_t_ref(autohint, -1, "Next autohint")) {
3696  if (ast_get_hint(NULL, 0, NULL, 0, NULL, autohint->context, device_name)) {
3697  continue;
3698  }
3699 
3700  /* The device has no hint in the context referenced by this autohint so create one */
3701  ast_add_extension(autohint->context, 0, device_name,
3702  PRIORITY_HINT, NULL, NULL, dev_state->device,
3703  ast_strdup(dev_state->device), ast_free_ptr, autohint->registrar);
3704 
3705  /* Since this hint was just created there are no watchers, so we don't need to notify anyone */
3706  }
3707  ao2_iterator_destroy(&auto_iter);
3708 
3709 end:
3711  ast_free(hint_app);
3712  return;
3713 }
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
Definition: astobj2.h:1696
static const char type[]
Definition: chan_ooh323.c:109
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
static int handle_hint_change_message_type(struct stasis_message *msg, enum ast_state_cb_update_reason reason)
Definition: pbx.c:3544
static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str **hint_app)
Definition: pbx.c:3377
static struct ao2_container * autohints
Container for autohint contexts.
Definition: pbx.c:380
static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
Definition: pbx.c:421
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.
Definition: pbx.c:4144
@ AST_EXTENSION_DEACTIVATED
Definition: pbx.h:63
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:640
char * registrar
Name of the registrar.
Definition: pbx.c:387
The structure that contains device state.
Definition: devicestate.h:238
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:246

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_callback, ao2_t_ref, ao2_unlock, ast_add_extension(), ast_alloca, ast_device_state_message_type(), AST_EXTENSION_DEACTIVATED, ast_free, ast_free_ptr(), ast_get_hint(), AST_HINT_UPDATE_DEVICE, ast_mutex_lock, ast_mutex_unlock, ast_str_create, ast_strdup, ast_strdupa, ast_strlen_zero(), autohints, ast_hint::callbacks, ast_state_cb::change_cb, ast_autohint::context, context_merge_lock, ast_hint::context_name, ast_state_cb::data, ast_device_state_message::device, device_state_notify_callbacks(), ast_device_state_message::eid, end, execute_state_callback(), ast_hint::exten_name, handle_hint_change_message_type(), ast_hintdevice::hint, ast_hintdevice::hintdevice, hintdevice_cmp_multiple(), hintdevices, ast_hint::laststate, NULL, OBJ_MULTIPLE, OBJ_SEARCH_OBJECT, PRIORITY_HINT, ast_autohint::registrar, stasis_message_data(), stasis_message_type(), and type.

◆ device_state_info_dt()

static void device_state_info_dt ( void *  obj)
static

Definition at line 3076 of file pbx.c.

3077 {
3078  struct ast_device_state_info *info = obj;
3079 
3080  ao2_cleanup(info->causing_channel);
3081 }
def info(msg)

References ao2_cleanup, and sip_to_pjsip::info().

Referenced by ast_extension_state3().

◆ device_state_notify_callbacks()

static void device_state_notify_callbacks ( struct ast_hint hint,
struct ast_str **  hint_app 
)
static

Definition at line 3377 of file pbx.c.

3378 {
3379  struct ao2_iterator cb_iter;
3380  struct ast_state_cb *state_cb;
3381  int state;
3382  int same_state;
3383  struct ao2_container *device_state_info;
3384  int first_extended_cb_call = 1;
3387 
3388  ao2_lock(hint);
3389  if (!hint->exten) {
3390  /* The extension has already been destroyed */
3391  ao2_unlock(hint);
3392  return;
3393  }
3394 
3395  /*
3396  * Save off strings in case the hint extension gets destroyed
3397  * while we are notifying the watchers.
3398  */
3401  sizeof(context_name));
3403  sizeof(exten_name));
3404  ast_str_set(hint_app, 0, "%s", ast_get_extension_app(hint->exten));
3405  ao2_unlock(hint);
3406 
3407  /*
3408  * Get device state for this hint.
3409  *
3410  * NOTE: We cannot hold any locks while determining the hint
3411  * device state or notifying the watchers without causing a
3412  * deadlock. (conlock, hints, and hint)
3413  */
3414 
3415  /* Make a container so state3 can fill it if we wish.
3416  * If that failed we simply do not provide the extended state info.
3417  */
3418  device_state_info = alloc_device_state_info();
3419 
3420  state = ast_extension_state3(*hint_app, device_state_info);
3421  same_state = state == hint->laststate;
3422  if (same_state && (~state & AST_EXTENSION_RINGING)) {
3423  ao2_cleanup(device_state_info);
3424  return;
3425  }
3426 
3427  /* Device state changed since last check - notify the watchers. */
3428  hint->laststate = state; /* record we saw the change */
3429 
3430  /* For general callbacks */
3431  if (!same_state) {
3432  cb_iter = ao2_iterator_init(statecbs, 0);
3433  for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3435  context_name,
3436  exten_name,
3437  state_cb->data,
3439  hint,
3440  NULL);
3441  }
3442  ao2_iterator_destroy(&cb_iter);
3443  }
3444 
3445  /* For extension callbacks */
3446  /* extended callbacks are called when the state changed or when AST_STATE_RINGING is
3447  * included. Normal callbacks are only called when the state changed.
3448  */
3449  cb_iter = ao2_iterator_init(hint->callbacks, 0);
3450  for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3451  if (state_cb->extended && first_extended_cb_call) {
3452  /* Fill detailed device_state_info now that we know it is used by extd. callback */
3453  first_extended_cb_call = 0;
3454  get_device_state_causing_channels(device_state_info);
3455  }
3456  if (state_cb->extended || !same_state) {
3458  context_name,
3459  exten_name,
3460  state_cb->data,
3462  hint,
3463  state_cb->extended ? device_state_info : NULL);
3464  }
3465  }
3466  ao2_iterator_destroy(&cb_iter);
3467 
3468  ao2_cleanup(device_state_info);
3469 }
#define AST_MAX_CONTEXT
Definition: channel.h:135
#define AST_MAX_EXTENSION
Definition: channel.h:134
static const char exten_name[]
static const char context_name[]
int extended
Definition: pbx.c:307

References alloc_device_state_info(), ao2_cleanup, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_copy_string(), AST_EXTENSION_RINGING, ast_extension_state3(), ast_get_context_name(), ast_get_extension_app(), ast_get_extension_context(), ast_get_extension_name(), AST_HINT_UPDATE_DEVICE, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_str_set(), ast_hint::callbacks, ast_state_cb::change_cb, context_name, ast_state_cb::data, execute_state_callback(), ast_hint::exten, exten_name, ast_state_cb::extended, get_device_state_causing_channels(), ast_hint::laststate, NULL, state, and statecbs.

Referenced by device_state_cb(), and handle_hint_change_message_type().

◆ exception_store_free()

static void exception_store_free ( void *  data)
static

Definition at line 2790 of file pbx.c.

2791 {
2792  struct pbx_exception *exception = data;
2793  ast_string_field_free_memory(exception);
2794  ast_free(exception);
2795 }
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374

References ast_free, and ast_string_field_free_memory.

◆ execute_state_callback()

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

Definition at line 3257 of file pbx.c.

3264 {
3265  int res = 0;
3266  struct ast_state_cb_info info = { 0, };
3267 
3268  info.reason = reason;
3269 
3270  /* Copy over current hint data */
3271  if (hint) {
3272  ao2_lock(hint);
3273  info.exten_state = hint->laststate;
3274  info.device_state_info = device_state_info;
3275  info.presence_state = hint->last_presence_state;
3276  if (!(ast_strlen_zero(hint->last_presence_subtype))) {
3277  info.presence_subtype = ast_strdupa(hint->last_presence_subtype);
3278  } else {
3279  info.presence_subtype = "";
3280  }
3281  if (!(ast_strlen_zero(hint->last_presence_message))) {
3282  info.presence_message = ast_strdupa(hint->last_presence_message);
3283  } else {
3284  info.presence_message = "";
3285  }
3286  ao2_unlock(hint);
3287  } else {
3288  info.exten_state = AST_EXTENSION_REMOVED;
3289  }
3290 
3291  res = cb(context, exten, &info, data);
3292 
3293  return res;
3294 }
@ AST_EXTENSION_REMOVED
Definition: pbx.h:62
enum ast_state_cb_update_reason reason
Definition: pbx.h:103
struct ao2_container * device_state_info
Definition: pbx.h:105

References ao2_lock, ao2_unlock, AST_EXTENSION_REMOVED, ast_strdupa, ast_strlen_zero(), context, ast_state_cb_info::device_state_info, exten, sip_to_pjsip::info(), ast_hint::last_presence_message, ast_hint::last_presence_state, ast_hint::last_presence_subtype, ast_hint::laststate, and ast_state_cb_info::reason.

Referenced by ast_add_hint(), device_state_cb(), device_state_notify_callbacks(), and presence_state_notify_callbacks().

◆ ext_cmp()

static int ext_cmp ( const char *  left,
const char *  right 
)
static

Definition at line 2133 of file pbx.c.

2134 {
2135  /* Make sure non-pattern extens come first. */
2136  if (left[0] != '_') {
2137  if (right[0] == '_') {
2138  return -1;
2139  }
2140  /* Compare two non-pattern extens. */
2141  return ext_cmp_exten(left, right);
2142  }
2143  if (right[0] != '_') {
2144  return 1;
2145  }
2146 
2147  /*
2148  * OK, we need full pattern sorting routine.
2149  *
2150  * Skip past the underscores
2151  */
2152  return ext_cmp_pattern(left + 1, right + 1);
2153 }

References ext_cmp_exten(), and ext_cmp_pattern().

Referenced by ast_extension_cmp().

◆ ext_cmp_exten()

static int ext_cmp_exten ( const char *  left,
const char *  right 
)
static

Definition at line 1883 of file pbx.c.

1884 {
1885  int cmp;
1886 
1887  for (;;) {
1888  /* Ignore '-' chars as eye candy fluff. */
1889  while (*left == '-') {
1890  ++left;
1891  }
1892  while (*right == '-') {
1893  ++right;
1894  }
1895 
1896  cmp = *left - *right;
1897  if (cmp) {
1898  break;
1899  }
1900  if (!*left) {
1901  /*
1902  * Get here only if both strings ended at the same time. cmp
1903  * would be non-zero if only one string ended.
1904  */
1905  break;
1906  }
1907  ++left;
1908  ++right;
1909  }
1910  return cmp;
1911 }

Referenced by _extension_match_core(), and ext_cmp().

◆ ext_cmp_exten_partial()

static int ext_cmp_exten_partial ( const char *  left,
const char *  right 
)
static

Definition at line 1840 of file pbx.c.

1841 {
1842  int cmp;
1843 
1844  for (;;) {
1845  /* Ignore '-' chars as eye candy fluff. */
1846  while (*left == '-') {
1847  ++left;
1848  }
1849  while (*right == '-') {
1850  ++right;
1851  }
1852 
1853  if (!*right) {
1854  /*
1855  * Right ended first for partial match or both ended at the same
1856  * time for a match.
1857  */
1858  cmp = 0;
1859  break;
1860  }
1861 
1862  cmp = *left - *right;
1863  if (cmp) {
1864  break;
1865  }
1866  ++left;
1867  ++right;
1868  }
1869  return cmp;
1870 }

Referenced by _extension_match_core().

◆ ext_cmp_exten_strlen()

static int ext_cmp_exten_strlen ( const char *  str)
static

Definition at line 1810 of file pbx.c.

1811 {
1812  int len;
1813 
1814  len = 0;
1815  for (;;) {
1816  /* Ignore '-' chars as eye candy fluff. */
1817  while (*str == '-') {
1818  ++str;
1819  }
1820  if (!*str) {
1821  break;
1822  }
1823  ++str;
1824  ++len;
1825  }
1826  return len;
1827 }
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

References len(), and str.

Referenced by _extension_match_core().

◆ ext_cmp_pattern()

static int ext_cmp_pattern ( const char *  left,
const char *  right 
)
static

Definition at line 2085 of file pbx.c.

2086 {
2087  int cmp;
2088  int left_pos;
2089  int right_pos;
2090 
2091  for (;;) {
2092  unsigned char left_bitwise[32] = { 0, };
2093  unsigned char right_bitwise[32] = { 0, };
2094 
2095  left_pos = ext_cmp_pattern_pos(&left, left_bitwise);
2096  right_pos = ext_cmp_pattern_pos(&right, right_bitwise);
2097  cmp = left_pos - right_pos;
2098  if (!cmp) {
2099  /*
2100  * Are the character sets different, even though they score the same?
2101  *
2102  * Note: Must swap left and right to get the sense of the
2103  * comparison correct. Otherwise, we would need to multiply by
2104  * -1 instead.
2105  */
2106  cmp = memcmp(right_bitwise, left_bitwise, ARRAY_LEN(left_bitwise));
2107  }
2108  if (cmp) {
2109  break;
2110  }
2111  if (!left) {
2112  /*
2113  * Get here only if both patterns ended at the same time. cmp
2114  * would be non-zero if only one pattern ended.
2115  */
2116  break;
2117  }
2118  }
2119  return cmp;
2120 }
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...
Definition: pbx.c:1970

References ARRAY_LEN, and ext_cmp_pattern_pos().

Referenced by _extension_match_core(), and ext_cmp().

◆ ext_cmp_pattern_pos()

static int ext_cmp_pattern_pos ( const char **  p,
unsigned char *  bitwise 
)
static

helper functions to sort extension patterns in the desired way, so that more specific patterns appear first.

The function compares individual characters (or sets of), returning an int where bits 0-7 are the ASCII code of the first char in the set, bits 8-15 are the number of characters in the set, and bits 16-20 are for special cases. This way more specific patterns (smaller character sets) appear first. Wildcards have a special value, so that we can directly compare them to sets by subtracting the two values. In particular: 0x001xx one character, character set starting with xx 0x0yyxx yy characters, character set starting with xx 0x18000 '.' (one or more of anything) 0x28000 '!' (zero or more of anything) 0x30000 NUL (end of string) 0x40000 error in set. The pointer to the string is advanced according to needs. NOTES:

  1. the empty set is ignored.
  2. given that a full set has always 0 as the first element, we could encode the special cases as 0xffXX where XX is 1, 2, 3, 4 as used above.

Definition at line 1970 of file pbx.c.

1971 {
1972 #define BITS_PER 8 /* Number of bits per unit (byte). */
1973  unsigned char c;
1974  unsigned char cmin;
1975  int count;
1976  const char *end;
1977 
1978  do {
1979  /* Get character and advance. (Ignore '-' chars as eye candy fluff.) */
1980  do {
1981  c = *(*p)++;
1982  } while (c == '-');
1983 
1984  /* always return unless we have a set of chars */
1985  switch (c) {
1986  default:
1987  /* ordinary character */
1988  bitwise[c / BITS_PER] = 1 << ((BITS_PER - 1) - (c % BITS_PER));
1989  return 0x0100 | c;
1990 
1991  case 'n':
1992  case 'N':
1993  /* 2..9 */
1994  bitwise[6] = 0x3f;
1995  bitwise[7] = 0xc0;
1996  return 0x0800 | '2';
1997 
1998  case 'x':
1999  case 'X':
2000  /* 0..9 */
2001  bitwise[6] = 0xff;
2002  bitwise[7] = 0xc0;
2003  return 0x0A00 | '0';
2004 
2005  case 'z':
2006  case 'Z':
2007  /* 1..9 */
2008  bitwise[6] = 0x7f;
2009  bitwise[7] = 0xc0;
2010  return 0x0900 | '1';
2011 
2012  case '.':
2013  /* wildcard */
2014  return 0x18000;
2015 
2016  case '!':
2017  /* earlymatch */
2018  return 0x28000; /* less specific than '.' */
2019 
2020  case '\0':
2021  /* empty string */
2022  *p = NULL;
2023  return 0x30000;
2024 
2025  case '[':
2026  /* char set */
2027  break;
2028  }
2029  /* locate end of set */
2030  end = strchr(*p, ']');
2031 
2032  if (!end) {
2033  ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
2034  return 0x40000; /* XXX make this entry go last... */
2035  }
2036 
2037  count = 0;
2038  cmin = 0xFF;
2039  for (; *p < end; ++*p) {
2040  unsigned char c1; /* first char in range */
2041  unsigned char c2; /* last char in range */
2042 
2043  c1 = (*p)[0];
2044  if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
2045  c2 = (*p)[2];
2046  *p += 2; /* skip a total of 3 chars */
2047  } else { /* individual character */
2048  c2 = c1;
2049  }
2050  if (c1 < cmin) {
2051  cmin = c1;
2052  }
2053  for (; c1 <= c2; ++c1) {
2054  unsigned char mask = 1 << ((BITS_PER - 1) - (c1 % BITS_PER));
2055 
2056  /*
2057  * Note: If two character sets score the same, the one with the
2058  * lowest ASCII values will compare as coming first. Must fill
2059  * in most significant bits for lower ASCII values to accomplish
2060  * the desired sort order.
2061  */
2062  if (!(bitwise[c1 / BITS_PER] & mask)) {
2063  /* Add the character to the set. */
2064  bitwise[c1 / BITS_PER] |= mask;
2065  count += 0x100;
2066  }
2067  }
2068  }
2069  ++*p;
2070  } while (!count);/* While the char set was empty. */
2071  return count | cmin;
2072 }
#define BITS_PER

References ast_log, BITS_PER, c, end, LOG_WARNING, and NULL.

Referenced by ext_cmp_pattern().

◆ ext_fluff_count()

static int ext_fluff_count ( const char *  exten)
static

Definition at line 2155 of file pbx.c.

2156 {
2157  int fluff = 0;
2158 
2159  if (*exten != '_') {
2160  /* not a pattern, simple check. */
2161  while (*exten) {
2162  if (*exten == '-') {
2163  fluff++;
2164  }
2165  exten++;
2166  }
2167 
2168  return fluff;
2169  }
2170 
2171  /* do pattern check */
2172  while (*exten) {
2173  if (*exten == '-') {
2174  fluff++;
2175  } else if (*exten == '[') {
2176  /* skip set, dashes here matter. */
2177  exte