Wed Oct 28 13:33:13 2009

Asterisk developer's documentation


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 "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/callerid.h"
#include "asterisk/cdr.h"
#include "asterisk/cel.h"
#include "asterisk/config.h"
#include "asterisk/term.h"
#include "asterisk/manager.h"
#include "asterisk/ast_expr.h"
#include "asterisk/linkedlists.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/musiconhold.h"
#include "asterisk/app.h"
#include "asterisk/devicestate.h"
#include "asterisk/event.h"
#include "asterisk/hashtab.h"
#include "asterisk/module.h"
#include "asterisk/indications.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/xmldoc.h"

Include dependency graph for pbx.c:

Go to the source code of this file.

Data Structures

struct  acf_root
struct  app_tmp
struct  apps
struct  ast_app
 ast_app: A registered application More...
struct  ast_context
 ast_context: An extension context More...
struct  ast_exten
 ast_exten: An extension The dialplan is saved as a linked list with each context having it's own linked list of extensions - one item per priority. More...
struct  ast_hint
 Structure for dial plan hints. More...
struct  ast_ignorepat
 ast_ignorepat: Ignore patterns in dial plan More...
struct  ast_include
 ast_include: include= support in extensions.conf More...
struct  ast_state_cb
 ast_state_cb: An extension state notify register item More...
struct  ast_sw
 ast_sw: Switch statement in extensions.conf More...
struct  async_stat
struct  cfextension_states
struct  dialplan_counters
 Counters for the show dialplan manager command. More...
struct  fake_context
struct  hints
struct  match_char
 match_char: forms a syntax tree for quick matching of extension patterns More...
struct  pbx_builtin
 Declaration of builtin applications. More...
struct  pbx_exception
struct  scoreboard
struct  statecbs
struct  statechange
struct  store_hint
struct  store_hints
struct  switches

Defines

#define AST_PBX_MAX_STACK   128
#define BACKGROUND_MATCHEXTEN   (1 << 2)
#define BACKGROUND_NOANSWER   (1 << 1)
#define BACKGROUND_PLAYBACK   (1 << 3)
#define BACKGROUND_SKIP   (1 << 0)
#define EXT_DATA_SIZE   8192
#define NEW_MATCHER_CHK_MATCH
#define NEW_MATCHER_RECURSE
#define SAY_STUBS
#define STATUS_NO_CONTEXT   1
#define STATUS_NO_EXTENSION   2
#define STATUS_NO_LABEL   4
#define STATUS_NO_PRIORITY   3
#define STATUS_SUCCESS   5
#define SWITCH_DATA_LENGTH   256
#define VAR_BUF_SIZE   4096
#define VAR_HARDTRAN   3
#define VAR_NORMAL   1
#define VAR_SOFTTRAN   2
#define WAITEXTEN_DIALTONE   (1 << 1)
#define WAITEXTEN_MOH   (1 << 0)

Functions

void __ast_context_destroy (struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
int __ast_custom_function_register (struct ast_custom_function *acf, struct ast_module *mod)
 Register a custom function.
static int __ast_goto_if_exists (struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
static void __ast_internal_context_destroy (struct ast_context *con)
static enum ast_pbx_result __ast_pbx_run (struct ast_channel *c, struct ast_pbx_args *args)
static void __fini_acf_root (void)
static void __fini_apps (void)
static void __fini_hints (void)
static void __fini_switches (void)
static void __init_acf_root (void)
static void __init_apps (void)
static void __init_extensionstate_buf (void)
static void __init_hints (void)
static void __init_switch_data (void)
static void __init_switches (void)
static int _extension_match_core (const char *pattern, const char *data, enum ext_match_t mode)
static int acf_exception_read (struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
static int acf_retrieve_docs (struct ast_custom_function *acf)
static struct match_charadd_exten_to_pattern_tree (struct ast_context *con, struct ast_exten *e1, int findonly)
static struct match_charadd_pattern_node (struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity, struct match_char **parent)
static int add_pri (struct ast_context *con, struct ast_exten *tmp, struct ast_exten *el, struct ast_exten *e, int replace)
 add the extension in the priority chain.
static int add_pri_lockopt (struct ast_context *con, struct ast_exten *tmp, struct ast_exten *el, struct ast_exten *e, int replace, int lockhints)
 add the extension in the priority chain.
static struct match_charalready_in_tree (struct match_char *current, char *pat, int is_pattern)
int ast_active_calls (void)
 Retrieve the number of active calls.
int ast_add_extension (const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
 Add and extension to an extension context.
int ast_add_extension2 (struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
 Main interface to add extensions to the list for out context.
static int ast_add_extension2_lockopt (struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, int lockconts, int lockhints)
 Does all the work of ast_add_extension2, but adds two args, to determine if context and hint locking should be done. In merge_and_delete, we need to do this without locking, as the locks are already held.
static int ast_add_extension_nolock (const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
static int ast_add_hint (struct ast_exten *e)
 Add hint to hint list, check initial extension state.
static int ast_add_hint_nolock (struct ast_exten *e)
 Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already!
int ast_async_goto (struct ast_channel *chan, const char *context, const char *exten, int priority)
 Set the channel to next execute the specified dialplan location.
int ast_async_goto_by_name (const char *channame, const char *context, const char *exten, int priority)
 Set the channel to next execute the specified dialplan location.
int ast_async_goto_if_exists (struct ast_channel *chan, const char *context, const char *exten, int priority)
int ast_async_parseable_goto (struct ast_channel *chan, const char *goto_string)
int ast_build_timing (struct ast_timing *i, const char *info_in)
 Construct a timing bitmap, for use in time-based conditionals.
int ast_canmatch_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
 Looks for a valid matching extension.
static int ast_change_hint (struct ast_exten *oe, struct ast_exten *ne)
 Change hint for an extension.
int ast_check_timing (const struct ast_timing *i)
 Evaluate a pre-constructed bitmap as to whether the current time falls within the range specified.
char * ast_complete_applications (const char *line, const char *word, int state)
 Command completion for the list of installed applications.
int ast_context_add_ignorepat (const char *context, const char *value, const char *registrar)
 Add an ignorepat.
int ast_context_add_ignorepat2 (struct ast_context *con, const char *value, const char *registrar)
int ast_context_add_include (const char *context, const char *include, const char *registrar)
 Add a context include.
int ast_context_add_include2 (struct ast_context *con, const char *value, const char *registrar)
 Add a context include.
int ast_context_add_switch (const char *context, const char *sw, const char *data, int eval, const char *registrar)
 Add a switch.
int ast_context_add_switch2 (struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
 Adds a switch (first param is a ast_context).
void ast_context_destroy (struct ast_context *con, const char *registrar)
 Destroy a context (matches the specified context (or ANY context if NULL).
struct ast_contextast_context_find (const char *name)
 Find a context.
struct ast_contextast_context_find_or_create (struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
 Register a new context or find an existing one.
int ast_context_lockmacro (const char *context)
 locks the macrolock in the given given context
int ast_context_remove_extension (const char *context, const char *extension, int priority, const char *registrar)
 Simply remove extension from context.
int ast_context_remove_extension2 (struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
 This functionc locks given context, search for the right extension and fires out all peer in this extensions with given priority. If priority is set to 0, all peers are removed. After that, unlock context and return.
int ast_context_remove_extension_callerid (const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
int ast_context_remove_extension_callerid2 (struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar, int already_locked)
int ast_context_remove_ignorepat (const char *context, const char *ignorepat, const char *registrar)
int ast_context_remove_ignorepat2 (struct ast_context *con, const char *ignorepat, const char *registrar)
int ast_context_remove_include (const char *context, const char *include, const char *registrar)
 Remove included contexts. This function locks contexts list by &conlist, search for the right context structure, leave context list locked and call ast_context_remove_include2 which removes include, unlock contexts list and return ...
int ast_context_remove_include2 (struct ast_context *con, const char *include, const char *registrar)
 Locks context, remove included contexts, unlocks context. When we call this function, &conlock lock must be locked, because when we giving *con argument, some process can remove/change this context and after that there can be segfault.
int ast_context_remove_switch (const char *context, const char *sw, const char *data, const char *registrar)
 Remove a switch.
int ast_context_remove_switch2 (struct ast_context *con, const char *sw, const char *data, const char *registrar)
 This function locks given context, removes switch, unlock context and return.
int ast_context_unlockmacro (const char *context)
 Unlocks the macrolock in the given context.
int ast_context_verify_includes (struct ast_context *con)
 Verifies includes in an ast_contect structure.
struct ast_custom_functionast_custom_function_find (const char *name)
int ast_custom_function_unregister (struct ast_custom_function *acf)
 Unregister a custom function.
int ast_destroy_timing (struct ast_timing *i)
 Deallocates memory structures associated with a timing bitmap.
enum ast_extension_states ast_devstate_to_extenstate (enum ast_device_state devstate)
 Map devstate to an extension state.
int ast_exists_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
 Determine whether an extension exists.
int ast_explicit_goto (struct ast_channel *chan, const char *context, const char *exten, int priority)
int ast_extension_close (const char *pattern, const char *data, int needmore)
int ast_extension_cmp (const char *a, const char *b)
 Determine if one extension should match before another.
int ast_extension_match (const char *pattern, const char *data)
 Determine if a given extension matches a given pattern (in NXX format).
int ast_extension_state (struct ast_channel *c, const char *context, const char *exten)
 Check extension state for an extension by using hint.
static int ast_extension_state2 (struct ast_exten *e)
 Check state of extension by using hints.
const char * ast_extension_state2str (int extension_state)
 Return extension_state as string.
int ast_extension_state_add (const char *context, const char *exten, ast_state_cb_type callback, void *data)
 Add watcher for extension states.
int ast_extension_state_del (int id, ast_state_cb_type callback)
 Remove a watcher from the callback list.
int ast_findlabel_extension (struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
 Find the priority of an extension that has the specified label.
int ast_findlabel_extension2 (struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
 Find the priority of an extension that has the specified label.
int ast_func_read (struct ast_channel *chan, const char *function, char *workspace, size_t len)
 executes a read operation on a function
int ast_func_read2 (struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
 executes a read operation on a function
int ast_func_write (struct ast_channel *chan, const char *function, const char *value)
 executes a write operation on a function
const char * ast_get_context_name (struct ast_context *con)
const char * ast_get_context_registrar (struct ast_context *c)
const char * ast_get_extension_app (struct ast_exten *e)
void * ast_get_extension_app_data (struct ast_exten *e)
const char * ast_get_extension_cidmatch (struct ast_exten *e)
struct ast_contextast_get_extension_context (struct ast_exten *exten)
const char * ast_get_extension_label (struct ast_exten *exten)
int ast_get_extension_matchcid (struct ast_exten *e)
const char * ast_get_extension_name (struct ast_exten *exten)
int ast_get_extension_priority (struct ast_exten *exten)
const char * ast_get_extension_registrar (struct ast_exten *e)
int ast_get_hint (char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
 Get hint for channel.
const char * ast_get_ignorepat_name (struct ast_ignorepat *ip)
const char * ast_get_ignorepat_registrar (struct ast_ignorepat *ip)
const char * ast_get_include_name (struct ast_include *inc)
const char * ast_get_include_registrar (struct ast_include *i)
const char * ast_get_switch_data (struct ast_sw *sw)
int ast_get_switch_eval (struct ast_sw *sw)
const char * ast_get_switch_name (struct ast_sw *sw)
const char * ast_get_switch_registrar (struct ast_sw *sw)
int ast_goto_if_exists (struct ast_channel *chan, const char *context, const char *exten, int priority)
int ast_hashtab_compare_contexts (const void *ah_a, const void *ah_b)
 hashtable functions for contexts
unsigned int ast_hashtab_hash_contexts (const void *obj)
static struct ast_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.
int ast_ignore_pattern (const char *context, const char *pattern)
 Checks to see if a number should be ignored.
int ast_matchmore_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
 Looks to see if adding anything to this extension might match something. (exists ^ canmatch).
void ast_merge_contexts_and_delete (struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
 Merge the temporary contexts into a global contexts list and delete from the global list the ones that are being added.
int ast_parseable_goto (struct ast_channel *chan, const char *goto_string)
int ast_pbx_outgoing_app (const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
static int ast_pbx_outgoing_cdr_failed (void)
 Function to post an empty cdr after a spool call fails.
int ast_pbx_outgoing_exten (const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
enum ast_pbx_result ast_pbx_run (struct ast_channel *c)
 Execute the PBX in the current thread.
static void * ast_pbx_run_app (void *data)
 run the application and free the descriptor once done
enum ast_pbx_result ast_pbx_run_args (struct ast_channel *c, struct ast_pbx_args *args)
 Execute the PBX in the current thread.
enum ast_pbx_result ast_pbx_start (struct ast_channel *c)
 Create a new thread and start the PBX.
int ast_processed_calls (void)
 Retrieve the total number of calls processed through the PBX since last restart.
int ast_rdlock_context (struct ast_context *con)
 Read locks a given context.
int ast_rdlock_contexts ()
 Read locks the context list.
int ast_register_application2 (const char *app, int(*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
 Dynamically register a new dial plan application.
int ast_register_switch (struct ast_switch *sw)
 Register an alternative dialplan switch.
static int ast_remove_hint (struct ast_exten *e)
 Remove hint from extension.
int ast_spawn_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
 Launch a new extension (i.e. new stack).
int ast_str_get_hint (struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten)
 Get hint for channel.
const char * ast_str_retrieve_variable (struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
void ast_str_substitute_variables (struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
void ast_str_substitute_variables_full (struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)
void ast_str_substitute_variables_varshead (struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
static const char * ast_str_substring (struct ast_str *value, int offset, int length)
int ast_unlock_context (struct ast_context *con)
int ast_unlock_contexts ()
 Unlocks contexts.
int ast_unregister_application (const char *app)
 Unregister an application.
void ast_unregister_switch (struct ast_switch *sw)
 Unregister an alternative switch.
struct ast_extenast_walk_context_extensions (struct ast_context *con, struct ast_exten *exten)
struct ast_ignorepatast_walk_context_ignorepats (struct ast_context *con, struct ast_ignorepat *ip)
struct ast_includeast_walk_context_includes (struct ast_context *con, struct ast_include *inc)
struct ast_swast_walk_context_switches (struct ast_context *con, struct ast_sw *sw)
struct ast_contextast_walk_contexts (struct ast_context *con)
struct ast_extenast_walk_extension_priorities (struct ast_exten *exten, struct ast_exten *priority)
int ast_wrlock_context (struct ast_context *con)
 Write locks a given context.
int ast_wrlock_contexts ()
 Write locks the context list.
int ast_wrlock_contexts_version (void)
static void * async_wait (void *data)
static void cli_match_char_tree (struct match_char *node, char *prefix, int fd)
static int collect_digits (struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
 collect digits from the channel into the buffer.
static int compare_char (const void *a, const void *b)
static char * complete_core_show_hint (const char *line, const char *word, int pos, int state)
 autocomplete for CLI command 'core show hint'
static char * complete_show_dialplan_context (const char *line, const char *word, int pos, int state)
static void context_merge (struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
static void context_merge_incls_swits_igps_other_registrars (struct ast_context *new, struct ast_context *old, const char *registrar)
static void create_match_char_tree (struct ast_context *con)
static void decrease_call_count (void)
static void destroy_exten (struct ast_exten *e)
static void destroy_pattern_tree (struct match_char *pattern_tree)
static void device_state_cb (const struct ast_event *event, void *unused)
static void exception_store_free (void *data)
static int ext_cmp (const char *a, const char *b)
 the full routine to compare extensions in rules.
static int ext_cmp1 (const char **p)
 helper functions to sort extensions and patterns in the desired way, so that more specific patterns appear first.
static int ext_strncpy (char *dst, const char *src, int len)
 copy a string skipping whitespace
static int extension_match_core (const char *pattern, const char *data, enum ext_match_t mode)
static struct ast_contextfind_context (const char *context)
 lookup for a context with a given name,
static struct ast_contextfind_context_locked (const char *context)
 lookup for a context with a given name,
static char * func_args (char *function)
 return a pointer to the arguments of the function, and terminates the function name with '\0'
static struct ast_extenget_canmatch_exten (struct match_char *node)
static unsigned get_range (char *src, int max, const char *const names[], const char *msg)
 helper function to return a range up to max (7, 12, 31 respectively). names, if supplied, is an array of names that should be mapped to numbers.
static void get_timerange (struct ast_timing *i, char *times)
 store a bitmask of valid times, one bit each 1 minute
static char * handle_debug_dialplan (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Send ack once.
static char * handle_set_chanvar (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_set_extenpatternmatchnew (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_set_global (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_application (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_applications (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_chanvar (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI support for listing chanvar's variables in a parseable way.
static char * handle_show_dialplan (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_function (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_functions (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_globals (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI support for listing global variables in a parseable way.
static char * handle_show_hint (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 handle_show_hint: CLI support for listing registered dial plan hint
static char * handle_show_hints (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 handle_show_hints: CLI support for listing registered dial plan hints
static char * handle_show_switches (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 handle_show_switches: CLI support for listing registered dial plan switches
static int handle_statechange (void *datap)
static char * handle_unset_extenpatternmatchnew (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int hashtab_compare_exten_labels (const void *ah_a, const void *ah_b)
static int hashtab_compare_exten_numbers (const void *ah_a, const void *ah_b)
static int hashtab_compare_extens (const void *ha_a, const void *ah_b)
static unsigned int hashtab_hash_extens (const void *obj)
static unsigned int hashtab_hash_labels (const void *obj)
static unsigned int hashtab_hash_priority (const void *obj)
static int include_valid (struct ast_include *i)
static int increase_call_count (const struct ast_channel *c)
 Increase call count for channel.
static void insert_in_next_chars_alt_char_list (struct match_char **parent_ptr, struct match_char *node)
int load_pbx (void)
static int lookup_name (const char *s, const char *const names[], int max)
 Helper for get_range. return the index of the matching entry, starting from 1. If names is not supplied, try numeric values.
static void manager_dpsendack (struct mansession *s, const struct message *m)
 Send ack once.
static int manager_show_dialplan (struct mansession *s, const struct message *m)
 Manager listing of dial plan.
static int manager_show_dialplan_helper (struct mansession *s, const struct message *m, const char *actionidtext, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude)
 Show dialplan extensions XXX this function is similar but not exactly the same as the CLI's show dialplan. Must check whether the difference is intentional or not.
static int matchcid (const char *cidpattern, const char *callerid)
static void new_find_extension (const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid, const char *label, enum ext_match_t action)
static int parse_variable_name (char *var, int *offset, int *length, int *isfunc)
 extract offset:length from variable name.
static int pbx_builtin_answer (struct ast_channel *, const char *)
static int pbx_builtin_background (struct ast_channel *, const char *)
static int pbx_builtin_busy (struct ast_channel *, const char *)
void pbx_builtin_clear_globals (void)
static int pbx_builtin_congestion (struct ast_channel *, const char *)
static int pbx_builtin_execiftime (struct ast_channel *, const char *)
const char * pbx_builtin_getvar_helper (struct ast_channel *chan, const char *name)
 Return a pointer to the value of the corresponding channel variable.
static int pbx_builtin_goto (struct ast_channel *, const char *)
static int pbx_builtin_gotoif (struct ast_channel *, const char *)
static int pbx_builtin_gotoiftime (struct ast_channel *, const char *)
static int pbx_builtin_hangup (struct ast_channel *, const char *)
static int pbx_builtin_importvar (struct ast_channel *, const char *)
static int pbx_builtin_incomplete (struct ast_channel *, const char *)
static int pbx_builtin_noop (struct ast_channel *, const char *)
static int pbx_builtin_proceeding (struct ast_channel *, const char *)
static int pbx_builtin_progress (struct ast_channel *, const char *)
void pbx_builtin_pushvar_helper (struct ast_channel *chan, const char *name, const char *value)
 Add a variable to the channel variable stack, without removing any previously set value.
int pbx_builtin_raise_exception (struct ast_channel *chan, const char *reason)
static int pbx_builtin_resetcdr (struct ast_channel *, const char *)
static int pbx_builtin_ringing (struct ast_channel *, const char *)
static int pbx_builtin_saycharacters (struct ast_channel *, const char *)
static int pbx_builtin_saydigits (struct ast_channel *, const char *)
static int pbx_builtin_saynumber (struct ast_channel *, const char *)
static int pbx_builtin_sayphonetic (struct ast_channel *, const char *)
int pbx_builtin_serialize_variables (struct ast_channel *chan, struct ast_str **buf)
 Create a human-readable string, specifying all variables and their corresponding values.
static int pbx_builtin_setamaflags (struct ast_channel *, const char *)
int pbx_builtin_setvar (struct ast_channel *chan, const char *data)
 Parse and set a single channel variable, where the name and value are separated with an '=' character.
void pbx_builtin_setvar_helper (struct ast_channel *chan, const char *name, const char *value)
 Add a variable to the channel variable stack, removing the most recently set value for the same name.
int pbx_builtin_setvar_multiple (struct ast_channel *chan, const char *vdata)
 Parse and set multiple channel variables, where the pairs are separated by the ',' character, and name and value are separated with an '=' character.
static int pbx_builtin_wait (struct ast_channel *, const char *)
static int pbx_builtin_waitexten (struct ast_channel *, const char *)
int pbx_checkcondition (const char *condition)
 Evaluate a condition.
static void pbx_destroy (struct ast_pbx *p)
int pbx_exec (struct ast_channel *c, struct ast_app *app, const char *data)
 Execute an application.
static int pbx_extension_helper (struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
 The return value depends on the action:.
struct ast_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)
struct ast_apppbx_findapp (const char *app)
 Find application handle in linked list.
static struct ast_switchpbx_findswitch (const char *sw)
static int pbx_parseable_goto (struct ast_channel *chan, const char *goto_string, int async)
void pbx_retrieve_variable (struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
 Support for Asterisk built-in variables in the dialplan.
int pbx_set_autofallthrough (int newval)
int pbx_set_extenpatternmatchnew (int newval)
void pbx_set_overrideswitch (const char *newval)
static void pbx_substitute_variables (char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
void pbx_substitute_variables_helper (struct ast_channel *c, const char *cp1, char *cp2, int count)
void pbx_substitute_variables_helper_full (struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
void pbx_substitute_variables_varshead (struct varshead *headp, const char *cp1, char *cp2, int count)
static void * pbx_thread (void *data)
static void print_app_docs (struct ast_app *aa, int fd)
static void print_ext (struct ast_exten *e, char *buf, int buflen)
 helper function to print an extension
static void set_ext_pri (struct ast_channel *c, const char *exten, int pri)
static int show_debug_helper (int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
static int show_dialplan_helper (int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
static char * substring (const char *value, int offset, int length, char *workspace, size_t workspace_len)
 takes a substring. It is ok to call with value == workspace.
static struct ast_extentrie_find_next_match (struct match_char *node)
static void unreference_cached_app (struct ast_app *app)
static void update_scoreboard (struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
static void wait_for_hangup (struct ast_channel *chan, const void *data)

Variables

static int autofallthrough = 1
static struct ast_app_option background_opts [128] = { [ 's' ] = { .flag = (1 << 0) }, [ 'n' ] = { .flag = (1 << 1) }, [ 'm' ] = { .flag = (1 << 2) }, [ 'p' ] = { .flag = (1 << 3) },}
static struct pbx_builtin builtins []
 Declaration of builtin applications.
static ast_rwlock_t conlock = { 0 }
static int conlock_wrlock_version = 0
static struct ast_contextcontexts
static struct ast_hashtabcontexts_table = NULL
static int countcalls
static const char *const days []
static struct ast_event_subdevice_state_sub
 Subscription for device state change events.
static struct ast_taskprocessordevice_state_tps
static struct ast_custom_function exception_function
static struct ast_datastore_info exception_store_info
static int extenpatternmatchnew = 0
static struct cfextension_states extension_states []
static struct ast_threadstorage extensionstate_buf = { .once = PTHREAD_ONCE_INIT, .key_init = __init_extensionstate_buf , .custom_init = NULL , }
static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
static ast_rwlock_t globalslock = { 0 }
static ast_mutex_t maxcalllock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static const char *const months []
static char * overrideswitch = NULL
static struct ast_cli_entry pbx_cli []
static struct ast_app_option resetcdr_opts [128] = { [ 'w' ] = { .flag = (1 << 1) }, [ 'a' ] = { .flag = (1 << 2) }, [ 'v' ] = { .flag = (1 << 0) }, [ 'e' ] = { .flag = (1 << 10) },}
static int stateid = 1
static struct ast_threadstorage switch_data = { .once = PTHREAD_ONCE_INIT, .key_init = __init_switch_data , .custom_init = NULL , }
static int totalcalls
static struct ast_app_option waitexten_opts [128] = { [ 'm' ] = { .flag = (1 << 0) , .arg_index = 0 + 1 }, [ 'd' ] = { .flag = (1 << 1) , .arg_index = 0 + 1 },}


Detailed Description

Core PBX routines.

Author:
Mark Spencer <markster@digium.com>

Definition in file pbx.c.


Define Documentation

#define AST_PBX_MAX_STACK   128

Go no deeper than this through includes (not counting loops)

Definition at line 1381 of file pbx.c.

#define BACKGROUND_MATCHEXTEN   (1 << 2)

Definition at line 756 of file pbx.c.

Referenced by pbx_builtin_background().

#define BACKGROUND_NOANSWER   (1 << 1)

Definition at line 755 of file pbx.c.

Referenced by pbx_builtin_background().

#define BACKGROUND_PLAYBACK   (1 << 3)

Definition at line 757 of file pbx.c.

Referenced by pbx_builtin_background().

#define BACKGROUND_SKIP   (1 << 0)

Definition at line 754 of file pbx.c.

Referenced by pbx_builtin_background().

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

Referenced by pbx_extension_helper(), and realtime_exec().

#define NEW_MATCHER_CHK_MATCH

Referenced by new_find_extension().

#define NEW_MATCHER_RECURSE

Referenced by new_find_extension().

#define SAY_STUBS

Definition at line 55 of file pbx.c.

#define STATUS_NO_CONTEXT   1

Definition at line 2475 of file pbx.c.

#define STATUS_NO_EXTENSION   2

Definition at line 2476 of file pbx.c.

#define STATUS_NO_LABEL   4

Definition at line 2478 of file pbx.c.

#define STATUS_NO_PRIORITY   3

Definition at line 2477 of file pbx.c.

#define STATUS_SUCCESS   5

Definition at line 2479 of file pbx.c.

#define SWITCH_DATA_LENGTH   256

Definition at line 746 of file pbx.c.

#define VAR_BUF_SIZE   4096

#define VAR_HARDTRAN   3

Definition at line 752 of file pbx.c.

#define VAR_NORMAL   1

Definition at line 750 of file pbx.c.

#define VAR_SOFTTRAN   2

Definition at line 751 of file pbx.c.

#define WAITEXTEN_DIALTONE   (1 << 1)

Definition at line 767 of file pbx.c.

Referenced by pbx_builtin_waitexten().

#define WAITEXTEN_MOH   (1 << 0)

Definition at line 766 of file pbx.c.

Referenced by pbx_builtin_waitexten().


Function Documentation

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

Definition at line 8563 of file pbx.c.

References __ast_internal_context_destroy(), ast_context::alts, ast_context_remove_extension_callerid2(), ast_debug, ast_free, ast_hashtab_end_traversal(), ast_hashtab_next(), ast_hashtab_remove_this_object(), ast_hashtab_start_traversal(), AST_LIST_EMPTY, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_exten::cidmatch, contexts, ast_exten::exten, ast_context::ignorepats, ast_context::includes, ast_context::name, ast_include::next, ast_ignorepat::next, ast_context::next, ast_sw::next, ast_exten::peer_table, ast_exten::priority, ast_context::refcount, ast_exten::registrar, ast_sw::registrar, ast_include::registrar, ast_ignorepat::registrar, ast_context::registrar, ast_context::root, and ast_context::root_table.

Referenced by ast_context_destroy().

08564 {
08565    struct ast_context *tmp, *tmpl=NULL;
08566    struct ast_exten *exten_item, *prio_item;
08567 
08568    for (tmp = list; tmp; ) {
08569       struct ast_context *next = NULL; /* next starting point */
08570          /* The following code used to skip forward to the next
08571             context with matching registrar, but this didn't
08572             make sense; individual priorities registrar'd to
08573             the matching registrar could occur in any context! */
08574       ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
08575       if (con) {
08576          for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
08577             ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
08578             if ( !strcasecmp(tmp->name, con->name) ) {
08579                break;   /* found it */
08580             }
08581          }
08582       }
08583 
08584       if (!tmp)   /* not found, we are done */
08585          break;
08586       ast_wrlock_context(tmp);
08587 
08588       if (registrar) {
08589          /* then search thru and remove any extens that match registrar. */
08590          struct ast_hashtab_iter *exten_iter;
08591          struct ast_hashtab_iter *prio_iter;
08592          struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
08593          struct ast_include *i, *pi = NULL, *ni = NULL;
08594          struct ast_sw *sw = NULL;
08595 
08596          /* remove any ignorepats whose registrar matches */
08597          for (ip = tmp->ignorepats; ip; ip = ipn) {
08598             ipn = ip->next;
08599             if (!strcmp(ip->registrar, registrar)) {
08600                if (ipl) {
08601                   ipl->next = ip->next;
08602                   ast_free(ip);
08603                   continue; /* don't change ipl */
08604                } else {
08605                   tmp->ignorepats = ip->next;
08606                   ast_free(ip);
08607                   continue; /* don't change ipl */
08608                }
08609             }
08610             ipl = ip;
08611          }
08612          /* remove any includes whose registrar matches */
08613          for (i = tmp->includes; i; i = ni) {
08614             ni = i->next;
08615             if (strcmp(i->registrar, registrar) == 0) {
08616                /* remove from list */
08617                if (pi) {
08618                   pi->next = i->next;
08619                   /* free include */
08620                   ast_free(i);
08621                   continue; /* don't change pi */
08622                } else {
08623                   tmp->includes = i->next;
08624                   /* free include */
08625                   ast_free(i);
08626                   continue; /* don't change pi */
08627                }
08628             }
08629             pi = i;
08630          }
08631          /* remove any switches whose registrar matches */
08632          AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
08633             if (strcmp(sw->registrar,registrar) == 0) {
08634                AST_LIST_REMOVE_CURRENT(list);
08635                ast_free(sw);
08636             }
08637          }
08638          AST_LIST_TRAVERSE_SAFE_END;
08639 
08640          if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
08641             exten_iter = ast_hashtab_start_traversal(tmp->root_table);
08642             while ((exten_item=ast_hashtab_next(exten_iter))) {
08643                prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
08644                while ((prio_item=ast_hashtab_next(prio_iter))) {
08645                   if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
08646                      continue;
08647                   }
08648                   ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
08649                          tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
08650                   /* set matchcid to 1 to insure we get a direct match, and NULL registrar to make sure no wildcarding is done */
08651                   ast_context_remove_extension_callerid2(tmp, prio_item->exten, prio_item->priority, prio_item->cidmatch, 1, NULL, 1);
08652                }
08653                ast_hashtab_end_traversal(prio_iter);
08654             }
08655             ast_hashtab_end_traversal(exten_iter);
08656          }
08657 
08658          /* delete the context if it's registrar matches, is empty, has refcount of 1, */
08659          /* it's not empty, if it has includes, ignorepats, or switches that are registered from
08660             another registrar. It's not empty if there are any extensions */
08661          if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
08662             ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
08663             ast_hashtab_remove_this_object(contexttab, tmp);
08664 
08665             next = tmp->next;
08666             if (tmpl)
08667                tmpl->next = next;
08668             else
08669                contexts = next;
08670             /* Okay, now we're safe to let it go -- in a sense, we were
08671                ready to let it go as soon as we locked it. */
08672             ast_unlock_context(tmp);
08673             __ast_internal_context_destroy(tmp);
08674          } else {
08675             ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
08676                     tmp->refcount, tmp->root);
08677             ast_unlock_context(tmp);
08678             next = tmp->next;
08679             tmpl = tmp;
08680          }
08681       } else if (con) {
08682          ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
08683          ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
08684          ast_hashtab_remove_this_object(contexttab, tmp);
08685 
08686          next = tmp->next;
08687          if (tmpl)
08688             tmpl->next = next;
08689          else
08690             contexts = next;
08691          /* Okay, now we're safe to let it go -- in a sense, we were
08692             ready to let it go as soon as we locked it. */
08693          ast_unlock_context(tmp);
08694          __ast_internal_context_destroy(tmp);
08695       }
08696 
08697       /* if we have a specific match, we are done, otherwise continue */
08698       tmp = con ? NULL : next;
08699    }
08700 }

int __ast_custom_function_register ( struct ast_custom_function acf,
struct ast_module mod 
)

Register a custom function.

Definition at line 3358 of file pbx.c.

References acf_retrieve_docs(), ast_custom_function::acflist, ast_log(), AST_RWLIST_INSERT_BEFORE_CURRENT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, AST_STATIC_DOC, ast_verb, COLOR_BRCYAN, ast_custom_function::docsrc, LOG_ERROR, ast_custom_function::mod, ast_custom_function::name, and term_color().

Referenced by load_pbx().

03359 {
03360    struct ast_custom_function *cur;
03361    char tmps[80];
03362 
03363    if (!acf) {
03364       return -1;
03365    }
03366 
03367    acf->mod = mod;
03368 #ifdef AST_XML_DOCS
03369    acf->docsrc = AST_STATIC_DOC;
03370 #endif
03371 
03372    if (acf_retrieve_docs(acf)) {
03373       return -1;
03374    }
03375 
03376    AST_RWLIST_WRLOCK(&acf_root);
03377 
03378    AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
03379       if (!strcmp(acf->name, cur->name)) {
03380          ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
03381          AST_RWLIST_UNLOCK(&acf_root);
03382          return -1;
03383       }
03384    }
03385 
03386    /* Store in alphabetical order */
03387    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
03388       if (strcasecmp(acf->name, cur->name) < 0) {
03389          AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
03390          break;
03391       }
03392    }
03393    AST_RWLIST_TRAVERSE_SAFE_END;
03394 
03395    if (!cur) {
03396       AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
03397    }
03398 
03399    AST_RWLIST_UNLOCK(&acf_root);
03400 
03401    ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
03402 
03403    return 0;
03404 }

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

Definition at line 9822 of file pbx.c.

References ast_async_goto(), ast_exists_extension(), ast_explicit_goto(), AST_PBX_GOTO_FAILED, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, and ast_channel::exten.

Referenced by ast_async_goto_if_exists(), and ast_goto_if_exists().

09823 {
09824    int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
09825 
09826    if (!chan)
09827       return -2;
09828 
09829    if (context == NULL)
09830       context = chan->context;
09831    if (exten == NULL)
09832       exten = chan->exten;
09833 
09834    goto_func = (async) ? ast_async_goto : ast_explicit_goto;
09835    if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
09836       return goto_func(chan, context, exten, priority);
09837    else {
09838       return AST_PBX_GOTO_FAILED;
09839    }
09840 }

static void __ast_internal_context_destroy ( struct ast_context con  )  [static]

Definition at line 8516 of file pbx.c.

References ast_context::alts, ast_free, ast_hashtab_destroy(), AST_LIST_REMOVE_HEAD, ast_rwlock_destroy(), destroy_exten(), destroy_pattern_tree(), el, ast_context::ignorepats, ast_context::includes, ast_context::lock, ast_exten::next, ast_ignorepat::next, ast_include::next, ast_context::pattern_tree, ast_exten::peer, ast_context::registrar, ast_context::root, and ast_context::root_table.

Referenced by __ast_context_destroy(), and ast_merge_contexts_and_delete().

08517 {
08518    struct ast_include *tmpi;
08519    struct ast_sw *sw;
08520    struct ast_exten *e, *el, *en;
08521    struct ast_ignorepat *ipi;
08522    struct ast_context *tmp = con;
08523 
08524    for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
08525       struct ast_include *tmpil = tmpi;
08526       tmpi = tmpi->next;
08527       ast_free(tmpil);
08528    }
08529    for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
08530       struct ast_ignorepat *ipl = ipi;
08531       ipi = ipi->next;
08532       ast_free(ipl);
08533    }
08534    if (tmp->registrar)
08535       ast_free(tmp->registrar);
08536 
08537    /* destroy the hash tabs */
08538    if (tmp->root_table) {
08539       ast_hashtab_destroy(tmp->root_table, 0);
08540    }
08541    /* and destroy the pattern tree */
08542    if (tmp->pattern_tree)
08543       destroy_pattern_tree(tmp->pattern_tree);
08544 
08545    while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
08546       ast_free(sw);
08547    for (e = tmp->root; e;) {
08548       for (en = e->peer; en;) {
08549          el = en;
08550          en = en->peer;
08551          destroy_exten(el);
08552       }
08553       el = e;
08554       e = e->next;
08555       destroy_exten(el);
08556    }
08557    tmp->root = NULL;
08558    ast_rwlock_destroy(&tmp->lock);
08559    ast_free(tmp);
08560 }

static enum ast_pbx_result __ast_pbx_run ( struct ast_channel c,
struct ast_pbx_args args 
) [static]

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

References ast_channel::_softhangup, ast_calloc, ast_cdr_end(), ast_cdr_update(), ast_check_hangup(), ast_clear_flag, ast_copy_string(), ast_debug, ast_exists_extension(), AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, ast_free, ast_hangup(), ast_log(), ast_matchmore_extension(), ast_opt_end_cdr_before_h_exten, AST_PBX_ERROR, AST_PBX_INCOMPLETE, ast_set2_flag, ast_set_flag, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_TIMEOUT, ast_spawn_extension(), ast_strlen_zero(), ast_test_flag, ast_verb, autofallthrough, ast_channel::cdr, ast_channel::cid, ast_callerid::cid_num, collect_digits(), ast_channel::context, ast_pbx::dtimeoutms, ast_channel::exten, LOG_WARNING, ast_channel::name, ast_pbx_args::no_hangup_chan, ast_channel::pbx, pbx_builtin_busy(), pbx_builtin_congestion(), pbx_builtin_getvar_helper(), pbx_builtin_raise_exception(), pbx_builtin_setvar_helper(), pbx_destroy(), ast_channel::priority, ast_pbx::rtimeoutms, set_ext_pri(), status, and ast_channel::whentohangup.

Referenced by ast_pbx_run_args(), and pbx_thread().

04553 {
04554    int found = 0; /* set if we find at least one match */
04555    int res = 0;
04556    int autoloopflag;
04557    int error = 0;    /* set an error conditions */
04558 
04559    /* A little initial setup here */
04560    if (c->pbx) {
04561       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
04562       /* XXX and now what ? */
04563       ast_free(c->pbx);
04564    }
04565    if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
04566       return -1;
04567    /* Set reasonable defaults */
04568    c->pbx->rtimeoutms = 10000;
04569    c->pbx->dtimeoutms = 5000;
04570 
04571    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);   /* save value to restore at the end */
04572    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
04573 
04574    /* Start by trying whatever the channel is set to */
04575    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
04576       /* If not successful fall back to 's' */
04577       ast_verb(2, "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
04578       /* XXX the original code used the existing priority in the call to
04579        * ast_exists_extension(), and reset it to 1 afterwards.
04580        * I believe the correct thing is to set it to 1 immediately.
04581        */
04582       set_ext_pri(c, "s", 1);
04583       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
04584          /* JK02: And finally back to default if everything else failed */
04585          ast_verb(2, "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
04586          ast_copy_string(c->context, "default", sizeof(c->context));
04587       }
04588    }
04589    for (;;) {
04590       char dst_exten[256]; /* buffer to accumulate digits */
04591       int pos = 0;      /* XXX should check bounds */
04592       int digit = 0;
04593       int invalid = 0;
04594       int timeout = 0;
04595 
04596       /* loop on priorities in this context/exten */
04597       while ( !(res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found,1))) {
04598          if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
04599             set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
04600             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
04601             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
04602             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
04603          } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04604             pbx_builtin_raise_exception(c, "ABSOLUTETIMEOUT");
04605             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
04606             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
04607             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
04608          } else if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
04609             c->_softhangup = 0;
04610             continue;
04611          } else if (ast_check_hangup(c)) {
04612             ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
04613                c->exten, c->priority);
04614             error = 1;
04615             break;
04616          }
04617          c->priority++;
04618       } /* end while  - from here on we can use 'break' to go out */
04619       if (found && res) {
04620          /* Something bad happened, or a hangup has been requested. */
04621          if (strchr("0123456789ABCDEF*#", res)) {
04622             ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
04623             pos = 0;
04624             dst_exten[pos++] = digit = res;
04625             dst_exten[pos] = '\0';
04626          } else if (res == AST_PBX_INCOMPLETE) {
04627             ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
04628             ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
04629 
04630             /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
04631             if (!ast_matchmore_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
04632                invalid = 1;
04633             } else {
04634                ast_copy_string(dst_exten, c->exten, sizeof(dst_exten));
04635                digit = 1;
04636                pos = strlen(dst_exten);
04637             }
04638          } else {
04639             ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
04640             ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
04641 
04642             if ((res == AST_PBX_ERROR) && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04643                /* if we are already on the 'e' exten, don't jump to it again */
04644                if (!strcmp(c->exten, "e")) {
04645                   ast_verb(2, "Spawn extension (%s, %s, %d) exited ERROR while already on 'e' exten on '%s'\n", c->context, c->exten, c->priority, c->name);
04646                   error = 1;
04647                } else {
04648                   pbx_builtin_raise_exception(c, "ERROR");
04649                   continue;
04650                }
04651             }
04652 
04653             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
04654                c->_softhangup = 0;
04655                continue;
04656             } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
04657                set_ext_pri(c, "T", 1);
04658                /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
04659                memset(&c->whentohangup, 0, sizeof(c->whentohangup));
04660                c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
04661                continue;
04662             } else {
04663                if (c->cdr)
04664                   ast_cdr_update(c);
04665                error = 1;
04666                break;
04667             }
04668          }
04669       }
04670       if (error)
04671          break;
04672 
04673       /*!\note
04674        * We get here on a failure of some kind:  non-existing extension or
04675        * hangup.  We have options, here.  We can either catch the failure
04676        * and continue, or we can drop out entirely. */
04677 
04678       if (invalid || !ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
04679          /*!\note
04680           * If there is no match at priority 1, it is not a valid extension anymore.
04681           * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
04682           * neither exist.
04683           */
04684          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
04685             ast_verb(3, "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
04686             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
04687             set_ext_pri(c, "i", 1);
04688          } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04689             pbx_builtin_raise_exception(c, "INVALID");
04690          } else {
04691             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
04692                c->name, c->exten, c->context);
04693             error = 1; /* we know what to do with it */
04694             break;
04695          }
04696       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
04697          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
04698          c->_softhangup = 0;
04699       } else { /* keypress received, get more digits for a full extension */
04700          int waittime = 0;
04701          if (digit)
04702             waittime = c->pbx->dtimeoutms;
04703          else if (!autofallthrough)
04704             waittime = c->pbx->rtimeoutms;
04705          if (!waittime) {
04706             const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
04707             if (!status)
04708                status = "UNKNOWN";
04709             ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
04710             if (!strcasecmp(status, "CONGESTION"))
04711                res = pbx_builtin_congestion(c, "10");
04712             else if (!strcasecmp(status, "CHANUNAVAIL"))
04713                res = pbx_builtin_congestion(c, "10");
04714             else if (!strcasecmp(status, "BUSY"))
04715                res = pbx_builtin_busy(c, "10");
04716             error = 1; /* XXX disable message */
04717             break;   /* exit from the 'for' loop */
04718          }
04719 
04720          if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
04721             break;
04722          if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
04723             timeout = 1;
04724          if (!timeout && ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
04725             set_ext_pri(c, dst_exten, 1);
04726          else {
04727             /* No such extension */
04728             if (!timeout && !ast_strlen_zero(dst_exten)) {
04729                /* An invalid extension */
04730                if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
04731                   ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
04732                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
04733                   set_ext_pri(c, "i", 1);
04734                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04735                   pbx_builtin_raise_exception(c, "INVALID");
04736                } else {
04737                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
04738                   found = 1; /* XXX disable message */
04739                   break;
04740                }
04741             } else {
04742                /* A simple timeout */
04743                if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
04744                   ast_verb(3, "Timeout on %s\n", c->name);
04745                   set_ext_pri(c, "t", 1);
04746                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04747                   pbx_builtin_raise_exception(c, "RESPONSETIMEOUT");
04748                } else {
04749                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
04750                   found = 1; /* XXX disable message */
04751                   break;
04752                }
04753             }
04754          }
04755          if (c->cdr) {
04756             ast_verb(2, "CDR updated on %s\n",c->name);
04757             ast_cdr_update(c);
04758          }
04759       }
04760    }
04761 
04762    if (!found && !error) {
04763       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
04764    }
04765 
04766    if (!args || !args->no_hangup_chan) {
04767       ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
04768    }
04769 
04770    if ((!args || !args->no_hangup_chan) &&
04771          !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) &&
04772          ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
04773       set_ext_pri(c, "h", 1);
04774       if (c->cdr && ast_opt_end_cdr_before_h_exten) {
04775          ast_cdr_end(c->cdr);
04776       }
04777       while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found, 1)) == 0) {
04778          c->priority++;
04779       }
04780       if (found && res) {
04781          /* Something bad happened, or a hangup has been requested. */
04782          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
04783          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
04784       }
04785    }
04786    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
04787    ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
04788    pbx_destroy(c->pbx);
04789    c->pbx = NULL;
04790 
04791    if (!args || !args->no_hangup_chan) {
04792       ast_hangup(c);
04793    }
04794 
04795    return 0;
04796 }

static void __fini_acf_root ( void   )  [static]

Definition at line 1099 of file pbx.c.

01102 {

static void __fini_apps ( void   )  [static]

Definition at line 1143 of file pbx.c.

01148 :
   When holding this list's lock, do _not_ do anything that will cause conlock

static void __fini_hints ( void   )  [static]

Definition at line 1154 of file pbx.c.

01175 {

static void __fini_switches ( void   )  [static]

Definition at line 1145 of file pbx.c.

01148 :
   When holding this list's lock, do _not_ do anything that will cause conlock

static void __init_acf_root ( void   )  [static]

Definition at line 1099 of file pbx.c.

01102 {

static void __init_apps ( void   )  [static]

Definition at line 1143 of file pbx.c.

01148 :
   When holding this list's lock, do _not_ do anything that will cause conlock

static void __init_extensionstate_buf ( void   )  [static]

Definition at line 780 of file pbx.c.

00783 : An extension

static void __init_hints ( void   )  [static]

Definition at line 1154 of file pbx.c.

01175 {

static void __init_switch_data ( void   )  [static]

Definition at line 779 of file pbx.c.

00783 : An extension

static void __init_switches ( void   )  [static]

Definition at line 1145 of file pbx.c.

01148 :
   When holding this list's lock, do _not_ do anything that will cause conlock

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

Definition at line 2250 of file pbx.c.

References ast_log(), E_MATCH, E_MATCH_MASK, E_MATCHMORE, LOG_NOTICE, and LOG_WARNING.

Referenced by extension_match_core().

02251 {
02252    mode &= E_MATCH_MASK;   /* only consider the relevant bits */
02253 
02254 #ifdef NEED_DEBUG_HERE
02255    ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
02256 #endif
02257 
02258    if ( (mode == E_MATCH) && (pattern[0] == '_') && (!strcasecmp(pattern,data)) ) { /* note: if this test is left out, then _x. will not match _x. !!! */
02259 #ifdef NEED_DEBUG_HERE
02260       ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
02261 #endif
02262       return 1;
02263    }
02264 
02265    if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
02266       int ld = strlen(data), lp = strlen(pattern);
02267 
02268       if (lp < ld) {    /* pattern too short, cannot match */
02269 #ifdef NEED_DEBUG_HERE
02270          ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
02271 #endif
02272          return 0;
02273       }
02274       /* depending on the mode, accept full or partial match or both */
02275       if (mode == E_MATCH) {
02276 #ifdef NEED_DEBUG_HERE
02277          ast_log(LOG_NOTICE,"return (!strcmp(%s,%s) when mode== E_MATCH)\n", pattern, data);
02278 #endif
02279          return !strcmp(pattern, data); /* 1 on match, 0 on fail */
02280       }
02281       if (ld == 0 || !strncasecmp(pattern, data, ld)) { /* partial or full match */
02282 #ifdef NEED_DEBUG_HERE
02283          ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
02284 #endif
02285          return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
02286       } else {
02287 #ifdef NEED_DEBUG_HERE
02288          ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
02289 #endif
02290          return 0;
02291       }
02292    }
02293    pattern++; /* skip leading _ */
02294    /*
02295     * XXX below we stop at '/' which is a separator for the CID info. However we should
02296     * not store '/' in the pattern at all. When we insure it, we can remove the checks.
02297     */
02298    while (*data && *pattern && *pattern != '/') {
02299       const char *end;
02300 
02301       if (*data == '-') { /* skip '-' in data (just a separator) */
02302          data++;
02303          continue;
02304       }
02305       switch (toupper(*pattern)) {
02306       case '[':   /* a range */
02307          end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
02308          if (end == NULL) {
02309             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
02310             return 0;   /* unconditional failure */
02311          }
02312          for (pattern++; pattern != end; pattern++) {
02313             if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
02314                if (*data >= pattern[0] && *data <= pattern[2])
02315                   break;   /* match found */
02316                else {
02317                   pattern += 2; /* skip a total of 3 chars */
02318                   continue;
02319                }
02320             } else if (*data == pattern[0])
02321                break;   /* match found */
02322          }
02323          if (pattern == end) {
02324 #ifdef NEED_DEBUG_HERE
02325             ast_log(LOG_NOTICE,"return (0) when pattern==end\n");
02326 #endif
02327             return 0;
02328          }
02329          pattern = end; /* skip and continue */
02330          break;
02331       case 'N':
02332          if (*data < '2' || *data > '9') {
02333 #ifdef NEED_DEBUG_HERE
02334             ast_log(LOG_NOTICE,"return (0) N is matched\n");
02335 #endif
02336             return 0;
02337          }
02338          break;
02339       case 'X':
02340          if (*data < '0' || *data > '9') {
02341 #ifdef NEED_DEBUG_HERE
02342             ast_log(LOG_NOTICE,"return (0) X is matched\n");
02343 #endif
02344             return 0;
02345          }
02346          break;
02347       case 'Z':
02348          if (*data < '1' || *data > '9') {
02349 #ifdef NEED_DEBUG_HERE
02350             ast_log(LOG_NOTICE,"return (0) Z is matched\n");
02351 #endif
02352             return 0;
02353          }
02354          break;
02355       case '.':   /* Must match, even with more digits */
02356 #ifdef NEED_DEBUG_HERE
02357          ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
02358 #endif
02359          return 1;
02360       case '!':   /* Early match */
02361 #ifdef NEED_DEBUG_HERE
02362          ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
02363 #endif
02364          return 2;
02365       case ' ':
02366       case '-':   /* Ignore these in patterns */
02367          data--; /* compensate the final data++ */
02368          break;
02369       default:
02370          if (*data != *pattern) {
02371 #ifdef NEED_DEBUG_HERE
02372             ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
02373 #endif
02374             return 0;
02375          }
02376       }
02377       data++;
02378       pattern++;
02379    }
02380    if (*data)        /* data longer than pattern, no match */ {
02381 #ifdef NEED_DEBUG_HERE
02382       ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
02383 #endif
02384       return 0;
02385    }
02386 
02387    /*
02388     * match so far, but ran off the end of the data.
02389     * Depending on what is next, determine match or not.
02390     */
02391    if (*pattern == '\0' || *pattern == '/') {   /* exact match */
02392 #ifdef NEED_DEBUG_HERE
02393       ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
02394 #endif
02395       return (mode == E_MATCHMORE) ? 0 : 1;  /* this is a failure for E_MATCHMORE */
02396    } else if (*pattern == '!')   {     /* early match */
02397 #ifdef NEED_DEBUG_HERE
02398       ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
02399 #endif
02400       return 2;
02401    } else {                /* partial match */
02402 #ifdef NEED_DEBUG_HERE
02403       ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
02404 #endif
02405       return (mode == E_MATCH) ? 0 : 1;   /* this is a failure for E_MATCH */
02406    }
02407 }

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

Definition at line 3098 of file pbx.c.

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

03099 {
03100    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
03101    struct pbx_exception *exception = NULL;
03102    if (!ds || !ds->data)
03103       return -1;
03104    exception = ds->data;
03105    if (!strcasecmp(data, "REASON"))
03106       ast_copy_string(buf, exception->reason, buflen);
03107    else if (!strcasecmp(data, "CONTEXT"))
03108       ast_copy_string(buf, exception->context, buflen);
03109    else if (!strncasecmp(data, "EXTEN", 5))
03110       ast_copy_string(buf, exception->exten, buflen);
03111    else if (!strcasecmp(data, "PRIORITY"))
03112       snprintf(buf, buflen, "%d", exception->priority);
03113    else
03114       return -1;
03115    return 0;
03116 }

static int acf_retrieve_docs ( struct ast_custom_function acf  )  [static]

Definition at line 3313 of file pbx.c.

References ast_custom_function::arguments, ast_free, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), AST_XML_DOC, desc, ast_custom_function::desc, ast_custom_function::docsrc, ast_custom_function::name, ast_custom_function::seealso, synopsis, ast_custom_function::synopsis, and ast_custom_function::syntax.

Referenced by __ast_custom_function_register().

03314 {
03315 #ifdef AST_XML_DOCS
03316    char *tmpxml;
03317 
03318    /* Let's try to find it in the Documentation XML */
03319    if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
03320       return 0;
03321    }
03322 
03323    if (ast_string_field_init(acf, 128)) {
03324       return -1;
03325    }
03326 
03327    /* load synopsis */
03328    tmpxml = ast_xmldoc_build_synopsis("function", acf->name);
03329    ast_string_field_set(acf, synopsis, tmpxml);
03330    ast_free(tmpxml);
03331 
03332    /* load description */
03333    tmpxml = ast_xmldoc_build_description("function", acf->name);
03334    ast_string_field_set(acf, desc, tmpxml);
03335    ast_free(tmpxml);
03336 
03337    /* load syntax */
03338    tmpxml = ast_xmldoc_build_syntax("function", acf->name);
03339    ast_string_field_set(acf, syntax, tmpxml);
03340    ast_free(tmpxml);
03341 
03342    /* load arguments */
03343    tmpxml = ast_xmldoc_build_arguments("function", acf->name);
03344    ast_string_field_set(acf, arguments, tmpxml);
03345    ast_free(tmpxml);
03346 
03347    /* load seealso */
03348    tmpxml = ast_xmldoc_build_seealso("function", acf->name);
03349    ast_string_field_set(acf, seealso, tmpxml);
03350    ast_free(tmpxml);
03351 
03352    acf->docsrc = AST_XML_DOC;
03353 #endif
03354 
03355    return 0;
03356 }

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

Definition at line 1906 of file pbx.c.

References add_pattern_node(), already_in_tree(), ast_copy_string(), ast_log(), buf, ast_exten::cidmatch, compare_char(), match_char::deleted, match_char::exten, ast_exten::exten, LOG_DEBUG, LOG_ERROR, LOG_WARNING, m1, m2, ast_exten::matchcid, match_char::next_char, and ast_context::pattern_tree.

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

01907 {
01908    struct match_char *m1 = NULL, *m2 = NULL, **m0;
01909    int specif;
01910    int already;
01911    int pattern = 0;
01912    char buf[256];
01913    char extenbuf[512];
01914    char *s1 = extenbuf;
01915    int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2;
01916 
01917 
01918    ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
01919 
01920    if (e1->matchcid &&  l1 <= sizeof(extenbuf)) {
01921       strcat(extenbuf, "/");
01922       strcat(extenbuf, e1->cidmatch);
01923    } else if (l1 > sizeof(extenbuf)) {
01924       ast_log(LOG_ERROR, "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n", e1->exten, e1->cidmatch);
01925       return 0;
01926    }
01927 #ifdef NEED_DEBUG
01928    ast_log(LOG_DEBUG, "Adding exten %s%c%s to tree\n", s1, e1->matchcid ? '/' : ' ', e1->matchcid ? e1->cidmatch : "");
01929 #endif
01930    m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
01931    m0 = &con->pattern_tree;
01932    already = 1;
01933 
01934    if ( *s1 == '_') {
01935       pattern = 1;
01936       s1++;
01937    }
01938    while (*s1) {
01939       if (pattern && *s1 == '[' && *(s1 - 1) != '\\') {
01940          char *s2 = buf;
01941          buf[0] = 0;
01942          s1++; /* get past the '[' */
01943          while (*s1 != ']' && *(s1 - 1) != '\\') {
01944             if (*s1 == '\\') {
01945                if (*(s1 + 1) == ']') {
01946                   *s2++ = ']';
01947                   s1 += 2;
01948                } else if (*(s1 + 1) == '\\') {
01949                   *s2++ = '\\';
01950                   s1 += 2;
01951                } else if (*(s1 + 1) == '-') {
01952                   *s2++ = '-';
01953                   s1 += 2;
01954                } else if (*(s1 + 1) == '[') {
01955                   *s2++ = '[';
01956                   s1 += 2;
01957                }
01958             } else if (*s1 == '-') { /* remember to add some error checking to all this! */
01959                char s3 = *(s1 - 1);
01960                char s4 = *(s1 + 1);
01961                for (s3++; s3 <= s4; s3++) {
01962                   *s2++ = s3;
01963                }
01964                s1 += 2;
01965             } else if (*s1 == '\0') {
01966                ast_log(LOG_WARNING, "A matching ']' was not found for '[' in pattern string '%s'\n", extenbuf);
01967                break;
01968             } else {
01969                *s2++ = *s1++;
01970             }
01971          }
01972          *s2 = 0; /* null terminate the exploded range */
01973          /* sort the characters */
01974 
01975          specif = strlen(buf);
01976          qsort(buf, specif, 1, compare_char);
01977          specif <<= 8;
01978          specif += buf[0];
01979       } else {
01980          if (*s1 == '\\') {
01981             s1++;
01982             buf[0] = *s1;
01983          } else {
01984             if (pattern) {
01985                if (*s1 == 'n') { /* make sure n,x,z patterns are canonicalized to N,X,Z */
01986                   *s1 = 'N';
01987                } else if (*s1 == 'x') {
01988                   *s1 = 'X';
01989                } else if (*s1 == 'z') {
01990                   *s1 = 'Z';
01991                }
01992             }
01993             buf[0] = *s1;
01994          }
01995          buf[1] = 0;
01996          specif = 1;
01997       }
01998       m2 = 0;
01999       if (already && (m2 = already_in_tree(m1, buf, pattern)) && m2->next_char) {
02000          if (!(*(s1 + 1))) {  /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten...
02001                         a shorter pattern might win if the longer one doesn't match */
02002             if (m2->exten) {
02003                ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", m2->exten->exten, e1->exten);
02004             }
02005             m2->exten = e1;
02006             m2->deleted = 0;
02007          }
02008          m1 = m2->next_char; /* m1 points to the node to compare against */
02009          m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
02010       } else { /* not already OR not m2 OR nor m2->next_char */
02011          if (m2) {
02012             if (findonly) {
02013                return m2;
02014             }
02015             m1 = m2; /* while m0 stays the same */
02016          } else {
02017             if (findonly) {
02018                return m1;
02019             }
02020             if (!(m1 = add_pattern_node(con, m1, buf, pattern, already,specif, m0))) { /* m1 is the node just added */
02021                return NULL;
02022             }
02023             m0 = &m1->next_char;
02024          }
02025          if (!(*(s1 + 1))) {
02026             if (m2 && m2->exten) {
02027                ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", m2->exten->exten, e1->exten);
02028             }
02029             m1->deleted = 0;
02030             m1->exten = e1;
02031          }
02032 
02033          /* The 'already' variable is a mini-optimization designed to make it so that we
02034           * don't have to call already_in_tree when we know it will return false.
02035           */
02036          already = 0;
02037       }
02038       s1++; /* advance to next char */
02039    }
02040    return m1;
02041 }

static struct match_char * add_pattern_node ( struct ast_context con,
struct match_char current,
char *  pattern,
int  is_pattern,
int  already,
int  specificity,
struct match_char **  parent 
) [static, read]

Definition at line 1864 of file pbx.c.

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

Referenced by add_exten_to_pattern_tree().

01865 {
01866    struct match_char *m;
01867    
01868    if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern)))) {
01869       return NULL;
01870    }
01871 
01872    /* strcpy is safe here since we know its size and have allocated
01873     * just enough space for when we allocated m
01874     */
01875    strcpy(m->x, pattern);
01876 
01877    /* the specificity scores are the same as used in the old
01878       pattern matcher. */
01879    m->is_pattern = is_pattern;
01880    if (specificity == 1 && is_pattern && pattern[0] == 'N')
01881       m->specificity = 0x0802;
01882    else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
01883       m->specificity = 0x0901;
01884    else if (specificity == 1 && is_pattern && pattern[0] == 'X')
01885       m->specificity = 0x0a00;
01886    else if (specificity == 1 && is_pattern && pattern[0] == '.')
01887       m->specificity = 0x10000;
01888    else if (specificity == 1 && is_pattern && pattern[0] == '!')
01889       m->specificity = 0x20000;
01890    else
01891       m->specificity = specificity;
01892 
01893    if (!con->pattern_tree) {
01894       insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
01895    } else {
01896       if (already) { /* switch to the new regime (traversing vs appending)*/
01897          insert_in_next_chars_alt_char_list(nextcharptr, m);
01898       } else {
01899          insert_in_next_chars_alt_char_list(&current->next_char, m);
01900       }
01901    }
01902 
01903    return m;
01904 }

static int add_pri ( struct ast_context con,
struct ast_exten tmp,
struct ast_exten el,
struct ast_exten e,
int  replace 
) [static]

add the extension in the priority chain.

Return values:
0 on success.
-1 on failure.

Definition at line 7727 of file pbx.c.

References add_pri_lockopt().

Referenced by ast_add_extension2_lockopt().

07729 {
07730    return add_pri_lockopt(con, tmp, el, e, replace, 1);
07731 }

static int add_pri_lockopt ( struct ast_context con,
struct ast_exten tmp,
struct ast_exten el,
struct ast_exten e,
int  replace,
int  lockhints 
) [static]

add the extension in the priority chain.

Return values:
0 on success.
-1 on failure.

Definition at line 7738 of file pbx.c.

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

Referenced by add_pri().

07740 {
07741    struct ast_exten *ep;
07742    struct ast_exten *eh=e;
07743 
07744    for (ep = NULL; e ; ep = e, e = e->peer) {
07745       if (e->priority >= tmp->priority)
07746          break;
07747    }
07748    if (!e) {   /* go at the end, and ep is surely set because the list is not empty */
07749       ast_hashtab_insert_safe(eh->peer_table, tmp);
07750 
07751       if (tmp->label) {
07752          ast_hashtab_insert_safe(eh->peer_label_table, tmp);
07753       }
07754       ep->peer = tmp;
07755       return 0;   /* success */
07756    }
07757    if (e->priority == tmp->priority) {
07758       /* Can't have something exactly the same.  Is this a
07759          replacement?  If so, replace, otherwise, bonk. */
07760       if (!replace) {
07761          ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
07762          if (tmp->datad) {
07763             tmp->datad(tmp->data);
07764             /* if you free this, null it out */
07765             tmp->data = NULL;
07766          }
07767 
07768          ast_free(tmp);
07769          return -1;
07770       }
07771       /* we are replacing e, so copy the link fields and then update
07772        * whoever pointed to e to point to us
07773        */
07774       tmp->next = e->next; /* not meaningful if we are not first in the peer list */
07775       tmp->peer = e->peer; /* always meaningful */
07776       if (ep)  {     /* We're in the peer list, just insert ourselves */
07777          ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
07778 
07779          if (e->label) {
07780             ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
07781          }
07782 
07783          ast_hashtab_insert_safe(eh->peer_table,tmp);
07784          if (tmp->label) {
07785             ast_hashtab_insert_safe(eh->peer_label_table,tmp);
07786          }
07787 
07788          ep->peer = tmp;
07789       } else if (el) {     /* We're the first extension. Take over e's functions */
07790          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
07791          tmp->peer_table = e->peer_table;
07792          tmp->peer_label_table = e->peer_label_table;
07793          ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
07794          ast_hashtab_insert_safe(tmp->peer_table,tmp);
07795          if (e->label) {
07796             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
07797          }
07798          if (tmp->label) {
07799             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07800          }
07801 
07802          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07803          ast_hashtab_insert_safe(con->root_table, tmp);
07804          el->next = tmp;
07805          /* The pattern trie points to this exten; replace the pointer,
07806             and all will be well */
07807          if (x) { /* if the trie isn't formed yet, don't sweat this */
07808             if (x->exten) { /* this test for safety purposes */
07809                x->exten = tmp; /* replace what would become a bad pointer */
07810             } else {
07811                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
07812             }
07813          }
07814       } else {       /* We're the very first extension.  */
07815          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
07816          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07817          ast_hashtab_insert_safe(con->root_table, tmp);
07818          tmp->peer_table = e->peer_table;
07819          tmp->peer_label_table = e->peer_label_table;
07820          ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
07821          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07822          if (e->label) {
07823             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
07824          }
07825          if (tmp->label) {
07826             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07827          }
07828 
07829          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07830          ast_hashtab_insert_safe(con->root_table, tmp);
07831          con->root = tmp;
07832          /* The pattern trie points to this exten; replace the pointer,
07833             and all will be well */
07834          if (x) { /* if the trie isn't formed yet; no problem */
07835             if (x->exten) { /* this test for safety purposes */
07836                x->exten = tmp; /* replace what would become a bad pointer */
07837             } else {
07838                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
07839             }
07840          }
07841       }
07842       if (tmp->priority == PRIORITY_HINT)
07843          ast_change_hint(e,tmp);
07844       /* Destroy the old one */
07845       if (e->datad)
07846          e->datad(e->data);
07847       ast_free(e);
07848    } else { /* Slip ourselves in just before e */
07849       tmp->peer = e;
07850       tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
07851       if (ep) {         /* Easy enough, we're just in the peer list */
07852          if (tmp->label) {
07853             ast_hashtab_insert_safe(eh->peer_label_table, tmp);
07854          }
07855          ast_hashtab_insert_safe(eh->peer_table, tmp);
07856          ep->peer = tmp;
07857       } else {       /* we are the first in some peer list, so link in the ext list */
07858          tmp->peer_table = e->peer_table;
07859          tmp->peer_label_table = e->peer_label_table;
07860          e->peer_table = 0;
07861          e->peer_label_table = 0;
07862          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07863          if (tmp->label) {
07864             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07865          }
07866          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07867          ast_hashtab_insert_safe(con->root_table, tmp);
07868          if (el)
07869             el->next = tmp;   /* in the middle... */
07870          else
07871             con->root = tmp; /* ... or at the head */
07872          e->next = NULL;   /* e is no more at the head, so e->next must be reset */
07873       }
07874       /* And immediately return success. */
07875       if (tmp->priority == PRIORITY_HINT) {
07876          if (lockhints) {
07877             ast_add_hint(tmp);
07878          } else {
07879             ast_add_hint_nolock(tmp);
07880          }
07881       }
07882    }
07883    return 0;
07884 }

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

Definition at line 1809 of file pbx.c.

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

Referenced by add_exten_to_pattern_tree().

01810 {
01811    struct match_char *t;
01812 
01813    if (!current) {
01814       return 0;
01815    }
01816 
01817    for (t = current; t; t = t->alt_char) {
01818       if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {/* uh, we may want to sort exploded [] contents to make matching easy */
01819          return t;
01820       }
01821    }
01822 
01823    return 0;
01824 }

int ast_active_calls ( void   ) 

Retrieve the number of active calls.

Definition at line 4934 of file pbx.c.

References countcalls.

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

04935 {
04936    return countcalls;
04937 }

int ast_add_extension ( const char *  context,
int  replace,
const char *  extension,
int  priority,
const char *  label,
const char *  callerid,
const char *  application,
void *  data,
void(*)(void *)  datad,
const char *  registrar 
)

Add and extension to an extension context.

Parameters:
context context to add the extension to
replace 
extension extension to add
priority priority level of extension addition
label extension label
callerid pattern to match CallerID, or NULL to match any CallerID
application application to run on the extension with that priority level
data data to pass to the application
datad 
registrar who registered the extension
Return values:
0 success
-1 failure

Definition at line 7590 of file pbx.c.

References ast_add_extension2(), ast_unlock_contexts(), and find_context_locked().

Referenced by ast_extension_state_add(), handle_cli_dialplan_add_extension(), park_add_hints(), register_exten(), register_peer_exten(), and RegisterExtension().

07593 {
07594    int ret = -1;
07595    struct ast_context *c = find_context_locked(context);
07596 
07597    if (c) {
07598       ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
07599          application, data, datad, registrar);
07600       ast_unlock_contexts();
07601    }
07602 
07603    return ret;
07604 }

int ast_add_extension2 ( struct ast_context con,
int  replace,
const char *  extension,
int  priority,
const char *  label,
const char *  callerid,
const char *  application,
void *  data,
void(*)(void *)  datad,
const char *  registrar 
)

Main interface to add extensions to the list for out context.

Add an extension to an extension context, this time with an ast_context *.

We sort extensions in order of matching preference, so that we can stop the search as soon as we find a suitable match. This ordering also takes care of wildcards such as '.' (meaning "one or more of any character") and '!' (which is 'earlymatch', meaning "zero or more of any character" but also impacts the return value from CANMATCH and EARLYMATCH.

The extension match rules defined in the devmeeting 2006.05.05 are quite simple: WE SELECT THE LONGEST MATCH. In detail, "longest" means the number of matched characters in the extension. In case of ties (e.g. _XXX and 333) in the length of a pattern, we give priority to entries with the smallest cardinality (e.g, [5-9] comes before [2-8] before the former has only 5 elements, while the latter has 7, etc. In case of same cardinality, the first element in the range counts. If we still have a tie, any final '!' will make this as a possibly less specific pattern.

EBUSY - can't lock EEXIST - extension with the same priority exist and no replace is set

Definition at line 7911 of file pbx.c.

References ast_add_extension2_lockopt().

Referenced by add_extensions(), ast_add_extension(), build_parkinglot(), context_merge(), load_config(), load_module(), manage_parkinglot(), park_call_full(), pbx_load_config(), pbx_load_users(), sla_build_station(), and sla_build_trunk().

07915 {
07916    return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
07917 }

static int ast_add_extension2_lockopt ( struct ast_context con,
int  replace,
const char *  extension,
int  priority,
const char *  label,
const char *  callerid,
const char *  application,
void *  data,
void(*)(void *)  datad,
const char *  registrar,
int  lockconts,
int  lockhints 
) [static]

Does all the work of ast_add_extension2, but adds two args, to determine if context and hint locking should be done. In merge_and_delete, we need to do this without locking, as the locks are already held.

Definition at line 7924 of file pbx.c.

References add_exten_to_pattern_tree(), add_pri(), ast_exten::app, ast_add_hint(), ast_add_hint_nolock(), ast_calloc, ast_channel_release(), ast_copy_string(), ast_debug, ast_dummy_channel_alloc(), ast_hashtab_create(), ast_hashtab_insert_safe(), ast_hashtab_lookup(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), ast_log(), ast_strlen_zero(), ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_exten::cidmatch, ast_channel::context, ast_exten::data, ast_exten::datad, el, errno, ext_cmp(), ext_strncpy(), ast_exten::exten, ast_channel::exten, hashtab_compare_exten_labels(), hashtab_compare_exten_numbers(), hashtab_compare_extens(), hashtab_hash_extens(), hashtab_hash_labels(), hashtab_hash_priority(), ast_exten::label, LOG_ERROR, ast_exten::matchcid, ast_context::name, ast_exten::next, option_debug, ast_exten::parent, ast_context::pattern_tree, pbx_substitute_variables_helper(), ast_exten::peer_label_table, ast_exten::peer_table, ast_exten::priority, PRIORITY_HINT, ast_exten::registrar, ast_context::root, ast_context::root_table, ast_exten::stuff, and VAR_BUF_SIZE.

Referenced by ast_add_extension2(), and ast_add_extension_nolock().

07928 {
07929    /*
07930     * Sort extensions (or patterns) according to the rules indicated above.
07931     * These are implemented by the function ext_cmp()).
07932     * All priorities for the same ext/pattern/cid are kept in a list,
07933     * using the 'peer' field  as a link field..
07934     */
07935    struct ast_exten *tmp, *tmp2, *e, *el = NULL;
07936    int res;
07937    int length;
07938    char *p;
07939    char expand_buf[VAR_BUF_SIZE];
07940    struct ast_exten dummy_exten = {0};
07941    char dummy_name[1024];
07942 
07943    if (ast_strlen_zero(extension)) {
07944       ast_log(LOG_ERROR,"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n",
07945             con->name);
07946       return -1;
07947    }
07948 
07949    /* If we are adding a hint evalulate in variables and global variables */
07950    if (priority == PRIORITY_HINT && strstr(application, "${") && !strstr(extension, "_")) {
07951       struct ast_channel *c = ast_dummy_channel_alloc();
07952       ast_copy_string(c->exten, extension, sizeof(c->exten));
07953       ast_copy_string(c->context, con->name, sizeof(c->context));
07954 
07955       pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
07956       application = expand_buf;
07957       ast_channel_release(c);
07958    }
07959 
07960    length = sizeof(struct ast_exten);
07961    length += strlen(extension) + 1;
07962    length += strlen(application) + 1;
07963    if (label)
07964       length += strlen(label) + 1;
07965    if (callerid)
07966       length += strlen(callerid) + 1;
07967    else
07968       length ++;  /* just the '\0' */
07969 
07970    /* Be optimistic:  Build the extension structure first */
07971    if (!(tmp = ast_calloc(1, length)))
07972       return -1;
07973 
07974    if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
07975       label = 0;
07976 
07977    /* use p as dst in assignments, as the fields are const char * */
07978    p = tmp->stuff;
07979    if (label) {
07980       tmp->label = p;
07981       strcpy(p, label);
07982       p += strlen(label) + 1;
07983    }
07984    tmp->exten = p;
07985    p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
07986    tmp->priority = priority;
07987    tmp->cidmatch = p;   /* but use p for assignments below */
07988    if (!ast_strlen_zero(callerid)) {
07989       p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
07990       tmp->matchcid = 1;
07991    } else {
07992       *p++ = '\0';
07993       tmp->matchcid = 0;
07994    }
07995    tmp->app = p;
07996    strcpy(p, application);
07997    tmp->parent = con;
07998    tmp->data = data;
07999    tmp->datad = datad;
08000    tmp->registrar = registrar;
08001 
08002    if (lockconts) {
08003       ast_wrlock_context(con);
08004    }
08005 
08006    if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
08007                         an extension, and the trie exists, then we need to incrementally add this pattern to it. */
08008       ast_copy_string(dummy_name, extension, sizeof(dummy_name));
08009       dummy_exten.exten = dummy_name;
08010       dummy_exten.matchcid = 0;
08011       dummy_exten.cidmatch = 0;
08012       tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
08013       if (!tmp2) {
08014          /* hmmm, not in the trie; */
08015          add_exten_to_pattern_tree(con, tmp, 0);
08016          ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
08017       }
08018    }
08019    res = 0; /* some compilers will think it is uninitialized otherwise */
08020    for (e = con->root; e; el = e, e = e->next) {   /* scan the extension list */
08021       res = ext_cmp(e->exten, tmp->exten);
08022       if (res == 0) { /* extension match, now look at cidmatch */
08023          if (!e->matchcid && !tmp->matchcid)
08024             res = 0;
08025          else if (tmp->matchcid && !e->matchcid)
08026             res = 1;
08027          else if (e->matchcid && !tmp->matchcid)
08028             res = -1;
08029          else
08030             res = ext_cmp(e->cidmatch, tmp->cidmatch);
08031       }
08032       if (res >= 0)
08033          break;
08034    }
08035    if (e && res == 0) { /* exact match, insert in the pri chain */
08036       res = add_pri(con, tmp, el, e, replace);
08037       if (lockconts) {
08038          ast_unlock_context(con);
08039       }
08040       if (res < 0) {
08041          errno = EEXIST;   /* XXX do we care ? */
08042          return 0; /* XXX should we return -1 maybe ? */
08043       }
08044    } else {
08045       /*
08046        * not an exact match, this is the first entry with this pattern,
08047        * so insert in the main list right before 'e' (if any)
08048        */
08049       tmp->next = e;
08050       if (el) {  /* there is another exten already in this context */
08051          el->next = tmp;
08052          tmp->peer_table = ast_hashtab_create(13,
08053                      hashtab_compare_exten_numbers,
08054                      ast_hashtab_resize_java,
08055                      ast_hashtab_newsize_java,
08056                      hashtab_hash_priority,
08057                      0);
08058          tmp->peer_label_table = ast_hashtab_create(7,
08059                         hashtab_compare_exten_labels,
08060                         ast_hashtab_resize_java,
08061                         ast_hashtab_newsize_java,
08062                         hashtab_hash_labels,
08063                         0);
08064          if (label) {
08065             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
08066          }
08067          ast_hashtab_insert_safe(tmp->peer_table, tmp);
08068       } else {  /* this is the first exten in this context */
08069          if (!con->root_table)
08070             con->root_table = ast_hashtab_create(27,
08071                                        hashtab_compare_extens,
08072                                        ast_hashtab_resize_java,
08073                                        ast_hashtab_newsize_java,
08074                                        hashtab_hash_extens,
08075                                        0);
08076          con->root = tmp;
08077          con->root->peer_table = ast_hashtab_create(13,
08078                         hashtab_compare_exten_numbers,
08079                         ast_hashtab_resize_java,
08080                         ast_hashtab_newsize_java,
08081                         hashtab_hash_priority,
08082                         0);
08083          con->root->peer_label_table = ast_hashtab_create(7,
08084                            hashtab_compare_exten_labels,
08085                            ast_hashtab_resize_java,
08086                            ast_hashtab_newsize_java,
08087                            hashtab_hash_labels,
08088                            0);
08089          if (label) {
08090             ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
08091          }
08092          ast_hashtab_insert_safe(con->root->peer_table, tmp);
08093 
08094       }
08095       ast_hashtab_insert_safe(con->root_table, tmp);
08096       if (lockconts) {
08097          ast_unlock_context(con);
08098       }
08099       if (tmp->priority == PRIORITY_HINT) {
08100          if (lockhints) {
08101             ast_add_hint(tmp);
08102          } else {
08103             ast_add_hint_nolock(tmp);
08104          }
08105       }
08106    }
08107    if (option_debug) {
08108       if (tmp->matchcid) {
08109          ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
08110                  tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
08111       } else {
08112          ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
08113                  tmp->exten, tmp->priority, con->name, con);
08114       }
08115    }
08116 
08117    if (tmp->matchcid) {
08118       ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
08119              tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
08120    } else {
08121       ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n",
08122              tmp->exten, tmp->priority, con->name, con);
08123    }
08124 
08125    return 0;
08126 }

static int ast_add_extension_nolock ( const char *  context,
int  replace,
const char *  extension,
int  priority,
const char *  label,
const char *  callerid,
const char *  application,
void *  data,
void(*)(void *)  datad,
const char *  registrar 
) [static]

Definition at line 7571 of file pbx.c.

References ast_add_extension2_lockopt(), and find_context().

Referenced by ast_merge_contexts_and_delete().

07574 {
07575    int ret = -1;
07576    struct ast_context *c = find_context(context);
07577 
07578    if (c) {
07579       ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
07580          application, data, datad, registrar, 0, 0);
07581    }
07582 
07583    return ret;
07584 }

static int ast_add_hint ( struct ast_exten e  )  [static]

Add hint to hint list, check initial extension state.

Definition at line 4376 of file pbx.c.

References ast_add_hint_nolock(), AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by add_pri_lockopt(), and ast_add_extension2_lockopt().

04377 {
04378    int ret;
04379 
04380    AST_RWLIST_WRLOCK(&hints);
04381    ret = ast_add_hint_nolock(e);
04382    AST_RWLIST_UNLOCK(&hints);
04383 
04384    return ret;
04385 }

static int ast_add_hint_nolock ( struct ast_exten e  )  [static]

Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already!

Definition at line 4347 of file pbx.c.

References ast_calloc, ast_debug, ast_extension_state2(), ast_get_extension_app(), ast_get_extension_name(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, ast_hint::exten, and ast_hint::laststate.

Referenced by add_pri_lockopt(), ast_add_extension2_lockopt(), and ast_add_hint().

04348 {
04349    struct ast_hint *hint;
04350 
04351    if (!e)
04352       return -1;
04353 
04354    /* Search if hint exists, do nothing */
04355    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04356       if (hint->exten == e) {
04357          ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
04358          return -1;
04359       }
04360    }
04361 
04362    ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
04363 
04364    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
04365       return -1;
04366    }
04367    /* Initialize and insert new item at the top */
04368    hint->exten = e;
04369    hint->laststate = ast_extension_state2(e);
04370    AST_RWLIST_INSERT_HEAD(&hints, hint, list);
04371 
04372    return 0;
04373 }

int ast_async_goto ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority 
)

Set the channel to next execute the specified dialplan location.

See also:
ast_async_parseable_goto, ast_async_goto_if_exists

Definition at line 7629 of file pbx.c.

References ast_channel::_state, ast_channel::accountcode, ast_channel::amaflags, ast_cdr_discard(), ast_cdr_dup(), ast_channel_alloc, ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_explicit_goto(), ast_hangup(), ast_log(), ast_pbx_start(), AST_SOFTHANGUP_ASYNCGOTO, ast_softhangup_nolock(), ast_channel::cdr, ast_channel::context, ast_channel::exten, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_channel::pbx, ast_channel::readformat, S_OR, and ast_channel::writeformat.

Referenced by __ast_goto_if_exists(), action_redirect(), ast_async_goto_by_name(), builtin_blindtransfer(), change_t38_state(), console_transfer(), dahdi_handle_dtmfup(), handle_request_bye(), handle_request_refer(), my_handle_dtmfup(), pbx_parseable_goto(), process_ast_dsp(), and socket_process().

07630 {
07631    int res = 0;
07632 
07633    ast_channel_lock(chan);
07634 
07635    if (chan->pbx) { /* This channel is currently in the PBX */
07636       ast_explicit_goto(chan, context, exten, priority + 1);
07637       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
07638    } else {
07639       /* In order to do it when the channel doesn't really exist within
07640          the PBX, we have to make a new channel, masquerade, and start the PBX
07641          at the new location */
07642       struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->linkedid, chan->amaflags, "AsyncGoto/%s", chan->name);
07643       if (!tmpchan) {
07644          res = -1;
07645       } else {
07646          if (chan->cdr) {
07647             ast_cdr_discard(tmpchan->cdr);
07648             tmpchan->cdr = ast_cdr_dup(chan->cdr);  /* share the love */
07649          }
07650          /* Make formats okay */
07651          tmpchan->readformat = chan->readformat;
07652          tmpchan->writeformat = chan->writeformat;
07653          /* Setup proper location */
07654          ast_explicit_goto(tmpchan,
07655             S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
07656 
07657          /* Masquerade into temp channel */
07658          if (ast_channel_masquerade(tmpchan, chan)) {
07659             /* Failed to set up the masquerade.  It's probably chan_local
07660              * in the middle of optimizing itself out.  Sad. :( */
07661             ast_hangup(tmpchan);
07662             tmpchan = NULL;
07663             res = -1;
07664          } else {
07665             /* it may appear odd to unlock chan here since the masquerade is on
07666              * tmpchan, but no channel locks should be held when doing a masquerade
07667              * since a masquerade requires a lock on the channels ao2 container. */
07668             ast_channel_unlock(chan);
07669             ast_do_masquerade(tmpchan);
07670             ast_channel_lock(chan);
07671             /* Start the PBX going on our stolen channel */
07672             if (ast_pbx_start(tmpchan)) {
07673                ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
07674                ast_hangup(tmpchan);
07675                res = -1;
07676             }
07677          }
07678       }
07679    }
07680    ast_channel_unlock(chan);
07681    return res;
07682 }

int ast_async_goto_by_name ( const char *  channame,
const char *  context,
const char *  exten,
int  priority 
)

Set the channel to next execute the specified dialplan location.

Definition at line 7684 of file pbx.c.

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

07685 {
07686    struct ast_channel *chan;
07687    int res = -1;
07688 
07689    if ((chan = ast_channel_get_by_name(channame))) {
07690       res = ast_async_goto(chan, context, exten, priority);
07691       chan = ast_channel_unref(chan);
07692    }
07693 
07694    return res;
07695 }

int ast_async_goto_if_exists ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority 
)

Note:
This function will handle locking the channel as needed.

Definition at line 9847 of file pbx.c.

References __ast_goto_if_exists().

09848 {
09849    return __ast_goto_if_exists(chan, context, exten, priority, 1);
09850 }

int ast_async_parseable_goto ( struct ast_channel chan,
const char *  goto_string 
)

Note:
This function will handle locking the channel as needed.

Definition at line 9910 of file pbx.c.

References pbx_parseable_goto().

Referenced by asyncgoto_exec(), and handle_redirect().

09911 {
09912    return pbx_parseable_goto(chan, goto_string, 1);
09913 }

int ast_build_timing ( struct ast_timing i,
const char *  info 
)

Construct a timing bitmap, for use in time-based conditionals.

Parameters:
i Pointer to an ast_timing structure.
info Standard string containing a timerange, weekday range, monthday range, and month range, as well as an optional timezone.
Return values:
Returns 1 on success or 0 on failure.

Definition at line 7224 of file pbx.c.

References ast_strdup, ast_strdupa, ast_strlen_zero(), ast_timing::daymask, days, ast_timing::dowmask, get_range(), get_timerange(), ast_timing::monthmask, months, strsep(), and ast_timing::timezone.

Referenced by ast_context_add_include2(), iftime(), pbx_builtin_execiftime(), and pbx_builtin_gotoiftime().

07225 {
07226    char *info_save, *info;
07227    int j, num_fields, last_sep = -1;
07228 
07229    /* Check for empty just in case */
07230    if (ast_strlen_zero(info_in)) {
07231       return 0;
07232    }
07233 
07234    /* make a copy just in case we were passed a static string */
07235    info_save = info = ast_strdupa(info_in);
07236 
07237    /* count the number of fields in the timespec */
07238    for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
07239       if (info[j] == ',') {
07240          last_sep = j;
07241          num_fields++;
07242       }
07243    }
07244 
07245    /* save the timezone, if it is specified */
07246    if (num_fields == 5) {
07247       i->timezone = ast_strdup(info + last_sep + 1);
07248    } else {
07249       i->timezone = NULL;
07250    }
07251 
07252    /* Assume everything except time */
07253    i->monthmask = 0xfff;   /* 12 bits */
07254    i->daymask = 0x7fffffffU; /* 31 bits */
07255    i->dowmask = 0x7f; /* 7 bits */
07256    /* on each call, use strsep() to move info to the next argument */
07257    get_timerange(i, strsep(&info, "|,"));
07258    if (info)
07259       i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
07260    if (info)
07261       i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
07262    if (info)
07263       i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
07264    return 1;
07265 }

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

Looks for a valid matching extension.

Parameters:
c not really important
context context to serach within
exten extension to check
priority priority of extension path
callerid callerid of extension being searched for
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 4495 of file pbx.c.

References E_CANMATCH, and pbx_extension_helper().

Referenced by __analog_ss_thread(), analog_ss_thread(), background_detect_exec(), cb_events(), do_immediate_setup(), dp_lookup(), dundi_lookup_local(), get_also_info(), get_destination(), handle_link_data(), handle_link_phone_dtmf(), leave_voicemail(), local_dtmf_helper(), loopback_canmatch(), mgcp_ss(), phone_check_exception(), skinny_ss(), and valid_exit().

04496 {
04497    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
04498 }

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

Change hint for an extension.

Definition at line 4388 of file pbx.c.

References AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_hint::exten.

Referenced by add_pri_lockopt().

04389 {
04390    struct ast_hint *hint;
04391    int res = -1;
04392 
04393    AST_RWLIST_WRLOCK(&hints);
04394    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04395       if (hint->exten == oe) {
04396          hint->exten = ne;
04397          res = 0;
04398          break;
04399       }
04400    }
04401    AST_RWLIST_UNLOCK(&hints);
04402 
04403    return res;
04404 }

int ast_check_timing ( const struct ast_timing i  ) 

Evaluate a pre-constructed bitmap as to whether the current time falls within the range specified.

Parameters:
i Pointer to an ast_timing structure.
Return values:
Returns 1, if the time matches or 0, if the current time falls outside of the specified range.

Definition at line 7267 of file pbx.c.

References ast_localtime(), ast_log(), ast_tvnow(), ast_timing::daymask, ast_timing::dowmask, LOG_WARNING, ast_timing::minmask, ast_timing::monthmask, ast_timing::timezone, ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, and ast_tm::tm_wday.

Referenced by iftime(), include_valid(), pbx_builtin_execiftime(), and pbx_builtin_gotoiftime().

07268 {
07269    struct ast_tm tm;
07270    struct timeval now = ast_tvnow();
07271 
07272    ast_localtime(&now, &tm, i->timezone);
07273 
07274    /* If it's not the right month, return */
07275    if (!(i->monthmask & (1 << tm.tm_mon)))
07276       return 0;
07277 
07278    /* If it's not that time of the month.... */
07279    /* Warning, tm_mday has range 1..31! */
07280    if (!(i->daymask & (1 << (tm.tm_mday-1))))
07281       return 0;
07282 
07283    /* If it's not the right day of the week */
07284    if (!(i->dowmask & (1 << tm.tm_wday)))
07285       return 0;
07286 
07287    /* Sanity check the hour just to be safe */
07288    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
07289       ast_log(LOG_WARNING, "Insane time...\n");
07290       return 0;
07291    }
07292 
07293    /* Now the tough part, we calculate if it fits
07294       in the right time based on min/hour */
07295    if (!(i->minmask[tm.tm_hour * 2 + (tm.tm_min >= 30 ? 1 : 0)] & (1 << (tm.tm_min >= 30 ? tm.tm_min - 30 : tm.tm_min))))
07296       return 0;
07297 
07298    /* If we got this far, then we're good */
07299    return 1;
07300 }

char* ast_complete_applications ( const char *  line,
const char *  word,
int  state 
)

Command completion for the list of installed applications.

This can be called from a CLI command completion function that wants to complete from the list of available applications.

Definition at line 9915 of file pbx.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, and ast_app::name.

Referenced by handle_orig(), and handle_show_application().

09916 {
09917    struct ast_app *app = NULL;
09918    int which = 0;
09919    char *ret = NULL;
09920    size_t wordlen = strlen(word);
09921 
09922    AST_RWLIST_RDLOCK(&apps);
09923    AST_RWLIST_TRAVERSE(&apps, app, list) {
09924       if (!strncasecmp(word, app->name, wordlen) && ++which > state) {
09925          ret = ast_strdup(app->name);
09926          break;
09927       }
09928    }
09929    AST_RWLIST_UNLOCK(&apps);
09930 
09931    return ret;
09932 }

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

Add an ignorepat.

Parameters:
context which context to add the ignorpattern to
ignorepat ignorepattern to set up for the extension
registrar registrar of the ignore pattern
Adds an ignore pattern to a particular context.

Return values:
0 on success
-1 on failure

Definition at line 7502 of file pbx.c.

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

Referenced by handle_cli_dialplan_add_ignorepat().

07503 {
07504    int ret = -1;
07505    struct ast_context *c = find_context_locked(context);
07506 
07507    if (c) {
07508       ret = ast_context_add_ignorepat2(c, value, registrar);
07509       ast_unlock_contexts();
07510    }
07511    return ret;
07512 }

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

Definition at line 7514 of file pbx.c.

References ast_calloc, ast_unlock_context(), ast_wrlock_context(), errno, ast_context::ignorepats, ast_ignorepat::next, ast_ignorepat::pattern, and ast_ignorepat::registrar.

Referenced by ast_compile_ael2(), ast_context_add_ignorepat(), context_merge_incls_swits_igps_other_registrars(), and pbx_load_config().

07515 {
07516    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
07517    int length;
07518    char *pattern;
07519    length = sizeof(struct ast_ignorepat);
07520    length += strlen(value) + 1;
07521    if (!(ignorepat = ast_calloc(1, length)))
07522       return -1;
07523    /* The cast to char * is because we need to write the initial value.
07524     * The field is not supposed to be modified otherwise.  Also, gcc 4.2
07525     * sees the cast as dereferencing a type-punned pointer and warns about
07526     * it.  This is the workaround (we're telling gcc, yes, that's really
07527     * what we wanted to do).
07528     */
07529    pattern = (char *) ignorepat->pattern;
07530    strcpy(pattern, value);
07531    ignorepat->next = NULL;
07532    ignorepat->registrar = registrar;
07533    ast_wrlock_context(con);
07534    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
07535       ignorepatl = ignorepatc;
07536       if (!strcasecmp(ignorepatc->pattern, value)) {
07537          /* Already there */
07538          ast_unlock_context(con);
07539          errno = EEXIST;
07540          return -1;
07541       }
07542    }
07543    if (ignorepatl)
07544       ignorepatl->next = ignorepat;
07545    else
07546       con->ignorepats = ignorepat;
07547    ast_unlock_context(con);
07548    return 0;
07549 
07550 }

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

Add a context include.

Parameters:
context context to add include to
include new include to add
registrar who's registering it
Adds an include taking a char * string as the context parameter

Return values:
0 on success
-1 on error

Definition at line 7053 of file pbx.c.

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

Referenced by handle_cli_dialplan_add_include().

07054 {
07055    int ret = -1;
07056    struct ast_context *c = find_context_locked(context);
07057 
07058    if (c) {
07059       ret = ast_context_add_include2(c, include, registrar);
07060       ast_unlock_contexts();
07061    }
07062    return ret;
07063 }

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

Add a context include.

Parameters:
con context to add the include to
include include to add
registrar who registered the context
Adds an include taking a struct ast_context as the first parameter

Return values:
0 on success
-1 on failure

Definition at line 7317 of file pbx.c.

References ast_build_timing(), ast_calloc, ast_destroy_timing(), ast_free, ast_get_context_name(), ast_unlock_context(), ast_verb, ast_wrlock_context(), errno, ast_include::hastime, ast_context::includes, ast_include::name, ast_include::next, ast_include::registrar, ast_include::rname, ast_include::stuff, and ast_include::timing.

Referenced by ast_compile_ael2(), ast_context_add_include(), context_merge_incls_swits_igps_other_registrars(), and pbx_load_config().

07319 {
07320    struct ast_include *new_include;
07321    char *c;
07322    struct ast_include *i, *il = NULL; /* include, include_last */
07323    int length;
07324    char *p;
07325 
07326    length = sizeof(struct ast_include);
07327    length += 2 * (strlen(value) + 1);
07328 
07329    /* allocate new include structure ... */
07330    if (!(new_include = ast_calloc(1, length)))
07331       return -1;
07332    /* Fill in this structure. Use 'p' for assignments, as the fields
07333     * in the structure are 'const char *'
07334     */
07335    p = new_include->stuff;
07336    new_include->name = p;
07337    strcpy(p, value);
07338    p += strlen(value) + 1;
07339    new_include->rname = p;
07340    strcpy(p, value);
07341    /* Strip off timing info, and process if it is there */
07342    if ( (c = strchr(p, ',')) ) {
07343       *c++ = '\0';
07344       new_include->hastime = ast_build_timing(&(new_include->timing), c);
07345    }
07346    new_include->next      = NULL;
07347    new_include->registrar = registrar;
07348 
07349    ast_wrlock_context(con);
07350 
07351    /* ... go to last include and check if context is already included too... */
07352    for (i = con->includes; i; i = i->next) {
07353       if (!strcasecmp(i->name, new_include->name)) {
07354          ast_destroy_timing(&(new_include->timing));
07355          ast_free(new_include);
07356          ast_unlock_context(con);
07357          errno = EEXIST;
07358          return -1;
07359       }
07360       il = i;
07361    }
07362 
07363    /* ... include new context into context list, unlock, return */
07364    if (il)
07365       il->next = new_include;
07366    else
07367       con->includes = new_include;
07368    ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
07369 
07370    ast_unlock_context(con);
07371 
07372    return 0;
07373 }

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

Add a switch.

Parameters:
context context to which to add the switch
sw switch to add
data data to pass to switch
eval whether to evaluate variables when running switch
registrar whoever registered the switch
This function registers a switch with the asterisk switch architecture

Return values:
0 on success
-1 on failure

Definition at line 7380 of file pbx.c.

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

07381 {
07382    int ret = -1;
07383    struct ast_context *c = find_context_locked(context);
07384 
07385    if (c) { /* found, add switch to this context */
07386       ret = ast_context_add_switch2(c, sw, data, eval, registrar);
07387       ast_unlock_contexts();
07388    }
07389    return ret;
07390 }

int ast_context_add_switch2 ( struct ast_context con,
const char *  sw,
const char *  data,
int  eval,
const char *  registrar 
)

Adds a switch (first param is a ast_context).

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

Definition at line 7399 of file pbx.c.

References ast_context::alts, ast_calloc, ast_free, ast_get_context_name(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_sw::data, errno, ast_sw::eval, ast_sw::name, ast_sw::registrar, and ast_sw::stuff.

Referenced by ast_compile_ael2(), ast_context_add_switch(), context_merge_incls_swits_igps_other_registrars(), lua_register_switches(), and pbx_load_config().

07401 {
07402    struct ast_sw *new_sw;
07403    struct ast_sw *i;
07404    int length;
07405    char *p;
07406 
07407    length = sizeof(struct ast_sw);
07408    length += strlen(value) + 1;
07409    if (data)
07410       length += strlen(data);
07411    length++;
07412 
07413    /* allocate new sw structure ... */
07414    if (!(new_sw = ast_calloc(1, length)))
07415       return -1;
07416    /* ... fill in this structure ... */
07417    p = new_sw->stuff;
07418    new_sw->name = p;
07419    strcpy(new_sw->name, value);
07420    p += strlen(value) + 1;
07421    new_sw->data = p;
07422    if (data) {
07423       strcpy(new_sw->data, data);
07424       p += strlen(data) + 1;
07425    } else {
07426       strcpy(new_sw->data, "");
07427       p++;
07428    }
07429    new_sw->eval     = eval;
07430    new_sw->registrar = registrar;
07431 
07432    /* ... try to lock this context ... */
07433    ast_wrlock_context(con);
07434 
07435    /* ... go to last sw and check if context is already swd too... */
07436    AST_LIST_TRAVERSE(&con->alts, i, list) {
07437       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
07438          ast_free(new_sw);
07439          ast_unlock_context(con);
07440          errno = EEXIST;
07441          return -1;
07442       }
07443    }
07444 
07445    /* ... sw new context into context list, unlock, return */
07446    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
07447 
07448    ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
07449 
07450    ast_unlock_context(con);
07451 
07452    return 0;
07453 }

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

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

Parameters:
con context to destroy
registrar who registered it
You can optionally leave out either parameter. It will find it based on either the ast_context or the registrar name.

Returns:
nothing

Definition at line 8702 of file pbx.c.

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

Referenced by __unload_module(), cleanup_stale_contexts(), parkinglot_destroy(), sla_destroy(), and unload_module().

struct ast_context* ast_context_find ( const char *  name  )  [read]

Find a context.

Parameters:
name name 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 2454 of file pbx.c.

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

Referenced by __unload_module(), _macro_exec(), ast_context_verify_includes(), ast_ignore_pattern(), cleanup_stale_contexts(), isexten_function_read(), load_config(), manage_parkinglot(), park_exec_full(), parkinglot_destroy(), register_exten(), register_peer_exten(), unload_module(), and unregister_exten().

02455 {
02456    struct ast_context *tmp = NULL;
02457    struct fake_context item;
02458 
02459    ast_copy_string(item.name, name, sizeof(item.name));
02460 
02461    ast_rdlock_contexts();
02462    if( contexts_table ) {
02463       tmp = ast_hashtab_lookup(contexts_table,&item);
02464    } else {
02465       while ( (tmp = ast_walk_contexts(tmp)) ) {
02466          if (!name || !strcasecmp(name, tmp->name)) {
02467             break;
02468          }
02469       }
02470    }
02471    ast_unlock_contexts();
02472    return tmp;
02473 }

struct ast_context* ast_context_find_or_create ( struct ast_context **  extcontexts,
struct ast_hashtab exttable,
const char *  name,
const char *  registrar 
) [read]

Register a new context or find an existing one.

Parameters:
extcontexts pointer to the ast_context structure pointer
exttable pointer to the hashtable that contains all the elements in extcontexts
name name of the new context
registrar registrar of the context
This function allows you to play in two environments: the global contexts (active dialplan) or an external context set of your choosing. To act on the external set, make sure extcontexts and exttable are set; for the globals, make sure both extcontexts and exttable are NULL.

This will first search for a context with your name. If it exists already, it will not create a new one. If it does not exist, it will create a new one with the given name and registrar.

Returns:
NULL on failure, and an ast_context structure on success

Definition at line 6710 of file pbx.c.

References ast_calloc, ast_copy_string(), ast_debug, ast_hashtab_compare_contexts(), ast_hashtab_create(), ast_hashtab_hash_contexts(), ast_hashtab_insert_immediate(), ast_hashtab_insert_safe(), ast_hashtab_lookup(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), ast_log(), ast_mutex_init(), ast_rdlock_contexts(), ast_rwlock_init(), ast_strdup, ast_unlock_contexts(), ast_verb, ast_wrlock_contexts(), contexts, contexts_table, ast_context::ignorepats, ast_context::includes, local_contexts, ast_context::lock, LOG_ERROR, ast_context::macrolock, ast_context::name, fake_context::name, ast_context::next, ast_context::refcount, ast_context::registrar, ast_context::root, and ast_context::root_table.

Referenced by ast_compile_ael2(), build_parkinglot(), config_parse_variables(), context_merge(), load_config(), load_module(), lua_register_switches(), manage_parkinglot(), park_call_full(), pbx_load_config(), pbx_load_users(), reload_config(), set_config(), sla_build_station(), and sla_build_trunk().

06711 {
06712    struct ast_context *tmp, **local_contexts;
06713    struct fake_context search;
06714    int length = sizeof(struct ast_context) + strlen(name) + 1;
06715 
06716    if (!contexts_table) {
06717       contexts_table = ast_hashtab_create(17,
06718                                  ast_hashtab_compare_contexts,
06719                                  ast_hashtab_resize_java,
06720                                  ast_hashtab_newsize_java,
06721                                  ast_hashtab_hash_contexts,
06722                                  0);
06723    }
06724 
06725    ast_copy_string(search.name, name, sizeof(search.name));
06726    if (!extcontexts) {
06727       ast_rdlock_contexts();
06728       local_contexts = &contexts;
06729       tmp = ast_hashtab_lookup(contexts_table, &search);
06730       ast_unlock_contexts();
06731       if (tmp) {
06732          tmp->refcount++;
06733          return tmp;
06734       }
06735    } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
06736       local_contexts = extcontexts;
06737       tmp = ast_hashtab_lookup(exttable, &search);
06738       if (tmp) {
06739          tmp->refcount++;
06740          return tmp;
06741       }
06742    }
06743 
06744    if ((tmp = ast_calloc(1, length))) {
06745       ast_rwlock_init(&tmp->lock);
06746       ast_mutex_init(&tmp->macrolock);
06747       strcpy(tmp->name, name);
06748       tmp->root = NULL;
06749       tmp->root_table = NULL;
06750       tmp->registrar = ast_strdup(registrar);
06751       tmp->includes = NULL;
06752       tmp->ignorepats = NULL;
06753       tmp->refcount = 1;
06754    } else {
06755       ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
06756       return NULL;
06757    }
06758 
06759    if (!extcontexts) {
06760       ast_wrlock_contexts();
06761       tmp->next = *local_contexts;
06762       *local_contexts = tmp;
06763       ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
06764       ast_unlock_contexts();
06765       ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
06766       ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
06767    } else {
06768       tmp->next = *local_contexts;
06769       if (exttable)
06770          ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
06771 
06772       *local_contexts = tmp;
06773       ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
06774       ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
06775    }
06776    return tmp;
06777 }

int ast_context_lockmacro ( const char *  context  ) 

locks the macrolock in the given given context

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

References ast_copy_string(), ast_hashtab_lookup(), ast_mutex_lock(), ast_rdlock_contexts(), ast_unlock_contexts(), contexts_table, ast_context::macrolock, and fake_context::name.

Referenced by _macro_exec().

05315 {
05316    struct ast_context *c = NULL;
05317    int ret = -1;
05318    struct fake_context item;
05319 
05320    ast_rdlock_contexts();
05321 
05322    ast_copy_string(item.name, context, sizeof(item.name));
05323 
05324    c = ast_hashtab_lookup(contexts_table,&item);
05325    if (c)
05326       ret = 0;
05327    ast_unlock_contexts();
05328 
05329    /* if we found context, lock macrolock */
05330    if (ret == 0) {
05331       ret = ast_mutex_lock(&c->macrolock);
05332    }
05333 
05334    return ret;
05335 }

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

Simply remove extension from context.

Parameters:
context context to remove extension from
extension which extension to remove
priority priority of extension to remove (0 to remove all)
callerid NULL to remove all; non-NULL to match a single record per priority
matchcid non-zero to match callerid element (if non-NULL); 0 to match default case
registrar registrar of the extension
This function removes an extension from a given context.

Return values:
0 on success
-1 on failure

Definition at line 5122 of file pbx.c.

References ast_context_remove_extension_callerid().

Referenced by destroy_station(), destroy_trunk(), register_peer_exten(), unregister_exten(), and UnregisterExtension().

05123 {
05124    return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
05125 }

int ast_context_remove_extension2 ( struct ast_context con,
const char *  extension,
int  priority,
const char *  registrar,
int  already_locked 
)

This functionc locks given context, search for the right extension and fires out all peer in this extensions with given priority. If priority is set to 0, all peers are removed. After that, unlock context and return.

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

References ast_context_remove_extension_callerid2().

Referenced by load_config(), manage_parkinglot(), park_exec_full(), and unload_module().

05150 {
05151    return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked);
05152 }

int ast_context_remove_extension_callerid ( const char *  context,
const char *  extension,
int  priority,
const char *  callerid,
int  matchcallerid,
const char *  registrar 
)

Definition at line 5127 of file pbx.c.

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

Referenced by ast_context_remove_extension(), and handle_cli_dialplan_remove_extension().

05128 {
05129    int ret = -1; /* default error return */
05130    struct ast_context *c = find_context_locked(context);
05131 
05132    if (c) { /* ... remove extension ... */
05133       ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcallerid, registrar, 1);
05134       ast_unlock_contexts();
05135    }
05136    return ret;
05137 }

int ast_context_remove_extension_callerid2 ( struct ast_context con,
const char *  extension,
int  priority,
const char *  callerid,
int  matchcallerid,
const char *  registrar,
int  already_locked 
)

Definition at line 5154 of file pbx.c.

References add_exten_to_pattern_tree(), ast_copy_string(), ast_hashtab_insert_immediate(), ast_hashtab_lookup(), ast_hashtab_remove_this_object(), ast_hashtab_size(), ast_log(), ast_strlen_zero(), ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_exten::cidmatch, match_char::deleted, destroy_exten(), match_char::exten, ast_exten::exten, ast_exten::label, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_exten::matchcid, ast_context::name, ast_exten::next, ast_context::pattern_tree, ast_exten::peer, ast_exten::peer_label_table, ast_exten::peer_table, ast_exten::priority, ast_exten::registrar, ast_context::root, ast_context::root_table, and match_char::x.

Referenced by __ast_context_destroy(), ast_context_remove_extension2(), and ast_context_remove_extension_callerid().

05155 {
05156    struct ast_exten *exten, *prev_exten = NULL;
05157    struct ast_exten *peer;
05158    struct ast_exten ex, *exten2, *exten3;
05159    char dummy_name[1024];
05160    struct ast_exten *previous_peer = NULL;
05161    struct ast_exten *next_peer = NULL;
05162    int found = 0;
05163 
05164    if (!already_locked)
05165       ast_wrlock_context(con);
05166 
05167    /* Handle this is in the new world */
05168 
05169    /* FIXME For backwards compatibility, if callerid==NULL, then remove ALL
05170     * peers, not just those matching the callerid. */
05171 #ifdef NEED_DEBUG
05172    ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
05173 #endif
05174 #ifdef CONTEXT_DEBUG
05175    check_contexts(__FILE__, __LINE__);
05176 #endif
05177    /* find this particular extension */
05178    ex.exten = dummy_name;
05179    ex.matchcid = matchcallerid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */
05180    ex.cidmatch = callerid;
05181    ast_copy_string(dummy_name, extension, sizeof(dummy_name));
05182    exten = ast_hashtab_lookup(con->root_table, &ex);
05183    if (exten) {
05184       if (priority == 0) {
05185          exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
05186          if (!exten2)
05187             ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name);
05188          if (con->pattern_tree) {
05189             struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
05190 
05191             if (x->exten) { /* this test for safety purposes */
05192                x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
05193                x->exten = 0; /* get rid of what will become a bad pointer */
05194             } else {
05195                ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
05196             }
05197          }
05198       } else {
05199          ex.priority = priority;
05200          exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
05201          if (exten2) {
05202 
05203             if (exten2->label) { /* if this exten has a label, remove that, too */
05204                exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
05205                if (!exten3)
05206                   ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
05207             }
05208 
05209             exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
05210             if (!exten3)
05211                ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
05212             if (exten2 == exten && exten2->peer) {
05213                exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
05214                ast_hashtab_insert_immediate(con->root_table, exten2->peer);
05215             }
05216             if (ast_hashtab_size(exten->peer_table) == 0) {
05217                /* well, if the last priority of an exten is to be removed,
05218                   then, the extension is removed, too! */
05219                exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
05220                if (!exten3)
05221                   ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
05222                if (con->pattern_tree) {
05223                   struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
05224                   if (x->exten) { /* this test for safety purposes */
05225                      x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
05226                      x->exten = 0; /* get rid of what will become a bad pointer */
05227                   }
05228                }
05229             }
05230          } else {
05231             ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
05232                   priority, exten->exten, con->name);
05233          }
05234       }
05235    } else {
05236       /* hmmm? this exten is not in this pattern tree? */
05237       ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
05238             extension, con->name);
05239    }
05240 #ifdef NEED_DEBUG
05241    if (con->pattern_tree) {
05242       ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
05243       log_match_char_tree(con->pattern_tree, " ");
05244    }
05245 #endif
05246 
05247    /* scan the extension list to find first matching extension-registrar */
05248    for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
05249       if (!strcmp(exten->exten, extension) &&
05250          (!registrar || !strcmp(exten->registrar, registrar)) &&
05251          (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
05252          break;
05253    }
05254    if (!exten) {
05255       /* we can't find right extension */
05256       if (!already_locked)
05257          ast_unlock_context(con);
05258       return -1;
05259    }
05260 
05261    /* scan the priority list to remove extension with exten->priority == priority */
05262    for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
05263        peer && !strcmp(peer->exten, extension) && (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(peer->cidmatch) && !strcmp(peer->cidmatch,callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(peer->cidmatch)));
05264          peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
05265       if ((priority == 0 || peer->priority == priority) &&
05266             (!callerid || !matchcallerid || (matchcallerid && !strcmp(peer->cidmatch, callerid))) &&
05267             (!registrar || !strcmp(peer->registrar, registrar) )) {
05268          found = 1;
05269 
05270          /* we are first priority extension? */
05271          if (!previous_peer) {
05272             /*
05273              * We are first in the priority chain, so must update the extension chain.
05274              * The next node is either the next priority or the next extension
05275              */
05276             struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
05277             if (peer->peer) {
05278                /* move the peer_table and peer_label_table down to the next peer, if
05279                   it is there */
05280                peer->peer->peer_table = peer->peer_table;
05281                peer->peer->peer_label_table = peer->peer_label_table;
05282                peer->peer_table = NULL;
05283                peer->peer_label_table = NULL;
05284             }
05285             if (!prev_exten) {   /* change the root... */
05286                con->root = next_node;
05287             } else {
05288                prev_exten->next = next_node; /* unlink */
05289             }
05290             if (peer->peer)   { /* update the new head of the pri list */
05291                peer->peer->next = peer->next;
05292             }
05293          } else { /* easy, we are not first priority in extension */
05294             previous_peer->peer = peer->peer;
05295          }
05296 
05297          /* now, free whole priority extension */
05298          destroy_exten(peer);
05299       } else {
05300          previous_peer = peer;
05301       }
05302    }
05303    if (!already_locked)
05304       ast_unlock_context(con);
05305    return found ? 0 : -1;
05306 }

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

Definition at line 7459 of file pbx.c.

References ast_context_remove_ignorepat2(), ast_unlock_contexts(), and find_context_locked().

Referenced by handle_cli_dialplan_remove_ignorepat().

07460 {
07461    int ret = -1;
07462    struct ast_context *c = find_context_locked(context);
07463 
07464    if (c) {
07465       ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
07466       ast_unlock_contexts();
07467    }
07468    return ret;
07469 }

int ast_context_remove_ignorepat2 ( struct ast_context con,
const char *  ignorepat,
const char *  registrar 
)

Definition at line 7471 of file pbx.c.

References ast_free, ast_unlock_context(), ast_wrlock_context(), errno, ast_context::ignorepats, ast_ignorepat::next, ast_ignorepat::pattern, and ast_ignorepat::registrar.

Referenced by ast_context_remove_ignorepat().

07472 {
07473    struct ast_ignorepat *ip, *ipl = NULL;
07474 
07475    ast_wrlock_context(con);
07476 
07477    for (ip = con->ignorepats; ip; ip = ip->next) {
07478       if (!strcmp(ip->pattern, ignorepat) &&
07479          (!registrar || (registrar == ip->registrar))) {
07480          if (ipl) {
07481             ipl->next = ip->next;
07482             ast_free(ip);
07483          } else {
07484             con->ignorepats = ip->next;
07485             ast_free(ip);
07486          }
07487          ast_unlock_context(con);
07488          return 0;
07489       }
07490       ipl = ip;
07491    }
07492 
07493    ast_unlock_context(con);
07494    errno = EINVAL;
07495    return -1;
07496 }

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

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

Remove a context include.

Definition at line 5013 of file pbx.c.

References ast_context_remove_include2(), ast_unlock_contexts(), and find_context_locked().

Referenced by handle_cli_dialplan_remove_include().

05014 {
05015    int ret = -1;
05016    struct ast_context *c = find_context_locked(context);
05017 
05018    if (c) {
05019       /* found, remove include from this context ... */
05020       ret = ast_context_remove_include2(c, include, registrar);
05021       ast_unlock_contexts();
05022    }
05023    return ret;
05024 }

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

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

Removes an include by an ast_context structure.

Return values:
0 on success.
-1 on failure.

Definition at line 5035 of file pbx.c.

References ast_destroy_timing(), ast_free, ast_get_context_name(), ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_context::includes, ast_include::name, ast_include::next, ast_include::registrar, and ast_include::timing.

Referenced by ast_context_remove_include().

05036 {
05037    struct ast_include *i, *pi = NULL;
05038    int ret = -1;
05039 
05040    ast_wrlock_context(con);
05041 
05042    /* find our include */
05043    for (i = con->includes; i; pi = i, i = i->next) {
05044       if (!strcmp(i->name, include) &&
05045             (!registrar || !strcmp(i->registrar, registrar))) {
05046          /* remove from list */
05047          ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
05048          if (pi)
05049             pi->next = i->next;
05050          else
05051             con->includes = i->next;
05052          /* free include and return */
05053          ast_destroy_timing(&(i->timing));
05054          ast_free(i);
05055          ret = 0;
05056          break;
05057       }
05058    }
05059 
05060    ast_unlock_context(con);
05061 
05062    return ret;
05063 }

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

Remove a switch.

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

Definition at line 5070 of file pbx.c.

References ast_context_remove_switch2(), ast_unlock_contexts(), and find_context_locked().

05071 {
05072    int ret = -1; /* default error return */
05073    struct ast_context *c = find_context_locked(context);
05074 
05075    if (c) {
05076       /* remove switch from this context ... */
05077       ret = ast_context_remove_switch2(c, sw, data, registrar);
05078       ast_unlock_contexts();
05079    }
05080    return ret;
05081 }

int ast_context_remove_switch2 ( struct ast_context con,
const char *  sw,
const char *  data,
const char *  registrar 
)

This function locks given context, removes switch, unlock context and return.

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

References ast_context::alts, ast_free, ast_get_context_name(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_sw::data, ast_sw::name, and ast_sw::registrar.

Referenced by ast_context_remove_switch().

05092 {
05093    struct ast_sw *i;
05094    int ret = -1;
05095 
05096    ast_wrlock_context(con);
05097 
05098    /* walk switches */
05099    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
05100       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
05101          (!registrar || !strcmp(i->registrar, registrar))) {
05102          /* found, remove from list */
05103          ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
05104          AST_LIST_REMOVE_CURRENT(list);
05105          ast_free(i); /* free switch and return */
05106          ret = 0;
05107          break;
05108       }
05109    }
05110    AST_LIST_TRAVERSE_SAFE_END;
05111 
05112    ast_unlock_context(con);
05113 
05114    return ret;
05115 }

int ast_context_unlockmacro ( const char *  context  ) 

Unlocks the macrolock in the given context.

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

References ast_copy_string(), ast_hashtab_lookup(), ast_mutex_unlock(), ast_rdlock_contexts(), ast_unlock_contexts(), contexts_table, ast_context::macrolock, and fake_context::name.

Referenced by _macro_exec().

05343 {
05344    struct ast_context *c = NULL;
05345    int ret = -1;
05346    struct fake_context item;
05347 
05348    ast_rdlock_contexts();
05349 
05350    ast_copy_string(item.name, context, sizeof(item.name));
05351 
05352    c = ast_hashtab_lookup(contexts_table,&item);
05353    if (c)
05354       ret = 0;
05355    ast_unlock_contexts();
05356 
05357    /* if we found context, unlock macrolock */
05358    if (ret == 0) {
05359       ret = ast_mutex_unlock(&c->macrolock);
05360    }
05361 
05362    return ret;
05363 }

int ast_context_verify_includes ( struct ast_context con  ) 

Verifies includes in an ast_contect structure.

Parameters:
con context in which to verify the includes
Return values:
0 if no problems found
-1 if there were any missing context

Definition at line 9803 of file pbx.c.

References ast_context_find(), ast_get_context_name(), ast_log(), ast_walk_context_includes(), LOG_WARNING, and ast_include::rname.

Referenced by pbx_load_module().

09804 {
09805    struct ast_include *inc = NULL;
09806    int res = 0;
09807 
09808    while ( (inc = ast_walk_context_includes(con, inc)) ) {
09809       if (ast_context_find(inc->rname))
09810          continue;
09811 
09812       res = -1;
09813       ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
09814          ast_get_context_name(con), inc->rname);
09815       break;
09816    }
09817 
09818    return res;
09819 }

struct ast_custom_function* ast_custom_function_find ( const char *  name  )  [read]

int ast_custom_function_unregister ( struct ast_custom_function acf  ) 

Unregister a custom function.

Definition at line 3283 of file pbx.c.

References ast_custom_function::acflist, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, ast_verb, AST_XML_DOC, ast_custom_function::docsrc, and ast_custom_function::name.

Referenced by load_module(), reload(), and unload_module().

03284 {
03285    struct ast_custom_function *cur;
03286 
03287    if (!acf) {
03288       return -1;
03289    }
03290 
03291    AST_RWLIST_WRLOCK(&acf_root);
03292    if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
03293 #ifdef AST_XML_DOCS
03294       if (cur->docsrc == AST_XML_DOC) {
03295          ast_string_field_free_memory(acf);
03296       }
03297 #endif
03298       ast_verb(2, "Unregistered custom function %s\n", cur->name);
03299    }
03300    AST_RWLIST_UNLOCK(&acf_root);
03301 
03302    return cur ? 0 : -1;
03303 }

int ast_destroy_timing ( struct ast_timing i  ) 

Deallocates memory structures associated with a timing bitmap.

Parameters:
i Pointer to an ast_timing structure.
Return values:
0 success
non-zero failure (number suitable to pass to
See also:
strerror)

Definition at line 7302 of file pbx.c.

References ast_free, and ast_timing::timezone.

Referenced by ast_context_add_include2(), ast_context_remove_include2(), iftime(), pbx_builtin_execiftime(), and pbx_builtin_gotoiftime().

07303 {
07304    if (i->timezone) {
07305       ast_free(i->timezone);
07306       i->timezone = NULL;
07307    }
07308    return 0;
07309 }

enum ast_extension_states ast_devstate_to_extenstate ( enum ast_device_state  devstate  ) 

Map devstate to an extension state.

Parameters:
[in] device state
Returns:
the extension state mapping.

Definition at line 4086 of file pbx.c.

References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_TOTAL, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_EXTENSION_BUSY, AST_EXTENSION_INUSE, AST_EXTENSION_NOT_INUSE, AST_EXTENSION_ONHOLD, AST_EXTENSION_RINGING, and AST_EXTENSION_UNAVAILABLE.

Referenced by ast_extension_state2().

04087 {
04088    switch (devstate) {
04089    case AST_DEVICE_ONHOLD:
04090       return AST_EXTENSION_ONHOLD;
04091    case AST_DEVICE_BUSY:
04092       return AST_EXTENSION_BUSY;
04093    case AST_DEVICE_UNAVAILABLE:
04094    case AST_DEVICE_UNKNOWN:
04095    case AST_DEVICE_INVALID:
04096       return AST_EXTENSION_UNAVAILABLE;
04097    case AST_DEVICE_RINGINUSE:
04098       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
04099    case AST_DEVICE_RINGING:
04100       return AST_EXTENSION_RINGING;
04101    case AST_DEVICE_INUSE:
04102       return AST_EXTENSION_INUSE;
04103    case AST_DEVICE_NOT_INUSE:
04104       return AST_EXTENSION_NOT_INUSE;
04105    case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
04106       break;
04107    }
04108 
04109    return AST_EXTENSION_NOT_INUSE;
04110 }

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

Determine whether an extension exists.

Parameters:
c this is not important
context which context to look in
exten which extension to search for
priority priority of the action within the extension
callerid callerid to search for
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 4480 of file pbx.c.

References E_MATCH, and pbx_extension_helper().

Referenced by __analog_ss_thread(), __ast_goto_if_exists(), __ast_pbx_run(), _macro_exec(), acf_isexten_exec(), analog_ss_thread(), answer_call(), ast_app_dtget(), ast_bridge_call(), ast_pbx_outgoing_exten(), builtin_atxfer(), builtin_blindtransfer(), cb_events(), change_t38_state(), cli_console_dial(), conf_run(), console_dial(), console_transfer(), dahdi_handle_dtmfup(), dial_exec_full(), disa_exec(), dp_lookup(), dundi_lookup_local(), get_also_info(), get_destination(), get_refer_info(), gosub_exec(), handle_gosub(), handle_link_data(), handle_link_phone_dtmf(), handle_stimulus_message(), isexten_function_read(), leave_voicemail(), local_alloc(), local_call(), local_devicestate(), local_dtmf_helper(), loopback_exists(), metermaidstate(), mgcp_ss(), minivm_greet_exec(), misdn_overlap_dial_task(), my_handle_dtmfup(), park_space_reserve(), parkandannounce_exec(), pbx_builtin_waitexten(), phone_check_exception(), privacy_exec(), process_ast_dsp(), readexten_exec(), register_peer_exten(), rpt_exec(), show_debug_helper(), skinny_ss(), socket_process(), and waitstream_core().

04481 {
04482    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
04483 }

int ast_explicit_goto ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority 
)

Note:
This function will handle locking the channel as needed.

Definition at line 7606 of file pbx.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_FLAG_IN_AUTOLOOP, ast_strlen_zero(), ast_test_flag, ast_channel::context, ast_channel::exten, and ast_channel::priority.

Referenced by __ast_goto_if_exists(), ast_async_goto(), builtin_atxfer(), disa_exec(), do_bridge_masquerade(), handle_setpriority(), pbx_parseable_goto(), and return_exec().

07607 {
07608    if (!chan)
07609       return -1;
07610 
07611    ast_channel_lock(chan);
07612 
07613    if (!ast_strlen_zero(context))
07614       ast_copy_string(chan->context, context, sizeof(chan->context));
07615    if (!ast_strlen_zero(exten))
07616       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
07617    if (priority > -1) {
07618       chan->priority = priority;
07619       /* see flag description in channel.h for explanation */
07620       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
07621          chan->priority--;
07622    }
07623 
07624    ast_channel_unlock(chan);
07625 
07626    return 0;
07627 }

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

Definition at line 2431 of file pbx.c.

References ast_log(), E_CANMATCH, E_MATCHMORE, extension_match_core(), and LOG_WARNING.

Referenced by lua_find_extension(), and realtime_switch_common().

02432 {
02433    if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
02434       ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
02435    return extension_match_core(pattern, data, needmore);
02436 }

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

Determine if one extension should match before another.

Parameters:
a extension to compare with b
b extension to compare with a
Checks whether or extension a should match before extension b

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

Definition at line 2233 of file pbx.c.

References ext_cmp().

Referenced by lua_extension_cmp().

02234 {
02235    return ext_cmp(a, b);
02236 }

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

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

Parameters:
pattern pattern to match
extension extension to check against the pattern.
Checks whether or not the given extension matches the given pattern.

Return values:
1 on match
0 on failure

Definition at line 2426 of file pbx.c.

References E_MATCH, and extension_match_core().

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

02427 {
02428    return extension_match_core(pattern, data, E_MATCH);
02429 }

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

Check extension state for an extension by using hint.

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

Definition at line 4148 of file pbx.c.

References ast_extension_state2(), and ast_hint_extension().

Referenced by action_extensionstate(), extstate_read(), and handle_request_subscribe().

04149 {
04150    struct ast_exten *e;
04151 
04152    if (!(e = ast_hint_extension(c, context, exten))) {  /* Do we have a hint for this extension ? */
04153       return -1;                   /* No hint, return -1 */
04154    }
04155 
04156    return ast_extension_state2(e);  /* Check all devices in the hint */
04157 }

static int ast_extension_state2 ( struct ast_exten e  )  [static]

Check state of extension by using hints.

Definition at line 4113 of file pbx.c.

References ast_devstate_aggregate_add(), ast_devstate_aggregate_init(), ast_devstate_aggregate_result(), ast_devstate_to_extenstate(), ast_get_extension_app(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), extensionstate_buf, and strsep().

Referenced by ast_add_hint_nolock(), ast_extension_state(), and handle_statechange().

04114 {
04115    struct ast_str *hint = ast_str_thread_get(&extensionstate_buf, 16);
04116    char *cur, *rest;
04117    struct ast_devstate_aggregate agg;
04118 
04119    if (!e)
04120       return -1;
04121 
04122    ast_devstate_aggregate_init(&agg);
04123 
04124    ast_str_set(&hint, 0, "%s", ast_get_extension_app(e));
04125 
04126    rest = ast_str_buffer(hint);  /* One or more devices separated with a & character */
04127 
04128    while ( (cur = strsep(&rest, "&")) ) {
04129       ast_devstate_aggregate_add(&agg, ast_device_state(cur));
04130    }
04131 
04132    return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
04133 }

const char* ast_extension_state2str ( int  extension_state  ) 

Return extension_state as string.

Return string representation of the state of an extension.

Definition at line 4136 of file pbx.c.

References ARRAY_LEN, extension_states, and cfextension_states::text.

Referenced by cb_extensionstate(), handle_request_subscribe(), handle_show_hint(), handle_show_hints(), and show_channels_cb().

04137 {
04138    int i;
04139 
04140    for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
04141       if (extension_states[i].extension_state == extension_state)
04142          return extension_states[i].text;
04143    }
04144    return "Unknown";
04145 }

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

Add watcher for extension states.

Registers a state change callback.

Definition at line 4212 of file pbx.c.

References ast_exten::app, ast_add_extension(), ast_calloc, ast_free_ptr, ast_hint_extension(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_state_cb::callback, ast_hint::callbacks, ast_exten::cidmatch, ast_exten::data, ast_state_cb::data, ast_hint::exten, ast_exten::exten, ast_state_cb::id, ast_exten::label, ast_context::name, ast_exten::parent, ast_exten::priority, ast_exten::registrar, and stateid.

Referenced by __init_manager(), handle_request_subscribe(), and skinny_register().

04214 {
04215    struct ast_hint *hint;
04216    struct ast_state_cb *cblist;
04217    struct ast_exten *e;
04218 
04219    /* If there's no context and extension:  add callback to statecbs list */
04220    if (!context && !exten) {
04221       AST_RWLIST_WRLOCK(&hints);
04222 
04223       AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
04224          if (cblist->callback == callback) {
04225             cblist->data = data;
04226             AST_RWLIST_UNLOCK(&hints);
04227             return 0;
04228          }
04229       }
04230 
04231       /* Now insert the callback */
04232       if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
04233          AST_RWLIST_UNLOCK(&hints);
04234          return -1;
04235       }
04236       cblist->id = 0;
04237       cblist->callback = callback;
04238       cblist->data = data;
04239 
04240       AST_LIST_INSERT_HEAD(&statecbs, cblist, entry);
04241 
04242       AST_RWLIST_UNLOCK(&hints);
04243 
04244       return 0;
04245    }
04246 
04247    if (!context || !exten)
04248       return -1;
04249 
04250    /* This callback type is for only one hint, so get the hint */
04251    e = ast_hint_extension(NULL, context, exten);
04252    if (!e) {
04253       return -1;
04254    }
04255 
04256    /* If this is a pattern, dynamically create a new extension for this
04257     * particular match.  Note that this will only happen once for each
04258     * individual extension, because the pattern will no longer match first.
04259     */
04260    if (e->exten[0] == '_') {
04261       ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
04262          e->cidmatch, e->app, ast_strdup(e->data), ast_free_ptr,
04263          e->registrar);
04264       e = ast_hint_extension(NULL, context, exten);
04265       if (!e || e->exten[0] == '_') {
04266          return -1;
04267       }
04268    }
04269 
04270    /* Find the hint in the list of hints */
04271    AST_RWLIST_WRLOCK(&hints);
04272 
04273    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04274       if (hint->exten == e)
04275          break;
04276    }
04277 
04278    if (!hint) {
04279       /* We have no hint, sorry */
04280       AST_RWLIST_UNLOCK(&hints);
04281       return -1;
04282    }
04283 
04284    /* Now insert the callback in the callback list  */
04285    if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
04286       AST_RWLIST_UNLOCK(&hints);
04287       return -1;
04288    }
04289 
04290    cblist->id = stateid++;    /* Unique ID for this callback */
04291    cblist->callback = callback;  /* Pointer to callback routine */
04292    cblist->data = data;    /* Data for the callback */
04293 
04294    AST_LIST_INSERT_HEAD(&hint->callbacks, cblist, entry);
04295 
04296    AST_RWLIST_UNLOCK(&hints);
04297 
04298    return cblist->id;
04299 }

int ast_extension_state_del ( int  id,
ast_state_cb_type  callback 
)

Remove a watcher from the callback list.

Deletes a registered state change callback by ID.

Definition at line 4302 of file pbx.c.

References ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_state_cb::callback, ast_hint::callbacks, and ast_state_cb::id.

Referenced by dialog_unlink_all(), handle_request_subscribe(), and skinny_unregister().

04303 {
04304    struct ast_state_cb *p_cur = NULL;
04305    int ret = -1;
04306 
04307    if (!id && !callback)
04308       return -1;
04309 
04310    AST_RWLIST_WRLOCK(&hints);
04311 
04312    if (!id) {  /* id == 0 is a callback without extension */
04313       AST_LIST_TRAVERSE_SAFE_BEGIN(&statecbs, p_cur, entry) {
04314          if (p_cur->callback == callback) {
04315             AST_LIST_REMOVE_CURRENT(entry);
04316             break;
04317          }
04318       }
04319       AST_LIST_TRAVERSE_SAFE_END;
04320    } else { /* callback with extension, find the callback based on ID */
04321       struct ast_hint *hint;
04322       AST_RWLIST_TRAVERSE(&hints, hint, list) {
04323          AST_LIST_TRAVERSE_SAFE_BEGIN(&hint->callbacks, p_cur, entry) {
04324             if (p_cur->id == id) {
04325                AST_LIST_REMOVE_CURRENT(entry);
04326                break;
04327             }
04328          }
04329          AST_LIST_TRAVERSE_SAFE_END;
04330 
04331          if (p_cur)
04332             break;
04333       }
04334    }
04335 
04336    if (p_cur) {
04337       ast_free(p_cur);
04338    }
04339 
04340    AST_RWLIST_UNLOCK(&hints);
04341 
04342    return ret;
04343 }

int ast_findlabel_extension ( struct ast_channel c,
const char *  context,
const char *  exten,
const char *  label,
const char *  callerid 
)

Find the priority of an extension that has the specified label.

Parameters:
c this is not important
context which context to look in
exten which extension to search for
label label of the action within the extension to match to priority
callerid callerid to search for
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:
the priority which matches the given label in the extension
-1 if not found.

Definition at line 4485 of file pbx.c.

References E_FINDLABEL, and pbx_extension_helper().

Referenced by action_originate(), action_redirect(), handle_gosub(), handle_setpriority(), isexten_function_read(), and pbx_parseable_goto().

04486 {
04487    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
04488 }

int ast_findlabel_extension2 ( struct ast_channel c,
struct ast_context con,
const char *  exten,
const char *  label,
const char *  callerid 
)

Find the priority of an extension that has the specified label.

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

References E_FINDLABEL, and pbx_extension_helper().

Referenced by pbx_load_config().

04491 {
04492    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
04493 }

int ast_func_read ( struct ast_channel chan,
const char *  function,
char *  workspace,
size_t  len 
)

executes a read operation on a function

Parameters:
chan Channel to execute on
function Data containing the function call string (will be modified)
workspace A pointer to safe memory to use for a return value
len the number of bytes in workspace
This application executes a function in read mode on a given channel.

Return values:
0 success
non-zero failure

Definition at line 3427 of file pbx.c.

References __ast_module_user_add(), __ast_module_user_remove(), ast_copy_string(), ast_custom_function_find(), ast_free, ast_log(), ast_str_buffer(), ast_str_create(), ast_str_size(), ast_strdupa, copy(), func_args(), LOG_ERROR, ast_custom_function::mod, ast_custom_function::read, ast_custom_function::read2, and str.

Referenced by action_getvar(), action_status(), handle_getvariable(), lua_get_variable_value(), and pbx_substitute_variables_helper_full().

03428 {
03429    char *copy = ast_strdupa(function);
03430    char *args = func_args(copy);
03431    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
03432    int res;
03433    struct ast_module_user *u = NULL;
03434 
03435    if (acfptr == NULL) {
03436       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
03437    } else if (!acfptr->read && !acfptr->read2) {
03438       ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
03439    } else if (acfptr->read) {
03440       if (acfptr->mod) {
03441          u = __ast_module_user_add(acfptr->mod, chan);
03442       }
03443       res = acfptr->read(chan, copy, args, workspace, len);
03444       if (acfptr->mod && u) {
03445          __ast_module_user_remove(acfptr->mod, u);
03446       }
03447       return res;
03448    } else {
03449       struct ast_str *str = ast_str_create(16);
03450       if (acfptr->mod) {
03451          u = __ast_module_user_add(acfptr->mod, chan);
03452       }
03453       res = acfptr->read2(chan, copy, args, &str, 0);
03454       if (acfptr->mod && u) {
03455          __ast_module_user_remove(acfptr->mod, u);
03456       }
03457       ast_copy_string(workspace, ast_str_buffer(str), len > ast_str_size(str) ? ast_str_size(str) : len);
03458       ast_free(str);
03459       return res;
03460    }
03461    return -1;
03462 }

int ast_func_read2 ( struct ast_channel chan,
const char *  function,
struct ast_str **  str,
ssize_t  maxlen 
)

executes a read operation on a function

Parameters:
chan Channel to execute on
function Data containing the function call string (will be modified)
str A dynamic string buffer into which to place the result.
maxlen <0 if the dynamic buffer should not grow; >0 if the dynamic buffer should be limited to that number of bytes; 0 if the dynamic buffer has no upper limit
This application executes a function in read mode on a given channel.

Return values:
0 success
non-zero failure

Definition at line 3464 of file pbx.c.

References __ast_module_user_add(), __ast_module_user_remove(), ast_custom_function_find(), ast_log(), ast_str_buffer(), ast_str_make_space(), ast_str_reset(), ast_str_size(), ast_strdupa, copy(), func_args(), LOG_ERROR, maxsize, ast_custom_function::mod, ast_custom_function::read, ast_custom_function::read2, ast_custom_function::read_max, and VAR_BUF_SIZE.

Referenced by ast_str_substitute_variables_full().

03465 {
03466    char *copy = ast_strdupa(function);
03467    char *args = func_args(copy);
03468    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
03469    int res;
03470    struct ast_module_user *u = NULL;
03471 
03472    if (acfptr == NULL) {
03473       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
03474    } else if (!acfptr->read && !acfptr->read2) {
03475       ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
03476    } else {
03477       if (acfptr->mod) {
03478          u = __ast_module_user_add(acfptr->mod, chan);
03479       }
03480       if (acfptr->read2) {
03481          /* ast_str enabled */
03482          ast_str_reset(*str);
03483          res = acfptr->read2(chan, copy, args, str, maxlen);
03484       } else {
03485          /* Legacy function pointer, allocate buffer for result */
03486          int maxsize = ast_str_size(*str);
03487          if (maxlen > -1) {
03488             if (maxlen == 0) {
03489                if (acfptr->read_max) {
03490                   maxsize = acfptr->read_max;
03491                } else {
03492                   maxsize = VAR_BUF_SIZE;
03493                }
03494             } else {
03495                maxsize = maxlen;
03496             }
03497             ast_str_make_space(str, maxsize);
03498          }
03499          res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
03500       }
03501       if (acfptr->mod && u) {
03502          __ast_module_user_remove(acfptr->mod, u);
03503       }
03504       return res;
03505    }
03506    return -1;
03507 }

int ast_func_write ( struct ast_channel chan,
const char *  function,
const char *  value 
)

executes a write operation on a function

Parameters:
chan Channel to execute on
function Data containing the function call string (will be modified)
value A value parameter to pass for writing
This application executes a function in write mode on a given channel.

Return values:
0 success
non-zero failure

Definition at line 3509 of file pbx.c.

References __ast_module_user_add(), __ast_module_user_remove(), ast_custom_function_find(), ast_log(), ast_strdupa, copy(), func_args(), LOG_ERROR, ast_custom_function::mod, and ast_custom_function::write.

Referenced by conf_run(), pbx_builtin_pushvar_helper(), and pbx_builtin_setvar_helper().

03510 {
03511    char *copy = ast_strdupa(function);
03512    char *args = func_args(copy);
03513    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
03514 
03515    if (acfptr == NULL)
03516       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
03517    else if (!acfptr->write)
03518       ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
03519    else {
03520       int res;
03521       struct ast_module_user *u = NULL;
03522       if (acfptr->mod)
03523          u = __ast_module_user_add(acfptr->mod, chan);
03524       res = acfptr->write(chan, copy, args, value);
03525       if (acfptr->mod && u)
03526          __ast_module_user_remove(acfptr->mod, u);
03527       return res;
03528    }
03529 
03530    return -1;
03531 }

const char* ast_get_context_name ( struct ast_context con  ) 

const char* ast_get_context_registrar ( struct ast_context c  ) 

Definition at line 9693 of file pbx.c.

References ast_context::registrar.

Referenced by handle_cli_dialplan_save(), show_debug_helper(), and show_dialplan_helper().

09694 {
09695    return c ? c->registrar : NULL;
09696 }

const char* ast_get_extension_app ( struct ast_exten e  ) 

void* ast_get_extension_app_data ( struct ast_exten e  ) 

Definition at line 9728 of file pbx.c.

References ast_exten::data.

Referenced by _macro_exec(), ast_get_hint(), ast_str_get_hint(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and print_ext().

09729 {
09730    return e ? e->data : NULL;
09731 }

const char* ast_get_extension_cidmatch ( struct ast_exten e  ) 

Definition at line 9718 of file pbx.c.

References ast_exten::cidmatch.

Referenced by complete_dialplan_remove_extension(), find_matching_priority(), and handle_cli_dialplan_save().

09719 {
09720    return e ? e->cidmatch : NULL;
09721 }

struct ast_context* ast_get_extension_context ( struct ast_exten exten  )  [read]

Definition at line 9660 of file pbx.c.

References ast_exten::parent.

Referenced by handle_show_hint(), and handle_show_hints().

09661 {
09662    return exten ? exten->parent : NULL;
09663 }

const char* ast_get_extension_label ( struct ast_exten exten  ) 

Definition at line 9670 of file pbx.c.

References ast_exten::label.

Referenced by handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().

09671 {
09672    return exten ? exten->label : NULL;
09673 }

int ast_get_extension_matchcid ( struct ast_exten e  ) 

Definition at line 9713 of file pbx.c.

References ast_exten::matchcid.

Referenced by complete_dialplan_remove_extension(), find_matching_priority(), and handle_cli_dialplan_save().

09714 {
09715    return e ? e->matchcid : 0;
09716 }

const char* ast_get_extension_name ( struct ast_exten exten  ) 

int ast_get_extension_priority ( struct ast_exten exten  ) 

Definition at line 9685 of file pbx.c.

References ast_exten::priority.

Referenced by complete_dialplan_remove_extension(), find_matching_priority(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and print_ext().

09686 {
09687    return exten ? exten->priority : -1;
09688 }

const char* ast_get_extension_registrar ( struct ast_exten e  ) 

Definition at line 9698 of file pbx.c.

References ast_exten::registrar.

Referenced by handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().

09699 {
09700    return e ? e->registrar : NULL;
09701 }

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

Get hint for channel.

If an extension hint exists, return non-zero.

Definition at line 4442 of file pbx.c.

References ast_copy_string(), ast_get_extension_app(), ast_get_extension_app_data(), and ast_hint_extension().

Referenced by action_extensionstate(), get_cid_name(), get_destination(), hint_read(), manager_state_cb(), skinny_extensionstate_cb(), and state_notify_build_xml().

04443 {
04444    struct ast_exten *e = ast_hint_extension(c, context, exten);
04445 
04446    if (e) {
04447       if (hint)
04448          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
04449       if (name) {
04450          const char *tmp = ast_get_extension_app_data(e);
04451          if (tmp)
04452             ast_copy_string(name, tmp, namesize);
04453       }
04454       return -1;
04455    }
04456    return 0;
04457 }

const char* ast_get_ignorepat_name ( struct ast_ignorepat ip  ) 

const char* ast_get_ignorepat_registrar ( struct ast_ignorepat ip  ) 

Definition at line 9708 of file pbx.c.

References ast_ignorepat::registrar.

Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().

09709 {
09710    return ip ? ip->registrar : NULL;
09711 }

const char* ast_get_include_name ( struct ast_include inc  ) 

const char* ast_get_include_registrar ( struct ast_include i  ) 

Definition at line 9703 of file pbx.c.

References ast_include::registrar.

Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().

09704 {
09705    return i ? i->registrar : NULL;
09706 }

const char* ast_get_switch_data ( struct ast_sw sw  ) 

Definition at line 9738 of file pbx.c.

References ast_sw::data.

Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().

09739 {
09740    return sw ? sw->data : NULL;
09741 }

int ast_get_switch_eval ( struct ast_sw sw  ) 

Definition at line 9743 of file pbx.c.

References ast_sw::eval.

Referenced by context_merge_incls_swits_igps_other_registrars().

09744 {
09745    return sw->eval;
09746 }

const char* ast_get_switch_name ( struct ast_sw sw  ) 

Definition at line 9733 of file pbx.c.

References ast_sw::name.

Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().

09734 {
09735    return sw ? sw->name : NULL;
09736 }

const char* ast_get_switch_registrar ( struct ast_sw sw  ) 

Definition at line 9748 of file pbx.c.

References ast_sw::registrar.

Referenced by context_merge_incls_swits_igps_other_registrars(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), and show_dialplan_helper().

09749 {
09750    return sw ? sw->registrar : NULL;
09751 }

int ast_goto_if_exists ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority 
)

Note:
This function will handle locking the channel as needed.

Definition at line 9842 of file pbx.c.

References __ast_goto_if_exists().

Referenced by background_detect_exec(), channel_spy(), common_exec(), conf_run(), dial_exec_full(), goto_exten(), onedigit_goto(), priority_jump(), select_entry(), and valid_exit().

09843 {
09844    return __ast_goto_if_exists(chan, context, exten, priority, 0);
09845 }

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

hashtable functions for contexts

Definition at line 1013 of file pbx.c.

References ast_context::name.

Referenced by ast_context_find_or_create(), lua_register_switches(), and pbx_load_module().

01014 {
01015    const struct ast_context *ac = ah_a;
01016    const struct ast_context *bc = ah_b;
01017    if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
01018       return 1;
01019    /* assume context names are registered in a string table! */
01020    return strcmp(ac->name, bc->name);
01021 }

unsigned int ast_hashtab_hash_contexts ( const void *  obj  ) 

Definition at line 1056 of file pbx.c.

References ast_hashtab_hash_string(), and ast_context::name.

Referenced by ast_context_find_or_create(), lua_register_switches(), and pbx_load_module().

01057 {
01058    const struct ast_context *ac = obj;
01059    return ast_hashtab_hash_string(ac->name);
01060 }

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

Definition at line 4077 of file pbx.c.

References ast_hint_extension_nolock(), ast_rdlock_contexts(), and ast_unlock_contexts().

Referenced by ast_extension_state(), ast_extension_state_add(), ast_get_hint(), and ast_str_get_hint().

04078 {
04079    struct ast_exten *e;
04080    ast_rdlock_contexts();
04081    e = ast_hint_extension_nolock(c, context, exten);
04082    ast_unlock_contexts();
04083    return e;
04084 }

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

Find hint for given extension in context.

Definition at line 4071 of file pbx.c.

References E_MATCH, pbx_find_extension(), PRIORITY_HINT, and pbx_find_info::stacklen.

Referenced by ast_hint_extension(), and ast_merge_contexts_and_delete().

04072 {
04073    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
04074    return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
04075 }

int ast_ignore_pattern ( const char *  context,
const char *  pattern 
)

Checks to see if a number should be ignored.

Parameters:
context context to search within
pattern to check whether it should be ignored or not
Check if a number should be ignored with respect to dialtone cancellation.

Return values:
0 if the pattern should not be ignored
non-zero if the pattern should be ignored

Definition at line 7552 of file pbx.c.

References ast_context_find(), ast_extension_match(), ast_context::ignorepats, ast_ignorepat::next, and ast_ignorepat::pattern.

Referenced by __analog_ss_thread(), analog_ss_thread(), ast_app_dtget(), disa_exec(), dp_lookup(), dundi_lookup_local(), handle_enbloc_call_message(), handle_soft_key_event_message(), handle_stimulus_message(), mgcp_ss(), and skinny_ss().

07553 {
07554    struct ast_context *con = ast_context_find(context);
07555    if (con) {
07556       struct ast_ignorepat *pat;
07557       for (pat = con->ignorepats; pat; pat = pat->next) {
07558          if (ast_extension_match(pat->pattern, pattern))
07559             return 1;
07560       }
07561    }
07562 
07563    return 0;
07564 }

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

Looks to see if adding anything to this extension might match something. (exists ^ canmatch).

Parameters:
c not really important XXX
context context to serach within
exten extension to check
priority priority of extension path
callerid callerid of extension being searched for
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 4500 of file pbx.c.

References E_MATCHMORE, and pbx_extension_helper().

Referenced by __analog_ss_thread(), __ast_pbx_run(), analog_ss_thread(), ast_app_dtget(), collect_digits(), disa_exec(), dp_lookup(), dundi_lookup_local(), handle_link_data(), handle_link_phone_dtmf(), local_dtmf_helper(), loopback_matchmore(), mgcp_ss(), pbx_builtin_background(), readexten_exec(), and skinny_ss().

04501 {
04502    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
04503 }

void ast_merge_contexts_and_delete ( struct ast_context **  extcontexts,
struct ast_hashtab exttable,
const char *  registrar 
)

Merge the temporary contexts into a global contexts list and delete from the global list the ones that are being added.

Parameters:
extcontexts pointer to the ast_context structure
exttable pointer to the ast_hashtab structure that contains all the elements in extcontexts
registrar of the context; if it's set the routine will delete all contexts that belong to that registrar; if NULL only the contexts that are specified in extcontexts

Definition at line 6909 of file pbx.c.

References __ast_internal_context_destroy(), ast_exten::app, ast_add_extension_nolock(), ast_calloc, AST_EXTENSION_REMOVED, ast_free, ast_free_ptr, ast_hashtab_destroy(), ast_hashtab_end_traversal(), ast_hashtab_next(), ast_hashtab_start_traversal(), ast_hint_extension_nolock(), AST_LIST_APPEND_LIST, AST_LIST_EMPTY, AST_LIST_HEAD_INIT_VALUE, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_rdlock_contexts(), AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_tvdiff_us(), ast_tvnow(), ast_unlock_contexts(), ast_verb, ast_wrlock_contexts(), ast_wrlock_contexts_version(), ast_state_cb::callback, ast_hint::callbacks, context_merge(), contexts, contexts_table, ast_state_cb::data, ast_exten::data, E_MATCH, ast_exten::exten, ast_hint::exten, ast_hint::laststate, LOG_WARNING, ast_context::name, ast_context::next, ast_sw::next, ast_exten::parent, pbx_find_extension(), PRIORITY_HINT, ast_context::registrar, and pbx_find_info::stacklen.

Referenced by lua_reload_extensions(), and pbx_load_module().

06910 {
06911    double ft;
06912    struct ast_context *tmp, *oldcontextslist;
06913    struct ast_hashtab *oldtable;
06914    struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
06915    struct store_hint *this;
06916    struct ast_hint *hint;
06917    struct ast_exten *exten;
06918    int length;
06919    struct ast_state_cb *thiscb;
06920    struct ast_hashtab_iter *iter;
06921 
06922    /* it is very important that this function hold the hint list lock _and_ the conlock
06923       during its operation; not only do we need to ensure that the list of contexts
06924       and extensions does not change, but also that no hint callbacks (watchers) are
06925       added or removed during the merge/delete process
06926 
06927       in addition, the locks _must_ be taken in this order, because there are already
06928       other code paths that use this order
06929    */
06930 
06931    struct timeval begintime, writelocktime, endlocktime, enddeltime;
06932    int wrlock_ver;
06933 
06934    begintime = ast_tvnow();
06935    ast_rdlock_contexts();
06936    iter = ast_hashtab_start_traversal(contexts_table);
06937    while ((tmp = ast_hashtab_next(iter))) {
06938       context_merge(extcontexts, exttable, tmp, registrar);
06939    }
06940    ast_hashtab_end_traversal(iter);
06941    wrlock_ver = ast_wrlock_contexts_version();
06942 
06943    ast_unlock_contexts(); /* this feels real retarded, but you must do
06944                        what you must do If this isn't done, the following 
06945                         wrlock is a guraranteed deadlock */
06946    ast_wrlock_contexts();
06947    if (ast_wrlock_contexts_version() > wrlock_ver+1) {
06948       ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
06949    }
06950 
06951    AST_RWLIST_WRLOCK(&hints);
06952    writelocktime = ast_tvnow();
06953 
06954    /* preserve all watchers for hints associated with this registrar */
06955    AST_RWLIST_TRAVERSE(&hints, hint, list) {
06956       if (!AST_LIST_EMPTY(&hint->callbacks) && !strcmp(registrar, hint->exten->parent->registrar)) {
06957          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
06958          if (!(this = ast_calloc(1, length)))
06959             continue;
06960          AST_LIST_APPEND_LIST(&this->callbacks, &hint->callbacks, entry);
06961          this->laststate = hint->laststate;
06962          this->context = this->data;
06963          strcpy(this->data, hint->exten->parent->name);
06964          this->exten = this->data + strlen(this->context) + 1;
06965          strcpy(this->exten, hint->exten->exten);
06966          AST_LIST_INSERT_HEAD(&store, this, list);
06967       }
06968    }
06969 
06970    /* save the old table and list */
06971    oldtable = contexts_table;
06972    oldcontextslist = contexts;
06973 
06974    /* move in the new table and list */
06975    contexts_table = exttable;
06976    contexts = *extcontexts;
06977 
06978    /* restore the watchers for hints that can be found; notify those that
06979       cannot be restored
06980    */
06981    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
06982       struct pbx_find_info q = { .stacklen = 0 };
06983       exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH);
06984       /* If this is a pattern, dynamically create a new extension for this
06985        * particular match.  Note that this will only happen once for each
06986        * individual extension, because the pattern will no longer match first.
06987        */
06988       if (exten && exten->exten[0] == '_') {
06989          ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
06990             0, exten->app, ast_strdup(exten->data), ast_free_ptr, registrar);
06991          /* rwlocks are not recursive locks */
06992          exten = ast_hint_extension_nolock(NULL, this->context, this->exten);
06993       }
06994 
06995       /* Find the hint in the list of hints */
06996       AST_RWLIST_TRAVERSE(&hints, hint, list) {
06997          if (hint->exten == exten)
06998             break;
06999       }
07000       if (!exten || !hint) {
07001          /* this hint has been removed, notify the watchers */
07002          while ((thiscb = AST_LIST_REMOVE_HEAD(&this->callbacks, entry))) {
07003             thiscb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, thiscb->data);
07004             ast_free(thiscb);
07005          }
07006       } else {
07007          AST_LIST_APPEND_LIST(&hint->callbacks, &this->callbacks, entry);
07008          hint->laststate = this->laststate;
07009       }
07010       ast_free(this);
07011    }
07012 
07013    AST_RWLIST_UNLOCK(&hints);
07014    ast_unlock_contexts();
07015    endlocktime = ast_tvnow();
07016 
07017    /* the old list and hashtab no longer are relevant, delete them while the rest of asterisk
07018       is now freely using the new stuff instead */
07019 
07020    ast_hashtab_destroy(oldtable, NULL);
07021 
07022    for (tmp = oldcontextslist; tmp; ) {
07023       struct ast_context *next;  /* next starting point */
07024       next = tmp->next;
07025       __ast_internal_context_destroy(tmp);
07026       tmp = next;
07027    }
07028    enddeltime = ast_tvnow();
07029 
07030    ft = ast_tvdiff_us(writelocktime, begintime);
07031    ft /= 1000000.0;
07032    ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
07033 
07034    ft = ast_tvdiff_us(endlocktime, writelocktime);
07035    ft /= 1000000.0;
07036    ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
07037 
07038    ft = ast_tvdiff_us(enddeltime, endlocktime);
07039    ft /= 1000000.0;
07040    ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
07041 
07042    ft = ast_tvdiff_us(enddeltime, begintime);
07043    ft /= 1000000.0;
07044    ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
07045    return;
07046 }

int ast_parseable_goto ( struct ast_channel chan,
const char *  goto_string 
)

Note:
This function will handle locking the channel as needed.

Definition at line 9905 of file pbx.c.

References pbx_parseable_goto().

Referenced by _while_exec(), check_goto_on_transfer(), dial_exec_full(), gosub_exec(), ivr_dispatch(), parkandannounce_exec(), pbx_builtin_goto(), and while_continue_exec().

09906 {
09907    return pbx_parseable_goto(chan, goto_string, 0);
09908 }

int ast_pbx_outgoing_app ( const char *  type,
int  format,
void *  data,
int  timeout,
const char *  app,
const char *  appdata,
int *  reason,
int  sync,
const char *  cid_num,
const char *  cid_name,
struct ast_variable vars,
const char *  account,
struct ast_channel **  locked_channel 
)

Synchronously or asynchronously make an outbound call and send it to a particular application with given extension

Definition at line 8393 of file pbx.c.

References __ast_request_and_dial(), ast_channel::_state, outgoing_helper::account, async_stat::app, app_tmp::app, async_stat::appdata, ast_calloc, ast_cdr_disposition(), ast_cdr_failed(), ast_cdr_setaccount(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_free, ast_hangup(), ast_log(), ast_pbx_outgoing_cdr_failed(), ast_pbx_run_app(), ast_pthread_create_detached, ast_set_variables(), AST_STATE_UP, ast_strlen_zero(), ast_variables_destroy(), ast_verb, async_wait(), ast_channel::cdr, async_stat::chan, app_tmp::chan, app_tmp::data, errno, ast_channel::hangupcause, LOG_WARNING, ast_channel::name, async_stat::p, app_tmp::t, async_stat::timeout, and outgoing_helper::vars.

Referenced by action_originate(), attempt_thread(), fast_originate(), orig_app(), and originate_exec().

08394 {
08395    struct ast_channel *chan;
08396    struct app_tmp *tmp;
08397    int res = -1, cdr_res = -1;
08398    struct outgoing_helper oh;
08399 
08400    memset(&oh, 0, sizeof(oh));
08401    oh.vars = vars;
08402    oh.account = account;
08403 
08404    if (locked_channel)
08405       *locked_channel = NULL;
08406    if (ast_strlen_zero(app)) {
08407       res = -1;
08408       goto outgoing_app_cleanup;
08409    }
08410    if (synchronous) {
08411       chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh);
08412       if (chan) {
08413          ast_set_variables(chan, vars);
08414          if (account)
08415             ast_cdr_setaccount(chan, account);
08416          if (chan->_state == AST_STATE_UP) {
08417             res = 0;
08418             ast_verb(4, "Channel %s was answered.\n", chan->name);
08419             tmp = ast_calloc(1, sizeof(*tmp));
08420             if (!tmp)
08421                res = -1;
08422             else {
08423                ast_copy_string(tmp->app, app, sizeof(tmp->app));
08424                if (appdata)
08425                   ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
08426                tmp->chan = chan;
08427                if (synchronous > 1) {
08428                   if (locked_channel)
08429                      ast_channel_unlock(chan);
08430                   ast_pbx_run_app(tmp);
08431                } else {
08432                   if (locked_channel)
08433                      ast_channel_lock(chan);
08434                   if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
08435                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
08436                      ast_free(tmp);
08437                      if (locked_channel)
08438                         ast_channel_unlock(chan);
08439                      ast_hangup(chan);
08440                      res = -1;
08441                   } else {
08442                      if (locked_channel)
08443                         *locked_channel = chan;
08444                   }
08445                }
08446             }
08447          } else {
08448             ast_verb(4, "Channel %s was never answered.\n", chan->name);
08449             if (chan->cdr) { /* update the cdr */
08450                /* here we update the status of the call, which sould be busy.
08451                 * if that fails then we set the status to failed */
08452                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
08453                   ast_cdr_failed(chan->cdr);
08454             }
08455             ast_hangup(chan);
08456          }
08457       }
08458 
08459       if (res < 0) { /* the call failed for some reason */
08460          if (*reason == 0) { /* if the call failed (not busy or no answer)
08461                         * update the cdr with the failed message */
08462             cdr_res = ast_pbx_outgoing_cdr_failed();
08463             if (cdr_res != 0) {
08464                res = cdr_res;
08465                goto outgoing_app_cleanup;
08466             }
08467          }
08468       }
08469 
08470    } else {
08471       struct async_stat *as;
08472       if (!(as = ast_calloc(1, sizeof(*as)))) {
08473          res = -1;
08474          goto outgoing_app_cleanup;
08475       }
08476       chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh);
08477       if (!chan) {
08478          ast_free(as);
08479          res = -1;
08480          goto outgoing_app_cleanup;
08481       }
08482       as->chan = chan;
08483       ast_copy_string(as->app, app, sizeof(as->app));
08484       if (appdata)
08485          ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
08486       as->timeout = timeout;
08487       ast_set_variables(chan, vars);
08488       if (account)
08489          ast_cdr_setaccount(chan, account);
08490       /* Start a new thread, and get something handling this channel. */
08491       if (locked_channel)
08492          ast_channel_lock(chan);
08493       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
08494          ast_log(LOG_WARNING, "Failed to start async wait\n");
08495          ast_free(as);
08496          if (locked_channel)
08497             ast_channel_unlock(chan);
08498          ast_hangup(chan);
08499          res = -1;
08500          goto outgoing_app_cleanup;
08501       } else {
08502          if (locked_channel)
08503             *locked_channel = chan;
08504       }
08505       res = 0;
08506    }
08507 outgoing_app_cleanup:
08508    ast_variables_destroy(vars);
08509    return res;
08510 }

static int ast_pbx_outgoing_cdr_failed ( void   )  [static]

Function to post an empty cdr after a spool call fails.

Note:
This function posts an empty cdr for a failed spool call

Definition at line 8200 of file pbx.c.

References ast_cdr_alloc(), ast_cdr_detach(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_start(), ast_channel_release(), ast_dummy_channel_alloc(), and ast_channel::cdr.

Referenced by ast_pbx_outgoing_app(), and ast_pbx_outgoing_exten().

08201 {
08202    /* allocate a channel */
08203    struct ast_channel *chan = ast_dummy_channel_alloc();
08204 
08205    if (!chan)
08206       return -1;  /* failure */
08207 
08208    chan->cdr = ast_cdr_alloc();
08209    if (!chan->cdr) {
08210       /* allocation of the cdr failed */
08211       chan = ast_channel_release(chan);   /* free the channel */
08212       return -1;                /* return failure */
08213    }
08214 
08215    /* allocation of the cdr was successful */
08216    ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
08217    ast_cdr_start(chan->cdr);       /* record the start and stop time */
08218    ast_cdr_end(chan->cdr);
08219    ast_cdr_failed(chan->cdr);      /* set the status to failed */
08220    ast_cdr_detach(chan->cdr);      /* post and free the record */
08221    chan->cdr = NULL;
08222    chan = ast_channel_release(chan);         /* free the channel */
08223 
08224    return 0;  /* success */
08225 }

int ast_pbx_outgoing_exten ( const char *  type,
int  format,
void *  data,
int  timeout,
const char *  context,
const char *  exten,
int  priority,
int *  reason,
int  sync,
const char *  cid_num,
const char *  cid_name,
struct ast_variable vars,
const char *  account,
struct ast_channel **  locked_channel 
)

Synchronously or asynchronously make an outbound call and send it to a particular extension

Definition at line 8227 of file pbx.c.

References __ast_request_and_dial(), ast_channel::_state, outgoing_helper::account, ast_calloc, ast_cdr_disposition(), ast_cdr_failed(), ast_cdr_setaccount(), ast_channel_alloc, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_exists_extension(), ast_free, ast_hangup(), ast_log(), ast_pbx_outgoing_cdr_failed(), ast_pbx_run(), ast_pbx_start(), ast_pthread_create_detached, ast_request_and_dial(), ast_set_variables(), AST_STATE_DOWN, AST_STATE_UP, ast_strlen_zero(), ast_variables_destroy(), ast_verb, async_wait(), ast_channel::cdr, async_stat::chan, outgoing_helper::cid_name, outgoing_helper::cid_num, async_stat::context, ast_channel::context, outgoing_helper::context, outgoing_helper::exten, ast_channel::hangupcause, LOG_ERROR, LOG_WARNING, ast_channel::name, async_stat::p, outgoing_helper::parent_channel, pbx_builtin_setvar_helper(), outgoing_helper::priority, set_ext_pri(), async_stat::timeout, and outgoing_helper::vars.

Referenced by action_originate(), attempt_thread(), fast_originate(), orig_exten(), and originate_exec().

08228 {
08229    struct ast_channel *chan;
08230    struct async_stat *as;
08231    int res = -1, cdr_res = -1;
08232    struct outgoing_helper oh;
08233 
08234    if (synchronous) {
08235       oh.context = context;
08236       oh.exten = exten;
08237       oh.priority = priority;
08238       oh.cid_num = cid_num;
08239       oh.cid_name = cid_name;
08240       oh.account = account;
08241       oh.vars = vars;
08242       oh.parent_channel = NULL;
08243 
08244       chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh);
08245       if (channel) {
08246          *channel = chan;
08247          if (chan)
08248             ast_channel_lock(chan);
08249       }
08250       if (chan) {
08251          if (chan->_state == AST_STATE_UP) {
08252                res = 0;
08253             ast_verb(4, "Channel %s was answered.\n", chan->name);
08254 
08255             if (synchronous > 1) {
08256                if (channel)
08257                   ast_channel_unlock(chan);
08258                if (ast_pbx_run(chan)) {
08259                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
08260                   if (channel)
08261                      *channel = NULL;
08262                   ast_hangup(chan);
08263                   chan = NULL;
08264                   res = -1;
08265                }
08266             } else {
08267                if (ast_pbx_start(chan)) {
08268                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
08269                   if (channel) {
08270                      *channel = NULL;
08271                      ast_channel_unlock(chan);
08272                   }
08273                   ast_hangup(chan);
08274                   res = -1;
08275                }
08276                chan = NULL;
08277             }
08278          } else {
08279             ast_verb(4, "Channel %s was never answered.\n", chan->name);
08280 
08281             if (chan->cdr) { /* update the cdr */
08282                /* here we update the status of the call, which sould be busy.
08283                 * if that fails then we set the status to failed */
08284                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
08285                   ast_cdr_failed(chan->cdr);
08286             }
08287 
08288             if (channel) {
08289                *channel = NULL;
08290                ast_channel_unlock(chan);
08291             }
08292             ast_hangup(chan);
08293             chan = NULL;
08294          }
08295       }
08296 
08297       if (res < 0) { /* the call failed for some reason */
08298          if (*reason == 0) { /* if the call failed (not busy or no answer)
08299                         * update the cdr with the failed message */
08300             cdr_res = ast_pbx_outgoing_cdr_failed();
08301             if (cdr_res != 0) {
08302                res = cdr_res;
08303                goto outgoing_exten_cleanup;
08304             }
08305          }
08306 
08307          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
08308          /* check if "failed" exists */
08309          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
08310             chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", NULL, 0, "OutgoingSpoolFailed");
08311             if (chan) {
08312                char failed_reason[4] = "";
08313                if (!ast_strlen_zero(context))
08314                   ast_copy_string(chan->context, context, sizeof(chan->context));
08315                set_ext_pri(chan, "failed", 1);
08316                ast_set_variables(chan, vars);
08317                snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
08318                pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
08319                if (account)
08320                   ast_cdr_setaccount(chan, account);
08321                if (ast_pbx_run(chan)) {
08322                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
08323                   ast_hangup(chan);
08324                }
08325                chan = NULL;
08326             }
08327          }
08328       }
08329    } else {
08330       if (!(as = ast_calloc(1, sizeof(*as)))) {
08331          res = -1;
08332          goto outgoing_exten_cleanup;
08333       }
08334       chan = ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name);
08335       if (channel) {
08336          *channel = chan;
08337          if (chan)
08338             ast_channel_lock(chan);
08339       }
08340       if (!chan) {
08341          ast_free(as);
08342          res = -1;
08343          goto outgoing_exten_cleanup;
08344       }
08345       as->chan = chan;
08346       ast_copy_string(as->context, context, sizeof(as->context));
08347       set_ext_pri(as->chan,  exten, priority);
08348       as->timeout = timeout;
08349       ast_set_variables(chan, vars);
08350       if (account)
08351          ast_cdr_setaccount(chan, account);
08352       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
08353          ast_log(LOG_WARNING, "Failed to start async wait\n");
08354          ast_free(as);
08355          if (channel) {
08356             *channel = NULL;
08357             ast_channel_unlock(chan);
08358          }
08359          ast_hangup(chan);
08360          res = -1;
08361          goto outgoing_exten_cleanup;
08362       }
08363       res = 0;
08364    }
08365 outgoing_exten_cleanup:
08366    ast_variables_destroy(vars);
08367    return res;
08368 }

enum ast_pbx_result ast_pbx_run ( struct ast_channel c  ) 

Execute the PBX in the current thread.

Parameters:
c channel 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:
Zero on success
non-zero on failure

Definition at line 4929 of file pbx.c.

References ast_pbx_run_args().

Referenced by __analog_ss_thread(), analog_ss_thread(), ast_pbx_outgoing_exten(), async_wait(), do_notify(), mgcp_ss(), skinny_newcall(), and unistim_ss().

04930 {
04931    return ast_pbx_run_args(c, NULL);
04932 }

static void* ast_pbx_run_app ( void *  data  )  [static]

run the application and free the descriptor once done

Definition at line 8378 of file pbx.c.

References app_tmp::app, ast_free, ast_hangup(), ast_log(), ast_verb, app_tmp::chan, app_tmp::data, LOG_WARNING, ast_channel::name, pbx_exec(), and pbx_findapp().

Referenced by ast_pbx_outgoing_app().

08379 {
08380    struct app_tmp *tmp = data;
08381    struct ast_app *app;
08382    app = pbx_findapp(tmp->app);
08383    if (app) {
08384       ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
08385       pbx_exec(tmp->chan, app, tmp->data);
08386    } else
08387       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
08388    ast_hangup(tmp->chan);
08389    ast_free(tmp);
08390    return NULL;
08391 }

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

Execute the PBX in the current thread.

Parameters:
c channel to run the pbx on
args options 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:
Zero on success
non-zero on failure

Definition at line 4914 of file pbx.c.

References __ast_pbx_run(), AST_PBX_CALL_LIMIT, AST_PBX_SUCCESS, decrease_call_count(), and increase_call_count().

Referenced by ast_pbx_run(), dial_exec_full(), handle_gosub(), and try_calling().

04915 {
04916    enum ast_pbx_result res = AST_PBX_SUCCESS;
04917 
04918    if (increase_call_count(c)) {
04919       return AST_PBX_CALL_LIMIT;
04920    }
04921 
04922    res = __ast_pbx_run(c, args);
04923 
04924    decrease_call_count();
04925 
04926    return res;
04927 }

enum ast_pbx_result ast_pbx_start ( struct ast_channel c  ) 

Create a new thread and start the PBX.

Parameters:
c channel 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:
Zero on success
non-zero on failure

Definition at line 4892 of file pbx.c.

References ast_log(), AST_PBX_CALL_LIMIT, AST_PBX_FAILED, AST_PBX_SUCCESS, ast_pthread_create_detached, decrease_call_count(), increase_call_count(), LOG_WARNING, and pbx_thread().

Referenced by __oh323_new(), alsa_new(), ast_async_goto(), ast_iax2_new(), ast_pbx_outgoing_exten(), bridge_call_thread(), bridge_exec(), check_goto_on_transfer(), console_new(), dahdi_new(), dial_exec_full(), gtalk_new(), gtalk_newcall(), handle_request_invite(), jingle_new(), jingle_newcall(), local_call(), manage_parkinglot(), mgcp_new(), nbs_new(), oss_new(), pbx_start_chan(), phone_new(), rpt_call(), sip_new(), skinny_new(), unistim_new(), and usbradio_new().

04893 {
04894    pthread_t t;
04895 
04896    if (!c) {
04897       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
04898       return AST_PBX_FAILED;
04899    }
04900 
04901    if (increase_call_count(c))
04902       return AST_PBX_CALL_LIMIT;
04903 
04904    /* Start a new thread, and get something handling this channel. */
04905    if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
04906       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
04907       decrease_call_count();
04908       return AST_PBX_FAILED;
04909    }
04910 
04911    return AST_PBX_SUCCESS;
04912 }

int ast_processed_calls ( void   ) 

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

Definition at line 4939 of file pbx.c.

References totalcalls.

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

04940 {
04941    return totalcalls;
04942 }

int ast_rdlock_context ( struct ast_context con  ) 

Read locks a given context.

Parameters:
con context to lock
Return values:
0 on success
-1 on failure

Definition at line 9642 of file pbx.c.

References ast_rwlock_rdlock(), and ast_context::lock.

Referenced by _macro_exec(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), dundi_precache_full(), find_matching_endwhile(), handle_cli_dialplan_save(), lookup_c_ip(), lookup_ci(), manager_show_dialplan_helper(), show_debug_helper(), and show_dialplan_helper().

09643 {
09644    return ast_rwlock_rdlock(&con->lock);
09645 }

int ast_rdlock_contexts ( void   ) 

int ast_register_application2 ( const char *  app,
int(*)(struct ast_channel *, const char *)  execute,
const char *  synopsis,
const char *  description,
void *  mod 
)

Dynamically register a new dial plan application.

Register an application.

Definition at line 5366 of file pbx.c.

References ast_app::arguments, ast_calloc, ast_free, ast_log(), AST_RWLIST_INSERT_BEFORE_CURRENT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, AST_STATIC_DOC, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_verb, AST_XML_DOC, COLOR_BRCYAN, ast_app::execute, LOG_WARNING, ast_app::module, ast_app::name, ast_app::seealso, ast_app::syntax, and term_color().

Referenced by ast_features_init(), and load_pbx().

05367 {
05368    struct ast_app *tmp, *cur = NULL;
05369    char tmps[80];
05370    int length, res;
05371 #ifdef AST_XML_DOCS
05372    char *tmpxml;
05373 #endif
05374 
05375    AST_RWLIST_WRLOCK(&apps);
05376    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
05377       if (!(res = strcasecmp(app, tmp->name))) {
05378          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
05379          AST_RWLIST_UNLOCK(&apps);
05380          return -1;
05381       } else if (res < 0)
05382          break;
05383    }
05384 
05385    length = sizeof(*tmp) + strlen(app) + 1;
05386 
05387    if (!(tmp = ast_calloc(1, length))) {
05388       AST_RWLIST_UNLOCK(&apps);
05389       return -1;
05390    }
05391 
05392    if (ast_string_field_init(tmp, 128)) {
05393       AST_RWLIST_UNLOCK(&apps);
05394       ast_free(tmp);
05395       return -1;
05396    }
05397 
05398 #ifdef AST_XML_DOCS
05399    /* Try to lookup the docs in our XML documentation database */
05400    if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
05401       /* load synopsis */
05402       tmpxml = ast_xmldoc_build_synopsis("application", app);
05403       ast_string_field_set(tmp, synopsis, tmpxml);
05404       ast_free(tmpxml);
05405 
05406       /* load description */
05407       tmpxml = ast_xmldoc_build_description("application", app);
05408       ast_string_field_set(tmp, description, tmpxml);
05409       ast_free(tmpxml);
05410 
05411       /* load syntax */
05412       tmpxml = ast_xmldoc_build_syntax("application", app);
05413       ast_string_field_set(tmp, syntax, tmpxml);
05414       ast_free(tmpxml);
05415 
05416       /* load arguments */
05417       tmpxml = ast_xmldoc_build_arguments("application", app);
05418       ast_string_field_set(tmp, arguments, tmpxml);
05419       ast_free(tmpxml);
05420 
05421       /* load seealso */
05422       tmpxml = ast_xmldoc_build_seealso("application", app);
05423       ast_string_field_set(tmp, seealso, tmpxml);
05424       ast_free(tmpxml);
05425       tmp->docsrc = AST_XML_DOC;
05426    } else {
05427 #endif
05428       ast_string_field_set(tmp, synopsis, synopsis);
05429       ast_string_field_set(tmp, description, description);
05430 #ifdef AST_XML_DOCS
05431       tmp->docsrc = AST_STATIC_DOC;
05432    }
05433 #endif
05434 
05435    strcpy(tmp->name, app);
05436    tmp->execute = execute;
05437    tmp->module = mod;
05438 
05439    /* Store in alphabetical order */
05440    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
05441       if (strcasecmp(tmp->name, cur->name) < 0) {
05442          AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
05443          break;
05444       }
05445    }
05446    AST_RWLIST_TRAVERSE_SAFE_END;
05447    if (!cur)
05448       AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
05449 
05450    ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
05451 
05452    AST_RWLIST_UNLOCK(&apps);
05453 
05454    return 0;
05455 }

int ast_register_switch ( struct ast_switch sw  ) 

Register an alternative dialplan switch.

Parameters:
sw switch to register
This function registers a populated ast_switch structure with the asterisk switching architecture.

Return values:
0 success
non-zero failure

Definition at line 5461 of file pbx.c.

References ast_log(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, LOG_WARNING, and ast_switch::name.

Referenced by load_module().

05462 {
05463    struct ast_switch *tmp;
05464 
05465    AST_RWLIST_WRLOCK(&switches);
05466    AST_RWLIST_TRAVERSE(&switches, tmp, list) {
05467       if (!strcasecmp(tmp->name, sw->name)) {
05468          AST_RWLIST_UNLOCK(&switches);
05469          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
05470          return -1;
05471       }
05472    }
05473    AST_RWLIST_INSERT_TAIL(&switches, sw, list);
05474    AST_RWLIST_UNLOCK(&switches);
05475 
05476    return 0;
05477 }

static int ast_remove_hint ( struct ast_exten e  )  [static]

Remove hint from extension.

Definition at line 4407 of file pbx.c.

References AST_EXTENSION_DEACTIVATED, ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, ast_state_cb::callback, ast_hint::callbacks, ast_state_cb::data, ast_exten::exten, ast_hint::exten, ast_context::name, and ast_exten::parent.

Referenced by destroy_exten().

04408 {
04409    /* Cleanup the Notifys if hint is removed */
04410    struct ast_hint *hint;
04411    struct ast_state_cb *cblist;
04412    int res = -1;
04413 
04414    if (!e)
04415       return -1;
04416 
04417    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
04418       if (hint->exten != e)
04419          continue;
04420 
04421       while ((cblist = AST_LIST_REMOVE_HEAD(&hint->callbacks, entry))) {
04422          /* Notify with -1 and remove all callbacks */
04423          cblist->callback(hint->exten->parent->name, hint->exten->exten,
04424             AST_EXTENSION_DEACTIVATED, cblist->data);
04425          ast_free(cblist);
04426       }
04427 
04428       AST_RWLIST_REMOVE_CURRENT(list);
04429       ast_free(hint);
04430 
04431       res = 0;
04432 
04433       break;
04434    }
04435    AST_RWLIST_TRAVERSE_SAFE_END;
04436 
04437    return res;
04438 }

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

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

Parameters:
c not important
context which context to generate the extension within
exten new extension to add
priority priority of new extension
callerid callerid of extension
found 
combined_find_spawn This adds a new extension to the asterisk extension list.
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:
0 on success
-1 on failure.

Definition at line 4505 of file pbx.c.

References E_SPAWN, and pbx_extension_helper().

Referenced by __ast_pbx_run(), _macro_exec(), ast_bridge_call(), dial_exec_full(), and loopback_exec().

04506 {
04507    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
04508 }

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

Get hint for channel.

If an extension hint exists, return non-zero.

Definition at line 4460 of file pbx.c.

References ast_get_extension_app(), ast_get_extension_app_data(), ast_hint_extension(), and ast_str_set().

Referenced by ast_str_retrieve_variable().

04461 {
04462    struct ast_exten *e = ast_hint_extension(c, context, exten);
04463 
04464    if (!e) {
04465       return 0;
04466    }
04467 
04468    if (hint) {
04469       ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
04470    }
04471    if (name) {
04472       const char *tmp = ast_get_extension_app_data(e);
04473       if (tmp) {
04474          ast_str_set(name, namesize, "%s", tmp);
04475       }
04476    }
04477    return -1;
04478 }

const char* ast_str_retrieve_variable ( struct ast_str **  buf,
ssize_t  maxlen,
struct ast_channel chan,
struct varshead headp,
const char *  var 
)

Parameters:
buf Result will be placed in this buffer.
maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
chan Channel variables from which to extract values, and channel to pass to any dialplan functions.
headp If no channel is specified, a channel list from which to extract variable values
var Variable name to retrieve.

Definition at line 2929 of file pbx.c.

References ARRAY_LEN, ast_channel_lock, ast_channel_unlock, ast_config_AST_SYSTEM_NAME, ast_debug, ast_eid_default, ast_eid_to_str(), AST_LIST_TRAVERSE, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_str_buffer(), ast_str_get_hint(), ast_str_set(), ast_str_substring(), ast_strdupa, ast_var_name(), ast_var_value(), ast_channel::cid, ast_callerid::cid_ani2, ast_callerid::cid_pres, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_var_t::entries, ast_channel::exten, globals, globalslock, ast_channel::hangupcause, ast_channel::name, parse_variable_name(), ast_channel::priority, s, ast_channel::uniqueid, and ast_channel::varshead.

Referenced by ast_str_substitute_variables_full(), and pbx_retrieve_variable().

02930 {
02931    const char not_found = '\0';
02932    char *tmpvar;
02933    const char *ret;
02934    const char *s; /* the result */
02935    int offset, length;
02936    int i, need_substring;
02937    struct varshead *places[2] = { headp, &globals };  /* list of places where we may look */
02938 
02939    if (c) {
02940       ast_channel_lock(c);
02941       places[0] = &c->varshead;
02942    }
02943    /*
02944     * Make a copy of var because parse_variable_name() modifies the string.
02945     * Then if called directly, we might need to run substring() on the result;
02946     * remember this for later in 'need_substring', 'offset' and 'length'
02947     */
02948    tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
02949    need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
02950 
02951    /*
02952     * Look first into predefined variables, then into variable lists.
02953     * Variable 's' points to the result, according to the following rules:
02954     * s == &not_found (set at the beginning) means that we did not find a
02955     * matching variable and need to look into more places.
02956     * If s != &not_found, s is a valid result string as follows:
02957     * s = NULL if the variable does not have a value;
02958     * you typically do this when looking for an unset predefined variable.
02959     * s = workspace if the result has been assembled there;
02960     * typically done when the result is built e.g. with an snprintf(),
02961     * so we don't need to do an additional copy.
02962     * s != workspace in case we have a string, that needs to be copied
02963     * (the ast_copy_string is done once for all at the end).
02964     * Typically done when the result is already available in some string.
02965     */
02966    s = &not_found;   /* default value */
02967    if (c) { /* This group requires a valid channel */
02968       /* Names with common parts are looked up a piece at a time using strncmp. */
02969       if (!strncmp(var, "CALL", 4)) {
02970          if (!strncmp(var + 4, "ING", 3)) {
02971             if (!strcmp(var + 7, "PRES")) {        /* CALLINGPRES */
02972                ast_str_set(str, maxlen, "%d", c->cid.cid_pres);
02973                s = ast_str_buffer(*str);
02974             } else if (!strcmp(var + 7, "ANI2")) {    /* CALLINGANI2 */
02975                ast_str_set(str, maxlen, "%d", c->cid.cid_ani2);
02976                s = ast_str_buffer(*str);
02977             } else if (!strcmp(var + 7, "TON")) {     /* CALLINGTON */
02978                ast_str_set(str, maxlen, "%d", c->cid.cid_ton);
02979                s = ast_str_buffer(*str);
02980             } else if (!strcmp(var + 7, "TNS")) {     /* CALLINGTNS */
02981                ast_str_set(str, maxlen, "%d", c->cid.cid_tns);
02982                s = ast_str_buffer(*str);
02983             }
02984          }
02985       } else if (!strcmp(var, "HINT")) {
02986          s = ast_str_get_hint(str, maxlen, NULL, 0, c, c->context, c->exten) ? ast_str_buffer(*str) : NULL;
02987       } else if (!strcmp(var, "HINTNAME")) {
02988          s = ast_str_get_hint(NULL, 0, str, maxlen, c, c->context, c->exten) ? ast_str_buffer(*str) : NULL;
02989       } else if (!strcmp(var, "EXTEN")) {
02990          s = c->exten;
02991       } else if (!strcmp(var, "CONTEXT")) {
02992          s = c->context;
02993       } else if (!strcmp(var, "PRIORITY")) {
02994          ast_str_set(str, maxlen, "%d", c->priority);
02995          s = ast_str_buffer(*str);
02996       } else if (!strcmp(var, "CHANNEL")) {
02997          s = c->name;
02998       } else if (!strcmp(var, "UNIQUEID")) {
02999          s = c->uniqueid;
03000       } else if (!strcmp(var, "HANGUPCAUSE")) {
03001          ast_str_set(str, maxlen, "%d", c->hangupcause);
03002          s = ast_str_buffer(*str);
03003       }
03004    }
03005    if (s == &not_found) { /* look for more */
03006       if (!strcmp(var, "EPOCH")) {
03007          ast_str_set(str, maxlen, "%u", (int) time(NULL));
03008          s = ast_str_buffer(*str);
03009       } else if (!strcmp(var, "SYSTEMNAME")) {
03010          s = ast_config_AST_SYSTEM_NAME;
03011       } else if (!strcmp(var, "ENTITYID")) {
03012          char workspace[20];
03013          ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
03014          s = workspace;
03015       }
03016    }
03017    /* if not found, look into chanvars or global vars */
03018    for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
03019       struct ast_var_t *variables;
03020       if (!places[i])
03021          continue;
03022       if (places[i] == &globals)
03023          ast_rwlock_rdlock(&globalslock);
03024       AST_LIST_TRAVERSE(places[i], variables, entries) {
03025          if (!strcasecmp(ast_var_name(variables), var)) {
03026             s = ast_var_value(variables);
03027             break;
03028          }
03029       }
03030       if (places[i] == &globals)
03031          ast_rwlock_unlock(&globalslock);
03032    }
03033    if (s == &not_found || s == NULL) {
03034       ast_debug(5, "Result of '%s' is NULL\n", var);
03035       ret = NULL;
03036    } else {
03037       ast_debug(5, "Result of '%s' is '%s'\n", var, s);
03038       if (s != ast_str_buffer(*str)) {
03039          ast_str_set(str, maxlen, "%s", s);
03040       }
03041       ret = ast_str_buffer(*str);
03042       if (need_substring) {
03043          ret = ast_str_substring(*str, offset, length);
03044          ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
03045       }
03046    }
03047 
03048    if (c) {
03049       ast_channel_unlock(c);
03050    }
03051    return ret;
03052 }

void ast_str_substitute_variables ( struct ast_str **  buf,
ssize_t  maxlen,
struct ast_channel chan,
const char *  templ 
)

Parameters:
buf Result will be placed in this buffer.
maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
chan Channel variables from which to extract values, and channel to pass to any dialplan functions.
templ Variable template to expand.

Definition at line 3709 of file pbx.c.

References ast_str_substitute_variables_full().

Referenced by _macro_exec(), acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), cli_odbc_write(), config_curl(), custom_log(), cut_internal(), destroy_curl(), exec_exec(), func_mchan_read(), function_eval2(), function_fieldqty_helper(), handle_getvariablefull(), import_helper(), make_email_file(), realtime_curl(), realtime_multi_curl(), require_curl(), sendmail(), sendpage(), store_curl(), syslog_log(), tryexec_exec(), update2_curl(), and update_curl().

03710 {
03711    size_t used;
03712    ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, &used);
03713 }

void ast_str_substitute_variables_full ( struct ast_str **  buf,
ssize_t  maxlen,
struct ast_channel c,
struct varshead headp,
const char *  templ,
size_t *  used 
)

Parameters:
buf Result will be placed in this buffer.
maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
c Channel variables from which to extract values, and channel to pass to any dialplan functions.
headp If no channel is specified, a channel list from which to extract variable values
templ Variable template to expand.
used Number of bytes read from the template.

Definition at line 3533 of file pbx.c.

References ast_channel_release(), ast_debug, ast_dummy_channel_alloc(), ast_free, ast_func_read2(), ast_log(), ast_str_append(), ast_str_append_substr(), ast_str_buffer(), ast_str_create(), ast_str_expr(), ast_str_reset(), ast_str_retrieve_variable(), ast_str_set_substr(), ast_str_strlen(), ast_str_substitute_variables_full(), ast_str_substring(), ast_strlen_zero(), len(), LOG_ERROR, LOG_WARNING, parse_variable_name(), and ast_channel::varshead.

Referenced by ast_str_substitute_variables(), ast_str_substitute_variables_full(), and ast_str_substitute_variables_varshead().

03534 {
03535    /* Substitutes variables into buf, based on string templ */
03536    char *cp4 = NULL;
03537    const char *tmp, *whereweare;
03538    int orig_size = 0;
03539    int offset, offset2, isfunction;
03540    const char *nextvar, *nextexp, *nextthing;
03541    const char *vars, *vare;
03542    char *finalvars;
03543    int pos, brackets, needsub, len;
03544    struct ast_str *substr1 = ast_str_create(16), *substr2 = NULL, *substr3 = ast_str_create(16);
03545 
03546    ast_str_reset(*buf);
03547    whereweare = tmp = templ;
03548    while (!ast_strlen_zero(whereweare)) {
03549       /* Assume we're copying the whole remaining string */
03550       pos = strlen(whereweare);
03551       nextvar = NULL;
03552       nextexp = NULL;
03553       nextthing = strchr(whereweare, '$');
03554       if (nextthing) {
03555          switch (nextthing[1]) {
03556          case '{':
03557             nextvar = nextthing;
03558             pos = nextvar - whereweare;
03559             break;
03560          case '[':
03561             nextexp = nextthing;
03562             pos = nextexp - whereweare;
03563             break;
03564          default:
03565             pos = 1;
03566          }
03567       }
03568 
03569       if (pos) {
03570          /* Copy that many bytes */
03571          ast_str_append_substr(buf, maxlen, whereweare, pos);
03572 
03573          templ += pos;
03574          whereweare += pos;
03575       }
03576 
03577       if (nextvar) {
03578          /* We have a variable.  Find the start and end, and determine
03579             if we are going to have to recursively call ourselves on the
03580             contents */
03581          vars = vare = nextvar + 2;
03582          brackets = 1;
03583          needsub = 0;
03584 
03585          /* Find the end of it */
03586          while (brackets && *vare) {
03587             if ((vare[0] == '$') && (vare[1] == '{')) {
03588                needsub++;
03589             } else if (vare[0] == '{') {
03590                brackets++;
03591             } else if (vare[0] == '}') {
03592                brackets--;
03593             } else if ((vare[0] == '$') && (vare[1] == '['))
03594                needsub++;
03595             vare++;
03596          }
03597          if (brackets)
03598             ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
03599          len = vare - vars - 1;
03600 
03601          /* Skip totally over variable string */
03602          whereweare += (len + 3);
03603 
03604          /* Store variable name (and truncate) */
03605          ast_str_set_substr(&substr1, 0, vars, len);
03606          ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
03607 
03608          /* Substitute if necessary */
03609          if (needsub) {
03610             size_t used;
03611             if (!substr2) {
03612                substr2 = ast_str_create(16);
03613             }
03614 
03615             ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
03616             finalvars = ast_str_buffer(substr2);
03617          } else {
03618             finalvars = ast_str_buffer(substr1);
03619          }
03620 
03621          parse_variable_name(finalvars, &offset, &offset2, &isfunction);
03622          if (isfunction) {
03623             /* Evaluate function */
03624             if (c || !headp) {
03625                cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
03626             } else {
03627                struct varshead old;
03628                struct ast_channel *bogus = ast_dummy_channel_alloc();
03629                if (bogus) {
03630                   memcpy(&old, &bogus->varshead, sizeof(old));
03631                   memcpy(&bogus->varshead, headp, sizeof(bogus->varshead));
03632                   cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
03633                   /* Don't deallocate the varshead that was passed in */
03634                   memcpy(&bogus->varshead, &old, sizeof(bogus->varshead));
03635                   ast_channel_release(bogus);
03636                } else {
03637                   ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
03638                }
03639             }
03640             ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
03641          } else {
03642             /* Retrieve variable value */
03643             ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
03644             cp4 = ast_str_buffer(substr3);
03645          }
03646          if (cp4) {
03647             ast_str_substring(substr3, offset, offset2);
03648             ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
03649          }
03650       } else if (nextexp) {
03651          /* We have an expression.  Find the start and end, and determine
03652             if we are going to have to recursively call ourselves on the
03653             contents */
03654          vars = vare = nextexp + 2;
03655          brackets = 1;
03656          needsub = 0;
03657 
03658          /* Find the end of it */
03659          while (brackets && *vare) {
03660             if ((vare[0] == '$') && (vare[1] == '[')) {
03661                needsub++;
03662                brackets++;
03663                vare++;
03664             } else if (vare[0] == '[') {
03665                brackets++;
03666             } else if (vare[0] == ']') {
03667                brackets--;
03668             } else if ((vare[0] == '$') && (vare[1] == '{')) {
03669                needsub++;
03670                vare++;
03671             }
03672             vare++;
03673          }
03674          if (brackets)
03675             ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
03676          len = vare - vars - 1;
03677 
03678          /* Skip totally over expression */
03679          whereweare += (len + 3);
03680 
03681          /* Store variable name (and truncate) */
03682          ast_str_set_substr(&substr1, 0, vars, len);
03683 
03684          /* Substitute if necessary */
03685          if (needsub) {
03686             size_t used;
03687             if (!substr2) {
03688                substr2 = ast_str_create(16);
03689             }
03690 
03691             ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
03692             finalvars = ast_str_buffer(substr2);
03693          } else {
03694             finalvars = ast_str_buffer(substr1);
03695          }
03696 
03697          if (ast_str_expr(&substr3, 0, c, finalvars)) {
03698             ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
03699          }
03700          ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
03701       }
03702    }
03703    *used = ast_str_strlen(*buf) - orig_size;
03704    ast_free(substr1);
03705    ast_free(substr2);
03706    ast_free(substr3);
03707 }

void ast_str_substitute_variables_varshead ( struct ast_str **  buf,
ssize_t  maxlen,
struct varshead headp,
const char *  templ 
)

Parameters:
buf Result will be placed in this buffer.
maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
headp If no channel is specified, a channel list from which to extract variable values
templ Variable template to expand.

Definition at line 3715 of file pbx.c.

References ast_str_substitute_variables_full().

Referenced by add_user_extension(), build_user_routes(), phoneprov_callback(), pp_each_extension_helper(), and pp_each_user_helper().

03716 {
03717    size_t used;
03718    ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, &used);
03719 }

static const char* ast_str_substring ( struct ast_str value,
int  offset,
int  length 
) [static]

Definition at line 2864 of file pbx.c.

References ast_str_buffer(), ast_str_reset(), ast_str_strlen(), and ast_str_update().

Referenced by ast_str_retrieve_variable(), and ast_str_substitute_variables_full().

02865 {
02866    int lr;  /* length of the input string after the copy */
02867 
02868    lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
02869 
02870    /* Quick check if no need to do anything */
02871    if (offset == 0 && length >= lr) /* take the whole string */
02872       return ast_str_buffer(value);
02873 
02874    if (offset < 0)   {  /* translate negative offset into positive ones */
02875       offset = lr + offset;
02876       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
02877          offset = 0;
02878    }
02879 
02880    /* too large offset result in empty string so we know what to return */
02881    if (offset >= lr) {
02882       ast_str_reset(value);
02883       return ast_str_buffer(value);
02884    }
02885 
02886    if (offset > 0) {
02887       /* Go ahead and chop off the beginning */
02888       memcpy(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
02889       lr -= offset;
02890    }
02891 
02892    if (length >= 0 && length < lr) {   /* truncate if necessary */
02893       char *tmp = ast_str_buffer(value);
02894       tmp[length] = '\0';
02895       ast_str_update(value);
02896    } else if (length < 0) {
02897       if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
02898          char *tmp = ast_str_buffer(value);
02899          tmp[lr + length] = '\0';
02900          ast_str_update(value);
02901       } else {
02902          ast_str_reset(value);
02903       }
02904    } else {
02905       /* Nothing to do, but update the buffer length */
02906       ast_str_update(value);
02907    }
02908 
02909    return ast_str_buffer(value);
02910 }

int ast_unlock_context ( struct ast_context con  ) 

int ast_unlock_contexts ( void   )