Thu Jul 9 13:41:24 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 <sys/sysinfo.h>
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/callerid.h"
#include "asterisk/cdr.h"
#include "asterisk/config.h"
#include "asterisk/term.h"
#include "asterisk/manager.h"
#include "asterisk/ast_expr.h"
#include "asterisk/linkedlists.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/musiconhold.h"
#include "asterisk/app.h"
#include "asterisk/devicestate.h"
#include "asterisk/stringfields.h"
#include "asterisk/event.h"
#include "asterisk/hashtab.h"
#include "asterisk/module.h"
#include "asterisk/indications.h"

Go to the source code of this file.

Data Structures

struct  acf_root
struct  app_tmp
struct  apps
struct  ast_app
 ast_app: A registered application More...
struct  ast_context
 ast_context: An extension context More...
struct  ast_exten
 ast_exten: An extension The dialplan is saved as a linked list with each context having it's own linked list of extensions - one item per priority. More...
struct  ast_hint
 Structure for dial plan hints. More...
struct  ast_ignorepat
 ast_ignorepat: Ignore patterns in dial plan More...
struct  ast_include
 ast_include: include= support in extensions.conf More...
struct  ast_state_cb
 ast_state_cb: An extension state notify register item More...
struct  ast_sw
 ast_sw: Switch statement in extensions.conf More...
struct  async_stat
struct  cfextension_states
struct  dialplan_counters
 Counters for the show dialplan manager command. More...
struct  fake_context
struct  hints
struct  match_char
 match_char: forms a syntax tree for quick matching of extension patterns More...
struct  pbx_builtin
 Declaration of builtin applications. More...
struct  pbx_exception
struct  scoreboard
struct  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 __init_switch_data (void)
static int _extension_match_core (const char *pattern, const char *data, enum ext_match_t mode)
static int acf_exception_read (struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
static struct match_charadd_exten_to_pattern_tree (struct ast_context *con, struct ast_exten *e1, int findonly)
static 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 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)
 Add an extension to an extension context, this time with an ast_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_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)
int ast_async_goto_by_name (const char *channame, const char *context, const char *exten, int priority)
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)
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)
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).
ast_contextast_context_find (const char *name)
 Find a context.
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 matchcid, const char *registrar)
int ast_context_remove_extension_callerid2 (struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcid, 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 a context include.
int ast_context_remove_include2 (struct ast_context *con, const char *include, const char *registrar)
 Removes an include by an ast_context structure.
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.
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_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)
 Uses hint and devicestate callback to get the state of an extension.
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 string representation of the state of an extension.
int ast_extension_state_add (const char *context, const char *exten, ast_state_cb_type callback, void *data)
 Registers a state change callback.
int ast_extension_state_del (int id, ast_state_cb_type callback)
 Deletes a registered state change callback by ID.
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_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)
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)
 If an extension hint exists, return non-zero.
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)
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)
 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 sync, 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 sync, 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 *, void *), const char *synopsis, const char *description, void *mod)
 Register an 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_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.
ast_extenast_walk_context_extensions (struct ast_context *con, struct ast_exten *exten)
ast_ignorepatast_walk_context_ignorepats (struct ast_context *con, struct ast_ignorepat *ip)
ast_includeast_walk_context_includes (struct ast_context *con, struct ast_include *inc)
ast_swast_walk_context_switches (struct ast_context *con, struct ast_sw *sw)
ast_contextast_walk_contexts (struct ast_context *con)
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 * device_state_thread (void *data)
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_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, 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 2 minute
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_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 void handle_statechange (const char *device)
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)
void log_match_char_tree (struct match_char *node, char *prefix)
static int lookup_name (const char *s, 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 *, void *)
static int pbx_builtin_background (struct ast_channel *, void *)
static int pbx_builtin_busy (struct ast_channel *, void *)
void pbx_builtin_clear_globals (void)
static int pbx_builtin_congestion (struct ast_channel *, void *)
static int pbx_builtin_execiftime (struct ast_channel *, void *)
const char * pbx_builtin_getvar_helper (struct ast_channel *chan, const char *name)
static int pbx_builtin_goto (struct ast_channel *, void *)
static int pbx_builtin_gotoif (struct ast_channel *, void *)
static int pbx_builtin_gotoiftime (struct ast_channel *, void *)
static int pbx_builtin_hangup (struct ast_channel *, void *)
static int pbx_builtin_importvar (struct ast_channel *, void *)
static int pbx_builtin_noop (struct ast_channel *, void *)
static int pbx_builtin_proceeding (struct ast_channel *, void *)
static int pbx_builtin_progress (struct ast_channel *, void *)
void pbx_builtin_pushvar_helper (struct ast_channel *chan, const char *name, const char *value)
int pbx_builtin_raise_exception (struct ast_channel *chan, void *vreason)
static int pbx_builtin_resetcdr (struct ast_channel *, void *)
static int pbx_builtin_ringing (struct ast_channel *, void *)
static int pbx_builtin_saycharacters (struct ast_channel *, void *)
static int pbx_builtin_saydigits (struct ast_channel *, void *)
static int pbx_builtin_saynumber (struct ast_channel *, void *)
static int pbx_builtin_sayphonetic (struct ast_channel *, void *)
int pbx_builtin_serialize_variables (struct ast_channel *chan, struct ast_str **buf)
static int pbx_builtin_setamaflags (struct ast_channel *, void *)
int pbx_builtin_setvar (struct ast_channel *, void *)
void pbx_builtin_setvar_helper (struct ast_channel *chan, const char *name, const char *value)
int pbx_builtin_setvar_multiple (struct ast_channel *, void *)
static int pbx_builtin_wait (struct ast_channel *, void *)
static int pbx_builtin_waitexten (struct ast_channel *, void *)
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, void *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:.
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)
ast_apppbx_findapp (const char *app)
 Look up an application.
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)
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)
static void pbx_substitute_variables_helper_full (struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
void pbx_substitute_variables_varshead (struct varshead *headp, const char *cp1, char *cp2, int count)
static void * pbx_thread (void *data)
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_dialplan_helper (int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
static int statechange_queue (const char *dev)
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, 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 = PTHREAD_RWLOCK_INITIALIZER
static int conlock_wrlock_version = 0
static struct ast_contextcontexts
static struct ast_hashtabcontexts_table = NULL
static int countcalls
static char * days []
struct {
   ast_cond_t   cond
   ast_mutex_t   lock
   struct {
      statechange *   first
      statechange *   last
   }   state_change_q
   unsigned int   stop:1
   pthread_t   thread
device_state
 Data used by the device state thread.
static struct ast_event_subdevice_state_sub
 Subscription for device state change events.
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 varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
static ast_rwlock_t globalslock = PTHREAD_RWLOCK_INITIALIZER
static char mandescr_show_dialplan []
static ast_mutex_t maxcalllock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
static char * months []
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) },}
ast_state_cbstatecbs
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 962 of file pbx.c.

Referenced by handle_show_dialplan(), pbx_find_extension(), and show_dialplan_helper().

#define BACKGROUND_MATCHEXTEN   (1 << 2)

Definition at line 105 of file pbx.c.

Referenced by pbx_builtin_background().

#define BACKGROUND_NOANSWER   (1 << 1)

Definition at line 104 of file pbx.c.

Referenced by pbx_builtin_background().

#define BACKGROUND_PLAYBACK   (1 << 3)

Definition at line 106 of file pbx.c.

Referenced by pbx_builtin_background().

#define BACKGROUND_SKIP   (1 << 0)

Definition at line 103 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 92 of file pbx.c.

Referenced by pbx_extension_helper().

#define NEW_MATCHER_CHK_MATCH

Referenced by new_find_extension().

#define NEW_MATCHER_RECURSE

#define SAY_STUBS

Definition at line 55 of file pbx.c.

#define STATUS_NO_CONTEXT   1

Definition at line 2019 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_NO_EXTENSION   2

Definition at line 2020 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_NO_LABEL   4

Definition at line 2022 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_NO_PRIORITY   3

Definition at line 2021 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_SUCCESS   5

Definition at line 2023 of file pbx.c.

Referenced by pbx_find_extension().

#define SWITCH_DATA_LENGTH   256

Definition at line 95 of file pbx.c.

#define VAR_BUF_SIZE   4096

Definition at line 97 of file pbx.c.

Referenced by ast_add_extension2_lockopt(), build_user_routes(), pbx_builtin_importvar(), pbx_substitute_variables_helper_full(), phoneprov_callback(), and pp_each_user_exec().

#define VAR_HARDTRAN   3

Definition at line 101 of file pbx.c.

#define VAR_NORMAL   1

Definition at line 99 of file pbx.c.

#define VAR_SOFTTRAN   2

Definition at line 100 of file pbx.c.

#define WAITEXTEN_DIALTONE   (1 << 1)

Definition at line 116 of file pbx.c.

Referenced by pbx_builtin_waitexten().

#define WAITEXTEN_MOH   (1 << 0)

Definition at line 115 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 7398 of file pbx.c.

References __ast_internal_context_destroy(), 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_sw::list, ast_context::name, ast_sw::next, ast_include::next, ast_ignorepat::next, ast_context::next, ast_exten::next, ast_exten::peer_table, ast_exten::priority, ast_exten::registrar, ast_sw::registrar, ast_include::registrar, ast_ignorepat::registrar, ast_context::registrar, and ast_context::root_table.

Referenced by ast_context_destroy().

07399 {
07400    struct ast_context *tmp, *tmpl=NULL;
07401    struct ast_exten *exten_item, *prio_item;
07402 
07403    for (tmp = list; tmp; ) {
07404       struct ast_context *next = NULL; /* next starting point */
07405          /* The following code used to skip forward to the next
07406             context with matching registrar, but this didn't
07407             make sense; individual priorities registrar'd to 
07408             the matching registrar could occur in any context! */
07409       ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
07410       if (con) {
07411          for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
07412             ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
07413             if ( !strcasecmp(tmp->name, con->name) ) {
07414                break;   /* found it */
07415             }
07416          }
07417       }
07418       
07419       if (!tmp)   /* not found, we are done */
07420          break;
07421       ast_wrlock_context(tmp);
07422 
07423       if (registrar) {
07424          /* then search thru and remove any extens that match registrar. */
07425          struct ast_hashtab_iter *exten_iter;
07426          struct ast_hashtab_iter *prio_iter;
07427          struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
07428          struct ast_include *i, *pi = NULL, *ni = NULL;
07429          struct ast_sw *sw = NULL;
07430   
07431          /* remove any ignorepats whose registrar matches */
07432          for (ip = tmp->ignorepats; ip; ip = ipn) {
07433             ipn = ip->next;
07434             if (!strcmp(ip->registrar, registrar)) {
07435                if (ipl) {
07436                   ipl->next = ip->next;
07437                   ast_free(ip);
07438                   continue; /* don't change ipl */
07439                } else {
07440                   tmp->ignorepats = ip->next;
07441                   ast_free(ip);
07442                   continue; /* don't change ipl */
07443                }
07444             }
07445             ipl = ip;
07446          }
07447          /* remove any includes whose registrar matches */
07448          for (i = tmp->includes; i; i = ni) {
07449             ni = i->next;
07450             if (strcmp(i->registrar, registrar) == 0) {
07451                /* remove from list */
07452                if (pi) {
07453                   pi->next = i->next;
07454                   /* free include */
07455                   ast_free(i);
07456                   continue; /* don't change pi */
07457                } else {
07458                   tmp->includes = i->next;
07459                   /* free include */
07460                   ast_free(i);
07461                   continue; /* don't change pi */
07462                }
07463             }
07464             pi = i;
07465          }
07466          /* remove any switches whose registrar matches */
07467          AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
07468             if (strcmp(sw->registrar,registrar) == 0) {
07469                AST_LIST_REMOVE_CURRENT(list);
07470                ast_free(sw);
07471             }
07472          }
07473          AST_LIST_TRAVERSE_SAFE_END
07474 
07475          if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
07476             exten_iter = ast_hashtab_start_traversal(tmp->root_table);
07477             while ((exten_item=ast_hashtab_next(exten_iter))) {
07478                prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
07479                while ((prio_item=ast_hashtab_next(prio_iter))) {
07480                   if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
07481                      continue;
07482                   }
07483                   ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
07484                          tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
07485                   /* set matchcid to 1 to insure we get a direct match, and NULL registrar to make sure no wildcarding is done */
07486                   ast_context_remove_extension_callerid2(tmp, prio_item->exten, prio_item->priority, prio_item->cidmatch, 1, NULL, 1);
07487                }
07488                ast_hashtab_end_traversal(prio_iter);
07489             }
07490             ast_hashtab_end_traversal(exten_iter);
07491          }
07492    
07493          /* delete the context if it's registrar matches, is empty, has refcount of 1, */
07494          /* it's not empty, if it has includes, ignorepats, or switches that are registered from
07495             another registrar. It's not empty if there are any extensions */
07496          if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
07497             ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
07498             ast_hashtab_remove_this_object(contexttab, tmp);
07499             
07500             next = tmp->next;
07501             if (tmpl)
07502                tmpl->next = next;
07503             else
07504                contexts = next;
07505             /* Okay, now we're safe to let it go -- in a sense, we were
07506                ready to let it go as soon as we locked it. */
07507             ast_unlock_context(tmp);
07508             __ast_internal_context_destroy(tmp);
07509          } else {
07510             ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
07511                     tmp->refcount, tmp->root);
07512             ast_unlock_context(tmp);
07513             next = tmp->next;
07514             tmpl = tmp;
07515          }
07516       } else if (con) {
07517          ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
07518          ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
07519          ast_hashtab_remove_this_object(contexttab, tmp);
07520          
07521          next = tmp->next;
07522          if (tmpl)
07523             tmpl->next = next;
07524          else
07525             contexts = next;
07526          /* Okay, now we're safe to let it go -- in a sense, we were
07527             ready to let it go as soon as we locked it. */
07528          ast_unlock_context(tmp);
07529          __ast_internal_context_destroy(tmp);
07530       }
07531 
07532       /* if we have a specific match, we are done, otherwise continue */
07533       tmp = con ? NULL : next;
07534    }
07535 }

int __ast_custom_function_register ( struct ast_custom_function acf,
struct ast_module mod 
)

Register a custom function.

Definition at line 2714 of file pbx.c.

References 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_verb, COLOR_BRCYAN, LOG_ERROR, ast_custom_function::mod, ast_custom_function::name, and term_color().

Referenced by load_pbx().

02715 {
02716    struct ast_custom_function *cur;
02717    char tmps[80];
02718 
02719    if (!acf)
02720       return -1;
02721 
02722    acf->mod = mod;
02723 
02724    AST_RWLIST_WRLOCK(&acf_root);
02725 
02726    AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
02727       if (!strcmp(acf->name, cur->name)) {
02728          ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
02729          AST_RWLIST_UNLOCK(&acf_root);
02730          return -1;
02731       }
02732    }
02733 
02734    /* Store in alphabetical order */
02735    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
02736       if (strcasecmp(acf->name, cur->name) < 0) {
02737          AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
02738          break;
02739       }
02740    }
02741    AST_RWLIST_TRAVERSE_SAFE_END;
02742    if (!cur)
02743       AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
02744 
02745    AST_RWLIST_UNLOCK(&acf_root);
02746 
02747    ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02748 
02749    return 0;
02750 }

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

Definition at line 8606 of file pbx.c.

References ast_async_goto(), ast_exists_extension(), ast_explicit_goto(), chan, 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().

08607 {
08608    int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
08609 
08610    if (!chan)
08611       return -2;
08612 
08613    if (context == NULL)
08614       context = chan->context;
08615    if (exten == NULL)
08616       exten = chan->exten;
08617 
08618    goto_func = (async) ? ast_async_goto : ast_explicit_goto;
08619    if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
08620       return goto_func(chan, context, exten, priority);
08621    else
08622       return -3;
08623 }

static void __ast_internal_context_destroy ( struct ast_context con  )  [static]

Definition at line 7351 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().

07352 {
07353    struct ast_include *tmpi;
07354    struct ast_sw *sw;
07355    struct ast_exten *e, *el, *en;
07356    struct ast_ignorepat *ipi;
07357    struct ast_context *tmp = con;
07358    
07359    for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
07360       struct ast_include *tmpil = tmpi;
07361       tmpi = tmpi->next;
07362       ast_free(tmpil);
07363    }
07364    for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
07365       struct ast_ignorepat *ipl = ipi;
07366       ipi = ipi->next;
07367       ast_free(ipl);
07368    }
07369    if (tmp->registrar)
07370       ast_free(tmp->registrar);
07371    
07372    /* destroy the hash tabs */
07373    if (tmp->root_table) {
07374       ast_hashtab_destroy(tmp->root_table, 0);
07375    }
07376    /* and destroy the pattern tree */
07377    if (tmp->pattern_tree)
07378       destroy_pattern_tree(tmp->pattern_tree);
07379    
07380    while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
07381       ast_free(sw);
07382    for (e = tmp->root; e;) {
07383       for (en = e->peer; en;) {
07384          el = en;
07385          en = en->peer;
07386          destroy_exten(el);
07387       }
07388       el = e;
07389       e = e->next;
07390       destroy_exten(el);
07391    }
07392    tmp->root = NULL;
07393    ast_rwlock_destroy(&tmp->lock);
07394    ast_free(tmp);
07395 }

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

Definition at line 3659 of file pbx.c.

References ast_channel::_softhangup, ast_calloc, ast_copy_string(), ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, ast_free, ast_log(), ast_set_flag, AST_SOFTHANGUP_TIMEOUT, ast_spawn_extension(), ast_test_flag, ast_verb, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_pbx::dtimeout, ast_channel::exten, LOG_WARNING, ast_channel::name, ast_channel::pbx, pbx_builtin_raise_exception(), ast_channel::priority, ast_pbx::rtimeout, set_ext_pri(), and ast_channel::whentohangup.

Referenced by ast_pbx_run_args(), and pbx_thread().

03661 {
03662    int found = 0; /* set if we find at least one match */
03663    int res = 0;
03664    int autoloopflag;
03665    int error = 0;    /* set an error conditions */
03666 
03667    /* A little initial setup here */
03668    if (c->pbx) {
03669       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
03670       /* XXX and now what ? */
03671       ast_free(c->pbx);
03672    }
03673    if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
03674       return -1;
03675    /* Set reasonable defaults */
03676    c->pbx->rtimeout = 10;
03677    c->pbx->dtimeout = 5;
03678 
03679    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);   /* save value to restore at the end */
03680    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
03681 
03682    /* Start by trying whatever the channel is set to */
03683    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03684       /* If not successful fall back to 's' */
03685       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);
03686       /* XXX the original code used the existing priority in the call to
03687        * ast_exists_extension(), and reset it to 1 afterwards.
03688        * I believe the correct thing is to set it to 1 immediately.
03689        */
03690       set_ext_pri(c, "s", 1);
03691       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03692          /* JK02: And finally back to default if everything else failed */
03693          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);
03694          ast_copy_string(c->context, "default", sizeof(c->context));
03695       }
03696    }
03697    for (;;) {
03698       char dst_exten[256]; /* buffer to accumulate digits */
03699       int pos = 0;      /* XXX should check bounds */
03700       int digit = 0;
03701 
03702       /* loop on priorities in this context/exten */
03703       while ( !(res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found,1))) {
03704          if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03705             set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
03706             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03707             c->whentohangup = 0;
03708             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03709          } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03710             pbx_builtin_raise_exception(c, "ABSOLUTETIMEOUT");
03711             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03712             c->whentohangup = 0;
03713             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03714          } else if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03715             c->_softhangup = 0;
03716             continue;
03717          } else if (ast_check_hangup(c)) {
03718             ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
03719                c->exten, c->priority);
03720             error = 1;
03721             break;
03722          }
03723          c->priority++;
03724       } /* end while  - from here on we can use 'break' to go out */
03725       if (found && res) {
03726          /* Something bad happened, or a hangup has been requested. */
03727          if (strchr("0123456789ABCDEF*#", res)) {
03728             ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
03729             pos = 0;
03730             dst_exten[pos++] = digit = res;
03731             dst_exten[pos] = '\0';
03732          } else {
03733             ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03734             ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03735             
03736             if ((res == AST_PBX_ERROR) && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03737                /* if we are already on the 'e' exten, don't jump to it again */
03738                if (!strcmp(c->exten, "e")) {
03739                   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);
03740                   error = 1;
03741                } else {
03742                   pbx_builtin_raise_exception(c, "ERROR");
03743                   continue;
03744                }
03745             }
03746             
03747             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03748                c->_softhangup = 0;
03749                continue;
03750             } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03751                set_ext_pri(c, "T", 1); 
03752                /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03753                c->whentohangup = 0;
03754                c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03755                continue;
03756             } else {
03757                if (c->cdr)
03758                   ast_cdr_update(c);
03759                error = 1;
03760                break;
03761             }
03762          }
03763       }
03764       if (error)
03765          break;
03766 
03767       /*!\note
03768        * We get here on a failure of some kind:  non-existing extension or
03769        * hangup.  We have options, here.  We can either catch the failure
03770        * and continue, or we can drop out entirely. */
03771 
03772       if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
03773          /*!\note
03774           * If there is no match at priority 1, it is not a valid extension anymore.
03775           * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
03776           * neither exist.
03777           */
03778          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03779             ast_verb(3, "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
03780             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
03781             set_ext_pri(c, "i", 1);
03782          } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03783             pbx_builtin_raise_exception(c, "INVALID");
03784          } else {
03785             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
03786                c->name, c->exten, c->context);
03787             error = 1; /* we know what to do with it */
03788             break;
03789          }
03790       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
03791          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
03792          c->_softhangup = 0;
03793       } else { /* keypress received, get more digits for a full extension */
03794          int waittime = 0;
03795          if (digit)
03796             waittime = c->pbx->dtimeout;
03797          else if (!autofallthrough)
03798             waittime = c->pbx->rtimeout;
03799          if (!waittime) {
03800             const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
03801             if (!status)
03802                status = "UNKNOWN";
03803             ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
03804             if (!strcasecmp(status, "CONGESTION"))
03805                res = pbx_builtin_congestion(c, "10");
03806             else if (!strcasecmp(status, "CHANUNAVAIL"))
03807                res = pbx_builtin_congestion(c, "10");
03808             else if (!strcasecmp(status, "BUSY"))
03809                res = pbx_builtin_busy(c, "10");
03810             error = 1; /* XXX disable message */
03811             break;   /* exit from the 'for' loop */
03812          }
03813 
03814          if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
03815             break;
03816          if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
03817             set_ext_pri(c, dst_exten, 1);
03818          else {
03819             /* No such extension */
03820             if (!ast_strlen_zero(dst_exten)) {
03821                /* An invalid extension */
03822                if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03823                   ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
03824                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
03825                   set_ext_pri(c, "i", 1);
03826                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03827                   pbx_builtin_raise_exception(c, "INVALID");
03828                } else {
03829                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
03830                   found = 1; /* XXX disable message */
03831                   break;
03832                }
03833             } else {
03834                /* A simple timeout */
03835                if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
03836                   ast_verb(3, "Timeout on %s\n", c->name);
03837                   set_ext_pri(c, "t", 1);
03838                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03839                   pbx_builtin_raise_exception(c, "RESPONSETIMEOUT");
03840                } else {
03841                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
03842                   found = 1; /* XXX disable message */
03843                   break;
03844                }
03845             }
03846          }
03847          if (c->cdr) {
03848             ast_verb(2, "CDR updated on %s\n",c->name);
03849             ast_cdr_update(c);
03850          }
03851       }
03852    }
03853 
03854    if (!found && !error) {
03855       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
03856    }
03857 
03858    if (!args || !args->no_hangup_chan) {
03859       ast_softhangup(c, c->hangupcause ? c->hangupcause : AST_CAUSE_NORMAL_CLEARING);
03860    }
03861 
03862    if ((!args || !args->no_hangup_chan) &&
03863          !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) && 
03864          ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
03865       set_ext_pri(c, "h", 1);
03866       if (c->cdr && ast_opt_end_cdr_before_h_exten) {
03867          ast_cdr_end(c->cdr);
03868       }
03869       while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found, 1)) == 0) {
03870          c->priority++;
03871       }
03872       if (found && res) {
03873          /* Something bad happened, or a hangup has been requested. */
03874          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03875          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03876       }
03877    }
03878    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03879    ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
03880    pbx_destroy(c->pbx);
03881    c->pbx = NULL;
03882 
03883    if (!args || !args->no_hangup_chan) {
03884       ast_hangup(c);
03885    }
03886 
03887    return 0;
03888 }

static void __init_switch_data ( void   )  [static]

Definition at line 126 of file pbx.c.

00129 : An extension

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

Definition at line 1797 of file pbx.c.

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

Referenced by extension_match_core().

01798 {
01799    mode &= E_MATCH_MASK;   /* only consider the relevant bits */
01800    
01801 #ifdef NEED_DEBUG_HERE
01802    ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
01803 #endif
01804    
01805    if ( (mode == E_MATCH) && (pattern[0] == '_') && (!strcasecmp(pattern,data)) ) { /* note: if this test is left out, then _x. will not match _x. !!! */
01806 #ifdef NEED_DEBUG_HERE
01807       ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
01808 #endif
01809       return 1;
01810    }
01811 
01812    if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
01813       int ld = strlen(data), lp = strlen(pattern);
01814       
01815       if (lp < ld) {    /* pattern too short, cannot match */
01816 #ifdef NEED_DEBUG_HERE
01817          ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
01818 #endif
01819          return 0;
01820       }
01821       /* depending on the mode, accept full or partial match or both */
01822       if (mode == E_MATCH) {
01823 #ifdef NEED_DEBUG_HERE
01824          ast_log(LOG_NOTICE,"return (!strcmp(%s,%s) when mode== E_MATCH)\n", pattern, data);
01825 #endif
01826          return !strcmp(pattern, data); /* 1 on match, 0 on fail */
01827       } 
01828       if (ld == 0 || !strncasecmp(pattern, data, ld)) { /* partial or full match */
01829 #ifdef NEED_DEBUG_HERE
01830          ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
01831 #endif
01832          return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
01833       } else {
01834 #ifdef NEED_DEBUG_HERE
01835          ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
01836 #endif
01837          return 0;
01838       }
01839    }
01840    pattern++; /* skip leading _ */
01841    /*
01842     * XXX below we stop at '/' which is a separator for the CID info. However we should
01843     * not store '/' in the pattern at all. When we insure it, we can remove the checks.
01844     */
01845    while (*data && *pattern && *pattern != '/') {
01846       const char *end;
01847 
01848       if (*data == '-') { /* skip '-' in data (just a separator) */
01849          data++;
01850          continue;
01851       }
01852       switch (toupper(*pattern)) {
01853       case '[':   /* a range */
01854          end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
01855          if (end == NULL) {
01856             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
01857             return 0;   /* unconditional failure */
01858          }
01859          for (pattern++; pattern != end; pattern++) {
01860             if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
01861                if (*data >= pattern[0] && *data <= pattern[2])
01862                   break;   /* match found */
01863                else {
01864                   pattern += 2; /* skip a total of 3 chars */
01865                   continue;
01866                }
01867             } else if (*data == pattern[0])
01868                break;   /* match found */
01869          }
01870          if (pattern == end) {
01871 #ifdef NEED_DEBUG_HERE
01872             ast_log(LOG_NOTICE,"return (0) when pattern==end\n");
01873 #endif
01874             return 0;
01875          }
01876          pattern = end; /* skip and continue */
01877          break;
01878       case 'N':
01879          if (*data < '2' || *data > '9') {
01880 #ifdef NEED_DEBUG_HERE
01881             ast_log(LOG_NOTICE,"return (0) N is matched\n");
01882 #endif
01883             return 0;
01884          }
01885          break;
01886       case 'X':
01887          if (*data < '0' || *data > '9') {
01888 #ifdef NEED_DEBUG_HERE
01889             ast_log(LOG_NOTICE,"return (0) X is matched\n");
01890 #endif
01891             return 0;
01892          }
01893          break;
01894       case 'Z':
01895          if (*data < '1' || *data > '9') {
01896 #ifdef NEED_DEBUG_HERE
01897             ast_log(LOG_NOTICE,"return (0) Z is matched\n");
01898 #endif
01899             return 0;
01900          }
01901          break;
01902       case '.':   /* Must match, even with more digits */
01903 #ifdef NEED_DEBUG_HERE
01904          ast_log(LOG_NOTICE,"return (1) when '.' is matched\n");
01905 #endif
01906          return 1;
01907       case '!':   /* Early match */
01908 #ifdef NEED_DEBUG_HERE
01909          ast_log(LOG_NOTICE,"return (2) when '!' is matched\n");
01910 #endif
01911          return 2;
01912       case ' ':
01913       case '-':   /* Ignore these in patterns */
01914          data--; /* compensate the final data++ */
01915          break;
01916       default:
01917          if (*data != *pattern) {
01918 #ifdef NEED_DEBUG_HERE
01919             ast_log(LOG_NOTICE,"return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
01920 #endif
01921             return 0;
01922          }
01923          
01924       }
01925       data++;
01926       pattern++;
01927    }
01928    if (*data)        /* data longer than pattern, no match */ {
01929 #ifdef NEED_DEBUG_HERE
01930       ast_log(LOG_NOTICE,"return (0) when data longer than pattern\n");
01931 #endif
01932       return 0;
01933    }
01934    
01935    /*
01936     * match so far, but ran off the end of the data.
01937     * Depending on what is next, determine match or not.
01938     */
01939    if (*pattern == '\0' || *pattern == '/') {   /* exact match */
01940 #ifdef NEED_DEBUG_HERE
01941       ast_log(LOG_NOTICE,"at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
01942 #endif
01943       return (mode == E_MATCHMORE) ? 0 : 1;  /* this is a failure for E_MATCHMORE */
01944    } else if (*pattern == '!')   {     /* early match */
01945 #ifdef NEED_DEBUG_HERE
01946       ast_log(LOG_NOTICE,"at end, return (2) when '!' is matched\n");
01947 #endif
01948       return 2;
01949    } else {                /* partial match */
01950 #ifdef NEED_DEBUG_HERE
01951       ast_log(LOG_NOTICE,"at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
01952 #endif
01953       return (mode == E_MATCH) ? 0 : 1;   /* this is a failure for E_MATCH */
01954    }
01955 }

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

Definition at line 2531 of file pbx.c.

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

02532 {
02533    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02534    struct pbx_exception *exception = NULL;
02535    if (!ds || !ds->data)
02536       return -1;
02537    exception = ds->data;
02538    if (!strcasecmp(data, "REASON"))
02539       ast_copy_string(buf, exception->reason, buflen);
02540    else if (!strcasecmp(data, "CONTEXT"))
02541       ast_copy_string(buf, exception->context, buflen);
02542    else if (!strncasecmp(data, "EXTEN", 5))
02543       ast_copy_string(buf, exception->exten, buflen);
02544    else if (!strcasecmp(data, "PRIORITY"))
02545       snprintf(buf, buflen, "%d", exception->priority);
02546    else
02547       return -1;
02548    return 0;
02549 }

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

Definition at line 1465 of file pbx.c.

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

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

01466 {
01467    struct match_char *m1 = NULL, *m2 = NULL, **m0;
01468    int specif;
01469    int already;
01470    int pattern = 0;
01471    char buf[256];
01472    char extenbuf[512];
01473    char *s1 = extenbuf;
01474    int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2;
01475    
01476 
01477    strncpy(extenbuf,e1->exten,sizeof(extenbuf));
01478    if (e1->matchcid &&  l1 <= sizeof(extenbuf)) {
01479       strcat(extenbuf,"/");
01480       strcat(extenbuf,e1->cidmatch);
01481    } else if (l1 > sizeof(extenbuf)) {
01482       ast_log(LOG_ERROR,"The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n", e1->exten, e1->cidmatch);
01483       return 0;
01484    }
01485 #ifdef NEED_DEBUG
01486    ast_log(LOG_DEBUG,"Adding exten %s%c%s to tree\n", s1, e1->matchcid? '/':' ', e1->matchcid? e1->cidmatch : "");
01487 #endif
01488    m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
01489    m0 = &con->pattern_tree;
01490    already = 1;
01491 
01492    if ( *s1 == '_') {
01493       pattern = 1;
01494       s1++;
01495    }
01496    while( *s1 ) {
01497       if (pattern && *s1 == '[' && *(s1-1) != '\\') {
01498          char *s2 = buf;
01499          buf[0] = 0;
01500          s1++; /* get past the '[' */
01501          while (*s1 != ']' && *(s1-1) != '\\' ) {
01502             if (*s1 == '\\') {
01503                if (*(s1+1) == ']') {
01504                   *s2++ = ']';
01505                   s1++;s1++;
01506                } else if (*(s1+1) == '\\') {
01507                   *s2++ = '\\';
01508                   s1++;s1++;
01509                } else if (*(s1+1) == '-') {
01510                   *s2++ = '-';
01511                   s1++; s1++;
01512                } else if (*(s1+1) == '[') {
01513                   *s2++ = '[';
01514                   s1++; s1++;
01515                }
01516             } else if (*s1 == '-') { /* remember to add some error checking to all this! */
01517                char s3 = *(s1-1);
01518                char s4 = *(s1+1);
01519                for (s3++; s3 <= s4; s3++) {
01520                   *s2++ = s3;
01521                }
01522                s1++; s1++;
01523             } else if (*s1 == '\0') {
01524                ast_log(LOG_WARNING, "A matching ']' was not found for '[' in pattern string '%s'\n", extenbuf);
01525                break;
01526             } else {
01527                *s2++ = *s1++;
01528             }
01529          }
01530          *s2 = 0; /* null terminate the exploded range */
01531          /* sort the characters */
01532 
01533          specif = strlen(buf);
01534          qsort(buf, specif, 1, compare_char);
01535          specif <<= 8;
01536          specif += buf[0];
01537       } else {
01538          
01539          if (*s1 == '\\') {
01540             s1++;
01541             buf[0] = *s1;
01542          } else {
01543             if (pattern) {
01544                if (*s1 == 'n') /* make sure n,x,z patterns are canonicalized to N,X,Z */
01545                   *s1 = 'N';
01546                else if (*s1 == 'x')
01547                   *s1 = 'X';
01548                else if (*s1 == 'z')
01549                   *s1 = 'Z';
01550             }
01551             buf[0] = *s1;
01552          }
01553          buf[1] = 0;
01554          specif = 1;
01555       }
01556       m2 = 0;
01557       if (already && (m2=already_in_tree(m1,buf)) && m2->next_char) {
01558          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...
01559                         a shorter pattern might win if the longer one doesn't match */
01560             m2->exten = e1;
01561             m2->deleted = 0;
01562          }
01563          m1 = m2->next_char; /* m1 points to the node to compare against */
01564          m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
01565       } else { /* not already OR not m2 OR nor m2->next_char */
01566          if (m2) {
01567             if (findonly)
01568                return m2;
01569             m1 = m2; /* while m0 stays the same */
01570          } else {
01571             if (findonly)
01572                return m1;
01573             m1 = add_pattern_node(con, m1, buf, pattern, already,specif, m0); /* m1 is the node just added */
01574             m0 = &m1->next_char;
01575          }
01576          
01577          if (!(*(s1+1))) {
01578             m1->deleted = 0;
01579             m1->exten = e1;
01580          }
01581          
01582          already = 0;
01583       }
01584       s1++; /* advance to next char */
01585    }
01586    return m1;
01587 }

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]

Definition at line 1425 of file pbx.c.

References ast_calloc, ast_free, ast_strdup, insert_in_next_chars_alt_char_list(), match_char::next_char, and ast_context::pattern_tree.

Referenced by add_exten_to_pattern_tree().

01426 {
01427    struct match_char *m;
01428    
01429    if (!(m = ast_calloc(1, sizeof(*m))))
01430       return NULL;
01431 
01432    if (!(m->x = ast_strdup(pattern))) {
01433       ast_free(m);
01434       return NULL;
01435    }
01436 
01437    /* the specificity scores are the same as used in the old
01438       pattern matcher. */
01439    m->is_pattern = is_pattern;
01440    if (specificity == 1 && is_pattern && pattern[0] == 'N')
01441       m->specificity = 0x0802;
01442    else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
01443       m->specificity = 0x0901;
01444    else if (specificity == 1 && is_pattern && pattern[0] == 'X')
01445       m->specificity = 0x0a00;
01446    else if (specificity == 1 && is_pattern && pattern[0] == '.')
01447       m->specificity = 0x10000;
01448    else if (specificity == 1 && is_pattern && pattern[0] == '!')
01449       m->specificity = 0x20000;
01450    else
01451       m->specificity = specificity;
01452    
01453    if (!con->pattern_tree) {
01454       insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
01455    } else {
01456       if (already) { /* switch to the new regime (traversing vs appending)*/
01457          insert_in_next_chars_alt_char_list(nextcharptr, m);
01458       } else {
01459          insert_in_next_chars_alt_char_list(&current->next_char, m);
01460       }
01461    }
01462    return m;
01463 }

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

References add_pri_lockopt(), and el.

Referenced by ast_add_extension2_lockopt().

06567 {
06568    return add_pri_lockopt(con, tmp, el, e, replace, 1);
06569 }

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

References ast_hashtab_insert_safe(), ast_exten::label, ast_exten::peer, ast_exten::peer_label_table, ast_exten::peer_table, and ast_exten::priority.

Referenced by add_pri().

06578 {
06579    struct ast_exten *ep;
06580    struct ast_exten *eh=e;
06581 
06582    for (ep = NULL; e ; ep = e, e = e->peer) {
06583       if (e->priority >= tmp->priority)
06584          break;
06585    }
06586    if (!e) {   /* go at the end, and ep is surely set because the list is not empty */
06587       ast_hashtab_insert_safe(eh->peer_table, tmp);
06588       
06589       if (tmp->label) {
06590          ast_hashtab_insert_safe(eh->peer_label_table, tmp);
06591       }
06592       ep->peer = tmp;
06593       return 0;   /* success */
06594    }
06595    if (e->priority == tmp->priority) {
06596       /* Can't have something exactly the same.  Is this a
06597          replacement?  If so, replace, otherwise, bonk. */
06598       if (!replace) {
06599          ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
06600          if (tmp->datad) {
06601             tmp->datad(tmp->data);
06602             /* if you free this, null it out */
06603             tmp->data = NULL;
06604          }
06605          
06606          ast_free(tmp);
06607          return -1;
06608       }
06609       /* we are replacing e, so copy the link fields and then update
06610        * whoever pointed to e to point to us
06611        */
06612       tmp->next = e->next; /* not meaningful if we are not first in the peer list */
06613       tmp->peer = e->peer; /* always meaningful */
06614       if (ep)  {     /* We're in the peer list, just insert ourselves */
06615          ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
06616 
06617          if (e->label) {
06618             ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
06619          }
06620          
06621          ast_hashtab_insert_safe(eh->peer_table,tmp);
06622          if (tmp->label) {
06623             ast_hashtab_insert_safe(eh->peer_label_table,tmp);
06624          }
06625          
06626          ep->peer = tmp;
06627       } else if (el) {     /* We're the first extension. Take over e's functions */
06628          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
06629          tmp->peer_table = e->peer_table;
06630          tmp->peer_label_table = e->peer_label_table;
06631          ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
06632          ast_hashtab_insert_safe(tmp->peer_table,tmp);
06633          if (e->label) {
06634             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
06635          }
06636          if (tmp->label) {
06637             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06638          }
06639          
06640          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06641          ast_hashtab_insert_safe(con->root_table, tmp);
06642          el->next = tmp;
06643          /* The pattern trie points to this exten; replace the pointer,
06644             and all will be well */
06645          if (x) { /* if the trie isn't formed yet, don't sweat this */
06646             if (x->exten) { /* this test for safety purposes */
06647                x->exten = tmp; /* replace what would become a bad pointer */
06648             } else {
06649                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
06650             }
06651          }
06652       } else {       /* We're the very first extension.  */
06653          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
06654          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06655          ast_hashtab_insert_safe(con->root_table, tmp);
06656          tmp->peer_table = e->peer_table;
06657          tmp->peer_label_table = e->peer_label_table;
06658          ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
06659          ast_hashtab_insert_safe(tmp->peer_table, tmp);
06660          if (e->label) {
06661             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
06662          }
06663          if (tmp->label) {
06664             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06665          }
06666          
06667          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06668          ast_hashtab_insert_safe(con->root_table, tmp);
06669          con->root = tmp;
06670          /* The pattern trie points to this exten; replace the pointer,
06671             and all will be well */
06672          if (x) { /* if the trie isn't formed yet; no problem */
06673             if (x->exten) { /* this test for safety purposes */
06674                x->exten = tmp; /* replace what would become a bad pointer */
06675             } else {
06676                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
06677             }
06678          }
06679       }
06680       if (tmp->priority == PRIORITY_HINT)
06681          ast_change_hint(e,tmp);
06682       /* Destroy the old one */
06683       if (e->datad)
06684          e->datad(e->data);
06685       ast_free(e);
06686    } else { /* Slip ourselves in just before e */
06687       tmp->peer = e;
06688       tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
06689       if (ep) {         /* Easy enough, we're just in the peer list */
06690          if (tmp->label) {
06691             ast_hashtab_insert_safe(eh->peer_label_table, tmp);
06692          }
06693          ast_hashtab_insert_safe(eh->peer_table, tmp);
06694          ep->peer = tmp;
06695       } else {       /* we are the first in some peer list, so link in the ext list */
06696          tmp->peer_table = e->peer_table;
06697          tmp->peer_label_table = e->peer_label_table;
06698          e->peer_table = 0;
06699          e->peer_label_table = 0;
06700          ast_hashtab_insert_safe(tmp->peer_table, tmp);
06701          if (tmp->label) {
06702             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06703          }
06704          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06705          ast_hashtab_insert_safe(con->root_table, tmp);
06706          if (el)
06707             el->next = tmp;   /* in the middle... */
06708          else
06709             con->root = tmp; /* ... or at the head */
06710          e->next = NULL;   /* e is no more at the head, so e->next must be reset */
06711       }
06712       /* And immediately return success. */
06713       if (tmp->priority == PRIORITY_HINT) {
06714          if (lockhints) {
06715             ast_add_hint(tmp);
06716          } else {
06717             ast_add_hint_nolock(tmp);
06718          }
06719       }
06720    }
06721    return 0;
06722 }

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

Definition at line 1376 of file pbx.c.

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

Referenced by add_exten_to_pattern_tree().

01377 {
01378    struct match_char *t;
01379    if (!current)
01380       return 0;
01381    for (t=current; t; t=t->alt_char) {
01382       if (strcmp(pat,t->x) == 0) /* uh, we may want to sort exploded [] contents to make matching easy */
01383          return t;
01384    }
01385    return 0;
01386 }

int ast_active_calls ( void   ) 

Retrieve the number of active calls.

Definition at line 4026 of file pbx.c.

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

04027 {
04028    return countcalls;
04029 }

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

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

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

06434 {
06435    int ret = -1;
06436    struct ast_context *c = find_context_locked(context);
06437 
06438    if (c) {
06439       ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
06440          application, data, datad, registrar);
06441       ast_unlock_contexts();
06442    }
06443    
06444    return ret;
06445 }

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 
)

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

References ast_add_extension2_lockopt().

Referenced by ast_add_extension(), context_merge(), do_parking_thread(), load_module(), park_call_full(), pbx_load_config(), and pbx_load_users().

06753 {
06754    return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
06755 }

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 6762 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_debug, ast_hashtab_create(), ast_hashtab_insert_safe(), ast_hashtab_lookup(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), AST_LIST_FIRST, ast_log(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strlen_zero(), ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_exten::cidmatch, ast_exten::data, ast_exten::datad, el, errno, ext_cmp(), ext_strncpy(), ast_exten::exten, globals, globalslock, 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_varshead(), 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().

06766 {
06767    /*
06768     * Sort extensions (or patterns) according to the rules indicated above.
06769     * These are implemented by the function ext_cmp()).
06770     * All priorities for the same ext/pattern/cid are kept in a list,
06771     * using the 'peer' field  as a link field..
06772     */
06773    struct ast_exten *tmp, *tmp2, *e, *el = NULL;
06774    int res;
06775    int length;
06776    char *p;
06777    char expand_buf[VAR_BUF_SIZE];
06778    struct ast_exten dummy_exten = {0};
06779    char dummy_name[1024];
06780 
06781    if (ast_strlen_zero(extension)) {
06782       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",
06783             con->name);
06784       return -1;
06785    }
06786    /* if we are adding a hint, and there are global variables, and the hint
06787       contains variable references, then expand them
06788    */
06789    ast_rwlock_rdlock(&globalslock);
06790    if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
06791       pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
06792       application = expand_buf;
06793    }
06794    ast_rwlock_unlock(&globalslock);
06795 
06796    length = sizeof(struct ast_exten);
06797    length += strlen(extension) + 1;
06798    length += strlen(application) + 1;
06799    if (label)
06800       length += strlen(label) + 1;
06801    if (callerid)
06802       length += strlen(callerid) + 1;
06803    else
06804       length ++;  /* just the '\0' */
06805 
06806    /* Be optimistic:  Build the extension structure first */
06807    if (!(tmp = ast_calloc(1, length)))
06808       return -1;
06809 
06810    if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
06811       label = 0;
06812 
06813    /* use p as dst in assignments, as the fields are const char * */
06814    p = tmp->stuff;
06815    if (label) {
06816       tmp->label = p;
06817       strcpy(p, label);
06818       p += strlen(label) + 1;
06819    }
06820    tmp->exten = p;
06821    p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
06822    tmp->priority = priority;
06823    tmp->cidmatch = p;   /* but use p for assignments below */
06824    if (!ast_strlen_zero(callerid)) {
06825       p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
06826       tmp->matchcid = 1;
06827    } else {
06828       *p++ = '\0';
06829       tmp->matchcid = 0;
06830    }
06831    tmp->app = p;
06832    strcpy(p, application);
06833    tmp->parent = con;
06834    tmp->data = data;
06835    tmp->datad = datad;
06836    tmp->registrar = registrar;
06837 
06838    if (lockconts) {
06839       ast_wrlock_context(con);
06840    }
06841    
06842    if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
06843                         an extension, and the trie exists, then we need to incrementally add this pattern to it. */
06844       strncpy(dummy_name,extension,sizeof(dummy_name));
06845       dummy_exten.exten = dummy_name;
06846       dummy_exten.matchcid = 0;
06847       dummy_exten.cidmatch = 0;
06848       tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
06849       if (!tmp2) {
06850          /* hmmm, not in the trie; */
06851          add_exten_to_pattern_tree(con, tmp, 0);
06852          ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
06853       }
06854    }
06855    res = 0; /* some compilers will think it is uninitialized otherwise */
06856    for (e = con->root; e; el = e, e = e->next) {   /* scan the extension list */
06857       res = ext_cmp(e->exten, tmp->exten);
06858       if (res == 0) { /* extension match, now look at cidmatch */
06859          if (!e->matchcid && !tmp->matchcid)
06860             res = 0;
06861          else if (tmp->matchcid && !e->matchcid)
06862             res = 1;
06863          else if (e->matchcid && !tmp->matchcid)
06864             res = -1;
06865          else
06866             res = strcasecmp(e->cidmatch, tmp->cidmatch);
06867       }
06868       if (res >= 0)
06869          break;
06870    }
06871    if (e && res == 0) { /* exact match, insert in the pri chain */
06872       res = add_pri(con, tmp, el, e, replace);
06873       if (lockconts) {
06874          ast_unlock_context(con);
06875       }
06876       if (res < 0) {
06877          errno = EEXIST;   /* XXX do we care ? */
06878          return 0; /* XXX should we return -1 maybe ? */
06879       }
06880    } else {
06881       /*
06882        * not an exact match, this is the first entry with this pattern,
06883        * so insert in the main list right before 'e' (if any)
06884        */
06885       tmp->next = e;
06886       if (el) {  /* there is another exten already in this context */
06887          el->next = tmp;
06888          tmp->peer_table = ast_hashtab_create(13,
06889                      hashtab_compare_exten_numbers,
06890                      ast_hashtab_resize_java,
06891                      ast_hashtab_newsize_java,
06892                      hashtab_hash_priority,
06893                      0);
06894          tmp->peer_label_table = ast_hashtab_create(7,
06895                         hashtab_compare_exten_labels,
06896                         ast_hashtab_resize_java,
06897                         ast_hashtab_newsize_java,
06898                         hashtab_hash_labels,
06899                         0);
06900          if (label) {
06901             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06902          }
06903          ast_hashtab_insert_safe(tmp->peer_table, tmp);
06904       } else {  /* this is the first exten in this context */
06905          if (!con->root_table)
06906             con->root_table = ast_hashtab_create(27,
06907                                        hashtab_compare_extens,
06908                                        ast_hashtab_resize_java,
06909                                        ast_hashtab_newsize_java,
06910                                        hashtab_hash_extens,
06911                                        0);
06912          con->root = tmp;
06913          con->root->peer_table = ast_hashtab_create(13,
06914                         hashtab_compare_exten_numbers,
06915                         ast_hashtab_resize_java,
06916                         ast_hashtab_newsize_java,
06917                         hashtab_hash_priority,
06918                         0);
06919          con->root->peer_label_table = ast_hashtab_create(7,
06920                            hashtab_compare_exten_labels,
06921                            ast_hashtab_resize_java,
06922                            ast_hashtab_newsize_java,
06923                            hashtab_hash_labels,
06924                            0);
06925          if (label) {
06926             ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
06927          }
06928          ast_hashtab_insert_safe(con->root->peer_table, tmp);
06929             
06930       }
06931       ast_hashtab_insert_safe(con->root_table, tmp);
06932       if (lockconts) {
06933          ast_unlock_context(con);
06934       }
06935       if (tmp->priority == PRIORITY_HINT) {
06936          if (lockhints) {
06937             ast_add_hint(tmp);
06938          } else {
06939             ast_add_hint_nolock(tmp);
06940          }
06941       }
06942    }
06943    if (option_debug) {
06944       if (tmp->matchcid) {
06945          ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
06946                  tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
06947       } else {
06948          ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
06949                  tmp->exten, tmp->priority, con->name, con);
06950       }
06951    }
06952 
06953    if (tmp->matchcid) {
06954       ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
06955              tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
06956    } else {
06957       ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n",
06958              tmp->exten, tmp->priority, con->name, con);
06959    }
06960    
06961    return 0;
06962 }

static int ast_add_hint ( struct ast_exten e  )  [static]

Add hint to hint list, check initial extension state.

Definition at line 3506 of file pbx.c.

References ast_add_hint_nolock(), AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by ast_add_extension2_lockopt().

03507 {
03508    int ret;
03509 
03510    AST_RWLIST_WRLOCK(&hints);
03511    ret = ast_add_hint_nolock(e);
03512    AST_RWLIST_UNLOCK(&hints);
03513    
03514    return ret;
03515 }

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 3477 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::list.

Referenced by ast_add_extension2_lockopt(), and ast_add_hint().

03478 {
03479    struct ast_hint *hint;
03480 
03481    if (!e)
03482       return -1;
03483 
03484    /* Search if hint exists, do nothing */
03485    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03486       if (hint->exten == e) {
03487          ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03488          return -1;
03489       }
03490    }
03491 
03492    ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03493 
03494    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
03495       return -1;
03496    }
03497    /* Initialize and insert new item at the top */
03498    hint->exten = e;
03499    hint->laststate = ast_extension_state2(e);
03500    AST_RWLIST_INSERT_HEAD(&hints, hint, list);
03501 
03502    return 0;
03503 }

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

Definition at line 6470 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, chan, ast_channel::context, ast_channel::exten, 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(), console_transfer(), dahdi_handle_dtmfup(), handle_request_bye(), handle_request_refer(), pbx_parseable_goto(), process_ast_dsp(), and socket_process().

06471 {
06472    int res = 0;
06473 
06474    ast_channel_lock(chan);
06475 
06476    if (chan->pbx) { /* This channel is currently in the PBX */
06477       ast_explicit_goto(chan, context, exten, priority + 1);
06478       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
06479    } else {
06480       /* In order to do it when the channel doesn't really exist within
06481          the PBX, we have to make a new channel, masquerade, and start the PBX
06482          at the new location */
06483       struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
06484       if (!tmpchan) {
06485          res = -1;
06486       } else {
06487          if (chan->cdr) {
06488             ast_cdr_discard(tmpchan->cdr);
06489             tmpchan->cdr = ast_cdr_dup(chan->cdr);  /* share the love */
06490          }
06491          /* Make formats okay */
06492          tmpchan->readformat = chan->readformat;
06493          tmpchan->writeformat = chan->writeformat;
06494          /* Setup proper location */
06495          ast_explicit_goto(tmpchan,
06496             S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
06497 
06498          /* Masquerade into temp channel */
06499          if (ast_channel_masquerade(tmpchan, chan)) {
06500             /* Failed to set up the masquerade.  It's probably chan_local
06501              * in the middle of optimizing itself out.  Sad. :( */
06502             ast_hangup(tmpchan);
06503             tmpchan = NULL;
06504             res = -1;
06505          } else {
06506             /* Grab the locks and get going */
06507             ast_channel_lock(tmpchan);
06508             ast_do_masquerade(tmpchan);
06509             ast_channel_unlock(tmpchan);
06510             /* Start the PBX going on our stolen channel */
06511             if (ast_pbx_start(tmpchan)) {
06512                ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
06513                ast_hangup(tmpchan);
06514                res = -1;
06515             }
06516          }
06517       }
06518    }
06519    ast_channel_unlock(chan);
06520    return res;
06521 }

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

Definition at line 6523 of file pbx.c.

References ast_async_goto(), ast_channel_unlock, ast_get_channel_by_name_locked(), and chan.

06524 {
06525    struct ast_channel *chan;
06526    int res = -1;
06527 
06528    chan = ast_get_channel_by_name_locked(channame);
06529    if (chan) {
06530       res = ast_async_goto(chan, context, exten, priority);
06531       ast_channel_unlock(chan);
06532    }
06533    return res;
06534 }

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

References __ast_goto_if_exists(), and chan.

08631 {
08632    return __ast_goto_if_exists(chan, context, exten, priority, 1);
08633 }

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

References chan, and pbx_parseable_goto().

Referenced by asyncgoto_exec().

08694 {
08695    return pbx_parseable_goto(chan, goto_string, 1);
08696 }

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

Definition at line 6110 of file pbx.c.

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

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

06111 {
06112    char info_save[256];
06113    char *info;
06114 
06115    /* Check for empty just in case */
06116    if (ast_strlen_zero(info_in))
06117       return 0;
06118    /* make a copy just in case we were passed a static string */
06119    ast_copy_string(info_save, info_in, sizeof(info_save));
06120    info = info_save;
06121    /* Assume everything except time */
06122    i->monthmask = 0xfff;   /* 12 bits */
06123    i->daymask = 0x7fffffffU; /* 31 bits */
06124    i->dowmask = 0x7f; /* 7 bits */
06125    /* on each call, use strsep() to move info to the next argument */
06126    get_timerange(i, strsep(&info, "|,"));
06127    if (info)
06128       i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
06129    if (info)
06130       i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
06131    if (info)
06132       i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
06133    return 1;
06134 }

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

References E_CANMATCH, and pbx_extension_helper().

Referenced by 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(), ss_thread(), and valid_exit().

03605 {
03606    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
03607 }

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

Change hint for an extension.

Definition at line 3518 of file pbx.c.

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

03519 {
03520    struct ast_hint *hint;
03521    int res = -1;
03522 
03523    AST_RWLIST_WRLOCK(&hints);
03524    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03525       if (hint->exten == oe) {
03526             hint->exten = ne;
03527          res = 0;
03528          break;
03529       }
03530    }
03531    AST_RWLIST_UNLOCK(&hints);
03532 
03533    return res;
03534 }

int ast_check_timing ( const struct ast_timing i  ) 

Definition at line 6136 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_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().

06137 {
06138    struct ast_tm tm;
06139    struct timeval tv = ast_tvnow();
06140 
06141    ast_localtime(&tv, &tm, NULL);
06142 
06143    /* If it's not the right month, return */
06144    if (!(i->monthmask & (1 << tm.tm_mon)))
06145       return 0;
06146 
06147    /* If it's not that time of the month.... */
06148    /* Warning, tm_mday has range 1..31! */
06149    if (!(i->daymask & (1 << (tm.tm_mday-1))))
06150       return 0;
06151 
06152    /* If it's not the right day of the week */
06153    if (!(i->dowmask & (1 << tm.tm_wday)))
06154       return 0;
06155 
06156    /* Sanity check the hour just to be safe */
06157    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
06158       ast_log(LOG_WARNING, "Insane time...\n");
06159       return 0;
06160    }
06161 
06162    /* Now the tough part, we calculate if it fits
06163       in the right time based on min/hour */
06164    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
06165       return 0;
06166 
06167    /* If we got this far, then we're good */
06168    return 1;
06169 }

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

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

Referenced by handle_cli_dialplan_add_ignorepat().

06363 {
06364    int ret = -1;
06365    struct ast_context *c = find_context_locked(context);
06366 
06367    if (c) {
06368       ret = ast_context_add_ignorepat2(c, value, registrar);
06369       ast_unlock_contexts();
06370    }
06371    return ret;
06372 }

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

Definition at line 6374 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_context_add_ignorepat(), context_merge_incls_swits_igps_other_registrars(), and pbx_load_config().

06375 {
06376    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
06377    int length;
06378    char *pattern;
06379    length = sizeof(struct ast_ignorepat);
06380    length += strlen(value) + 1;
06381    if (!(ignorepat = ast_calloc(1, length)))
06382       return -1;
06383    /* The cast to char * is because we need to write the initial value.
06384     * The field is not supposed to be modified otherwise.  Also, gcc 4.2
06385     * sees the cast as dereferencing a type-punned pointer and warns about
06386     * it.  This is the workaround (we're telling gcc, yes, that's really
06387     * what we wanted to do).
06388     */
06389    pattern = (char *) ignorepat->pattern;
06390    strcpy(pattern, value);
06391    ignorepat->next = NULL;
06392    ignorepat->registrar = registrar;
06393    ast_wrlock_context(con);
06394    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
06395       ignorepatl = ignorepatc;
06396       if (!strcasecmp(ignorepatc->pattern, value)) {
06397          /* Already there */
06398          ast_unlock_context(con);
06399          errno = EEXIST;
06400          return -1;
06401       }
06402    }
06403    if (ignorepatl)
06404       ignorepatl->next = ignorepat;
06405    else
06406       con->ignorepats = ignorepat;
06407    ast_unlock_context(con);
06408    return 0;
06409 
06410 }

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

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

Referenced by handle_cli_dialplan_add_include().

05917 {
05918    int ret = -1;
05919    struct ast_context *c = find_context_locked(context);
05920 
05921    if (c) {
05922       ret = ast_context_add_include2(c, include, registrar);
05923       ast_unlock_contexts();
05924    }
05925    return ret;
05926 }

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

References ast_build_timing(), ast_calloc, 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_context_add_include(), context_merge_incls_swits_igps_other_registrars(), and pbx_load_config().

06180 {
06181    struct ast_include *new_include;
06182    char *c;
06183    struct ast_include *i, *il = NULL; /* include, include_last */
06184    int length;
06185    char *p;
06186 
06187    length = sizeof(struct ast_include);
06188    length += 2 * (strlen(value) + 1);
06189 
06190    /* allocate new include structure ... */
06191    if (!(new_include = ast_calloc(1, length)))
06192       return -1;
06193    /* Fill in this structure. Use 'p' for assignments, as the fields
06194     * in the structure are 'const char *'
06195     */
06196    p = new_include->stuff;
06197    new_include->name = p;
06198    strcpy(p, value);
06199    p += strlen(value) + 1;
06200    new_include->rname = p;
06201    strcpy(p, value);
06202    /* Strip off timing info, and process if it is there */
06203    if ( (c = strchr(p, ',')) ) {
06204       *c++ = '\0';
06205       new_include->hastime = ast_build_timing(&(new_include->timing), c);
06206    }
06207    new_include->next      = NULL;
06208    new_include->registrar = registrar;
06209 
06210    ast_wrlock_context(con);
06211 
06212    /* ... go to last include and check if context is already included too... */
06213    for (i = con->includes; i; i = i->next) {
06214       if (!strcasecmp(i->name, new_include->name)) {
06215          ast_free(new_include);
06216          ast_unlock_context(con);
06217          errno = EEXIST;
06218          return -1;
06219       }
06220       il = i;
06221    }
06222 
06223    /* ... include new context into context list, unlock, return */
06224    if (il)
06225       il->next = new_include;
06226    else
06227       con->includes = new_include;
06228    ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
06229 
06230    ast_unlock_context(con);
06231 
06232    return 0;
06233 }

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

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

06241 {
06242    int ret = -1;
06243    struct ast_context *c = find_context_locked(context);
06244 
06245    if (c) { /* found, add switch to this context */
06246       ret = ast_context_add_switch2(c, sw, data, eval, registrar);
06247       ast_unlock_contexts();
06248    }
06249    return ret;
06250 }

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 6259 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, store_hint::list, ast_sw::name, ast_sw::registrar, and ast_sw::stuff.

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

06261 {
06262    struct ast_sw *new_sw;
06263    struct ast_sw *i;
06264    int length;
06265    char *p;
06266 
06267    length = sizeof(struct ast_sw);
06268    length += strlen(value) + 1;
06269    if (data)
06270       length += strlen(data);
06271    length++;
06272 
06273    /* allocate new sw structure ... */
06274    if (!(new_sw = ast_calloc(1, length)))
06275       return -1;
06276    /* ... fill in this structure ... */
06277    p = new_sw->stuff;
06278    new_sw->name = p;
06279    strcpy(new_sw->name, value);
06280    p += strlen(value) + 1;
06281    new_sw->data = p;
06282    if (data) {
06283       strcpy(new_sw->data, data);
06284       p += strlen(data) + 1;
06285    } else {
06286       strcpy(new_sw->data, "");
06287       p++;
06288    }
06289    new_sw->eval     = eval;
06290    new_sw->registrar = registrar;
06291 
06292    /* ... try to lock this context ... */
06293    ast_wrlock_context(con);
06294 
06295    /* ... go to last sw and check if context is already swd too... */
06296    AST_LIST_TRAVERSE(&con->alts, i, list) {
06297       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
06298          ast_free(new_sw);
06299          ast_unlock_context(con);
06300          errno = EEXIST;
06301          return -1;
06302       }
06303    }
06304 
06305    /* ... sw new context into context list, unlock, return */
06306    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
06307 
06308    ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
06309 
06310    ast_unlock_context(con);
06311 
06312    return 0;
06313 }

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 7537 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(), sla_destroy(), and unload_module().

struct ast_context* ast_context_find ( const char *  name  ) 

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

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

Referenced by __unload_module(), _macro_exec(), ast_context_verify_includes(), ast_ignore_pattern(), cleanup_stale_contexts(), do_parking_thread(), isexten_function_read(), park_exec(), register_exten(), register_peer_exten(), unload_module(), and unregister_exten().

02002 {
02003    struct ast_context *tmp = NULL;
02004    struct fake_context item;
02005    strncpy(item.name,name,256);
02006    ast_rdlock_contexts();
02007    if( contexts_table ) {
02008       tmp = ast_hashtab_lookup(contexts_table,&item);
02009    } else {
02010       while ( (tmp = ast_walk_contexts(tmp)) ) {
02011          if (!name || !strcasecmp(name, tmp->name))
02012             break;
02013       }
02014    }
02015    ast_unlock_contexts();
02016    return tmp;
02017 }

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

Register a new context or find an existing one.

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

References ast_calloc, 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, name, fake_context::name, ast_context::name, ast_context::next, ast_context::refcount, ast_context::registrar, ast_context::root, and ast_context::root_table.

Referenced by context_merge(), do_parking_thread(), load_module(), lua_register_switches(), park_call_full(), pbx_load_config(), pbx_load_users(), reload_config(), and set_config().

05576 {
05577    struct ast_context *tmp, **local_contexts;
05578    struct fake_context search;
05579    int length = sizeof(struct ast_context) + strlen(name) + 1;
05580 
05581    if (!contexts_table) {
05582       contexts_table = ast_hashtab_create(17,
05583                                  ast_hashtab_compare_contexts, 
05584                                  ast_hashtab_resize_java,
05585                                  ast_hashtab_newsize_java,
05586                                  ast_hashtab_hash_contexts,
05587                                  0);
05588    }
05589    
05590    strncpy(search.name,name,sizeof(search.name));
05591    if (!extcontexts) {
05592       ast_rdlock_contexts();
05593       local_contexts = &contexts;
05594       tmp = ast_hashtab_lookup(contexts_table, &search);
05595       ast_unlock_contexts();
05596       if (tmp) {
05597          tmp->refcount++;
05598          return tmp;
05599       }
05600    } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
05601       local_contexts = extcontexts;
05602       tmp = ast_hashtab_lookup(exttable, &search);
05603       if (tmp) {
05604          tmp->refcount++;
05605          return tmp;
05606       }
05607    }
05608    
05609    if ((tmp = ast_calloc(1, length))) {
05610       ast_rwlock_init(&tmp->lock);
05611       ast_mutex_init(&tmp->macrolock);
05612       strcpy(tmp->name, name);
05613       tmp->root = NULL;
05614       tmp->root_table = NULL;
05615       tmp->registrar = ast_strdup(registrar);
05616       tmp->includes = NULL;
05617       tmp->ignorepats = NULL;
05618       tmp->refcount = 1;
05619    } else {
05620       ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
05621       return NULL;
05622    }
05623    
05624    if (!extcontexts) {
05625       ast_wrlock_contexts();
05626       tmp->next = *local_contexts;
05627       *local_contexts = tmp;
05628       ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
05629       ast_unlock_contexts();
05630       ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05631       ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05632    } else {
05633       tmp->next = *local_contexts;
05634       if (exttable)
05635          ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
05636       
05637       *local_contexts = tmp;
05638       ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05639       ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05640    }
05641    return tmp;
05642 }

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

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

Referenced by _macro_exec().

04386 {
04387    struct ast_context *c = NULL;
04388    int ret = -1;
04389    struct fake_context item;
04390 
04391    ast_rdlock_contexts();
04392 
04393    strncpy(item.name,context,256);
04394    c = ast_hashtab_lookup(contexts_table,&item);
04395    if (c)
04396       ret = 0;
04397 
04398 
04399 #ifdef NOTNOW
04400 
04401    while ((c = ast_walk_contexts(c))) {
04402       if (!strcmp(ast_get_context_name(c), context)) {
04403          ret = 0;
04404          break;
04405       }
04406    }
04407 
04408 #endif
04409    ast_unlock_contexts();
04410 
04411    /* if we found context, lock macrolock */
04412    if (ret == 0) 
04413       ret = ast_mutex_lock(&c->macrolock);
04414 
04415    return ret;
04416 }

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

References ast_context_remove_extension_callerid().

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

04193 {
04194    return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
04195 }

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

References ast_context_remove_extension_callerid2().

Referenced by do_parking_thread(), park_exec(), and unload_module().

04220 {
04221    return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked);
04222 }

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

Definition at line 4197 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().

04198 {
04199    int ret = -1; /* default error return */
04200    struct ast_context *c = find_context_locked(context);
04201 
04202    if (c) { /* ... remove extension ... */
04203       ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcid, registrar, 1);
04204       ast_unlock_contexts();
04205    }
04206    return ret;
04207 }

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

Definition at line 4224 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, destroy_exten(), exten, ast_exten::exten, ast_exten::label, LOG_ERROR, log_match_char_tree(), LOG_NOTICE, LOG_WARNING, ast_exten::matchcid, ast_exten::next, ast_exten::peer, ast_exten::peer_label_table, ast_exten::peer_table, ast_exten::priority, ast_exten::registrar, and match_char::x.

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

04225 {
04226    struct ast_exten *exten, *prev_exten = NULL;
04227    struct ast_exten *peer;
04228    struct ast_exten ex, *exten2, *exten3;
04229    char dummy_name[1024];
04230    struct ast_exten *previous_peer = NULL;
04231    struct ast_exten *next_peer = NULL;
04232    int found = 0;
04233 
04234    if (!already_locked)
04235       ast_wrlock_context(con);
04236 
04237    /* Handle this is in the new world */
04238 
04239    /* FIXME For backwards compatibility, if callerid==NULL, then remove ALL
04240     * peers, not just those matching the callerid. */
04241 #ifdef NEED_DEBUG
04242    ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcid ? "/" : "", matchcid ? callerid : "", registrar);
04243 #endif
04244 #ifdef CONTEXT_DEBUG
04245    check_contexts(__FILE__, __LINE__);
04246 #endif
04247    /* find this particular extension */
04248    ex.exten = dummy_name;
04249    ex.matchcid = matchcid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */
04250    ex.cidmatch = callerid;
04251    ast_copy_string(dummy_name, extension, sizeof(dummy_name));
04252    exten = ast_hashtab_lookup(con->root_table, &ex);
04253    if (exten) {
04254       if (priority == 0) {
04255          exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04256          if (!exten2)
04257             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);
04258          if (con->pattern_tree) {
04259             
04260             struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04261             
04262             if (x->exten) { /* this test for safety purposes */
04263                x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04264                x->exten = 0; /* get rid of what will become a bad pointer */
04265             } else {
04266                ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
04267             }
04268          }
04269       } else {
04270          ex.priority = priority;
04271          exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
04272          if (exten2) {
04273             
04274             if (exten2->label) { /* if this exten has a label, remove that, too */
04275                exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
04276                if (!exten3)
04277                   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);
04278             }
04279          
04280             exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
04281             if (!exten3)
04282                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);
04283             if (exten2 == exten && exten2->peer) {
04284                exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04285                ast_hashtab_insert_immediate(con->root_table, exten2->peer);
04286             }
04287             if (ast_hashtab_size(exten->peer_table) == 0) {
04288                /* well, if the last priority of an exten is to be removed,
04289                   then, the extension is removed, too! */
04290                exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
04291                if (!exten3)
04292                   ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
04293                if (con->pattern_tree) {
04294                   struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04295                   if (x->exten) { /* this test for safety purposes */
04296                      x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04297                      x->exten = 0; /* get rid of what will become a bad pointer */
04298                   }
04299                }
04300             }
04301          } else {
04302             ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
04303                   priority, exten->exten, con->name);
04304          }
04305       }
04306    } else {
04307       /* hmmm? this exten is not in this pattern tree? */
04308       ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
04309             extension, con->name);
04310    }
04311 #ifdef NEED_DEBUG
04312    if (con->pattern_tree) {
04313       ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
04314       log_match_char_tree(con->pattern_tree, " ");
04315    }
04316 #endif
04317 
04318    /* scan the extension list to find first matching extension-registrar */
04319    for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
04320       if (!strcmp(exten->exten, extension) &&
04321          (!registrar || !strcmp(exten->registrar, registrar)) &&
04322          (!matchcid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
04323          break;
04324    }
04325    if (!exten) {
04326       /* we can't find right extension */
04327       if (!already_locked)
04328          ast_unlock_context(con);
04329       return -1;
04330    }
04331 
04332    /* scan the priority list to remove extension with exten->priority == priority */
04333    for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
04334        peer && !strcmp(peer->exten, extension) && (!matchcid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(peer->cidmatch) && !strcmp(peer->cidmatch,callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(peer->cidmatch)));
04335          peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
04336       if ((priority == 0 || peer->priority == priority) &&
04337             (!callerid || !matchcid || (matchcid && !strcmp(peer->cidmatch, callerid))) &&
04338             (!registrar || !strcmp(peer->registrar, registrar) )) {
04339          found = 1;
04340 
04341          /* we are first priority extension? */
04342          if (!previous_peer) {
04343             /*
04344              * We are first in the priority chain, so must update the extension chain.
04345              * The next node is either the next priority or the next extension
04346              */
04347             struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
04348             if (peer->peer) {
04349                /* move the peer_table and peer_label_table down to the next peer, if
04350                   it is there */
04351                peer->peer->peer_table = peer->peer_table;
04352                peer->peer->peer_label_table = peer->peer_label_table;
04353                peer->peer_table = NULL;
04354                peer->peer_label_table = NULL;
04355             }
04356             if (!prev_exten) {   /* change the root... */
04357                con->root = next_node;
04358             } else {
04359                prev_exten->next = next_node; /* unlink */
04360             }
04361             if (peer->peer)   { /* update the new head of the pri list */
04362                peer->peer->next = peer->next;
04363             }
04364          } else { /* easy, we are not first priority in extension */
04365             previous_peer->peer = peer->peer;
04366          }
04367 
04368          /* now, free whole priority extension */
04369          destroy_exten(peer);
04370       } else {
04371          previous_peer = peer;
04372       }
04373    }
04374    if (!already_locked)
04375       ast_unlock_context(con);
04376    return found ? 0 : -1;
04377 }

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

Definition at line 6319 of file pbx.c.

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

Referenced by handle_cli_dialplan_remove_ignorepat().

06320 {
06321    int ret = -1;
06322    struct ast_context *c = find_context_locked(context);
06323 
06324    if (c) {
06325       ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
06326       ast_unlock_contexts();
06327    }
06328    return ret;
06329 }

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

Definition at line 6331 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().

06332 {
06333    struct ast_ignorepat *ip, *ipl = NULL;
06334 
06335    ast_wrlock_context(con);
06336 
06337    for (ip = con->ignorepats; ip; ip = ip->next) {
06338       if (!strcmp(ip->pattern, ignorepat) &&
06339          (!registrar || (registrar == ip->registrar))) {
06340          if (ipl) {
06341             ipl->next = ip->next;
06342             ast_free(ip);
06343          } else {
06344             con->ignorepats = ip->next;
06345             ast_free(ip);
06346          }
06347          ast_unlock_context(con);
06348          return 0;
06349       }
06350       ipl = ip;
06351    }
06352 
06353    ast_unlock_context(con);
06354    errno = EINVAL;
06355    return -1;
06356 }

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

Remove a context include.

Note:
See ast_context_add_include for information on arguments
Return values:
0 on success
-1 on failure

Definition at line 4084 of file pbx.c.

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

Referenced by handle_cli_dialplan_remove_include().

04085 {
04086    int ret = -1;
04087    struct ast_context *c = find_context_locked(context);
04088 
04089    if (c) {
04090       /* found, remove include from this context ... */
04091       ret = ast_context_remove_include2(c, include, registrar);
04092       ast_unlock_contexts();
04093    }
04094    return ret;
04095 }

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

Removes an include by an ast_context structure.

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

Definition at line 4106 of file pbx.c.

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

Referenced by ast_context_remove_include().

04107 {
04108    struct ast_include *i, *pi = NULL;
04109    int ret = -1;
04110 
04111    ast_wrlock_context(con);
04112 
04113    /* find our include */
04114    for (i = con->includes; i; pi = i, i = i->next) {
04115       if (!strcmp(i->name, include) &&
04116             (!registrar || !strcmp(i->registrar, registrar))) {
04117          /* remove from list */
04118          ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
04119          if (pi)
04120             pi->next = i->next;
04121          else
04122             con->includes = i->next;
04123          /* free include and return */
04124          ast_free(i);
04125          ret = 0;
04126          break;
04127       }
04128    }
04129 
04130    ast_unlock_context(con);
04131 
04132    return ret;
04133 }

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

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

04141 {
04142    int ret = -1; /* default error return */
04143    struct ast_context *c = find_context_locked(context);
04144 
04145    if (c) {
04146       /* remove switch from this context ... */
04147       ret = ast_context_remove_switch2(c, sw, data, registrar);
04148       ast_unlock_contexts();
04149    }
04150    return ret;
04151 }

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 4161 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::list, ast_sw::name, and ast_sw::registrar.

Referenced by ast_context_remove_switch().

04162 {
04163    struct ast_sw *i;
04164    int ret = -1;
04165 
04166    ast_wrlock_context(con);
04167 
04168    /* walk switches */
04169    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
04170       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
04171          (!registrar || !strcmp(i->registrar, registrar))) {
04172          /* found, remove from list */
04173          ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
04174          AST_LIST_REMOVE_CURRENT(list);
04175          ast_free(i); /* free switch and return */
04176          ret = 0;
04177          break;
04178       }
04179    }
04180    AST_LIST_TRAVERSE_SAFE_END;
04181 
04182    ast_unlock_context(con);
04183 
04184    return ret;
04185 }

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

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

Referenced by _macro_exec().

04424 {
04425    struct ast_context *c = NULL;
04426    int ret = -1;
04427    struct fake_context item;
04428 
04429    ast_rdlock_contexts();
04430 
04431    strncpy(item.name, context, 256);
04432    c = ast_hashtab_lookup(contexts_table,&item);
04433    if (c)
04434       ret = 0;
04435 #ifdef NOTNOW
04436 
04437    while ((c = ast_walk_contexts(c))) {
04438       if (!strcmp(ast_get_context_name(c), context)) {
04439          ret = 0;
04440          break;
04441       }
04442    }
04443 
04444 #endif
04445    ast_unlock_contexts();
04446 
04447    /* if we found context, unlock macrolock */
04448    if (ret == 0) 
04449       ret = ast_mutex_unlock(&c->macrolock);
04450 
04451    return ret;
04452 }

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

08588 {
08589    struct ast_include *inc = NULL;
08590    int res = 0;
08591 
08592    while ( (inc = ast_walk_context_includes(con, inc)) ) {
08593       if (ast_context_find(inc->rname))
08594          continue;
08595 
08596       res = -1;
08597       ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
08598          ast_get_context_name(con), inc->rname);
08599       break;
08600    }
08601 
08602    return res;
08603 }

struct ast_custom_function* ast_custom_function_find ( const char *  name  ) 

Definition at line 2685 of file pbx.c.

References ast_custom_function::acflist, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, and ast_custom_function::name.

Referenced by ast_func_read(), ast_func_write(), config_curl(), destroy_curl(), handle_show_function(), op_func(), realtime_curl(), realtime_multi_curl(), store_curl(), and update_curl().

02686 {
02687    struct ast_custom_function *acf = NULL;
02688 
02689    AST_RWLIST_RDLOCK(&acf_root);
02690    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02691       if (!strcmp(name, acf->name))
02692          break;
02693    }
02694    AST_RWLIST_UNLOCK(&acf_root);
02695 
02696    return acf;
02697 }

int ast_custom_function_unregister ( struct ast_custom_function acf  ) 

Unregister a custom function.

Definition at line 2699 of file pbx.c.

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

Referenced by reload(), and unload_module().

02700 {
02701    struct ast_custom_function *cur;
02702 
02703    if (!acf)
02704       return -1;
02705 
02706    AST_RWLIST_WRLOCK(&acf_root);
02707    if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist)))
02708       ast_verb(2, "Unregistered custom function %s\n", cur->name);
02709    AST_RWLIST_UNLOCK(&acf_root);
02710 
02711    return cur ? 0 : -1;
02712 }

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

References E_MATCH, and pbx_extension_helper().

Referenced by __ast_goto_if_exists(), __ast_pbx_run(), _macro_exec(), acf_isexten_exec(), answer_call(), ast_app_dtget(), ast_bridge_call(), ast_pbx_outgoing_exten(), builtin_atxfer(), builtin_blindtransfer(), cb_events(), 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_devicestate(), local_dtmf_helper(), loopback_exists(), metermaidstate(), mgcp_ss(), minivm_greet_exec(), misdn_overlap_dial_task(), park_space_reserve(), parkandannounce_exec(), pbx_builtin_waitexten(), phone_check_exception(), pri_dchannel(), process_ast_dsp(), readexten_exec(), register_peer_exten(), skinny_ss(), socket_process(), ss_thread(), and waitstream_core().

03590 {
03591    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
03592 }

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

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

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

06448 {
06449    if (!chan)
06450       return -1;
06451 
06452    ast_channel_lock(chan);
06453 
06454    if (!ast_strlen_zero(context))
06455       ast_copy_string(chan->context, context, sizeof(chan->context));
06456    if (!ast_strlen_zero(exten))
06457       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06458    if (priority > -1) {
06459       chan->priority = priority;
06460       /* see flag description in channel.h for explanation */
06461       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
06462          chan->priority--;
06463    }
06464 
06465    ast_channel_unlock(chan);
06466 
06467    return 0;
06468 }

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

Definition at line 1978 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().

01979 {
01980    if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
01981       ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
01982    return extension_match_core(pattern, data, needmore);
01983 }

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

References ext_cmp().

Referenced by lua_extension_cmp().

01781 {
01782    return ext_cmp(a, b);
01783 }

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

01974 {
01975    return extension_match_core(pattern, data, E_MATCH);
01976 }

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

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

Parameters:
c this is not important
context which context to look in
exten which extension to get state
Returns:
extension state as defined in the ast_extension_states enum

Definition at line 3266 of file pbx.c.

References ast_extension_state2(), and ast_hint_extension().

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

03267 {
03268    struct ast_exten *e;
03269 
03270    e = ast_hint_extension(c, context, exten);   /* Do we have a hint for this extension ? */
03271    if (!e)
03272       return -1;           /* No hint, return -1 */
03273 
03274    return ast_extension_state2(e);        /* Check all devices in the hint */
03275 }

static int ast_extension_state2 ( struct ast_exten e  )  [static]

Check state of extension by using hints.

Definition at line 3176 of file pbx.c.

References ast_copy_string(), AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, ast_device_state(), AST_DEVICE_UNAVAILABLE, AST_EXTENSION_BUSY, AST_EXTENSION_INUSE, AST_EXTENSION_NOT_INUSE, AST_EXTENSION_ONHOLD, AST_EXTENSION_RINGING, AST_EXTENSION_UNAVAILABLE, ast_get_extension_app(), AST_MAX_EXTENSION, inuse, and strsep().

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

03177 {
03178    char hint[AST_MAX_EXTENSION];
03179    char *cur, *rest;
03180    int allunavailable = 1, allbusy = 1, allfree = 1;
03181    int busy = 0, inuse = 0, ring = 0, onhold = 0;
03182 
03183    if (!e)
03184       return -1;
03185 
03186    ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
03187 
03188    rest = hint;   /* One or more devices separated with a & character */
03189    while ( (cur = strsep(&rest, "&")) ) {
03190       int res = ast_device_state(cur);
03191       switch (res) {
03192       case AST_DEVICE_NOT_INUSE:
03193          allunavailable = 0;
03194          allbusy = 0;
03195          break;
03196       case AST_DEVICE_INUSE:
03197          inuse = 1;
03198          allunavailable = 0;
03199          allfree = 0;
03200          break;
03201       case AST_DEVICE_RINGING:
03202          ring = 1;
03203          allunavailable = 0;
03204          allfree = 0;
03205          break;
03206       case AST_DEVICE_RINGINUSE:
03207          inuse = 1;
03208          ring = 1;
03209          allunavailable = 0;
03210          allfree = 0;
03211          break;
03212       case AST_DEVICE_ONHOLD:
03213          allunavailable = 0;
03214          allfree = 0;
03215          onhold = 1;
03216          break;
03217       case AST_DEVICE_BUSY:
03218          allunavailable = 0;
03219          allfree = 0;
03220          busy = 1;
03221          inuse = 1;
03222          break;
03223       case AST_DEVICE_UNAVAILABLE:
03224       case AST_DEVICE_INVALID:
03225          allbusy = 0;
03226          allfree = 0;
03227          break;
03228       default:
03229          allunavailable = 0;
03230          allbusy = 0;
03231          allfree = 0;
03232       }
03233    }
03234 
03235    if (allfree)
03236       return AST_EXTENSION_NOT_INUSE;
03237    if ((inuse || onhold) && ring)
03238       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
03239    if (allbusy)
03240       return AST_EXTENSION_BUSY;
03241    if (inuse)
03242       return AST_EXTENSION_INUSE;
03243    if (ring)
03244       return AST_EXTENSION_RINGING;
03245    if (onhold)
03246       return AST_EXTENSION_ONHOLD;
03247    if (allunavailable)
03248       return AST_EXTENSION_UNAVAILABLE;
03249 
03250    return AST_EXTENSION_NOT_INUSE;
03251 }

const char* ast_extension_state2str ( int  extension_state  ) 

Return string representation of the state of an extension.

Parameters:
extension_state is the numerical state delivered by ast_extension_state
Returns:
the state of an extension as string

Definition at line 3254 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().

03255 {
03256    int i;
03257 
03258    for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
03259       if (extension_states[i].extension_state == extension_state)
03260          return extension_states[i].text;
03261    }
03262    return "Unknown";
03263 }

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

Registers a state change callback.

Parameters:
context which context to look in
exten which extension to get state
callback callback to call if state changed
data to pass to callback
The callback is called if the state of an extension is changed.

Return values:
-1 on failure
ID on success

Definition at line 3364 of file pbx.c.

References ast_calloc, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_state_cb::callback, ast_state_cb::data, ast_state_cb::next, and statecbs.

Referenced by __init_manager(), and handle_request_subscribe().

03366 {
03367    struct ast_hint *hint;
03368    struct ast_state_cb *cblist;
03369    struct ast_exten *e;
03370 
03371    /* If there's no context and extension:  add callback to statecbs list */
03372    if (!context && !exten) {
03373       AST_RWLIST_WRLOCK(&hints);
03374 
03375       for (cblist = statecbs; cblist; cblist = cblist->next) {
03376          if (cblist->callback == callback) {
03377             cblist->data = data;
03378             AST_RWLIST_UNLOCK(&hints);
03379             return 0;
03380          }
03381       }
03382 
03383       /* Now insert the callback */
03384       if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03385          AST_RWLIST_UNLOCK(&hints);
03386          return -1;
03387       }
03388       cblist->id = 0;
03389       cblist->callback = callback;
03390       cblist->data = data;
03391 
03392       cblist->next = statecbs;
03393       statecbs = cblist;
03394 
03395       AST_RWLIST_UNLOCK(&hints);
03396       return 0;
03397    }
03398 
03399    if (!context || !exten)
03400       return -1;
03401 
03402    /* This callback type is for only one hint, so get the hint */
03403    e = ast_hint_extension(NULL, context, exten);
03404    if (!e) {
03405       return -1;
03406    }
03407 
03408    /* Find the hint in the list of hints */
03409    AST_RWLIST_WRLOCK(&hints);
03410 
03411    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03412       if (hint->exten == e)
03413          break;
03414    }
03415 
03416    if (!hint) {
03417       /* We have no hint, sorry */
03418       AST_RWLIST_UNLOCK(&hints);
03419       return -1;
03420    }
03421 
03422    /* Now insert the callback in the callback list  */
03423    if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03424       AST_RWLIST_UNLOCK(&hints);
03425       return -1;
03426    }
03427    cblist->id = stateid++;    /* Unique ID for this callback */
03428    cblist->callback = callback;  /* Pointer to callback routine */
03429    cblist->data = data;    /* Data for the callback */
03430 
03431    cblist->next = hint->callbacks;
03432    hint->callbacks = cblist;
03433 
03434    AST_RWLIST_UNLOCK(&hints);
03435    return cblist->id;
03436 }

int ast_extension_state_del ( int  id,
ast_state_cb_type  callback 
)

Deletes a registered state change callback by ID.

Parameters:
id of the callback to delete
callback callback
Removes the callback from list of callbacks

Return values:
0 success
-1 failure

Definition at line 3439 of file pbx.c.

References ast_free, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_hint::callbacks, ast_hint::list, ast_state_cb::next, and statecbs.

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

03440 {
03441    struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
03442    int ret = -1;
03443 
03444    if (!id && !callback)
03445       return -1;
03446 
03447    AST_RWLIST_WRLOCK(&hints);
03448 
03449    if (!id) {  /* id == 0 is a callback without extension */
03450       for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
03451          if ((*p_cur)->callback == callback)
03452             break;
03453       }
03454    } else { /* callback with extension, find the callback based on ID */
03455       struct ast_hint *hint;
03456       AST_RWLIST_TRAVERSE(&hints, hint, list) {
03457          for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
03458             if ((*p_cur)->id == id)
03459                break;
03460          }
03461          if (*p_cur) /* found in the inner loop */
03462             break;
03463       }
03464    }
03465    if (p_cur && *p_cur) {
03466       struct ast_state_cb *cur = *p_cur;
03467       *p_cur = cur->next;
03468       ast_free(cur);
03469       ret = 0;
03470    }
03471    AST_RWLIST_UNLOCK(&hints);
03472    return ret;
03473 }

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

03595 {
03596    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03597 }

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

References E_FINDLABEL, and pbx_extension_helper().

Referenced by pbx_load_config().

03600 {
03601    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03602 }

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.

Returns:
zero on success, non-zero on failure

Definition at line 2772 of file pbx.c.

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

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

02773 {
02774    char *copy = ast_strdupa(function);
02775    char *args = func_args(copy);
02776    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02777 
02778    if (acfptr == NULL)
02779       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02780    else if (!acfptr->read)
02781       ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
02782    else {
02783       int res;
02784       struct ast_module_user *u = NULL;
02785       if (acfptr->mod)
02786          u = __ast_module_user_add(acfptr->mod, chan);
02787       res = acfptr->read(chan, copy, args, workspace, len);
02788       if (acfptr->mod && u)
02789          __ast_module_user_remove(acfptr->mod, u);
02790       return res;
02791    }
02792    return -1;
02793 }

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.

Returns:
zero on success, non-zero on failure

Definition at line 2795 of file pbx.c.

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

Referenced by pbx_builtin_pushvar_helper(), and pbx_builtin_setvar_helper().

02796 {
02797    char *copy = ast_strdupa(function);
02798    char *args = func_args(copy);
02799    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02800 
02801    if (acfptr == NULL)
02802       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02803    else if (!acfptr->write)
02804       ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
02805    else {
02806       int res;
02807       struct ast_module_user *u = NULL;
02808       if (acfptr->mod)
02809          u = __ast_module_user_add(acfptr->mod, chan);
02810       res = acfptr->write(chan, copy, args, value);
02811       if (acfptr->mod && u)
02812          __ast_module_user_remove(acfptr->mod, u);
02813       return res;
02814    }
02815 
02816    return -1;
02817 }

const char* ast_get_context_name ( struct ast_context con  ) 

Definition at line 8439 of file pbx.c.

References ast_context::name.

Referenced by _macro_exec(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_lockmacro(), ast_context_remove_include2(), ast_context_remove_switch2(), ast_context_unlockmacro(), ast_context_verify_includes(), complete_dialplan_add_extension(), complete_dialplan_add_ignorepat(), complete_dialplan_add_include(), complete_dialplan_remove_extension(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), complete_show_dialplan_context(), context_merge_incls_swits_igps_other_registrars(), dundi_precache_full(), find_context_locked(), find_matching_endwhile(), find_matching_priority(), handle_cli_dialplan_save(), handle_show_hint(), handle_show_hints(), manager_show_dialplan_helper(), and show_dialplan_helper().

08440 {
08441    return con ? con->name : NULL;
08442 }

const char* ast_get_context_registrar ( struct ast_context c  ) 

Definition at line 8477 of file pbx.c.

References ast_context::registrar.

Referenced by handle_cli_dialplan_save(), and show_dialplan_helper().

08478 {
08479    return c ? c->registrar : NULL;
08480 }

const char* ast_get_extension_app ( struct ast_exten e  ) 

Definition at line 8507 of file pbx.c.

References ast_exten::app.

Referenced by _macro_exec(), ast_add_hint_nolock(), ast_extension_state2(), ast_get_hint(), find_matching_endwhile(), handle_cli_dialplan_save(), handle_show_hint(), handle_show_hints(), handle_statechange(), manager_show_dialplan_helper(), and print_ext().

08508 {
08509    return e ? e->app : NULL;
08510 }

void* ast_get_extension_app_data ( struct ast_exten e  ) 

Definition at line 8512 of file pbx.c.

References ast_exten::data.

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

08513 {
08514    return e ? e->data : NULL;
08515 }

const char* ast_get_extension_cidmatch ( struct ast_exten e  ) 

Definition at line 8502 of file pbx.c.

References ast_exten::cidmatch.

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

08503 {
08504    return e ? e->cidmatch : NULL;
08505 }

struct ast_context* ast_get_extension_context ( struct ast_exten exten  ) 

Definition at line 8444 of file pbx.c.

References exten.

Referenced by handle_show_hint(), and handle_show_hints().

08445 {
08446    return exten ? exten->parent : NULL;
08447 }

const char* ast_get_extension_label ( struct ast_exten exten  ) 

Definition at line 8454 of file pbx.c.

References exten.

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

08455 {
08456    return exten ? exten->label : NULL;
08457 }

int ast_get_extension_matchcid ( struct ast_exten e  ) 

Definition at line 8497 of file pbx.c.

References ast_exten::matchcid.

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

08498 {
08499    return e ? e->matchcid : 0;
08500 }

const char* ast_get_extension_name ( struct ast_exten exten  ) 

Definition at line 8449 of file pbx.c.

References exten.

Referenced by ast_add_hint_nolock(), complete_core_show_hint(), complete_dialplan_remove_extension(), dundi_precache_full(), find_matching_priority(), handle_cli_dialplan_save(), handle_show_hint(), handle_show_hints(), manager_show_dialplan_helper(), and show_dialplan_helper().

08450 {
08451    return exten ? exten->exten : NULL;
08452 }

int ast_get_extension_priority ( struct ast_exten exten  ) 

Definition at line 8469 of file pbx.c.

References exten.

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

08470 {
08471    return exten ? exten->priority : -1;
08472 }

const char* ast_get_extension_registrar ( struct ast_exten e  ) 

Definition at line 8482 of file pbx.c.

References ast_exten::registrar.

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

08483 {
08484    return e ? e->registrar : NULL;
08485 }

int ast_get_hint ( char *  hint,
int  maxlen,
char *  name,
int  maxnamelen,
struct ast_channel c,
const char *  context,
const char *  exten 
)

If an extension hint exists, return non-zero.

Parameters:
hint buffer for hint
maxlen size of hint buffer
name buffer for name portion of hint
maxnamelen size of name buffer
c this is not important
context which context to look in
exten which extension to search for
Returns:
If an extension within the given context with the priority PRIORITY_HINT is found a non zero value will be returned. Otherwise, 0 is returned.

Definition at line 3572 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(), pbx_retrieve_variable(), skinny_extensionstate_cb(), and transmit_state_notify().

03573 {
03574    struct ast_exten *e = ast_hint_extension(c, context, exten);
03575 
03576    if (e) {
03577       if (hint)
03578          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
03579       if (name) {
03580          const char *tmp = ast_get_extension_app_data(e);
03581          if (tmp)
03582             ast_copy_string(name, tmp, namesize);
03583       }
03584       return -1;
03585    }
03586    return 0;
03587 }

const char* ast_get_ignorepat_name ( struct ast_ignorepat ip  ) 

Definition at line 8464 of file pbx.c.

References ast_ignorepat::pattern.

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

08465 {
08466    return ip ? ip->pattern : NULL;
08467 }

const char* ast_get_ignorepat_registrar ( struct ast_ignorepat ip  ) 

Definition at line 8492 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().

08493 {
08494    return ip ? ip->registrar : NULL;
08495 }

const char* ast_get_include_name ( struct ast_include inc  ) 

Definition at line 8459 of file pbx.c.

References ast_include::name.

Referenced by complete_dialplan_remove_include(), context_merge_incls_swits_igps_other_registrars(), find_matching_priority(), handle_cli_dialplan_save(), lookup_ci(), manager_show_dialplan_helper(), and show_dialplan_helper().

08460 {
08461    return inc ? inc->name : NULL;
08462 }

const char* ast_get_include_registrar ( struct ast_include i  ) 

Definition at line 8487 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().

08488 {
08489    return i ? i->registrar : NULL;
08490 }

const char* ast_get_switch_data ( struct ast_sw sw  ) 

Definition at line 8522 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().

08523 {
08524    return sw ? sw->data : NULL;
08525 }

int ast_get_switch_eval ( struct ast_sw sw  ) 

Definition at line 8527 of file pbx.c.

References ast_sw::eval.

Referenced by context_merge_incls_swits_igps_other_registrars().

08528 {
08529    return sw->eval;
08530 }

const char* ast_get_switch_name ( struct ast_sw sw  ) 

Definition at line 8517 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().

08518 {
08519    return sw ? sw->name : NULL;
08520 }

const char* ast_get_switch_registrar ( struct ast_sw sw  ) 

Definition at line 8532 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().

08533 {
08534    return sw ? sw->registrar : NULL;
08535 }

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

References __ast_goto_if_exists(), and chan.

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

08626 {
08627    return __ast_goto_if_exists(chan, context, exten, priority, 0);
08628 }

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

Definition at line 363 of file pbx.c.

References ast_context::name.

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

00364 {
00365    const struct ast_context *ac = ah_a;
00366    const struct ast_context *bc = ah_b;
00367    if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
00368       return 1;
00369    /* assume context names are registered in a string table! */
00370    return strcmp(ac->name, bc->name);
00371 }

unsigned int ast_hashtab_hash_contexts ( const void *  obj  ) 

Definition at line 406 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().

00407 {
00408    const struct ast_context *ac = obj;
00409    return ast_hashtab_hash_string(ac->name);
00410 }

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

Find hint for given extension in context.

Definition at line 3163 of file pbx.c.

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

Referenced by ast_extension_state(), and ast_get_hint().

03164 {
03165    struct ast_exten *e;
03166    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
03167 
03168    ast_rdlock_contexts();
03169    e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
03170    ast_unlock_contexts();
03171 
03172    return e;
03173 }

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

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

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

06413 {
06414    struct ast_context *con = ast_context_find(context);
06415    if (con) {
06416       struct ast_ignorepat *pat;
06417       for (pat = con->ignorepats; pat; pat = pat->next) {
06418          if (ast_extension_match(pat->pattern, pattern))
06419             return 1;
06420       }
06421    }
06422 
06423    return 0;
06424 }

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

References E_MATCHMORE, and pbx_extension_helper().

Referenced by ast_app_dtget(), collect_digits(), disa_exec(), dp_lookup(), dundi_lookup_local(), loopback_matchmore(), mgcp_ss(), pbx_builtin_background(), readexten_exec(), skinny_ss(), and ss_thread().

03610 {
03611    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
03612 }

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

References __ast_internal_context_destroy(), ast_calloc, AST_EXTENSION_REMOVED, ast_free, ast_hashtab_destroy(), ast_hashtab_end_traversal(), ast_hashtab_next(), ast_hashtab_start_traversal(), 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_tvdiff_us(), ast_tvnow(), ast_unlock_contexts(), ast_verb, ast_wrlock_contexts(), ast_wrlock_contexts_version(), ast_state_cb::callback, ast_hint::callbacks, store_hint::callbacks, store_hint::context, context_merge(), contexts, contexts_table, ast_state_cb::data, E_MATCH, store_hint::exten, ast_hint::exten, ast_exten::exten, store_hint::laststate, ast_hint::laststate, store_hint::list, LOG_WARNING, ast_context::name, ast_state_cb::next, store_hint::next, ast_context::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().

05775 {
05776    double ft;
05777    struct ast_context *tmp, *oldcontextslist;
05778    struct ast_hashtab *oldtable;
05779    struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
05780    struct store_hint *this;
05781    struct ast_hint *hint;
05782    struct ast_exten *exten;
05783    int length;
05784    struct ast_state_cb *thiscb, *prevcb;
05785    struct ast_hashtab_iter *iter;
05786    
05787    /* it is very important that this function hold the hint list lock _and_ the conlock
05788       during its operation; not only do we need to ensure that the list of contexts
05789       and extensions does not change, but also that no hint callbacks (watchers) are
05790       added or removed during the merge/delete process
05791 
05792       in addition, the locks _must_ be taken in this order, because there are already
05793       other code paths that use this order
05794    */
05795    
05796    struct timeval begintime, writelocktime, endlocktime, enddeltime;
05797    int wrlock_ver;
05798    
05799    begintime = ast_tvnow();
05800    ast_rdlock_contexts();
05801    iter = ast_hashtab_start_traversal(contexts_table);
05802    while ((tmp=ast_hashtab_next(iter))) {
05803       context_merge(extcontexts, exttable, tmp, registrar);
05804    }
05805    ast_hashtab_end_traversal(iter);
05806    wrlock_ver = ast_wrlock_contexts_version();
05807    
05808    ast_unlock_contexts(); /* this feels real retarded, but you must do
05809                        what you must do If this isn't done, the following 
05810                         wrlock is a guraranteed deadlock */
05811    ast_wrlock_contexts();
05812    if (ast_wrlock_contexts_version() > wrlock_ver+1) {
05813       ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
05814    }
05815    
05816    AST_RWLIST_WRLOCK(&hints);
05817    writelocktime = ast_tvnow();
05818 
05819    /* preserve all watchers for hints associated with this registrar */
05820    AST_RWLIST_TRAVERSE(&hints, hint, list) {
05821       if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
05822          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
05823          if (!(this = ast_calloc(1, length)))
05824             continue;
05825          this->callbacks = hint->callbacks;
05826          hint->callbacks = NULL;
05827          this->laststate = hint->laststate;
05828          this->context = this->data;
05829          strcpy(this->data, hint->exten->parent->name);
05830          this->exten = this->data + strlen(this->context) + 1;
05831          strcpy(this->exten, hint->exten->exten);
05832          AST_LIST_INSERT_HEAD(&store, this, list);
05833       }
05834    }
05835 
05836    /* save the old table and list */
05837    oldtable = contexts_table;
05838    oldcontextslist = contexts;
05839 
05840    /* move in the new table and list */
05841    contexts_table = exttable;
05842    contexts = *extcontexts;
05843    
05844    /* restore the watchers for hints that can be found; notify those that
05845       cannot be restored
05846    */
05847    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
05848       struct pbx_find_info q = { .stacklen = 0 };
05849       exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH);
05850       /* Find the hint in the list of hints */
05851       AST_RWLIST_TRAVERSE(&hints, hint, list) {
05852          if (hint->exten == exten)
05853             break;
05854       }
05855       if (!exten || !hint) {
05856          /* this hint has been removed, notify the watchers */
05857          prevcb = NULL;
05858          thiscb = this->callbacks;
05859          while (thiscb) {
05860             prevcb = thiscb;
05861             thiscb = thiscb->next;
05862             prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
05863             ast_free(prevcb);
05864             }
05865       } else {
05866          thiscb = this->callbacks;
05867          while (thiscb->next)
05868             thiscb = thiscb->next;
05869          thiscb->next = hint->callbacks;
05870          hint->callbacks = this->callbacks;
05871          hint->laststate = this->laststate;
05872       }
05873       ast_free(this);
05874    }
05875 
05876    AST_RWLIST_UNLOCK(&hints);
05877    ast_unlock_contexts();
05878    endlocktime = ast_tvnow();
05879    
05880    /* the old list and hashtab no longer are relevant, delete them while the rest of asterisk
05881       is now freely using the new stuff instead */
05882    
05883    ast_hashtab_destroy(oldtable, NULL);
05884    
05885    for (tmp = oldcontextslist; tmp; ) {
05886       struct ast_context *next;  /* next starting point */
05887       next = tmp->next;
05888       __ast_internal_context_destroy(tmp);
05889       tmp = next;
05890    }
05891    enddeltime = ast_tvnow();
05892    
05893    ft = ast_tvdiff_us(writelocktime, begintime);
05894    ft /= 1000000.0;
05895    ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
05896    
05897    ft = ast_tvdiff_us(endlocktime, writelocktime);
05898    ft /= 1000000.0;
05899    ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
05900 
05901    ft = ast_tvdiff_us(enddeltime, endlocktime);
05902    ft /= 1000000.0;
05903    ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
05904 
05905    ft = ast_tvdiff_us(enddeltime, begintime);
05906    ft /= 1000000.0;
05907    ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
05908    return;
05909 }

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

Note:
I can find neither parsable nor parseable at dictionary.com, but google gives me 169000 hits for parseable and only 49,800 for parsable

This function will handle locking the channel as needed.

Definition at line 8688 of file pbx.c.

References chan, and 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().

08689 {
08690    return pbx_parseable_goto(chan, goto_string, 0);
08691 }

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

References __ast_request_and_dial(), 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(), chan, errno, LOG_WARNING, and outgoing_helper::vars.

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

07229 {
07230    struct ast_channel *chan;
07231    struct app_tmp *tmp;
07232    int res = -1, cdr_res = -1;
07233    struct outgoing_helper oh;
07234 
07235    memset(&oh, 0, sizeof(oh));
07236    oh.vars = vars;
07237    oh.account = account;
07238 
07239    if (locked_channel)
07240       *locked_channel = NULL;
07241    if (ast_strlen_zero(app)) {
07242       res = -1;
07243       goto outgoing_app_cleanup;
07244    }
07245    if (sync) {
07246       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07247       if (chan) {
07248          ast_set_variables(chan, vars);
07249          if (account)
07250             ast_cdr_setaccount(chan, account);
07251          if (chan->_state == AST_STATE_UP) {
07252             res = 0;
07253             ast_verb(4, "Channel %s was answered.\n", chan->name);
07254             tmp = ast_calloc(1, sizeof(*tmp));
07255             if (!tmp)
07256                res = -1;
07257             else {
07258                ast_copy_string(tmp->app, app, sizeof(tmp->app));
07259                if (appdata)
07260                   ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
07261                tmp->chan = chan;
07262                if (sync > 1) {
07263                   if (locked_channel)
07264                      ast_channel_unlock(chan);
07265                   ast_pbx_run_app(tmp);
07266                } else {
07267                   if (locked_channel)
07268                      ast_channel_lock(chan);
07269                   if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
07270                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
07271                      ast_free(tmp);
07272                      if (locked_channel)
07273                         ast_channel_unlock(chan);
07274                      ast_hangup(chan);
07275                      res = -1;
07276                   } else {
07277                      if (locked_channel)
07278                         *locked_channel = chan;
07279                   }
07280                }
07281             }
07282          } else {
07283             ast_verb(4, "Channel %s was never answered.\n", chan->name);
07284             if (chan->cdr) { /* update the cdr */
07285                /* here we update the status of the call, which sould be busy.
07286                 * if that fails then we set the status to failed */
07287                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
07288                   ast_cdr_failed(chan->cdr);
07289             }
07290             ast_hangup(chan);
07291          }
07292       }
07293 
07294       if (res < 0) { /* the call failed for some reason */
07295          if (*reason == 0) { /* if the call failed (not busy or no answer)
07296                         * update the cdr with the failed message */
07297             cdr_res = ast_pbx_outgoing_cdr_failed();
07298             if (cdr_res != 0) {
07299                res = cdr_res;
07300                goto outgoing_app_cleanup;
07301             }
07302          }
07303       }
07304 
07305    } else {
07306       struct async_stat *as;
07307       if (!(as = ast_calloc(1, sizeof(*as)))) {
07308          res = -1;
07309          goto outgoing_app_cleanup;
07310       }
07311       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07312       if (!chan) {
07313          ast_free(as);
07314          res = -1;
07315          goto outgoing_app_cleanup;
07316       }
07317       as->chan = chan;
07318       ast_copy_string(as->app, app, sizeof(as->app));
07319       if (appdata)
07320          ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
07321       as->timeout = timeout;
07322       ast_set_variables(chan, vars);
07323       if (account)
07324          ast_cdr_setaccount(chan, account);
07325       /* Start a new thread, and get something handling this channel. */
07326       if (locked_channel)
07327          ast_channel_lock(chan);
07328       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
07329          ast_log(LOG_WARNING, "Failed to start async wait\n");
07330          ast_free(as);
07331          if (locked_channel)
07332             ast_channel_unlock(chan);
07333          ast_hangup(chan);
07334          res = -1;
07335          goto outgoing_app_cleanup;
07336       } else {
07337          if (locked_channel)
07338             *locked_channel = chan;
07339       }
07340       res = 0;
07341    }
07342 outgoing_app_cleanup:
07343    ast_variables_destroy(vars);
07344    return res;
07345 }

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

References ast_cdr_detach(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_start(), ast_channel_alloc, ast_channel_free(), AST_STATE_DOWN, ast_channel::cdr, and chan.

Referenced by ast_pbx_outgoing_app(), and ast_pbx_outgoing_exten().

07037 {
07038    /* allocate a channel */
07039    struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");
07040 
07041    if (!chan)
07042       return -1;  /* failure */
07043 
07044    if (!chan->cdr) {
07045       /* allocation of the cdr failed */
07046       ast_channel_free(chan);   /* free the channel */
07047       return -1;                /* return failure */
07048    }
07049 
07050    /* allocation of the cdr was successful */
07051    ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
07052    ast_cdr_start(chan->cdr);       /* record the start and stop time */
07053    ast_cdr_end(chan->cdr);
07054    ast_cdr_failed(chan->cdr);      /* set the status to failed */
07055    ast_cdr_detach(chan->cdr);      /* post and free the record */
07056    chan->cdr = NULL;
07057    ast_channel_free(chan);         /* free the channel */
07058 
07059    return 0;  /* success */
07060 }

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 7062 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, chan, outgoing_helper::cid_name, outgoing_helper::cid_num, outgoing_helper::context, ast_channel::context, outgoing_helper::exten, ast_channel::hangupcause, LOG_ERROR, LOG_WARNING, ast_channel::name, outgoing_helper::parent_channel, pbx_builtin_setvar_helper(), outgoing_helper::priority, set_ext_pri(), and outgoing_helper::vars.

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

07063 {
07064    struct ast_channel *chan;
07065    struct async_stat *as;
07066    int res = -1, cdr_res = -1;
07067    struct outgoing_helper oh;
07068 
07069    if (sync) {
07070       oh.context = context;
07071       oh.exten = exten;
07072       oh.priority = priority;
07073       oh.cid_num = cid_num;
07074       oh.cid_name = cid_name;
07075       oh.account = account;
07076       oh.vars = vars;
07077       oh.parent_channel = NULL;
07078 
07079       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07080       if (channel) {
07081          *channel = chan;
07082          if (chan)
07083             ast_channel_lock(chan);
07084       }
07085       if (chan) {
07086          if (chan->_state == AST_STATE_UP) {
07087                res = 0;
07088             ast_verb(4, "Channel %s was answered.\n", chan->name);
07089 
07090             if (sync > 1) {
07091                if (channel)
07092                   ast_channel_unlock(chan);
07093                if (ast_pbx_run(chan)) {
07094                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
07095                   if (channel)
07096                      *channel = NULL;
07097                   ast_hangup(chan);
07098                   chan = NULL;
07099                   res = -1;
07100                }
07101             } else {
07102                if (ast_pbx_start(chan)) {
07103                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
07104                   if (channel) {
07105                      *channel = NULL;
07106                      ast_channel_unlock(chan);
07107                   }
07108                   ast_hangup(chan);
07109                   res = -1;
07110                }
07111                chan = NULL;
07112             }
07113          } else {
07114             ast_verb(4, "Channel %s was never answered.\n", chan->name);
07115 
07116             if (chan->cdr) { /* update the cdr */
07117                /* here we update the status of the call, which sould be busy.
07118                 * if that fails then we set the status to failed */
07119                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
07120                   ast_cdr_failed(chan->cdr);
07121             }
07122 
07123             if (channel) {
07124                *channel = NULL;
07125                ast_channel_unlock(chan);
07126             }
07127             ast_hangup(chan);
07128             chan = NULL;
07129          }
07130       }
07131 
07132       if (res < 0) { /* the call failed for some reason */
07133          if (*reason == 0) { /* if the call failed (not busy or no answer)
07134                         * update the cdr with the failed message */
07135             cdr_res = ast_pbx_outgoing_cdr_failed();
07136             if (cdr_res != 0) {
07137                res = cdr_res;
07138                goto outgoing_exten_cleanup;
07139             }
07140          }
07141 
07142          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
07143          /* check if "failed" exists */
07144          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
07145             chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
07146             if (chan) {
07147                char failed_reason[4] = "";
07148                if (!ast_strlen_zero(context))
07149                   ast_copy_string(chan->context, context, sizeof(chan->context));
07150                set_ext_pri(chan, "failed", 1);
07151                ast_set_variables(chan, vars);
07152                snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
07153                pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
07154                if (account)
07155                   ast_cdr_setaccount(chan, account);
07156                if (ast_pbx_run(chan)) {
07157                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
07158                   ast_hangup(chan);
07159                }
07160                chan = NULL;
07161             }
07162          }
07163       }
07164    } else {
07165       if (!(as = ast_calloc(1, sizeof(*as)))) {
07166          res = -1;
07167          goto outgoing_exten_cleanup;
07168       }
07169       chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
07170       if (channel) {
07171          *channel = chan;
07172          if (chan)
07173             ast_channel_lock(chan);
07174       }
07175       if (!chan) {
07176          ast_free(as);
07177          res = -1;
07178          goto outgoing_exten_cleanup;
07179       }
07180       as->chan = chan;
07181       ast_copy_string(as->context, context, sizeof(as->context));
07182       set_ext_pri(as->chan,  exten, priority);
07183       as->timeout = timeout;
07184       ast_set_variables(chan, vars);
07185       if (account)
07186          ast_cdr_setaccount(chan, account);
07187       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
07188          ast_log(LOG_WARNING, "Failed to start async wait\n");
07189          ast_free(as);
07190          if (channel) {
07191             *channel = NULL;
07192             ast_channel_unlock(chan);
07193          }
07194          ast_hangup(chan);
07195          res = -1;
07196          goto outgoing_exten_cleanup;
07197       }
07198       res = 0;
07199    }
07200 outgoing_exten_cleanup:
07201    ast_variables_destroy(vars);
07202    return res;
07203 }

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

References ast_pbx_run_args().

Referenced by ast_pbx_outgoing_exten(), async_wait(), do_idle_thread(), mgcp_ss(), skinny_newcall(), ss_thread(), and unistim_ss().

04022 {
04023    return ast_pbx_run_args(c, NULL);
04024 }

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

run the application and free the descriptor once done

Definition at line 7213 of file pbx.c.

References app_tmp::app, 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().

07214 {
07215    struct app_tmp *tmp = data;
07216    struct ast_app *app;
07217    app = pbx_findapp(tmp->app);
07218    if (app) {
07219       ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
07220       pbx_exec(tmp->chan, app, tmp->data);
07221    } else
07222       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
07223    ast_hangup(tmp->chan);
07224    ast_free(tmp);
07225    return NULL;
07226 }

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 4006 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(), and handle_gosub().

04007 {
04008    enum ast_pbx_result res = AST_PBX_SUCCESS;
04009 
04010    if (increase_call_count(c)) {
04011       return AST_PBX_CALL_LIMIT;
04012    }
04013 
04014    res = __ast_pbx_run(c, args);
04015 
04016    decrease_call_count();
04017 
04018    return res;
04019 }

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 3984 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_bridge_call_thread(), ast_iax2_new(), ast_pbx_outgoing_exten(), bridge_exec(), check_goto_on_transfer(), console_new(), dahdi_new(), dial_exec_full(), do_parking_thread(), gtalk_new(), gtalk_newcall(), handle_request_invite(), jingle_new(), jingle_newcall(), local_call(), mgcp_new(), nbs_new(), oss_new(), pbx_start_chan(), phone_new(), rpt_call(), sip_new(), skinny_new(), unistim_new(), and usbradio_new().

03985 {
03986    pthread_t t;
03987 
03988    if (!c) {
03989       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
03990       return AST_PBX_FAILED;
03991    }
03992 
03993    if (increase_call_count(c))
03994       return AST_PBX_CALL_LIMIT;
03995 
03996    /* Start a new thread, and get something handling this channel. */
03997    if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
03998       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
03999       decrease_call_count();
04000       return AST_PBX_FAILED;
04001    }
04002 
04003    return AST_PBX_SUCCESS;
04004 }

int ast_processed_calls ( void   ) 

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

Definition at line 4031 of file pbx.c.

Referenced by handle_chanlist(), and handle_showcalls().

04032 {
04033    return totalcalls;
04034 }

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 8426 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(), and show_dialplan_helper().

08427 {
08428    return ast_rwlock_rdlock(&con->lock);
08429 }

int ast_rdlock_contexts ( void   ) 

Read locks the context list.

Return values:
0 on success
-1 on error

Definition at line 8408 of file pbx.c.

References ast_rwlock_rdlock(), and conlock.

Referenced by _macro_exec(), ast_context_find(), ast_context_find_or_create(), ast_context_lockmacro(), ast_context_unlockmacro(), ast_hint_extension(), ast_merge_contexts_and_delete(), complete_dialplan_add_extension(), complete_dialplan_add_ignorepat(), complete_dialplan_add_include(), complete_dialplan_remove_extension(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), complete_show_dialplan_context(), dundi_precache_full(), find_context_locked(), find_matching_endwhile(), handle_cli_dialplan_save(), handle_statechange(), manager_show_dialplan_helper(), pbx_extension_helper(), show_dialplan_helper(), and unreference_cached_app().

08409 {
08410    return ast_rwlock_rdlock(&conlock);
08411 }

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

Register an application.

Parameters:
app Short name of the application
execute a function callback to execute the application. It should return non-zero if the channel needs to be hung up.
synopsis a short description (one line synopsis) of the application
description long description with all of the details about the use of the application
mod module this application belongs to
This registers an application with Asterisk's internal application list.
Note:
The individual applications themselves are responsible for registering and unregistering and unregistering their own CLI commands.
Return values:
0 success
-1 failure.

Definition at line 4455 of file pbx.c.

References ast_calloc, 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_verb, COLOR_BRCYAN, ast_app::description, ast_app::execute, ast_app::list, LOG_WARNING, ast_app::module, ast_app::name, ast_app::synopsis, and term_color().

Referenced by ast_features_init(), and load_pbx().

04456 {
04457    struct ast_app *tmp, *cur = NULL;
04458    char tmps[80];
04459    int length, res;
04460 
04461    AST_RWLIST_WRLOCK(&apps);
04462    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
04463       if (!(res = strcasecmp(app, tmp->name))) {
04464          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
04465          AST_RWLIST_UNLOCK(&apps);
04466          return -1;
04467       } else if (res < 0)
04468          break;
04469    }
04470 
04471    length = sizeof(*tmp) + strlen(app) + 1;
04472 
04473    if (!(tmp = ast_calloc(1, length))) {
04474       AST_RWLIST_UNLOCK(&apps);
04475       return -1;
04476    }
04477 
04478    strcpy(tmp->name, app);
04479    tmp->execute = execute;
04480    tmp->synopsis = synopsis;
04481    tmp->description = description;
04482    tmp->module = mod;
04483 
04484    /* Store in alphabetical order */
04485    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
04486       if (strcasecmp(tmp->name, cur->name) < 0) {
04487          AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
04488          break;
04489       }
04490    }
04491    AST_RWLIST_TRAVERSE_SAFE_END;
04492    if (!cur)
04493       AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
04494 
04495    ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
04496 
04497    AST_RWLIST_UNLOCK(&apps);
04498 
04499    return 0;
04500 }

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.

Returns:
0 on success, and other than 0 on failure

Definition at line 4506 of file pbx.c.

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

Referenced by load_module().

04507 {
04508    struct ast_switch *tmp;
04509 
04510    AST_RWLIST_WRLOCK(&switches);
04511    AST_RWLIST_TRAVERSE(&switches, tmp, list) {
04512       if (!strcasecmp(tmp->name, sw->name)) {
04513          AST_RWLIST_UNLOCK(&switches);
04514          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
04515          return -1;
04516       }
04517    }
04518    AST_RWLIST_INSERT_TAIL(&switches, sw, list);
04519    AST_RWLIST_UNLOCK(&switches);
04520 
04521    return 0;
04522 }

static int ast_remove_hint ( struct ast_exten e  )  [static]

Remove hint from extension.

Definition at line 3537 of file pbx.c.

References AST_EXTENSION_DEACTIVATED, ast_free, 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, ast_state_cb::next, and ast_exten::parent.

Referenced by destroy_exten().

03538 {
03539    /* Cleanup the Notifys if hint is removed */
03540    struct ast_hint *hint;
03541    struct ast_state_cb *cblist, *cbprev;
03542    int res = -1;
03543 
03544    if (!e)
03545       return -1;
03546 
03547    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
03548       if (hint->exten == e) {
03549          cbprev = NULL;
03550          cblist = hint->callbacks;
03551          while (cblist) {
03552             /* Notify with -1 and remove all callbacks */
03553             cbprev = cblist;
03554             cblist = cblist->next;
03555             cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
03556             ast_free(cbprev);
03557             }
03558             hint->callbacks = NULL;
03559          AST_RWLIST_REMOVE_CURRENT(list);
03560             ast_free(hint);
03561             res = 0;
03562          break;
03563       }
03564    }
03565    AST_RWLIST_TRAVERSE_SAFE_END;
03566 
03567    return res;
03568 }

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

03615 {
03616    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
03617 }

int ast_unlock_context ( struct ast_context con  ) 

Return values:
Unlocks the given context
Parameters:
con context to unlock
Return values:
0 on success
-1 on failure

Definition at line 8431 of file pbx.c.

References ast_rwlock_unlock(), and ast_context::lock.

Referenced by __ast_context_destroy(), _macro_exec(), ast_add_extension2_lockopt(), ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_remove_extension_callerid2(), ast_context_remove_ignorepat2(), ast_context_remove_include2(), ast_context_remove_switch2(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), dundi_precache_full(), find_matching_endwhile(), handle_cli_dialplan_save(), lookup_c_ip(), lookup_ci(), manager_show_dialplan_helper(), and show_dialplan_helper().

08432 {
08433    return ast_rwlock_unlock(&con->lock);
08434 }

int ast_unlock_contexts ( void   ) 

Unlocks contexts.

Return values:
0 on success
-1 on failure

Definition at line 8413 of file pbx.c.

References ast_rwlock_unlock(), and conlock.

Referenced by _macro_exec(), ast_add_extension(), ast_context_add_ignorepat(), ast_context_add_include(), ast_context_add_switch(), ast_context_destroy(), ast_context_find(), ast_context_find_or_create(), ast_context_lockmacro(), ast_context_remove_extension_callerid(), ast_context_remove_ignorepat(), ast_context_remove_include(), ast_context_remove_switch(), ast_context_unlockmacro(), ast_hint_extension(), ast_merge_contexts_and_delete(), complete_dialplan_add_extension(), complete_dialplan_add_ignorepat(), complete_dialplan_add_include(), complete_dialplan_remove_extension(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), complete_show_dialplan_context(), dundi_precache_full(), find_context_locked(), find_matching_endwhile(), handle_cli_dialplan_save(), handle_statechange(), manager_show_dialplan_helper(), pbx_extension_helper(), show_dialplan_helper(), and unreference_cached_app().

08414 {
08415    return ast_rwlock_unlock(&conlock);
08416 }

int ast_unregister_application ( const char *  app  ) 

Unregister an application.

Parameters:
app name of the application (does not have to be the same string as the one that was registered)
This unregisters an application from Asterisk's internal application list.

Return values:
0 success
-1 failure

Definition at line 5555 of file pbx.c.

References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_app::list, ast_app::name, and unreference_cached_app().

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

05556 {
05557    struct ast_app *tmp;
05558 
05559    AST_RWLIST_WRLOCK(&apps);
05560    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
05561       if (!strcasecmp(app, tmp->name)) {
05562          unreference_cached_app(tmp);
05563          AST_RWLIST_REMOVE_CURRENT(list);
05564          ast_verb(2, "Unregistered application '%s'\n", tmp->name);
05565          ast_free(tmp);
05566          break;
05567       }
05568    }
05569    AST_RWLIST_TRAVERSE_SAFE_END;
05570    AST_RWLIST_UNLOCK(&apps);
05571 
05572    return tmp ? 0 : -1;
05573 }

void ast_unregister_switch ( struct ast_switch sw  ) 

Unregister an alternative switch.

Parameters:
sw switch to unregister
Unregisters a switch from asterisk.

Returns:
nothing

Definition at line 4524 of file pbx.c.

References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_switch::list.

Referenced by __unload_module(), and unload_module().

04525 {
04526    AST_RWLIST_WRLOCK(&switches);
04527    AST_RWLIST_REMOVE(&switches, sw, list);
04528    AST_RWLIST_UNLOCK(&switches);
04529 }

struct ast_exten* ast_walk_context_extensions ( struct ast_context con,
struct ast_exten exten 
)

Definition at line 8545 of file pbx.c.

References exten, and ast_context::root.

Referenced by complete_dialplan_remove_extension(), dundi_precache_full(), find_matching_priority(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), pbx_find_extension(), show_dialplan_helper(), and unreference_cached_app().

08547 {
08548    if (!exten)
08549       return con ? con->root : NULL;
08550    else
08551       return exten->next;
08552 }

struct ast_ignorepat* ast_walk_context_ignorepats ( struct ast_context con,
struct ast_ignorepat ip 
)

Definition at line 8578 of file pbx.c.

References ast_context::ignorepats, and ast_ignorepat::next.

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

08580 {
08581    if (!ip)
08582       return con ? con->ignorepats : NULL;
08583    else
08584       return ip->next;
08585 }

struct ast_include* ast_walk_context_includes ( struct ast_context con,
struct ast_include inc 
)

Definition at line 8569 of file pbx.c.

References ast_context::includes, and ast_include::next.

Referenced by ast_context_verify_includes(), complete_dialplan_remove_include(), context_merge_incls_swits_igps_other_registrars(), find_matching_priority(), handle_cli_dialplan_save(), lookup_ci(), manager_show_dialplan_helper(), and show_dialplan_helper().

08571 {
08572    if (!inc)
08573       return con ? con->includes : NULL;
08574    else
08575       return inc->next;
08576 }

struct ast_sw* ast_walk_context_switches ( struct ast_context con,
struct ast_sw sw 
)

Definition at line 8554 of file pbx.c.

References ast_context::alts, AST_LIST_FIRST, AST_LIST_NEXT, and ast_sw::list.

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

08556 {
08557    if (!sw)
08558       return con ? AST_LIST_FIRST(&con->alts) : NULL;
08559    else
08560       return AST_LIST_NEXT(sw, list);
08561 }

struct ast_context* ast_walk_contexts ( struct ast_context con  ) 

Definition at line 8540 of file pbx.c.

References contexts, and ast_context::next.

Referenced by _macro_exec(), ast_context_find(), ast_context_lockmacro(), ast_context_unlockmacro(), complete_dialplan_add_extension(), complete_dialplan_add_ignorepat(), complete_dialplan_add_include(), complete_dialplan_remove_extension(), complete_dialplan_remove_ignorepat(), complete_dialplan_remove_include(), complete_show_dialplan_context(), dundi_precache_full(), find_context_locked(), find_matching_endwhile(), find_matching_priority(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), pbx_find_extension(), pbx_load_module(), show_dialplan_helper(), and unreference_cached_app().

08541 {
08542    return con ? con->next : contexts;
08543 }

struct ast_exten* ast_walk_extension_priorities ( struct ast_exten exten,
struct ast_exten priority 
)

Definition at line 8563 of file pbx.c.

References exten, and ast_exten::priority.

Referenced by complete_dialplan_remove_extension(), find_matching_priority(), handle_cli_dialplan_save(), manager_show_dialplan_helper(), pbx_find_extension(), show_dialplan_helper(), and unreference_cached_app().

08565 {
08566    return priority ? priority->peer : exten;
08567 }

int ast_wrlock_context ( struct ast_context con  ) 

Write locks a given context.

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

Definition at line 8421 of file pbx.c.

References ast_rwlock_wrlock(), and ast_context::lock.

Referenced by __ast_context_destroy(), ast_add_extension2_lockopt(), ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_remove_extension_callerid2(), ast_context_remove_ignorepat2(), ast_context_remove_include2(), and ast_context_remove_switch2().

08422 {
08423    return ast_rwlock_wrlock(&con->lock);
08424 }

int ast_wrlock_contexts ( void   ) 

Write locks the context list.

Return values:
0 on success
-1 on error

Definition at line 8400 of file pbx.c.

References ast_atomic_fetchadd_int(), ast_rwlock_wrlock(), and conlock.

Referenced by ast_context_destroy(), ast_context_find_or_create(), ast_merge_contexts_and_delete(), and complete_dialplan_remove_include().

08401 {
08402    int res = ast_rwlock_wrlock(&conlock);
08403    if (!res)
08404       ast_atomic_fetchadd_int(&conlock_wrlock_version, 1);
08405    return res;
08406 }

int ast_wrlock_contexts_version ( void   ) 

Definition at line 8392 of file pbx.c.

Referenced by ast_merge_contexts_and_delete().

08393 {
08394    return conlock_wrlock_version;
08395 }

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

Definition at line 6975 of file pbx.c.

References ast_channel::_state, app, async_stat::app, async_stat::appdata, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, ast_copy_string(), AST_FRAME_CONTROL, ast_free, ast_frfree, ast_hangup(), ast_log(), ast_pbx_run(), ast_read(), AST_STATE_UP, ast_strlen_zero(), ast_verb, ast_waitfor(), async_stat::chan, chan, ast_channel::context, async_stat::context, ast_channel::exten, async_stat::exten, f, LOG_ERROR, LOG_WARNING, ast_channel::name, pbx_exec(), pbx_findapp(), ast_channel::priority, async_stat::priority, and async_stat::timeout.

Referenced by ast_pbx_outgoing_app(), and ast_pbx_outgoing_exten().

06976 {
06977    struct async_stat *as = data;
06978    struct ast_channel *chan = as->chan;
06979    int timeout = as->timeout;
06980    int res;
06981    struct ast_frame *f;
06982    struct ast_app *app;
06983 
06984    while (timeout && (chan->_state != AST_STATE_UP)) {
06985       res = ast_waitfor(chan, timeout);
06986       if (res < 1)
06987          break;
06988       if (timeout > -1)
06989          timeout = res;
06990       f = ast_read(chan);
06991       if (!f)
06992          break;
06993       if (f->frametype == AST_FRAME_CONTROL) {
06994          if ((f->subclass == AST_CONTROL_BUSY)  ||
06995              (f->subclass == AST_CONTROL_CONGESTION) ) {
06996             ast_frfree(f);
06997             break;
06998          }
06999       }
07000       ast_frfree(f);
07001    }
07002    if (chan->_state == AST_STATE_UP) {
07003       if (!ast_strlen_zero(as->app)) {
07004          app = pbx_findapp(as->app);
07005          if (app) {
07006             ast_verb(3, "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
07007             pbx_exec(chan, app, as->appdata);
07008          } else
07009             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
07010       } else {
07011          if (!ast_strlen_zero(as->context))
07012             ast_copy_string(chan->context, as->context, sizeof(chan->context));
07013          if (!ast_strlen_zero(as->exten))
07014             ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
07015          if (as->priority > 0)
07016             chan->priority = as->priority;
07017          /* Run the PBX */
07018          if (ast_pbx_run(chan)) {
07019             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
07020          } else {
07021             /* PBX will have taken care of this */
07022             chan = NULL;
07023          }
07024       }
07025    }
07026    ast_free(as);
07027    if (chan)
07028       ast_hangup(chan);
07029    return NULL;
07030 }

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

Definition at line 1126 of file pbx.c.

References match_char::alt_char, ast_cli(), ast_str_alloca, ast_str_set(), match_char::deleted, ast_exten::exten, match_char::exten, match_char::is_pattern, match_char::next_char, match_char::specificity, ast_str::str, and match_char::x.

Referenced by show_dialplan_helper().

01127 {
01128    char extenstr[40];
01129    struct ast_str *my_prefix = ast_str_alloca(1024);
01130    
01131    extenstr[0] = '\0';
01132 
01133    if (node && node->exten && node->exten)
01134       snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01135    
01136    if (strlen(node->x) > 1) {
01137       ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N', 
01138          node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "", 
01139          node->exten ? node->exten->exten : "", extenstr);
01140    } else {
01141       ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N', 
01142          node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "", 
01143          node->exten ? node->exten->exten : "", extenstr);
01144    }
01145 
01146    ast_str_set(&my_prefix, 0, "%s+       ", prefix);
01147 
01148    if (node->next_char)
01149       cli_match_char_tree(node->next_char, my_prefix->str, fd);
01150 
01151    if (node->alt_char)
01152       cli_match_char_tree(node->alt_char, prefix, fd);
01153 }

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

collect digits from the channel into the buffer.

Return values:
0 on timeout or done.
-1 on error.

Definition at line 3633 of file pbx.c.

References ast_channel::_softhangup, ast_matchmore_extension(), AST_SOFTHANGUP_ASYNCGOTO, ast_waitfordigit(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_pbx::dtimeout, and ast_channel::pbx.

03634 {
03635    int digit;
03636 
03637    buf[pos] = '\0';  /* make sure it is properly terminated */
03638    while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
03639       /* As long as we're willing to wait, and as long as it's not defined,
03640          keep reading digits until we can't possibly get a right answer anymore.  */
03641       digit = ast_waitfordigit(c, waittime * 1000);
03642       if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03643          c->_softhangup = 0;
03644       } else {
03645          if (!digit) /* No entry */
03646             break;
03647          if (digit < 0) /* Error, maybe a  hangup */
03648             return -1;
03649          if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
03650             buf[pos++] = digit;
03651             buf[pos] = '\0';
03652          }
03653          waittime = c->pbx->dtimeout;
03654       }
03655    }
03656    return 0;
03657 }

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

Definition at line 350 of file pbx.c.

Referenced by add_exten_to_pattern_tree().

00351 {
00352    const char *ac = a;
00353    const char *bc = b;
00354    if ((*ac) < (*bc))
00355       return -1;
00356    else if ((*ac) == (*bc))
00357       return 0;
00358    else
00359       return 1;
00360 }

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

autocomplete for CLI command 'core show hint'

Definition at line 4683 of file pbx.c.

References ast_get_extension_name(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, ast_hint::exten, and ast_hint::list.

Referenced by handle_show_hint().

04684 {
04685    struct ast_hint *hint;
04686    char *ret = NULL;
04687    int which = 0;
04688    int wordlen;
04689 
04690    if (pos != 3)
04691       return NULL;
04692    
04693    wordlen = strlen(word);
04694 
04695    AST_RWLIST_RDLOCK(&hints);
04696    /* walk through all hints */
04697    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04698       if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
04699          ret = ast_strdup(ast_get_extension_name(hint->exten));
04700          break;
04701       }
04702    }
04703    AST_RWLIST_UNLOCK(&hints);
04704 
04705    return ret;
04706 }

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

Definition at line 4878 of file pbx.c.

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

Referenced by handle_show_dialplan().

04880 {
04881    struct ast_context *c = NULL;
04882    char *ret = NULL;
04883    int which = 0;
04884    int wordlen;
04885 
04886    /* we are do completion of [exten@]context on second position only */
04887    if (pos != 2)
04888       return NULL;
04889 
04890    ast_rdlock_contexts();
04891 
04892    wordlen = strlen(word);
04893 
04894    /* walk through all contexts and return the n-th match */
04895    while ( (c = ast_walk_contexts(c)) ) {
04896       if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
04897          ret = ast_strdup(ast_get_context_name(c));
04898          break;
04899       }
04900    }
04901 
04902    ast_unlock_contexts();
04903 
04904    return ret;
04905 }

static void context_merge ( struct ast_context **  extcontexts,
struct ast_hashtab exttable,
struct ast_context context,
const char *  registrar 
) [static]

Definition at line 5690 of file pbx.c.

References ast_exten::app, ast_add_extension2(), ast_context_find_or_create(), ast_hashtab_end_traversal(), ast_hashtab_lookup(), ast_hashtab_next(), ast_hashtab_start_traversal(), ast_log(), ast_strdup, ast_verb, ast_exten::cidmatch, store_hint::context, context_merge_incls_swits_igps_other_registrars(), ast_exten::data, ast_exten::datad, ast_exten::exten, first, ast_exten::label, LOG_ERROR, ast_exten::peer_table, ast_exten::priority, and ast_exten::registrar.

Referenced by ast_merge_contexts_and_delete().

05691 {
05692    struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
05693    struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
05694    struct ast_hashtab_iter *exten_iter;
05695    struct ast_hashtab_iter *prio_iter;
05696    int insert_count = 0;
05697    int first = 1;
05698    
05699    /* We'll traverse all the extensions/prios, and see which are not registrar'd with
05700       the current registrar, and copy them to the new context. If the new context does not
05701       exist, we'll create it "on demand". If no items are in this context to copy, then we'll
05702       only create the empty matching context if the old one meets the criteria */
05703    
05704    if (context->root_table) {
05705       exten_iter = ast_hashtab_start_traversal(context->root_table);
05706       while ((exten_item=ast_hashtab_next(exten_iter))) {
05707          if (new) {
05708             new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
05709          } else {
05710             new_exten_item = NULL;
05711          }
05712          prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
05713          while ((prio_item=ast_hashtab_next(prio_iter))) {
05714             int res1;
05715             char *dupdstr;
05716             
05717             if (new_exten_item) {
05718                new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
05719             } else {
05720                new_prio_item = NULL;
05721             }
05722             if (strcmp(prio_item->registrar,registrar) == 0) {
05723                continue;
05724             }
05725             /* make sure the new context exists, so we have somewhere to stick this exten/prio */
05726             if (!new) {
05727                new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */
05728             }
05729 
05730             /* copy in the includes, switches, and ignorepats */
05731             if (first) { /* but, only need to do this once */
05732                context_merge_incls_swits_igps_other_registrars(new, context, registrar);
05733                first = 0;
05734             }
05735             
05736             if (!new) {
05737                ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
05738                return; /* no sense continuing. */
05739             }
05740             /* we will not replace existing entries in the new context with stuff from the old context.
05741                but, if this is because of some sort of registrar conflict, we ought to say something... */
05742             
05743             dupdstr = ast_strdup(prio_item->data);
05744             
05745             res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label, 
05746                                 prio_item->cidmatch, prio_item->app, dupdstr, prio_item->datad, prio_item->registrar);
05747             if (!res1 && new_exten_item && new_prio_item){
05748                ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
05749                      context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
05750             } else {
05751                /* we do NOT pass the priority data from the old to the new -- we pass a copy of it, so no changes to the current dialplan take place,
05752                 and no double frees take place, either! */
05753                insert_count++;
05754             }
05755          }
05756          ast_hashtab_end_traversal(prio_iter);
05757       }
05758       ast_hashtab_end_traversal(exten_iter);
05759    }
05760    
05761    if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
05762         (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
05763       /* we could have given it the registrar of the other module who incremented the refcount,
05764          but that's not available, so we give it the registrar we know about */
05765       new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
05766       
05767       /* copy in the includes, switches, and ignorepats */
05768       context_merge_incls_swits_igps_other_registrars(new, context, registrar);
05769    }
05770 }

static void context_merge_incls_swits_igps_other_registrars ( struct ast_context new,
struct ast_context old,
const char *  registrar 
) [static]

Definition at line 5657 of file pbx.c.

References ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_get_context_name(), ast_get_ignorepat_name(), ast_get_ignorepat_registrar(), ast_get_include_name(), ast_get_include_registrar(), ast_get_switch_data(), ast_get_switch_eval(), ast_get_switch_name(), ast_get_switch_registrar(), ast_verb, ast_walk_context_ignorepats(), ast_walk_context_includes(), and ast_walk_context_switches().

Referenced by context_merge().

05658 {
05659    struct ast_include *i;
05660    struct ast_ignorepat *ip;
05661    struct ast_sw *sw;
05662    
05663    ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar);
05664    /* copy in the includes, switches, and ignorepats */
05665    /* walk through includes */
05666    for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
05667       if (strcmp(ast_get_include_registrar(i), registrar) == 0)
05668          continue; /* not mine */
05669       ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
05670    }
05671    
05672    /* walk through switches */
05673    for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
05674       if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
05675          continue; /* not mine */
05676       ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw));
05677    }
05678    
05679    /* walk thru ignorepats ... */
05680    for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
05681       if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
05682          continue; /* not mine */
05683       ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
05684    }
05685 }

static void create_match_char_tree ( struct ast_context con  )  [static]

Definition at line 1589 of file pbx.c.

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

Referenced by pbx_find_extension().

01590 {
01591    struct ast_hashtab_iter *t1;
01592    struct ast_exten *e1;
01593 #ifdef NEED_DEBUG
01594    int biggest_bucket, resizes, numobjs, numbucks;
01595    
01596    ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
01597    ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
01598    ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
01599          numobjs, numbucks, biggest_bucket, resizes);
01600 #endif
01601    t1 = ast_hashtab_start_traversal(con->root_table);
01602    while( (e1 = ast_hashtab_next(t1)) ) {
01603       if (e1->exten)
01604          add_exten_to_pattern_tree(con, e1, 0);
01605       else
01606          ast_log(LOG_ERROR,"Attempt to create extension with no extension name.\n");
01607    }
01608    ast_hashtab_end_traversal(t1);
01609 }

static void decrease_call_count ( void   )  [static]

Definition at line 3942 of file pbx.c.

References ast_mutex_lock(), ast_mutex_unlock(), and maxcalllock.

Referenced by ast_pbx_run_args(), ast_pbx_start(), and pbx_thread().

03943 {
03944    ast_mutex_lock(&maxcalllock);
03945    if (countcalls > 0)
03946       countcalls--;
03947    ast_mutex_unlock(&maxcalllock);
03948 }

static void destroy_exten ( struct ast_exten e  )  [static]

Definition at line 3950 of file pbx.c.

References ast_free, ast_hashtab_destroy(), ast_remove_hint(), ast_exten::priority, and PRIORITY_HINT.

Referenced by __ast_internal_context_destroy(), and ast_context_remove_extension_callerid2().

03951 {
03952    if (e->priority == PRIORITY_HINT)
03953       ast_remove_hint(e);
03954 
03955    if (e->peer_table)
03956       ast_hashtab_destroy(e->peer_table,0);
03957    if (e->peer_label_table)
03958       ast_hashtab_destroy(e->peer_label_table, 0);
03959    if (e->datad)
03960       e->datad(e->data);
03961    ast_free(e);
03962 }

static void destroy_pattern_tree ( struct match_char pattern_tree  )  [static]

Definition at line 1611 of file pbx.c.

References match_char::alt_char, match_char::exten, free, match_char::next_char, and match_char::x.

Referenced by __ast_internal_context_destroy().

01612 {
01613    /* destroy all the alternates */
01614    if (pattern_tree->alt_char) {
01615       destroy_pattern_tree(pattern_tree->alt_char);
01616       pattern_tree->alt_char = 0;
01617    }
01618    /* destroy all the nexts */
01619    if (pattern_tree->next_char) {
01620       destroy_pattern_tree(pattern_tree->next_char);
01621       pattern_tree->next_char = 0;
01622    }
01623    pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
01624    if (pattern_tree->x)
01625       free(pattern_tree->x);
01626    free(pattern_tree);
01627 }

static void device_state_cb ( const struct ast_event event,
void *  unused 
) [static]

Definition at line 8343 of file pbx.c.

References ast_event_get_ie_str(), AST_EVENT_IE_DEVICE, ast_log(), ast_strlen_zero(), LOG_ERROR, and statechange_queue().

Referenced by load_module(), and load_pbx().

08344 {
08345    const char *device;
08346 
08347    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
08348    if (ast_strlen_zero(device)) {
08349       ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
08350       return;
08351    }
08352 
08353    statechange_queue(device);
08354 }

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

Definition at line 3339 of file pbx.c.

References ast_cond_wait(), ast_free, AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), statechange::dev, device_state, statechange::entry, and handle_statechange().

Referenced by load_module(), and load_pbx().

03340 {
03341    struct statechange *sc;
03342 
03343    while (!device_state.stop) {
03344       ast_mutex_lock(&device_state.lock);
03345       while (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
03346          ast_cond_wait(&device_state.cond, &device_state.lock);
03347          /* Check to see if we were woken up to see the request to stop */
03348          if (device_state.stop) {
03349             ast_mutex_unlock(&device_state.lock);
03350             return NULL;
03351          }
03352       }
03353       ast_mutex_unlock(&device_state.lock);
03354 
03355       handle_statechange(sc->dev);
03356 
03357       ast_free(sc);
03358    }
03359 
03360    return NULL;
03361 }

static void exception_store_free ( void *  data  )  [static]

Definition at line 2486 of file pbx.c.

References ast_free, and ast_string_field_free_memory.

02487 {
02488    struct pbx_exception *exception = data;
02489    ast_string_field_free_memory(exception);
02490    ast_free(exception);
02491 }

static int ext_cmp ( const char *  a,
const char *  b 
) [static]

the full routine to compare extensions in rules.

Definition at line 1754 of file pbx.c.

References ext_cmp1().

Referenced by ast_add_extension2_lockopt(), and ast_extension_cmp().

01755 {
01756    /* make sure non-patterns come first.
01757     * If a is not a pattern, it either comes first or
01758     * we use strcmp to compare the strings.
01759     */
01760    int ret = 0;
01761 
01762    if (a[0] != '_')
01763       return (b[0] == '_') ? -1 : strcmp(a, b);
01764 
01765    /* Now we know a is a pattern; if b is not, a comes first */
01766    if (b[0] != '_')
01767       return 1;
01768 #if 0 /* old mode for ext matching */
01769    return strcmp(a, b);
01770 #endif
01771    /* ok we need full pattern sorting routine */
01772    while (!ret && a && b)
01773       ret = ext_cmp1(&a) - ext_cmp1(&b);
01774    if (ret == 0)
01775       return 0;
01776    else
01777       return (ret > 0) ? 1 : -1;
01778 }

static int ext_cmp1 ( const char **  p  )  [static]

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

ext_cmp1 compares individual characters (or sets of), returning an int where bits 0-7 are the ASCII code of the first char in the set, while bit 8-15 are the cardinality of the set minus 1. This way more specific patterns (smaller cardinality) appear first. Wildcards have a special value, so that we can directly compare them to sets by subtracting the two values. In particular: 0x000xx one character, xx 0x0yyxx yy character set starting with xx 0x10000 '.' (one or more of anything) 0x20000 '!' (zero or more of anything) 0x30000 NUL (end of string) 0x40000 error in set. The pointer to the string is advanced according to needs. NOTES: 1. the empty set is equivalent to NUL. 2. given that a full set has always 0 as the first element, we could encode the special cases as 0xffXX where XX is 1, 2, 3, 4 as used above.

Definition at line 1683 of file pbx.c.

References ast_log(), and LOG_WARNING.

Referenced by ext_cmp().

01684 {
01685    uint32_t chars[8];
01686    int c, cmin = 0xff, count = 0;
01687    const char *end;
01688 
01689    /* load, sign extend and advance pointer until we find
01690     * a valid character.
01691     */
01692    c = *(*p)++;
01693 
01694    /* always return unless we have a set of chars */
01695    switch (toupper(c)) {
01696    default: /* ordinary character */
01697       return 0x0000 | (c & 0xff);
01698 
01699    case 'N':   /* 2..9 */
01700       return 0x0800 | '2' ;
01701 
01702    case 'X':   /* 0..9 */
01703       return 0x0A00 | '0';
01704 
01705    case 'Z':   /* 1..9 */
01706       return 0x0900 | '1';
01707 
01708    case '.':   /* wildcard */
01709       return 0x10000;
01710 
01711    case '!':   /* earlymatch */
01712       return 0x20000;   /* less specific than NULL */
01713 
01714    case '\0':  /* empty string */
01715       *p = NULL;
01716       return 0x30000;
01717 
01718    case '[':   /* pattern */
01719       break;
01720    }
01721    /* locate end of set */
01722    end = strchr(*p, ']');  
01723 
01724    if (end == NULL) {
01725       ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
01726       return 0x40000;   /* XXX make this entry go last... */
01727    }
01728 
01729    memset(chars, '\0', sizeof(chars)); /* clear all chars in the set */
01730    for (; *p < end  ; (*p)++) {
01731       unsigned char c1, c2;   /* first-last char in range */
01732       c1 = (unsigned char)((*p)[0]);
01733       if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
01734          c2 = (unsigned char)((*p)[2]);
01735          *p += 2; /* skip a total of 3 chars */
01736       } else         /* individual character */
01737          c2 = c1;
01738       if (c1 < cmin)
01739          cmin = c1;
01740       for (; c1 <= c2; c1++) {
01741          uint32_t mask = 1 << (c1 % 32);
01742          if ( (chars[ c1 / 32 ] & mask) == 0)
01743             count += 0x100;
01744          chars[ c1 / 32 ] |= mask;
01745       }
01746    }
01747    (*p)++;
01748    return count == 0 ? 0x30000 : (count | cmin);
01749 }

static int ext_strncpy ( char *  dst,
const char *  src,
int  len 
) [static]

copy a string skipping whitespace

Definition at line 6537 of file pbx.c.

Referenced by ast_add_extension2_lockopt().

06538 {
06539    int count = 0;
06540 
06541    while (*src && (count < len - 1)) {
06542       switch (*src) {
06543       case ' ':
06544          /* otherwise exten => [a-b],1,... doesn't work */
06545          /*    case '-': */
06546          /* Ignore */
06547          break;
06548       default:
06549          *dst = *src;
06550          dst++;
06551       }
06552       src++;
06553       count++;
06554    }
06555    *dst = '\0';
06556 
06557    return count;
06558 }

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

Definition at line 1961 of file pbx.c.

References _extension_match_core(), ast_add_profile(), and ast_mark().

Referenced by ast_extension_close(), ast_extension_match(), and pbx_find_extension().

01962 {
01963    int i;
01964    static int prof_id = -2;   /* marker for 'unallocated' id */
01965    if (prof_id == -2)
01966       prof_id = ast_add_profile("ext_match", 0);
01967    ast_mark(prof_id, 1);
01968    i = _extension_match_core(pattern, data, mode);
01969    ast_mark(prof_id, 0);
01970    return i;
01971 }

static struct ast_context* find_context_locked ( const char *  context  )  [static]

lookup for a context with a given name,

Return values:
with conlock held if found.
NULL if not found.

Definition at line 4055 of file pbx.c.

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

Referenced by ast_add_extension(), ast_context_add_ignorepat(), ast_context_add_include(), ast_context_add_switch(), ast_context_remove_extension_callerid(), ast_context_remove_ignorepat(), ast_context_remove_include(), and ast_context_remove_switch().

04056 {
04057    struct ast_context *c = NULL;
04058    struct fake_context item;
04059 
04060    ast_copy_string(item.name, context, sizeof(item.name));
04061 
04062    ast_rdlock_contexts();
04063    c = ast_hashtab_lookup(contexts_table,&item);
04064 
04065 #ifdef NOTNOW
04066 
04067    while ( (c = ast_walk_contexts(c)) ) {
04068       if (!strcmp(ast_get_context_name(c), context))
04069          return c;
04070    }
04071 #endif
04072    if (!c)
04073       ast_unlock_contexts();
04074 
04075    return c;
04076 }

static char* func_args ( char *  function  )  [static]

return a pointer to the arguments of the function, and terminates the function name with '\0'

Definition at line 2755 of file pbx.c.

References ast_log(), and LOG_WARNING.

Referenced by ast_func_read(), and ast_func_write().

02756 {
02757    char *args = strchr(function, '(');
02758 
02759    if (!args)
02760       ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
02761    else {
02762       char *p;
02763       *args++ = '\0';
02764       if ((p = strrchr(args, ')')) )
02765          *p = '\0';
02766       else
02767          ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
02768    }
02769    return args;
02770 }

static struct ast_exten * get_canmatch_exten ( struct match_char node  )  [static]

Definition at line 1155 of file pbx.c.

References ast_log(), ast_exten::exten, match_char::exten, LOG_NOTICE, and match_char::next_char.

01156 {
01157    /* find the exten at the end of the rope */
01158    struct match_char *node2 = node;
01159 
01160    for (node2 = node; node2; node2 = node2->next_char) {
01161       if (node2->exten) {
01162 #ifdef NEED_DEBUG_HERE
01163          ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
01164 #endif
01165          return node2->exten;
01166       }
01167    }
01168 #ifdef NEED_DEBUG_HERE
01169    ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
01170 #endif
01171    return 0;
01172 }

static unsigned get_range ( char *  src,
int  max,
char *const   names[],
const char *  msg 
) [static]

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.

Definition at line 5950 of file pbx.c.

References ast_log(), ast_strlen_zero(), LOG_WARNING, lookup_name(), and s.

Referenced by ast_build_timing().

05951 {
05952    int s, e; /* start and ending position */
05953    unsigned int mask = 0;
05954 
05955    /* Check for whole range */
05956    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
05957       s = 0;
05958       e = max - 1;
05959    } else {
05960       /* Get start and ending position */
05961       char *c = strchr(src, '-');
05962       if (c)
05963          *c++ = '\0';
05964       /* Find the start */
05965       s = lookup_name(src, names, max);
05966       if (!s) {
05967          ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
05968          return 0;
05969       }
05970       s--;
05971       if (c) { /* find end of range */
05972          e = lookup_name(c, names, max);
05973          if (!e) {
05974             ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
05975             return 0;
05976          }
05977          e--;
05978       } else
05979          e = s;
05980    }
05981    /* Fill the mask. Remember that ranges are cyclic */
05982    mask = 1 << e; /* initialize with last element */
05983    while (s != e) {
05984       if (s >= max) {
05985          s = 0;
05986          mask |= (1 << s);
05987       } else {
05988          mask |= (1 << s);
05989          s++;
05990       }
05991    }
05992    return mask;
05993 }

static void get_timerange ( struct ast_timing i,
char *  times 
) [static]

store a bitmask of valid times, one bit each 2 minute

Definition at line 5996 of file pbx.c.

References ast_log(), ast_strlen_zero(), LOG_WARNING, and ast_timing::minmask.

Referenced by ast_build_timing().

05997 {
05998    char *e;
05999    int x;
06000    int s1, s2;
06001    int e1, e2;
06002    /* int cth, ctm; */
06003 
06004    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
06005    memset(i->minmask, 0, sizeof(i->minmask));
06006 
06007    /* 2-minutes per bit, since the mask has only 32 bits :( */
06008    /* Star is all times */
06009    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
06010       for (x = 0; x < 24; x++)
06011          i->minmask[x] = 0x3fffffff; /* 30 bits */
06012       return;
06013    }
06014    /* Otherwise expect a range */
06015    e = strchr(times, '-');
06016    if (!e) {
06017       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
06018       return;
06019    }
06020    *e++ = '\0';
06021    /* XXX why skip non digits ? */
06022    while (*e && !isdigit(*e))
06023       e++;
06024    if (!*e) {
06025       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
06026       return;
06027    }
06028    if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
06029       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
06030       return;
06031    }
06032    if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
06033       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
06034       return;
06035    }
06036    /* XXX this needs to be optimized */
06037 #if 1
06038    s1 = s1 * 30 + s2/2;
06039    if ((s1 < 0) || (s1 >= 24*30)) {
06040       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
06041       return;
06042    }
06043    e1 = e1 * 30 + e2/2;
06044    if ((e1 < 0) || (e1 >= 24*30)) {
06045       ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
06046       return;
06047    }
06048    /* Go through the time and enable each appropriate bit */
06049    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
06050       i->minmask[x/30] |= (1 << (x % 30));
06051    }
06052    /* Do the last one */
06053    i->minmask[x/30] |= (1 << (x % 30));
06054 #else
06055    for (cth = 0; cth < 24; cth++) {
06056       /* Initialize masks to blank */
06057       i->minmask[cth] = 0;
06058       for (ctm = 0; ctm < 30; ctm++) {
06059          if (
06060          /* First hour with more than one hour */
06061                (((cth == s1) && (ctm >= s2)) &&
06062                 ((cth < e1)))
06063          /* Only one hour */
06064          ||    (((cth == s1) && (ctm >= s2)) &&
06065                 ((cth == e1) && (ctm <= e2)))
06066          /* In between first and last hours (more than 2 hours) */
06067          ||    ((cth > s1) &&
06068                 (cth < e1))
06069          /* Last hour with more than one hour */
06070          ||    ((cth > s1) &&
06071                 ((cth == e1) && (ctm <= e2)))
06072          )
06073             i->minmask[cth] |= (1 << (ctm / 2));
06074       }
06075    }
06076 #endif
06077    /* All done */
06078    return;
06079 }

static char* handle_set_chanvar ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 5423 of file pbx.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_channel_unlock, ast_cli(), ast_complete_channels(), ast_get_channel_by_name_locked(), chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, pbx_builtin_setvar_helper(), ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

05424 {
05425    struct ast_channel *chan;
05426    const char *chan_name, *var_name, *var_value;
05427 
05428    switch (cmd) {
05429    case CLI_INIT:
05430       e->command = "core set chanvar";
05431       e->usage = 
05432          "Usage: core set chanvar <channel> <varname> <value>\n"
05433          "       Set channel variable <varname> to <value>\n";
05434       return NULL;
05435    case CLI_GENERATE:
05436       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05437    }
05438 
05439    if (a->argc != e->args + 3)
05440       return CLI_SHOWUSAGE;
05441 
05442    chan_name = a->argv[e->args];
05443    var_name = a->argv[e->args + 1];
05444    var_value = a->argv[e->args + 2];
05445 
05446    if (!(chan = ast_get_channel_by_name_locked(chan_name))) {
05447       ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
05448       return CLI_FAILURE;
05449    }
05450 
05451    pbx_builtin_setvar_helper(chan, var_name, var_value);
05452 
05453    ast_channel_unlock(chan);
05454 
05455    ast_cli(a->fd, "\n    -- Channel variable '%s' set to '%s' for '%s'\n", 
05456       var_name, var_value, chan_name);
05457 
05458    return CLI_SUCCESS;
05459 }

static char* handle_set_extenpatternmatchnew ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 5461 of file pbx.c.

References ast_cli_args::argc, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, pbx_set_extenpatternmatchnew(), and ast_cli_entry::usage.

05462 {
05463    int oldval = 0;
05464    
05465    switch (cmd) {
05466    case CLI_INIT:
05467       e->command = "dialplan set extenpatternmatchnew true";
05468       e->usage = 
05469          "Usage: dialplan set extenpatternmatchnew true|false\n"
05470          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05471       return NULL;
05472    case CLI_GENERATE:
05473       return NULL;   
05474    }
05475 
05476    if (a->argc != 4)
05477       return CLI_SHOWUSAGE;
05478 
05479    oldval =  pbx_set_extenpatternmatchnew(1);
05480    
05481    if (oldval)
05482       ast_cli(a->fd, "\n    -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
05483    else
05484       ast_cli(a->fd, "\n    -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
05485 
05486    return CLI_SUCCESS;
05487 }

static char* handle_set_global ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 5401 of file pbx.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, pbx_builtin_setvar_helper(), and ast_cli_entry::usage.

05402 {
05403    switch (cmd) {
05404    case CLI_INIT:
05405       e->command = "core set global";
05406       e->usage = 
05407          "Usage: core set global <name> <value>\n"
05408          "       Set global dialplan variable <name> to <value>\n";
05409       return NULL;
05410    case CLI_GENERATE:
05411       return NULL;   
05412    }
05413 
05414    if (a->argc != e->args + 2)
05415       return CLI_SHOWUSAGE;
05416 
05417    pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
05418    ast_cli(a->fd, "\n    -- Global variable %s set to %s\n", a->argv[3], a->argv[4]);
05419 
05420    return CLI_SUCCESS;
05421 }

static char* handle_show_application ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4538 of file pbx.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_MAX_APP, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, COLOR_CYAN, COLOR_MAGENTA, ast_cli_entry::command, ast_app::description, ast_cli_args::fd, ast_app::list, ast_cli_args::n, ast_app::name, ast_app::synopsis, term_color(), ast_cli_entry::usage, and ast_cli_args::word.

04539 {
04540    struct ast_app *aa;
04541    int app, no_registered_app = 1;
04542    char *ret = NULL;
04543    int which = 0;
04544    int wordlen;
04545 
04546    switch (cmd) {
04547    case CLI_INIT: 
04548       e->command = "core show application";
04549       e->usage = 
04550          "Usage: core show application <application> [<application> [<application> [...]]]\n"
04551          "       Describes a particular application.\n";
04552       return NULL;
04553    case CLI_GENERATE:
04554       /*
04555        * There is a possibility to show informations about more than one
04556        * application at one time. You can type 'show application Dial Echo' and
04557        * you will see informations about these two applications ...
04558        */
04559       wordlen = strlen(a->word);
04560       /* return the n-th [partial] matching entry */
04561       AST_RWLIST_RDLOCK(&apps);
04562       AST_RWLIST_TRAVERSE(&apps, aa, list) {
04563          if (!strncasecmp(a->word, aa->name, wordlen) && ++which > a->n) {
04564             ret = ast_strdup(aa->name);
04565             break;
04566          }
04567       }
04568       AST_RWLIST_UNLOCK(&apps);
04569 
04570       return ret;
04571    }
04572 
04573    if (a->argc < 4)
04574       return CLI_SHOWUSAGE;
04575 
04576    /* ... go through all applications ... */
04577    AST_RWLIST_RDLOCK(&apps);
04578    AST_RWLIST_TRAVERSE(&apps, aa, list) {
04579       /* ... compare this application name with all arguments given
04580        * to 'show application' command ... */
04581       for (app = 3; app < a->argc; app++) {
04582          if (!strcasecmp(aa->name, a->argv[app])) {
04583             /* Maximum number of characters added by terminal coloring is 22 */
04584             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
04585             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
04586             int synopsis_size, description_size;
04587 
04588             no_registered_app = 0;
04589 
04590             if (aa->synopsis)
04591                synopsis_size = strlen(aa->synopsis) + 23;
04592             else
04593                synopsis_size = strlen("Not available") + 23;
04594             synopsis = alloca(synopsis_size);
04595 
04596             if (aa->description)
04597                description_size = strlen(aa->description) + 23;
04598             else
04599                description_size = strlen("Not available") + 23;
04600             description = alloca(description_size);
04601 
04602             if (synopsis && description) {
04603                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", aa->name);
04604                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
04605                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
04606                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
04607                term_color(synopsis,
04608                            aa->synopsis ? aa->synopsis : "Not available",
04609                            COLOR_CYAN, 0, synopsis_size);
04610                term_color(description,
04611                            aa->description ? aa->description : "Not available",
04612                            COLOR_CYAN, 0, description_size);
04613 
04614                ast_cli(a->fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
04615             } else {
04616                /* ... one of our applications, show info ...*/
04617                ast_cli(a->fd,"\n  -= Info about application '%s' =- \n\n"
04618                   "[Synopsis]\n  %s\n\n"
04619                   "[Description]\n%s\n",
04620                   aa->name,
04621                   aa->synopsis ? aa->synopsis : "Not available",
04622                   aa->description ? aa->description : "Not available");
04623             }
04624          }
04625       }
04626    }
04627    AST_RWLIST_UNLOCK(&apps);
04628 
04629    /* we found at least one app? no? */
04630    if (no_registered_app) {
04631       ast_cli(a->fd, "Your application(s) is (are) not registered\n");
04632       return CLI_FAILURE;
04633    }
04634 
04635    return CLI_SUCCESS;
04636 }

static char* handle_show_applications ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4792 of file pbx.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_cli_complete(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_app::description, ast_cli_args::fd, ast_app::list, ast_cli_args::n, ast_app::name, ast_cli_args::pos, strcasestr(), ast_app::synopsis, ast_cli_entry::usage, and ast_cli_args::word.

04793 {
04794    struct ast_app *aa;
04795    int like = 0, describing = 0;
04796    int total_match = 0;    /* Number of matches in like clause */
04797    int total_apps = 0;  /* Number of apps registered */
04798    static char* choices[] = { "like", "describing", NULL };
04799 
04800    switch (cmd) {
04801    case CLI_INIT:
04802       e->command = "core show applications [like|describing]";
04803       e->usage = 
04804          "Usage: core show applications [{like|describing} <text>]\n"
04805          "       List applications which are currently available.\n"
04806          "       If 'like', <text> will be a substring of the app name\n"
04807          "       If 'describing', <text> will be a substring of the description\n";
04808       return NULL;
04809    case CLI_GENERATE:
04810       return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n);
04811    }
04812 
04813    AST_RWLIST_RDLOCK(&apps);
04814 
04815    if (AST_RWLIST_EMPTY(&apps)) {
04816       ast_cli(a->fd, "There are no registered applications\n");
04817       AST_RWLIST_UNLOCK(&apps);
04818       return CLI_SUCCESS;
04819    }
04820 
04821    /* core list applications like <keyword> */
04822    if ((a->argc == 5) && (!strcmp(a->argv[3], "like"))) {
04823       like = 1;
04824    } else if ((a->argc > 4) && (!strcmp(a->argv[3], "describing"))) {
04825       describing = 1;
04826    }
04827 
04828    /* core list applications describing <keyword1> [<keyword2>] [...] */
04829    if ((!like) && (!describing)) {
04830       ast_cli(a->fd, "    -= Registered Asterisk Applications =-\n");
04831    } else {
04832       ast_cli(a->fd, "    -= Matching Asterisk Applications =-\n");
04833    }
04834 
04835    AST_RWLIST_TRAVERSE(&apps, aa, list) {
04836       int printapp = 0;
04837       total_apps++;
04838       if (like) {
04839          if (strcasestr(aa->name, a->argv[4])) {
04840             printapp = 1;
04841             total_match++;
04842          }
04843       } else if (describing) {
04844          if (aa->description) {
04845             /* Match all words on command line */
04846             int i;
04847             printapp = 1;
04848             for (i = 4; i < a->argc; i++) {
04849                if (!strcasestr(aa->description, a->argv[i])) {
04850                   printapp = 0;
04851                } else {
04852                   total_match++;
04853                }
04854             }
04855          }
04856       } else {
04857          printapp = 1;
04858       }
04859 
04860       if (printapp) {
04861          ast_cli(a->fd,"  %20s: %s\n", aa->name, aa->synopsis ? aa->synopsis : "<Synopsis not available>");
04862       }
04863    }
04864    if ((!like) && (!describing)) {
04865       ast_cli(a->fd, "    -= %d Applications Registered =-\n",total_apps);
04866    } else {
04867       ast_cli(a->fd, "    -= %d Applications Matching =-\n",total_match);
04868    }
04869 
04870    AST_RWLIST_UNLOCK(&apps);
04871 
04872    return CLI_SUCCESS;
04873 }

static char* handle_show_dialplan ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 5097 of file pbx.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_PBX_MAX_STACK, ast_strdupa, ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_show_dialplan_context(), context, exten, ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, show_dialplan_helper(), strsep(), ast_cli_entry::usage, and ast_cli_args::word.

05098 {
05099    char *exten = NULL, *context = NULL;
05100    /* Variables used for different counters */
05101    struct dialplan_counters counters;
05102    const char *incstack[AST_PBX_MAX_STACK];
05103 
05104    switch (cmd) {
05105    case CLI_INIT:
05106       e->command = "dialplan show";
05107       e->usage = 
05108          "Usage: dialplan show [[exten@]context]\n"
05109          "       Show dialplan\n";
05110       return NULL;
05111    case CLI_GENERATE:   
05112       return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05113    }
05114 
05115    memset(&counters, 0, sizeof(counters));
05116 
05117    if (a->argc != 2 && a->argc != 3)
05118       return CLI_SHOWUSAGE;
05119 
05120    /* we obtain [exten@]context? if yes, split them ... */
05121    if (a->argc == 3) {
05122       if (strchr(a->argv[2], '@')) {   /* split into exten & context */
05123          context = ast_strdupa(a->argv[2]);
05124          exten = strsep(&context, "@");
05125          /* change empty strings to NULL */
05126          if (ast_strlen_zero(exten))
05127             exten = NULL;
05128       } else { /* no '@' char, only context given */
05129          context = a->argv[2];
05130       }
05131       if (ast_strlen_zero(context))
05132          context = NULL;
05133    }
05134    /* else Show complete dial plan, context and exten are NULL */
05135    show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05136 
05137    /* check for input failure and throw some error messages */
05138    if (context && !counters.context_existence) {
05139       ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05140       return CLI_FAILURE;
05141    }
05142 
05143    if (exten && !counters.extension_existence) {
05144       if (context)
05145          ast_cli(a->fd, "There is no existence of %s@%s extension\n",
05146             exten, context);
05147       else
05148          ast_cli(a->fd,
05149             "There is no existence of '%s' extension in all contexts\n",
05150             exten);
05151       return CLI_FAILURE;
05152    }
05153 
05154    ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
05155             counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
05156             counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
05157             counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05158 
05159    /* everything ok */
05160    return CLI_SUCCESS;
05161 }

static char* handle_show_function ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2604 of file pbx.c.

References ast_custom_function::acflist, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_custom_function_find(), AST_MAX_APP, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, COLOR_CYAN, COLOR_MAGENTA, ast_cli_entry::command, ast_custom_function::desc, ast_cli_args::fd, ast_cli_args::n, ast_custom_function::name, ast_custom_function::synopsis, ast_custom_function::syntax, term_color(), ast_cli_entry::usage, and ast_cli_args::word.

02605 {
02606    struct ast_custom_function *acf;
02607    /* Maximum number of characters added by terminal coloring is 22 */
02608    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
02609    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
02610    char stxtitle[40], *syntax = NULL;
02611    int synopsis_size, description_size, syntax_size;
02612    char *ret = NULL;
02613    int which = 0;
02614    int wordlen;
02615 
02616    switch (cmd) {
02617    case CLI_INIT:
02618       e->command = "core show function";
02619       e->usage = 
02620          "Usage: core show function <function>\n"
02621          "       Describe a particular dialplan function.\n";
02622       return NULL;
02623    case CLI_GENERATE:   
02624       wordlen = strlen(a->word);
02625       /* case-insensitive for convenience in this 'complete' function */
02626       AST_RWLIST_RDLOCK(&acf_root);
02627       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02628          if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
02629             ret = ast_strdup(acf->name);
02630             break;
02631          }
02632       }
02633       AST_RWLIST_UNLOCK(&acf_root);
02634 
02635       return ret;
02636    }
02637 
02638    if (a->argc < 4)
02639       return CLI_SHOWUSAGE;
02640 
02641    if (!(acf = ast_custom_function_find(a->argv[3]))) {
02642       ast_cli(a->fd, "No function by that name registered.\n");
02643       return CLI_FAILURE;
02644 
02645    }
02646 
02647    if (acf->synopsis)
02648       synopsis_size = strlen(acf->synopsis) + 23;
02649    else
02650       synopsis_size = strlen("Not available") + 23;
02651    synopsis = alloca(synopsis_size);
02652 
02653    if (acf->desc)
02654       description_size = strlen(acf->desc) + 23;
02655    else
02656       description_size = strlen("Not available") + 23;
02657    description = alloca(description_size);
02658 
02659    if (acf->syntax)
02660       syntax_size = strlen(acf->syntax) + 23;
02661    else
02662       syntax_size = strlen("Not available") + 23;
02663    syntax = alloca(syntax_size);
02664 
02665    snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
02666    term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
02667    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
02668    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
02669    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
02670    term_color(syntax,
02671          acf->syntax ? acf->syntax : "Not available",
02672          COLOR_CYAN, 0, syntax_size);
02673    term_color(synopsis,
02674          acf->synopsis ? acf->synopsis : "Not available",
02675          COLOR_CYAN, 0, synopsis_size);
02676    term_color(description,
02677          acf->desc ? acf->desc : "Not available",
02678          COLOR_CYAN, 0, description_size);
02679 
02680    ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
02681 
02682    return CLI_SUCCESS;
02683 }

static char* handle_show_functions ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2565 of file pbx.c.

References ast_custom_function::acflist, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_custom_function::name, ast_custom_function::synopsis, ast_custom_function::syntax, and ast_cli_entry::usage.

02566 {
02567    struct ast_custom_function *acf;
02568    int count_acf = 0;
02569    int like = 0;
02570 
02571    switch (cmd) {
02572    case CLI_INIT:
02573       e->command = "core show functions [like]";
02574       e->usage = 
02575          "Usage: core show functions [like <text>]\n"
02576          "       List builtin functions, optionally only those matching a given string\n";
02577       return NULL;
02578    case CLI_GENERATE:
02579       return NULL;
02580    }
02581 
02582    if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
02583       like = 1;
02584    } else if (a->argc != 3) {
02585       return CLI_SHOWUSAGE;
02586    }
02587 
02588    ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
02589 
02590    AST_RWLIST_RDLOCK(&acf_root);
02591    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02592       if (!like || strstr(acf->name, a->argv[4])) {
02593          count_acf++;
02594          ast_cli(a->fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
02595       }
02596    }
02597    AST_RWLIST_UNLOCK(&acf_root);
02598 
02599    ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
02600 
02601    return CLI_SUCCESS;
02602 }

static char* handle_show_globals ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI support for listing global variables in a parseable way.

Definition at line 5374 of file pbx.c.

References ast_cli(), AST_LIST_TRAVERSE, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_var_name(), ast_var_value(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_var_t::entries, ast_cli_args::fd, globals, globalslock, and ast_cli_entry::usage.

05375 {
05376    int i = 0;
05377    struct ast_var_t *newvariable;
05378 
05379    switch (cmd) {
05380    case CLI_INIT:
05381       e->command = "core show globals";
05382       e->usage = 
05383          "Usage: core show globals\n"
05384          "       List current global dialplan variables and their values\n";
05385       return NULL;
05386    case CLI_GENERATE:
05387       return NULL;
05388    }
05389 
05390    ast_rwlock_rdlock(&globalslock);
05391    AST_LIST_TRAVERSE (&globals, newvariable, entries) {
05392       i++;
05393       ast_cli(a->fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
05394    }
05395    ast_rwlock_unlock(&globalslock);
05396    ast_cli(a->fd, "\n    -- %d variables\n", i);
05397 
05398    return CLI_SUCCESS;
05399 }

static char* handle_show_hint ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

handle_show_hint: CLI support for listing registered dial plan hint

Definition at line 4709 of file pbx.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_extension_state2str(), ast_get_context_name(), ast_get_extension_app(), ast_get_extension_context(), ast_get_extension_name(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_hint::callbacks, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_core_show_hint(), ast_hint::exten, ast_cli_args::fd, ast_hint::laststate, ast_cli_args::line, ast_cli_args::n, ast_state_cb::next, num, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

04710 {
04711    struct ast_hint *hint;
04712    int watchers;
04713    int num = 0, extenlen;
04714    struct ast_state_cb *watcher;
04715 
04716    switch (cmd) {
04717    case CLI_INIT:
04718       e->command = "core show hint";
04719       e->usage =
04720          "Usage: core show hint <exten>\n"
04721          "       List registered hint\n";
04722       return NULL;
04723    case CLI_GENERATE:
04724       return complete_core_show_hint(a->line, a->word, a->pos, a->n);
04725    }
04726 
04727    if (a->argc < 4)
04728       return CLI_SHOWUSAGE;
04729 
04730    AST_RWLIST_RDLOCK(&hints);
04731    if (AST_RWLIST_EMPTY(&hints)) {
04732       ast_cli(a->fd, "There are no registered dialplan hints\n");
04733       AST_RWLIST_UNLOCK(&hints);
04734       return CLI_SUCCESS;
04735    }
04736    extenlen = strlen(a->argv[3]);
04737    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04738       if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
04739          watchers = 0;
04740          for (watcher = hint->callbacks; watcher; watcher = watcher->next)
04741             watchers++;
04742          ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04743             ast_get_extension_name(hint->exten),
04744             ast_get_context_name(ast_get_extension_context(hint->exten)),
04745             ast_get_extension_app(hint->exten),
04746             ast_extension_state2str(hint->laststate), watchers);
04747          num++;
04748       }
04749    }
04750    AST_RWLIST_UNLOCK(&hints);
04751    if (!num)
04752       ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
04753    else
04754       ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
04755    return CLI_SUCCESS;
04756 }

static char* handle_show_hints ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

handle_show_hints: CLI support for listing registered dial plan hints

Definition at line 4639 of file pbx.c.

References ast_cli(), ast_extension_state2str(), ast_get_context_name(), ast_get_extension_app(), ast_get_extension_context(), ast_get_extension_name(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_hint::callbacks, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_hint::exten, ast_cli_args::fd, ast_hint::laststate, ast_state_cb::next, num, and ast_cli_entry::usage.

04640 {
04641    struct ast_hint *hint;
04642    int num = 0;
04643    int watchers;
04644    struct ast_state_cb *watcher;
04645 
04646    switch (cmd) {
04647    case CLI_INIT:
04648       e->command = "core show hints";
04649       e->usage = 
04650          "Usage: core show hints\n"
04651          "       List registered hints\n";
04652       return NULL;
04653    case CLI_GENERATE:
04654       return NULL;   
04655    }
04656 
04657    AST_RWLIST_RDLOCK(&hints);
04658    if (AST_RWLIST_EMPTY(&hints)) {
04659       ast_cli(a->fd, "There are no registered dialplan hints\n");
04660       AST_RWLIST_UNLOCK(&hints);
04661       return CLI_SUCCESS;
04662    }
04663    /* ... we have hints ... */
04664    ast_cli(a->fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
04665    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04666       watchers = 0;
04667       for (watcher = hint->callbacks; watcher; watcher = watcher->next)
04668          watchers++;
04669       ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04670          ast_get_extension_name(hint->exten),
04671          ast_get_context_name(ast_get_extension_context(hint->exten)),
04672          ast_get_extension_app(hint->exten),
04673          ast_extension_state2str(hint->laststate), watchers);
04674       num++;
04675    }
04676    ast_cli(a->fd, "----------------\n");
04677    ast_cli(a->fd, "- %d hints registered\n", num);
04678    AST_RWLIST_UNLOCK(&hints);
04679    return CLI_SUCCESS;
04680 }

static char* handle_show_switches ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

handle_show_switches: CLI support for listing registered dial plan switches

Definition at line 4760 of file pbx.c.

References ast_cli(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_switch::description, ast_cli_args::fd, ast_switch::list, ast_switch::name, and ast_cli_entry::usage.

04761 {
04762    struct ast_switch *sw;
04763 
04764    switch (cmd) {
04765    case CLI_INIT:
04766       e->command = "core show switches";
04767       e->usage = 
04768          "Usage: core show switches\n"
04769          "       List registered switches\n";
04770       return NULL;
04771    case CLI_GENERATE:
04772       return NULL;   
04773    }
04774 
04775    AST_RWLIST_RDLOCK(&switches);
04776 
04777    if (AST_RWLIST_EMPTY(&switches)) {
04778       AST_RWLIST_UNLOCK(&switches);
04779       ast_cli(a->fd, "There are no registered alternative switches\n");
04780       return CLI_SUCCESS;
04781    }
04782 
04783    ast_cli(a->fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
04784    AST_RWLIST_TRAVERSE(&switches, sw, list)
04785       ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
04786 
04787    AST_RWLIST_UNLOCK(&switches);
04788 
04789    return CLI_SUCCESS;
04790 }

static void handle_statechange ( const char *  device  )  [static]

Definition at line 3277 of file pbx.c.

References ast_copy_string(), ast_extension_state2(), ast_get_extension_app(), AST_MAX_EXTENSION, ast_rdlock_contexts(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_unlock_contexts(), buf, ast_state_cb::callback, ast_hint::callbacks, ast_state_cb::data, ast_exten::exten, ast_hint::exten, ast_hint::laststate, ast_hint::list, ast_context::name, ast_state_cb::next, ast_exten::parent, parse(), statecbs, and strsep().

Referenced by device_state_thread().

03278 {
03279    struct ast_hint *hint;
03280 
03281    ast_rdlock_contexts();
03282    AST_RWLIST_RDLOCK(&hints);
03283 
03284    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03285       struct ast_state_cb *cblist;
03286       char buf[AST_MAX_EXTENSION];
03287       char *parse = buf;
03288       char *cur;
03289       int state;
03290 
03291       ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
03292       while ( (cur = strsep(&parse, "&")) ) {
03293          if (!strcasecmp(cur, device))
03294             break;
03295       }
03296       if (!cur)
03297          continue;
03298 
03299       /* Get device state for this hint */
03300       state = ast_extension_state2(hint->exten);
03301 
03302       if ((state == -1) || (state == hint->laststate))
03303          continue;
03304 
03305       /* Device state changed since last check - notify the watchers */
03306 
03307       /* For general callbacks */
03308       for (cblist = statecbs; cblist; cblist = cblist->next)
03309          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03310 
03311       /* For extension callbacks */
03312       for (cblist = hint->callbacks; cblist; cblist = cblist->next)
03313          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03314 
03315       hint->laststate = state;   /* record we saw the change */
03316    }
03317 
03318    AST_RWLIST_UNLOCK(&hints);
03319    ast_unlock_contexts();
03320 }

static char* handle_unset_extenpatternmatchnew ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 5489 of file pbx.c.

References ast_cli_args::argc, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, pbx_set_extenpatternmatchnew(), and ast_cli_entry::usage.

05490 {
05491    int oldval = 0;
05492    
05493    switch (cmd) {
05494    case CLI_INIT:
05495       e->command = "dialplan set extenpatternmatchnew false";
05496       e->usage = 
05497          "Usage: dialplan set extenpatternmatchnew true|false\n"
05498          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05499       return NULL;
05500    case CLI_GENERATE:
05501       return NULL;   
05502    }
05503 
05504    if (a->argc != 4)
05505       return CLI_SHOWUSAGE;
05506 
05507    oldval =  pbx_set_extenpatternmatchnew(0);
05508    
05509    if (!oldval)
05510       ast_cli(a->fd, "\n    -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
05511    else
05512       ast_cli(a->fd, "\n    -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
05513 
05514    return CLI_SUCCESS;
05515 }

static int hashtab_compare_exten_labels ( const void *  ah_a,
const void *  ah_b 
) [static]

Definition at line 399 of file pbx.c.

References ast_exten::label, and S_OR.

Referenced by ast_add_extension2_lockopt().

00400 {
00401    const struct ast_exten *ac = ah_a;
00402    const struct ast_exten *bc = ah_b;
00403    return strcmp(S_OR(ac->label, ""), S_OR(bc->label, ""));
00404 }

static int hashtab_compare_exten_numbers ( const void *  ah_a,
const void *  ah_b 
) [static]

Definition at line 392 of file pbx.c.

References ast_exten::priority.

Referenced by ast_add_extension2_lockopt().

00393 {
00394    const struct ast_exten *ac = ah_a;
00395    const struct ast_exten *bc = ah_b;
00396    return ac->priority != bc->priority;
00397 }

static int hashtab_compare_extens ( const void *  ha_a,
const void *  ah_b 
) [static]

Definition at line 373 of file pbx.c.

References ast_exten::cidmatch, ast_exten::exten, and ast_exten::matchcid.

Referenced by ast_add_extension2_lockopt().

00374 {
00375    const struct ast_exten *ac = ah_a;
00376    const struct ast_exten *bc = ah_b;
00377    int x = strcmp(ac->exten, bc->exten);
00378    if (x) { /* if exten names are diff, then return */
00379       return x;
00380    }
00381    
00382    /* but if they are the same, do the cidmatch values match? */
00383    if (ac->matchcid && bc->matchcid) {
00384       return strcmp(ac->cidmatch,bc->cidmatch);
00385    } else if (!ac->matchcid && !bc->matchcid) {
00386       return 0; /* if there's no matchcid on either side, then this is a match */
00387    } else {
00388       return 1; /* if there's matchcid on one but not the other, they are different */
00389    }
00390 }

static unsigned int hashtab_hash_extens ( const void *  obj  )  [static]

Definition at line 412 of file pbx.c.

References ast_hashtab_hash_string(), ast_exten::cidmatch, ast_exten::exten, and ast_exten::matchcid.

Referenced by ast_add_extension2_lockopt().

00413 {
00414    const struct ast_exten *ac = obj;
00415    unsigned int x = ast_hashtab_hash_string(ac->exten);
00416    unsigned int y = 0;
00417    if (ac->matchcid)
00418       y = ast_hashtab_hash_string(ac->cidmatch);
00419    return x+y;
00420 }

static unsigned int hashtab_hash_labels ( const void *  obj  )  [static]

Definition at line 428 of file pbx.c.

References ast_hashtab_hash_string(), ast_exten::label, and S_OR.

Referenced by ast_add_extension2_lockopt().

00429 {
00430    const struct ast_exten *ac = obj;
00431    return ast_hashtab_hash_string(S_OR(ac->label, ""));
00432 }

static unsigned int hashtab_hash_priority ( const void *  obj  )  [static]

Definition at line 422 of file pbx.c.

References ast_hashtab_hash_int(), and ast_exten::priority.

Referenced by ast_add_extension2_lockopt().

00423 {
00424    const struct ast_exten *ac = obj;
00425    return ast_hashtab_hash_int(ac->priority);
00426 }

static int include_valid ( struct ast_include i  )  [inline, static]

Definition at line 994 of file pbx.c.

References ast_check_timing(), ast_include::hastime, and ast_include::timing.

Referenced by pbx_find_extension().

00995 {
00996    if (!i->hastime)
00997       return 1;
00998 
00999    return ast_check_timing(&(i->timing));
01000 }

static int increase_call_count ( const struct ast_channel c  )  [static]

Increase call count for channel.

Return values:
0 on success
non-zero if a configured limit (maxcalls, maxload, minmemfree) was reached

Definition at line 3895 of file pbx.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), getloadavg(), LOG_WARNING, maxcalllock, ast_channel::name, option_maxcalls, option_maxload, and option_minmemfree.

Referenced by ast_pbx_run_args(), and ast_pbx_start().

03896 {
03897    int failed = 0;
03898    double curloadavg;
03899 #if defined(HAVE_SYSINFO)
03900    long curfreemem;
03901    struct sysinfo sys_info;
03902 #endif
03903 
03904    ast_mutex_lock(&maxcalllock);
03905    if (option_maxcalls) {
03906       if (countcalls >= option_maxcalls) {
03907          ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
03908          failed = -1;
03909       }
03910    }
03911    if (option_maxload) {
03912       getloadavg(&curloadavg, 1);
03913       if (curloadavg >= option_maxload) {
03914          ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
03915          failed = -1;
03916       }
03917    }
03918 #if defined(HAVE_SYSINFO)
03919    if (option_minmemfree) {
03920       if (!sysinfo(&sys_info)) {
03921          /* make sure that the free system memory is above the configured low watermark
03922           * convert the amount of freeram from mem_units to MB */
03923          curfreemem = sys_info.freeram / sys_info.mem_unit; 
03924          curfreemem /= 1024*1024; 
03925          if (curfreemem < option_minmemfree) {
03926             ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
03927             failed = -1;
03928          }
03929       }
03930    }
03931 #endif
03932       
03933    if (!failed) {
03934       countcalls++;
03935       totalcalls++;
03936    }
03937    ast_mutex_unlock(&maxcalllock);
03938 
03939    return failed;
03940 }

static void insert_in_next_chars_alt_char_list ( struct match_char **  parent_ptr,
struct match_char node 
) [static]

Definition at line 1392 of file pbx.c.

References match_char::alt_char, and match_char::specificity.

Referenced by add_pattern_node().

01393 {
01394    struct match_char *curr, *lcurr;
01395    
01396    /* insert node into the tree at "current", so the alt_char list from current is
01397       sorted in increasing value as you go to the leaves */
01398    if (!(*parent_ptr)) {
01399       *parent_ptr = node;
01400    } else {
01401       if ((*parent_ptr)->specificity > node->specificity){
01402          /* insert at head */
01403          node->alt_char = (*parent_ptr);
01404          *parent_ptr = node;
01405       } else {
01406          lcurr = *parent_ptr;
01407          for (curr=(*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
01408             if (curr->specificity > node->specificity) {
01409                node->alt_char = curr;
01410                lcurr->alt_char = node;
01411                break;
01412             }
01413             lcurr = curr;
01414          }
01415          if (!curr)
01416          {
01417             lcurr->alt_char = node;
01418          }
01419       }
01420    }
01421 }

int load_pbx ( void   ) 

Provided by pbx.c

Definition at line 8356 of file pbx.c.

References __ast_custom_function_register(), ast_cli_register_multiple(), ast_cond_init(), AST_EVENT_DEVICE_STATE, AST_EVENT_IE_END, ast_event_subscribe(), ast_log(), ast_manager_register2(), ast_mutex_init(), ast_pthread_create, ast_register_application2(), ast_verb, builtins, device_state, device_state_cb(), device_state_sub, device_state_thread(), EVENT_FLAG_CONFIG, EVENT_FLAG_REPORTING, exception_function, LOG_ERROR, manager_show_dialplan(), and pbx_cli.

Referenced by main().

08357 {
08358    int x;
08359 
08360    /* Initialize the PBX */
08361    ast_verb(1, "Asterisk PBX Core Initializing\n");
08362    ast_verb(1, "Registering builtin applications:\n");
08363    
08364    ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
08365    __ast_custom_function_register(&exception_function, NULL);
08366 
08367    /* Register builtin applications */
08368    for (x = 0; x < sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
08369       ast_verb(1, "[%s]\n", builtins[x].name);
08370       if (ast_register_application2(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description, NULL)) {
08371          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
08372          return -1;
08373       }
08374    }
08375    
08376    /* Register manager application */
08377    ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
08378 
08379    ast_mutex_init(&device_state.lock);
08380    ast_cond_init(&device_state.cond, NULL);
08381    ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
08382 
08383    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL,
08384          AST_EVENT_IE_END))) {
08385       return -1;
08386    }
08387 
08388    return 0;
08389 }

void log_match_char_tree ( struct match_char node,
char *  prefix 
)

Definition at line 1097 of file pbx.c.

References match_char::alt_char, ast_debug, ast_str_alloca, ast_str_set(), match_char::deleted, ast_exten::exten, match_char::exten, match_char::is_pattern, match_char::next_char, match_char::specificity, ast_str::str, and match_char::x.

Referenced by ast_context_remove_extension_callerid2(), and pbx_find_extension().

01098 {
01099    char extenstr[40];
01100    struct ast_str *my_prefix = ast_str_alloca(1024); 
01101 
01102    extenstr[0] = '\0';
01103 
01104    if (node && node->exten && node->exten)
01105       snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01106    
01107    if (strlen(node->x) > 1) {
01108       ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', 
01109          node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"", 
01110          node->exten ? node->exten->exten : "", extenstr);
01111    } else {
01112       ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', 
01113          node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"", 
01114          node->exten ? node->exten->exten : "", extenstr);
01115    }
01116 
01117    ast_str_set(&my_prefix, 0, "%s+       ", prefix);
01118 
01119    if (node->next_char)
01120       log_match_char_tree(node->next_char, my_prefix->str);
01121 
01122    if (node->alt_char)
01123       log_match_char_tree(node->alt_char, prefix);
01124 }

static int lookup_name ( const char *  s,
char *const   names[],
int  max 
) [static]

Helper for get_range. return the index of the matching entry, starting from 1. If names is not supplied, try numeric values.

Definition at line 5932 of file pbx.c.

Referenced by get_range().

05933 {
05934    int i;
05935 
05936    if (names) {
05937       for (i = 0; names[i]; i++) {
05938          if (!strcasecmp(s, names[i]))
05939             return i+1;
05940       }
05941    } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
05942       return i;
05943    }
05944    return 0; /* error return */
05945 }

static void manager_dpsendack ( struct mansession s,
const struct message m 
) [static]

Send ack once.

Definition at line 5164 of file pbx.c.

References astman_send_listack(), and s.

Referenced by manager_show_dialplan_helper().

05165 {
05166    astman_send_listack(s, m, "DialPlan list will follow", "start");
05167 }

static int manager_show_dialplan ( struct mansession s,
const struct message m 
) [static]

Manager listing of dial plan.

Definition at line 5310 of file pbx.c.

References ast_strlen_zero(), astman_get_header(), astman_send_error(), context, EVENT_FLAG_CONFIG, exten, manager_event, manager_show_dialplan_helper(), and s.

Referenced by load_pbx().

05311 {
05312    const char *exten, *context;
05313    const char *id = astman_get_header(m, "ActionID");
05314    char idtext[256];
05315    int res;
05316 
05317    /* Variables used for different counters */
05318    struct dialplan_counters counters;
05319 
05320    if (!ast_strlen_zero(id))
05321       snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
05322    else
05323       idtext[0] = '\0';
05324 
05325    memset(&counters, 0, sizeof(counters));
05326 
05327    exten = astman_get_header(m, "Extension");
05328    context = astman_get_header(m, "Context");
05329    
05330    res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
05331 
05332    if (context && !counters.context_existence) {
05333       char errorbuf[BUFSIZ];
05334    
05335       snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
05336       astman_send_error(s, m, errorbuf);
05337       return 0;
05338    }
05339    if (exten && !counters.extension_existence) {
05340       char errorbuf[BUFSIZ];
05341 
05342       if (context)
05343          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
05344       else
05345          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
05346       astman_send_error(s, m, errorbuf);
05347       return 0;
05348    }
05349 
05350    manager_event(EVENT_FLAG_CONFIG, "ShowDialPlanComplete",
05351       "EventList: Complete\r\n"
05352       "ListItems: %d\r\n"
05353       "ListExtensions: %d\r\n"
05354       "ListPriorities: %d\r\n"   
05355       "ListContexts: %d\r\n"  
05356       "%s"
05357       "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
05358 
05359    /* everything ok */
05360    return 0;
05361 }

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 
) [static]

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.

Definition at line 5173 of file pbx.c.

References ast_debug, ast_extension_match(), ast_get_context_name(), ast_get_extension_app(), ast_get_extension_app_data(), ast_get_extension_label(), ast_get_extension_name(), ast_get_extension_priority(), ast_get_extension_registrar(), ast_get_ignorepat_name(), ast_get_ignorepat_registrar(), ast_get_include_name(), ast_get_include_registrar(), ast_get_switch_data(), ast_get_switch_name(), ast_get_switch_registrar(), ast_log(), AST_MAX_EXTENSION, ast_rdlock_context(), ast_rdlock_contexts(), ast_strlen_zero(), ast_unlock_context(), ast_unlock_contexts(), ast_walk_context_extensions(), ast_walk_context_ignorepats(), ast_walk_context_includes(), ast_walk_context_switches(), ast_walk_contexts(), ast_walk_extension_priorities(), astman_append(), astman_send_error(), dialplan_counters::context_existence, dialplan_counters::extension_existence, LOG_WARNING, manager_dpsendack(), PRIORITY_HINT, s, dialplan_counters::total_context, dialplan_counters::total_exten, dialplan_counters::total_items, and dialplan_counters::total_prio.

Referenced by manager_show_dialplan().

05177 {
05178    struct ast_context *c;
05179    int res = 0, old_total_exten = dpc->total_exten;
05180 
05181    if (ast_strlen_zero(exten))
05182       exten = NULL;
05183    if (ast_strlen_zero(context))
05184       context = NULL;
05185 
05186    ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
05187 
05188    /* try to lock contexts */
05189    if (ast_rdlock_contexts()) {
05190       astman_send_error(s, m, "Failed to lock contexts");
05191       ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
05192       return -1;
05193    }
05194 
05195    c = NULL;      /* walk all contexts ... */
05196    while ( (c = ast_walk_contexts(c)) ) {
05197       struct ast_exten *e;
05198       struct ast_include *i;
05199       struct ast_ignorepat *ip;
05200 
05201       if (context && strcmp(ast_get_context_name(c), context) != 0)
05202          continue;   /* not the name we want */
05203 
05204       dpc->context_existence = 1;
05205 
05206       ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
05207 
05208       if (ast_rdlock_context(c)) {  /* failed to lock */
05209          ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
05210          continue;
05211       }
05212 
05213       /* XXX note- an empty context is not printed */
05214       e = NULL;      /* walk extensions in context  */
05215       while ( (e = ast_walk_context_extensions(c, e)) ) {
05216          struct ast_exten *p;
05217 
05218          /* looking for extension? is this our extension? */
05219          if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
05220             /* not the one we are looking for, continue */
05221             ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
05222             continue;
05223          }
05224          ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
05225 
05226          dpc->extension_existence = 1;
05227 
05228          /* may we print context info? */ 
05229          dpc->total_context++;
05230          dpc->total_exten++;
05231 
05232          p = NULL;      /* walk next extension peers */
05233          while ( (p = ast_walk_extension_priorities(e, p)) ) {
05234             int prio = ast_get_extension_priority(p);
05235 
05236             dpc->total_prio++;
05237             if (!dpc->total_items++)
05238                manager_dpsendack(s, m);
05239             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05240             astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
05241 
05242             /* XXX maybe make this conditional, if p != e ? */
05243             if (ast_get_extension_label(p))
05244                astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
05245 
05246             if (prio == PRIORITY_HINT) {
05247                astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
05248             } else {
05249                astman_append(s, "Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(p), (char *) ast_get_extension_app_data(p));
05250             }
05251             astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
05252          }
05253       }
05254 
05255       i = NULL;      /* walk included and write info ... */
05256       while ( (i = ast_walk_context_includes(c, i)) ) {
05257          if (exten) {
05258             /* Check all includes for the requested extension */
05259             manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
05260          } else {
05261             if (!dpc->total_items++)
05262                manager_dpsendack(s, m);
05263             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05264             astman_append(s, "Context: %s\r\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i));
05265             astman_append(s, "\r\n");
05266             ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
05267          }
05268       }
05269 
05270       ip = NULL;  /* walk ignore patterns and write info ... */
05271       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05272          const char *ipname = ast_get_ignorepat_name(ip);
05273          char ignorepat[AST_MAX_EXTENSION];
05274 
05275          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05276          if (!exten || ast_extension_match(ignorepat, exten)) {
05277             if (!dpc->total_items++)
05278                manager_dpsendack(s, m);
05279             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05280             astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
05281             astman_append(s, "\r\n");
05282          }
05283       }
05284       if (!rinclude) {
05285          struct ast_sw *sw = NULL;
05286          while ( (sw = ast_walk_context_switches(c, sw)) ) {
05287             if (!dpc->total_items++)
05288                manager_dpsendack(s, m);
05289             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05290             astman_append(s, "Context: %s\r\nSwitch: %s/%s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_registrar(sw));  
05291             astman_append(s, "\r\n");
05292             ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
05293          }
05294       }
05295 
05296       ast_unlock_context(c);
05297    }
05298    ast_unlock_contexts();
05299 
05300    if (dpc->total_exten == old_total_exten) {
05301       ast_debug(3, "manager_show_dialplan: Found nothing new\n");
05302       /* Nothing new under the sun */
05303       return -1;
05304    } else {
05305       return res;
05306    }
05307 }

static int matchcid ( const char *  cidpattern,
const char *  callerid 
) [static]

Definition at line 2025 of file pbx.c.

References ast_extension_match(), and ast_strlen_zero().

Referenced by pbx_find_extension().

02026 {
02027    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
02028       failing to get a number should count as a match, otherwise not */
02029 
02030    if (ast_strlen_zero(callerid))
02031       return ast_strlen_zero(cidpattern) ? 1 : 0;
02032 
02033    return ast_extension_match(cidpattern, callerid);
02034 }

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]

Definition at line 1227 of file pbx.c.

References match_char::alt_char, ast_debug, ast_hashtab_lookup(), ast_log(), match_char::deleted, E_FINDLABEL, E_MATCH, E_SPAWN, ast_exten::exten, match_char::exten, ast_exten::label, LOG_NOTICE, NEW_MATCHER_CHK_MATCH, match_char::specificity, update_scoreboard(), and match_char::x.

Referenced by pbx_find_extension().

01228 {
01229    struct match_char *p; /* note minimal stack storage requirements */
01230    struct ast_exten pattern = { .label = label };
01231 #ifdef DEBUG_THIS
01232    if (tree)
01233       ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
01234    else
01235       ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
01236 #endif
01237    for (p=tree; p; p=p->alt_char) {
01238       if (p->x[0] == 'N') {
01239          if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
01240 #define NEW_MATCHER_CHK_MATCH        \
01241             if (p->exten && !(*(str+1))) { /* if a shorter pattern matches along the way, might as well report it */             \
01242                if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */   \
01243                   update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p);                 \
01244                   if (!p->deleted) {                                                                                           \
01245                      if (action == E_FINDLABEL) {                                                                             \
01246                         if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) {                                   \
01247                            ast_debug(4, "Found label in preferred extension\n");                                            \
01248                            return;                                                                                          \
01249                         }                                                                                                    \
01250                      } else {                                                                                                 \
01251                         ast_debug(4,"returning an exact match-- first found-- %s\n", p->exten->exten);                       \
01252                         return; /* the first match, by definition, will be the best, because of the sorted tree */           \
01253                      }                                                                                                        \
01254                   }                                                                                                            \
01255                }                                                                                                                \
01256             }
01257             
01258 #define NEW_MATCHER_RECURSE              \
01259             if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0)                 \
01260                                                || p->next_char->x[0] == '!')) {                                          \
01261                if (*(str+1) || p->next_char->x[0] == '!') {                                                         \
01262                   new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid, label, action); \
01263                   if (score->exten)  {                                                                             \
01264                        ast_debug(4,"returning an exact match-- %s\n", score->exten->exten);                         \
01265                      return; /* the first match is all we need */                                                 \
01266                   }                                                                                    \
01267                } else {                                                                                             \
01268                   new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid, label, action);  \
01269                   if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {      \
01270                        ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten :     \
01271                                        "NULL");                                                                        \
01272                      return; /* the first match is all we need */                                                 \
01273                   }                                                                                    \
01274                }                                                                                                    \
01275             } else if (p->next_char && !*(str+1)) {                                                                  \
01276                score->canmatch = 1;                                                                                 \
01277                score->canmatch_exten = get_canmatch_exten(p);                                                       \
01278                if (action == E_CANMATCH || action == E_MATCHMORE) {                                                 \
01279                     ast_debug(4,"returning a canmatch/matchmore--- str=%s\n", str);                                  \
01280                   return;                                                                                          \
01281                }                                                                                        \
01282             }
01283             
01284             NEW_MATCHER_CHK_MATCH;
01285             NEW_MATCHER_RECURSE;
01286          }
01287       } else if (p->x[0] == 'Z') {
01288          if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
01289             NEW_MATCHER_CHK_MATCH;
01290             NEW_MATCHER_RECURSE;
01291          }
01292       } else if (p->x[0] == 'X') { 
01293          if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
01294             NEW_MATCHER_CHK_MATCH;
01295             NEW_MATCHER_RECURSE;
01296          }
01297       } else if (p->x[0] == '.' && p->x[1] == 0) {
01298          /* how many chars will the . match against? */
01299          int i = 0;
01300          const char *str2 = str;
01301          while (*str2 && *str2 != '/') {
01302             str2++;
01303             i++;
01304          }
01305          if (p->exten && *str2 != '/') {
01306             update_scoreboard(score, length+i, spec+(i*p->specificity), p->exten, '.', callerid, p->deleted, p);
01307             if (score->exten) {
01308                ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
01309                return; /* the first match is all we need */
01310             }
01311          }
01312          if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01313             new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid, label, action);
01314             if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01315                ast_debug(4,"return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
01316                return; /* the first match is all we need */
01317             }
01318          }
01319       } else if (p->x[0] == '!' && p->x[1] == 0) {
01320          /* how many chars will the . match against? */
01321          int i = 1;
01322          const char *str2 = str;
01323          while (*str2 && *str2 != '/') {
01324             str2++;
01325             i++;
01326          }
01327          if (p->exten && *str2 != '/') {
01328             update_scoreboard(score, length+1, spec+(p->specificity*i), p->exten, '!', callerid, p->deleted, p);
01329             if (score->exten) {
01330                ast_debug(4,"return because scoreboard has a '!' match--- %s\n", score->exten->exten);
01331                return; /* the first match is all we need */
01332             }
01333          }
01334          if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01335             new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid, label, action);
01336             if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01337                ast_debug(4,"return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
01338                return; /* the first match is all we need */
01339             }
01340          }
01341       } else if (p->x[0] == '/' && p->x[1] == 0) {
01342          /* the pattern in the tree includes the cid match! */
01343          if (p->next_char && callerid && *callerid) {
01344             new_find_extension(callerid, score, p->next_char, length+1, spec, callerid, label, action);
01345             if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01346                ast_debug(4,"return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
01347                return; /* the first match is all we need */
01348             }
01349          }
01350       } else if (strchr(p->x, *str)) {
01351          ast_debug(4, "Nothing strange about this match\n");
01352          NEW_MATCHER_CHK_MATCH;
01353          NEW_MATCHER_RECURSE;
01354       }
01355    }
01356    ast_debug(4,"return at end of func\n");
01357 }

static int parse_variable_name ( char *  var,
int *  offset,
int *  length,
int *  isfunc 
) [static]

extract offset:length from variable name.

Returns:
1 if there is a offset:length part, which is trimmed off (values go into variables)

Definition at line 2298 of file pbx.c.

Referenced by pbx_retrieve_variable(), and pbx_substitute_variables_helper_full().

02299 {
02300    int parens = 0;
02301 
02302    *offset = 0;
02303    *length = INT_MAX;
02304    *isfunc = 0;
02305    for (; *var; var++) {
02306       if (*var == '(') {
02307          (*isfunc)++;
02308          parens++;
02309       } else if (*var == ')') {
02310          parens--;
02311       } else if (*var == ':' && parens == 0) {
02312          *var++ = '\0';
02313          sscanf(var, "%d:%d", offset, length);
02314          return 1; /* offset:length valid */
02315       }
02316    }
02317    return 0;
02318 }

void pbx_builtin_clear_globals ( void   ) 

Definition at line 8244 of file pbx.c.

References AST_LIST_REMOVE_HEAD, ast_rwlock_unlock(), ast_rwlock_wrlock(), ast_var_delete(), ast_var_t::entries, globals, and globalslock.

Referenced by handle_cli_dialplan_reload(), and reload().

08245 {
08246    struct ast_var_t *vardata;
08247 
08248    ast_rwlock_wrlock(&globalslock);
08249    while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
08250       ast_var_delete(vardata);
08251    ast_rwlock_unlock(&globalslock);
08252 }

const char* pbx_builtin_getvar_helper ( struct ast_channel chan,
const char *  name 
)

Note:
Will lock the channel.

This function will return a pointer to the buffer inside the channel variable. This value should only be accessed with the channel locked. If the value needs to be kept around, it should be done by using the following thread-safe code:

      const char *var;

      ast_channel_lock(chan);
      if ((var = pbx_builtin_getvar_helper(chan, "MYVAR"))) {
         var = ast_strdupa(var);
      }
      ast_channel_unlock(chan);

Definition at line 8014 of file pbx.c.

References ast_channel_lock, ast_channel_unlock, AST_LIST_TRAVERSE, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_var_name(), ast_var_value(), chan, globals, and globalslock.

Referenced by _macro_exec(), _while_exec(), agent_hangup(), agent_read(), agentmonitoroutgoing_exec(), array(), ast_bridge_call(), ast_call_forward(), ast_eivr_getvariable(), ast_feature_interpret(), ast_monitor_stop(), builtin_automixmonitor(), builtin_automonitor(), check_goto_on_transfer(), common_exec(), conf_exec(), conf_run(), dahdi_call(), dahdi_hangup(), dial_exec_full(), do_forward(), do_timelimit(), dundi_exec(), dundi_helper(), get_also_info(), get_index(), get_refer_info(), global_read(), hash_read(), iax2_exec(), import_ch(), leave_voicemail(), local_hangup(), local_read(), login_exec(), macro_fixup(), minivm_delete_exec(), minivm_notify_exec(), misdn_answer(), misdn_hangup(), morsecode_exec(), notify_new_message(), oh323_call(), oh323_hangup(), park_call_full(), park_space_reserve(), pickup_by_mark(), queue_exec(), real_ctx(), retrydial_exec(), ring_entry(), run_agi(), set_config_flags(), set_local_info(), sip_addheader(), sla_trunk_exec(), speech_background(), try_suggested_sip_codec(), and update_bridge_vars().

08015 {
08016    struct ast_var_t *variables;
08017    const char *ret = NULL;
08018    int i;
08019    struct varshead *places[2] = { NULL, &globals };
08020 
08021    if (!name)
08022       return NULL;
08023 
08024    if (chan) {
08025       ast_channel_lock(chan);
08026       places[0] = &chan->varshead;
08027    }
08028 
08029    for (i = 0; i < 2; i++) {
08030       if (!places[i])
08031          continue;
08032       if (places[i] == &globals)
08033          ast_rwlock_rdlock(&globalslock);
08034       AST_LIST_TRAVERSE(places[i], variables, entries) {
08035          if (!strcmp(name, ast_var_name(variables))) {
08036             ret = ast_var_value(variables);
08037             break;
08038          }
08039       }
08040       if (places[i] == &globals)
08041          ast_rwlock_unlock(&globalslock);
08042       if (ret)
08043          break;
08044    }
08045 
08046    if (chan)
08047       ast_channel_unlock(chan);
08048 
08049    return ret;
08050 }

static int pbx_builtin_gotoif ( struct ast_channel ,
void *   
) [static]

Definition at line 8264 of file pbx.c.

References ast_debug, ast_log(), ast_strdupa, ast_strlen_zero(), chan, LOG_WARNING, pbx_builtin_goto(), pbx_checkcondition(), and strsep().

08265 {
08266    char *condition, *branch1, *branch2, *branch;
08267    char *stringp;
08268 
08269    if (ast_strlen_zero(data)) {
08270       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
08271       return 0;
08272    }
08273 
08274    stringp = ast_strdupa(data);
08275    condition = strsep(&stringp,"?");
08276    branch1 = strsep(&stringp,":");
08277    branch2 = strsep(&stringp,"");
08278    branch = pbx_checkcondition(condition) ? branch1 : branch2;
08279 
08280    if (ast_strlen_zero(branch)) {
08281       ast_debug(1, "Not taking any branch\n");
08282       return 0;
08283    }
08284 
08285    return pbx_builtin_goto(chan, branch);
08286 }

int pbx_builtin_importvar ( struct ast_channel ,
void *   
) [static]

Definition at line 8202 of file pbx.c.

References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_log(), ast_strdupa, ast_strlen_zero(), chan, LOG_WARNING, pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), s, strsep(), and VAR_BUF_SIZE.

08203 {
08204    char *name;
08205    char *value;
08206    char *channel;
08207    char tmp[VAR_BUF_SIZE];
08208    static int deprecation_warning = 0;
08209 
08210    if (ast_strlen_zero(data)) {
08211       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
08212       return 0;
08213    }
08214    tmp[0] = 0;
08215    if (!deprecation_warning) {
08216       ast_log(LOG_WARNING, "ImportVar is deprecated.  Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
08217       deprecation_warning = 1;
08218    }
08219 
08220    value = ast_strdupa(data);
08221    name = strsep(&value,"=");
08222    channel = strsep(&value,",");
08223    if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
08224       struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
08225       if (chan2) {
08226          char *s = alloca(strlen(value) + 4);
08227          if (s) {
08228             sprintf(s, "${%s}", value);
08229             pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
08230          }
08231          ast_channel_unlock(chan2);
08232       }
08233       pbx_builtin_setvar_helper(chan, name, tmp);
08234    }
08235 
08236    return(0);
08237 }

static int pbx_builtin_noop ( struct ast_channel ,
void *   
) [static]

Definition at line 8239 of file pbx.c.

08240 {
08241    return 0;
08242 }

void pbx_builtin_pushvar_helper ( struct ast_channel chan,
const char *  name,
const char *  value 
)

Note:
Will lock the channel.

Definition at line 8052 of file pbx.c.

References ast_channel_lock, ast_channel_unlock, ast_func_write(), AST_LIST_INSERT_HEAD, ast_log(), ast_rwlock_unlock(), ast_rwlock_wrlock(), ast_strdupa, ast_var_assign(), ast_verb, chan, globals, globalslock, and LOG_WARNING.

Referenced by acf_odbc_read(), acf_odbc_write(), and frame_set_var().

08053 {
08054    struct ast_var_t *newvariable;
08055    struct varshead *headp;
08056 
08057    if (name[strlen(name)-1] == ')') {
08058       char *function = ast_strdupa(name);
08059 
08060       ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
08061       ast_func_write(chan, function, value);
08062       return;
08063    }
08064 
08065    if (chan) {
08066       ast_channel_lock(chan);
08067       headp = &chan->varshead;
08068    } else {
08069       ast_rwlock_wrlock(&globalslock);
08070       headp = &globals;
08071    }
08072 
08073    if (value) {
08074       if (headp == &globals)
08075          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08076       newvariable = ast_var_assign(name, value);
08077       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08078    }
08079 
08080    if (chan)
08081       ast_channel_unlock(chan);
08082    else
08083       ast_rwlock_unlock(&globalslock);
08084 }

int pbx_builtin_raise_exception ( struct ast_channel chan,
void *  vreason 
)

Definition at line 2498 of file pbx.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_free, ast_string_field_init, ast_string_field_set, chan, context, ast_channel::context, ast_datastore::data, exception_store_info, exten, ast_channel::exten, pbx_exception::priority, ast_channel::priority, and set_ext_pri().

Referenced by __ast_pbx_run().

02499 {
02500    const char *reason = vreason;
02501    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02502    struct pbx_exception *exception = NULL;
02503 
02504    if (!ds) {
02505       ds = ast_channel_datastore_alloc(&exception_store_info, NULL);
02506       if (!ds)
02507          return -1;
02508       exception = ast_calloc(1, sizeof(struct pbx_exception));
02509       if (!exception) {
02510          ast_channel_datastore_free(ds);
02511          return -1;
02512       }
02513       if (ast_string_field_init(exception, 128)) {
02514          ast_free(exception);
02515          ast_channel_datastore_free(ds);
02516          return -1;
02517       }
02518       ds->data = exception;
02519       ast_channel_datastore_add(chan, ds);
02520    } else
02521       exception = ds->data;
02522 
02523    ast_string_field_set(exception, reason, reason);
02524    ast_string_field_set(exception, context, chan->context);
02525    ast_string_field_set(exception, exten, chan->exten);
02526    exception->priority = chan->priority;
02527    set_ext_pri(chan, "e", 0);
02528    return 0;
02529 }

static int pbx_builtin_saycharacters ( struct ast_channel ,
void *   
) [static]

Definition at line 8325 of file pbx.c.

References ast_say_character_str(), chan, and ast_channel::language.

08326 {
08327    int res = 0;
08328 
08329    if (data)
08330       res = ast_say_character_str(chan, data, "", chan->language);
08331    return res;
08332 }

static int pbx_builtin_saydigits ( struct ast_channel ,
void *   
) [static]

Definition at line 8316 of file pbx.c.

References ast_say_digit_str(), chan, and ast_channel::language.

08317 {
08318    int res = 0;
08319 
08320    if (data)
08321       res = ast_say_digit_str(chan, data, "", chan->language);
08322    return res;
08323 }

static int pbx_builtin_saynumber ( struct ast_channel ,
void *   
) [static]

Definition at line 8288 of file pbx.c.

References ast_copy_string(), ast_log(), ast_say_number(), ast_strlen_zero(), chan, ast_channel::language, LOG_WARNING, and strsep().

08289 {
08290    char tmp[256];
08291    char *number = tmp;
08292    char *options;
08293 
08294    if (ast_strlen_zero(data)) {
08295       ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
08296       return -1;
08297    }
08298    ast_copy_string(tmp, data, sizeof(tmp));
08299    strsep(&number, ",");
08300    options = strsep(&number, ",");
08301    if (options) {
08302       if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
08303          strcasecmp(options, "c") && strcasecmp(options, "n") ) {
08304          ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
08305          return -1;
08306       }
08307    }
08308 
08309    if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
08310       ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
08311    }
08312 
08313    return 0;
08314 }

static int pbx_builtin_sayphonetic ( struct ast_channel ,
void *   
) [static]

Definition at line 8334 of file pbx.c.

References ast_say_phonetic_str(), chan, and ast_channel::language.

08335 {
08336    int res = 0;
08337 
08338    if (data)
08339       res = ast_say_phonetic_str(chan, data, "", chan->language);
08340    return res;
08341 }

int pbx_builtin_serialize_variables ( struct ast_channel chan,
struct ast_str **  buf 
)

Note:
Will lock the channel.

Definition at line 7982 of file pbx.c.

References ast_channel_lock, ast_channel_unlock, AST_LIST_TRAVERSE, ast_log(), ast_str_append(), ast_var_name(), ast_var_value(), buf, chan, ast_var_t::entries, LOG_ERROR, total, var, and ast_channel::varshead.

Referenced by dumpchan_exec(), handle_showchan(), and vars2manager().

07983 {
07984    struct ast_var_t *variables;
07985    const char *var, *val;
07986    int total = 0;
07987 
07988    if (!chan)
07989       return 0;
07990 
07991    (*buf)->used = 0;
07992    (*buf)->str[0] = '\0';
07993 
07994    ast_channel_lock(chan);
07995 
07996    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
07997       if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
07998          /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
07999          ) {
08000          if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
08001             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
08002             break;
08003          } else
08004             total++;
08005       } else
08006          break;
08007    }
08008 
08009    ast_channel_unlock(chan);
08010 
08011    return total;
08012 }

int pbx_builtin_setvar ( struct ast_channel ,
void *   
)

Definition at line 8143 of file pbx.c.

References ast_compat_app_set, ast_log(), ast_strdupa, ast_strlen_zero(), chan, LOG_WARNING, pbx_builtin_setvar_helper(), pbx_builtin_setvar_multiple(), and strsep().

08144 {
08145    char *name, *value, *mydata;
08146 
08147    if (ast_compat_app_set) {
08148       return pbx_builtin_setvar_multiple(chan, data);
08149    }
08150 
08151    if (ast_strlen_zero(data)) {
08152       ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
08153       return 0;
08154    }
08155 
08156    mydata = ast_strdupa(data);
08157    name = strsep(&mydata, "=");
08158    value = mydata;
08159    if (strchr(name, ' '))
08160       ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
08161 
08162    pbx_builtin_setvar_helper(chan, name, value);
08163    return(0);
08164 }

void pbx_builtin_setvar_helper ( struct ast_channel chan,
const char *  name,
const char *  value 
)

Note:
Will lock the channel.

Definition at line 8086 of file pbx.c.

References ast_channel_lock, ast_channel_unlock, ast_func_write(), AST_LIST_INSERT_HEAD, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_rwlock_unlock(), ast_rwlock_wrlock(), ast_strdupa, ast_var_assign(), ast_var_delete(), ast_var_name(), ast_verb, chan, EVENT_FLAG_DIALPLAN, globals, globalslock, manager_event, ast_channel::name, and ast_channel::uniqueid.

Referenced by __oh323_new(), _macro_exec(), _while_exec(), acf_fetch(), acf_odbc_read(), acf_odbc_write(), action_setvar(), agi_exec_full(), aji_status_exec(), aqm_exec(), array(), ast_bridge_call(), ast_eivr_setvariable(), ast_feature_request_and_dial(), ast_iax2_new(), ast_monitor_start(), ast_pbx_outgoing_exten(), ast_set_variables(), asyncgoto_exec(), background_detect_exec(), bridge_exec(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), cb_events(), chanavail_exec(), channel_spy(), conf_run(), controlplayback_exec(), count_exec(), dahdi_handle_dtmfup(), dahdi_new(), dial_exec_full(), do_parking_thread(), do_waiting(), end_bridge_callback(), export_aoc_vars(), export_ch(), frame_set_var(), function_db_delete(), function_db_exists(), function_db_read(), function_realtime_store(), get_rdnis(), get_refer_info(), global_write(), gosub_release_frame(), handle_request_bye(), handle_request_refer(), handle_set_chanvar(), handle_set_global(), handle_setvariable(), hash_read(), hash_write(), isAnsweringMachine(), leave_voicemail(), local_hangup(), lua_set_variable(), lua_set_variable_value(), macro_fixup(), minivm_accmess_exec(), minivm_delete_exec(), minivm_greet_exec(), minivm_notify_exec(), minivm_record_exec(), misdn_call(), mixmonitor_exec(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), park_exec(), parse_moved_contact(), pbx_builtin_background(), pbx_builtin_importvar(), pbx_builtin_setvar(), pbx_builtin_setvar_multiple(), pbx_load_config(), phase_e_handler(), play_message_datetime(), playback_exec(), pqm_exec(), prep_email_sub_vars(), privacy_exec(), process_ast_dsp(), read_exec(), readexten_exec(), readfile_exec(), record_exec(), return_exec(), rotate_file(), rqm_exec(), sendimage_exec(), sendtext_exec(), sendurl_exec(), set(), set_agentbycallerid(), set_queue_result(), sip_addheader(), sip_hangup(), sip_new(), skinny_new(), sla_calc_trunk_timeouts(), sla_station_exec(), sla_trunk_exec(), socket_process(), speech_create(), ss_thread(), start_monitor_exec(), system_exec_helper(), transfer_exec(), transmit(), tryexec_exec(), update_bridge_vars(), update_qe_rule(), upqm_exec(), vm_box_exists(), vm_exec(), vmauthenticate(), waituntil_exec(), and zapateller_exec().

08087 {
08088    struct ast_var_t *newvariable;
08089    struct varshead *headp;
08090    const char *nametail = name;
08091 
08092    if (name[strlen(name) - 1] == ')') {
08093       char *function = ast_strdupa(name);
08094 
08095       ast_func_write(chan, function, value);
08096       return;
08097    }
08098 
08099    if (chan) {
08100       ast_channel_lock(chan);
08101       headp = &chan->varshead;
08102    } else {
08103       ast_rwlock_wrlock(&globalslock);
08104       headp = &globals;
08105    }
08106 
08107    /* For comparison purposes, we have to strip leading underscores */
08108    if (*nametail == '_') {
08109       nametail++;
08110       if (*nametail == '_')
08111          nametail++;
08112    }
08113 
08114    AST_LIST_TRAVERSE (headp, newvariable, entries) {
08115       if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
08116          /* there is already such a variable, delete it */
08117          AST_LIST_REMOVE(headp, newvariable, entries);
08118          ast_var_delete(newvariable);
08119          break;
08120       }
08121    }
08122 
08123    if (value) {
08124       if (headp == &globals)
08125          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08126       newvariable = ast_var_assign(name, value);
08127       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08128       manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
08129          "Channel: %s\r\n"
08130          "Variable: %s\r\n"
08131          "Value: %s\r\n"
08132          "Uniqueid: %s\r\n", 
08133          chan ? chan->name : "none", name, value, 
08134          chan ? chan->uniqueid : "none");
08135    }
08136 
08137    if (chan)
08138       ast_channel_unlock(chan);
08139    else
08140       ast_rwlock_unlock(&globalslock);
08141 }

int pbx_builtin_setvar_multiple ( struct ast_channel ,
void *   
)

Definition at line 8166 of file pbx.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), chan, ast_channel::context, ast_channel::exten, LOG_WARNING, ast_channel::name, pbx_builtin_setvar_helper(), and ast_channel::priority.

Referenced by pbx_builtin_setvar(), queue_function_var(), and set_queue_variables().

08167 {
08168    char *data;
08169    int x;
08170    AST_DECLARE_APP_ARGS(args,
08171       AST_APP_ARG(pair)[24];
08172    );
08173    AST_DECLARE_APP_ARGS(pair,
08174       AST_APP_ARG(name);
08175       AST_APP_ARG(value);
08176    );
08177 
08178    if (ast_strlen_zero(vdata)) {
08179       ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
08180       return 0;
08181    }
08182 
08183    data = ast_strdupa(vdata);
08184    AST_STANDARD_APP_ARGS(args, data);
08185 
08186    for (x = 0; x < args.argc; x++) {
08187       AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
08188       if (pair.argc == 2) {
08189          pbx_builtin_setvar_helper(chan, pair.name, pair.value);
08190          if (strchr(pair.name, ' '))
08191             ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
08192       } else if (!chan) {
08193          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
08194       } else {
08195          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, chan->exten, chan->context, chan->priority);
08196       }
08197    }
08198 
08199    return 0;
08200 }

int pbx_checkcondition ( const char *  condition  ) 

Evaluate a condition.

Return values:
0 if the condition is NULL or of zero length
int If the string is an integer, the integer representation of the integer is returned
1 Any other non-empty string

Definition at line 8254 of file pbx.c.

References ast_strlen_zero().

Referenced by _macro_exec(), _while_exec(), acf_if(), execif_exec(), gosubif_exec(), macroif_exec(), and pbx_builtin_gotoif().

08255 {
08256    if (ast_strlen_zero(condition))  /* NULL or empty strings are false */
08257       return 0;
08258    else if (*condition >= '0' && *condition <= '9')   /* Numbers are evaluated for truth */
08259       return atoi(condition);
08260    else  /* Strings are true */
08261       return 1;
08262 }

static void pbx_destroy ( struct ast_pbx p  )  [static]

Definition at line 1002 of file pbx.c.

References ast_free.

01003 {
01004    ast_free(p);
01005 }

int pbx_exec ( struct ast_channel c,
struct ast_app app,
void *  data 
)

Execute an application.

Parameters:
c channel to execute on
app which app to execute
data the data passed into the app
This application executes an application on a given channel. It saves the stack and executes the given application passing in the given data.

Returns:
0 on success, and -1 on failure
Parameters:
c  Channel
app  Application
data  Data for execution

Definition at line 925 of file pbx.c.

References __ast_module_user_add(), __ast_module_user_remove(), app, ast_channel::appl, ast_cdr_setapp(), ast_check_hangup(), ast_log(), ast_strlen_zero(), ast_channel::cdr, ast_channel::data, LOG_WARNING, ast_channel::name, and S_OR.

Referenced by answer_exec_run(), ast_bridge_call(), ast_pbx_run_app(), async_wait(), builtin_automixmonitor(), builtin_automonitor(), conf_run(), dial_exec_full(), dundi_exec(), exec_exec(), execif_exec(), feature_exec_app(), forward_message(), handle_exec(), handle_gosub(), iax2_exec(), lua_pbx_exec(), milliwatt_exec(), page_exec(), pbx_builtin_execiftime(), pbx_extension_helper(), and tryexec_exec().

00928 {
00929    int res;
00930    struct ast_module_user *u = NULL;
00931    const char *saved_c_appl;
00932    const char *saved_c_data;
00933 
00934    if (c->cdr && !ast_check_hangup(c))
00935       ast_cdr_setapp(c->cdr, app->name, data);
00936 
00937    /* save channel values */
00938    saved_c_appl= c->appl;
00939    saved_c_data= c->data;
00940 
00941    c->appl = app->name;
00942    c->data = data;
00943    if (app->module)
00944       u = __ast_module_user_add(app->module, c);
00945    if (strcasecmp(app->name, "system") && !ast_strlen_zero(data) &&
00946          strchr(data, '|') && !strchr(data, ',')) {
00947       ast_log(LOG_WARNING, "The application delimiter is now the comma, not "
00948          "the pipe.  Did you forget to convert your dialplan?  (%s(%s))\n",
00949          app->name, (char *) data);
00950    }
00951    res = app->execute(c, S_OR(data, ""));
00952    if (app->module && u)
00953       __ast_module_user_remove(app->module, u);
00954    /* restore channel values */
00955    c->appl = saved_c_appl;
00956    c->data = saved_c_data;
00957    return res;
00958 }

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 
) [static]

The return value depends on the action:.

E_MATCH, E_CANMATCH, E_MATCHMORE require a real match, and return 0 on failure, -1 on match; E_FINDLABEL maps the label to a priority, and returns the priority on success, ... XXX E_SPAWN, spawn an application,

Return values:
0 on success.
-1 on failure.
Note:
The channel is auto-serviced in this function, because doing an extension match may block for a long time. For example, if the lookup has to use a network dialplan switch, such as DUNDi or IAX2, it may take a while. However, the channel auto-service code will queue up any important signalling frames to be processed after this is done.

Definition at line 3056 of file pbx.c.

References ast_exten::app, app, ast_copy_string(), ast_debug, ast_log(), ast_rdlock_contexts(), ast_unlock_contexts(), ast_verb, ast_exten::cached_app, COLOR_BRCYAN, COLOR_BRMAGENTA, ast_channel::context, pbx_find_info::data, E_CANMATCH, E_FINDLABEL, E_MATCH, E_MATCHMORE, EVENT_FLAG_DIALPLAN, ast_switch::exec, EXT_DATA_SIZE, ast_channel::exten, pbx_find_info::foundcontext, LOG_NOTICE, LOG_WARNING, manager_event, ast_switch::name, ast_channel::name, pbx_exec(), pbx_find_extension(), pbx_findapp(), pbx_substitute_variables(), ast_channel::priority, ast_exten::priority, pbx_find_info::stacklen, pbx_find_info::status, STATUS_NO_CONTEXT, STATUS_NO_EXTENSION, STATUS_NO_LABEL, STATUS_NO_PRIORITY, pbx_find_info::swo, term_color(), ast_channel::uniqueid, and VERBOSITY_ATLEAST.

Referenced by ast_canmatch_extension(), ast_exists_extension(), ast_findlabel_extension(), ast_findlabel_extension2(), ast_matchmore_extension(), and ast_spawn_extension().

03059 {
03060    struct ast_exten *e;
03061    struct ast_app *app;
03062    int res;
03063    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
03064    char passdata[EXT_DATA_SIZE];
03065 
03066    int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
03067 
03068    ast_rdlock_contexts();
03069    if (found)
03070       *found = 0;
03071 
03072    e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
03073    if (e) {
03074       if (found)
03075          *found = 1;
03076       if (matching_action) {
03077          ast_unlock_contexts();
03078          return -1;  /* success, we found it */
03079       } else if (action == E_FINDLABEL) { /* map the label to a priority */
03080          res = e->priority;
03081          ast_unlock_contexts();
03082          return res; /* the priority we were looking for */
03083       } else { /* spawn */
03084          if (!e->cached_app)
03085             e->cached_app = pbx_findapp(e->app);
03086          app = e->cached_app;
03087          ast_unlock_contexts();
03088          if (!app) {
03089             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
03090             return -1;
03091          }
03092          if (c->context != context)
03093             ast_copy_string(c->context, context, sizeof(c->context));
03094          if (c->exten != exten)
03095             ast_copy_string(c->exten, exten, sizeof(c->exten));
03096          c->priority = priority;
03097          pbx_substitute_variables(passdata, sizeof(passdata), c, e);
03098 #ifdef CHANNEL_TRACE
03099          ast_channel_trace_update(c);
03100 #endif
03101          ast_debug(1, "Launching '%s'\n", app->name);
03102          if (VERBOSITY_ATLEAST(3)) {
03103             char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
03104             ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
03105                exten, context, priority,
03106                term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
03107                term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
03108                term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
03109                "in new stack");
03110          }
03111          manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
03112                "Channel: %s\r\n"
03113                "Context: %s\r\n"
03114                "Extension: %s\r\n"
03115                "Priority: %d\r\n"
03116                "Application: %s\r\n"
03117                "AppData: %s\r\n"
03118                "Uniqueid: %s\r\n",
03119                c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
03120          return pbx_exec(c, app, passdata);  /* 0 on success, -1 on failure */
03121       }
03122    } else if (q.swo) {  /* not found here, but in another switch */
03123       if (found)
03124          *found = 1;
03125       ast_unlock_contexts();
03126       if (matching_action) {
03127          return -1;
03128       } else {
03129          if (!q.swo->exec) {
03130             ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
03131             res = -1;
03132          }
03133          return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
03134       }
03135    } else { /* not found anywhere, see what happened */
03136       ast_unlock_contexts();
03137       switch (q.status) {
03138       case STATUS_NO_CONTEXT:
03139          if (!matching_action && !combined_find_spawn)
03140             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
03141          break;
03142       case STATUS_NO_EXTENSION:
03143          if (!matching_action && !combined_find_spawn)
03144             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
03145          break;
03146       case STATUS_NO_PRIORITY:
03147          if (!matching_action && !combined_find_spawn)
03148             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
03149          break;
03150       case STATUS_NO_LABEL:
03151          if (context && !combined_find_spawn)
03152             ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
03153          break;
03154       default:
03155          ast_debug(1, "Shouldn't happen!\n");
03156       }
03157 
03158       return (matching_action) ? 0 : -1;
03159    }
03160 }

struct ast_exten* pbx_find_extension ( struct ast_channel chan,
struct ast_context bypass,
struct pbx_find_info q,
const char *  context,
const char *  exten,
int  priority,
const char *  label,
const char *  callerid,
enum ext_match_t  action 
)

Definition at line 2036 of file pbx.c.

References ast_context::alts, ast_autoservice_start(), ast_autoservice_stop(), ast_hashtab_lookup(), AST_LIST_TRAVERSE, ast_log(), AST_PBX_MAX_STACK, ast_str_thread_get(), ast_walk_context_extensions(), ast_walk_contexts(), ast_walk_extension_priorities(), ast_switch::canmatch, scoreboard::canmatch_exten, chan, contexts_table, create_match_char_tree(), pbx_find_info::data, ast_sw::data, E_CANMATCH, E_FINDLABEL, E_MATCHMORE, ast_sw::eval, ast_switch::exists, scoreboard::exten, ast_exten::exten, extension_match_core(), pbx_find_info::foundcontext, include_valid(), ast_context::includes, pbx_find_info::incstack, ast_exten::label, scoreboard::last_char, ast_str::len, LOG_DEBUG, log_match_char_tree(), LOG_NOTICE, LOG_WARNING, match(), matchcid(), ast_switch::matchmore, fake_context::name, ast_context::name, ast_sw::name, new_find_extension(), ast_include::next, scoreboard::node, ast_context::pattern_tree, pbx_find_extension(), pbx_findswitch(), pbx_substitute_variables_helper(), ast_exten::priority, ast_include::rname, ast_context::root_table, pbx_find_info::stacklen, pbx_find_info::status, STATUS_NO_CONTEXT, STATUS_NO_EXTENSION, STATUS_NO_LABEL, STATUS_NO_PRIORITY, STATUS_SUCCESS, ast_str::str, switch_data, pbx_find_info::swo, scoreboard::total_length, scoreboard::total_specificity, and trie_find_next_match().

Referenced by ast_hint_extension(), ast_merge_contexts_and_delete(), pbx_extension_helper(), pbx_find_extension(), and register_peer_exten().

02040 {
02041    int x, res;
02042    struct ast_context *tmp = NULL;
02043    struct ast_exten *e = NULL, *eroot = NULL;
02044    struct ast_include *i = NULL;
02045    struct ast_sw *sw = NULL;
02046    struct ast_exten pattern = {NULL, };
02047    struct scoreboard score = {0, };
02048    struct ast_str *tmpdata = NULL;
02049 
02050    pattern.label = label;
02051    pattern.priority = priority;
02052 #ifdef NEED_DEBUG_HERE
02053    ast_log(LOG_NOTICE,"Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int)action);
02054 #endif
02055    /* Initialize status if appropriate */
02056    if (q->stacklen == 0) {
02057       q->status = STATUS_NO_CONTEXT;
02058       q->swo = NULL;
02059       q->data = NULL;
02060       q->foundcontext = NULL;
02061    } else if (q->stacklen >= AST_PBX_MAX_STACK) {
02062       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
02063       return NULL;
02064    }
02065 
02066    /* Check first to see if we've already been checked */
02067    for (x = 0; x < q->stacklen; x++) {
02068       if (!strcasecmp(q->incstack[x], context))
02069          return NULL;
02070    }
02071 
02072    if (bypass) /* bypass means we only look there */
02073       tmp = bypass;
02074    else {   /* look in contexts */
02075       struct fake_context item;
02076       strncpy(item.name,context,256);
02077       tmp = ast_hashtab_lookup(contexts_table,&item);
02078 #ifdef NOTNOW
02079       tmp = NULL;
02080       while ((tmp = ast_walk_contexts(tmp)) ) {
02081          if (!strcmp(tmp->name, context))
02082             break;
02083       }
02084 #endif
02085       if (!tmp)
02086          return NULL;
02087       
02088    }
02089 
02090    if (q->status < STATUS_NO_EXTENSION)
02091       q->status = STATUS_NO_EXTENSION;
02092    
02093    /* Do a search for matching extension */
02094 
02095    eroot = NULL;
02096    score.total_specificity = 0;
02097    score.exten = 0;
02098    score.total_length = 0;
02099    if (!tmp->pattern_tree && tmp->root_table)
02100    {
02101       create_match_char_tree(tmp);
02102 #ifdef NEED_DEBUG
02103       ast_log(LOG_DEBUG,"Tree Created in context %s:\n", context);
02104       log_match_char_tree(tmp->pattern_tree," ");
02105 #endif
02106    }
02107 #ifdef NEED_DEBUG
02108    ast_log(LOG_NOTICE,"The Trie we are searching in:\n");
02109    log_match_char_tree(tmp->pattern_tree, "::  ");
02110 #endif
02111 
02112    if (extenpatternmatchnew) {
02113       new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
02114       eroot = score.exten;
02115       
02116       if (score.last_char == '!' && action == E_MATCHMORE) {
02117          /* We match an extension ending in '!'.
02118           * The decision in this case is final and is NULL (no match).
02119           */
02120 #ifdef NEED_DEBUG_HERE
02121          ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
02122 #endif
02123          return NULL;
02124       }
02125       
02126       if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
02127          q->status = STATUS_SUCCESS;
02128 #ifdef NEED_DEBUG_HERE
02129          ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
02130 #endif
02131          return score.canmatch_exten;
02132       }
02133       
02134       if ((action == E_MATCHMORE || action == E_CANMATCH)  && eroot) {
02135          if (score.node) {
02136             struct ast_exten *z = trie_find_next_match(score.node);
02137             if (z) {
02138 #ifdef NEED_DEBUG_HERE
02139                ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
02140 #endif
02141             } else {
02142                if (score.canmatch_exten) {
02143 #ifdef NEED_DEBUG_HERE
02144                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
02145 #endif
02146                   return score.canmatch_exten;
02147                } else {
02148 #ifdef NEED_DEBUG_HERE
02149                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
02150 #endif
02151                }
02152             }
02153             return z;
02154          }
02155 #ifdef NEED_DEBUG_HERE
02156          ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
02157 #endif
02158          return NULL;  /* according to the code, complete matches are null matches in MATCHMORE mode */
02159       }
02160       
02161       if (eroot) {
02162          /* found entry, now look for the right priority */
02163          if (q->status < STATUS_NO_PRIORITY)
02164             q->status = STATUS_NO_PRIORITY;
02165          e = NULL;
02166          if (action == E_FINDLABEL && label ) {
02167             if (q->status < STATUS_NO_LABEL)
02168                q->status = STATUS_NO_LABEL;
02169             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02170          } else {
02171             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02172          }
02173          if (e) { /* found a valid match */
02174             q->status = STATUS_SUCCESS;
02175             q->foundcontext = context;
02176 #ifdef NEED_DEBUG_HERE
02177             ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
02178 #endif
02179             return e;
02180          }
02181       }
02182    } else {   /* the old/current default exten pattern match algorithm */
02183       
02184       /* scan the list trying to match extension and CID */
02185       eroot = NULL;
02186       while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
02187          int match = extension_match_core(eroot->exten, exten, action);
02188          /* 0 on fail, 1 on match, 2 on earlymatch */
02189          
02190          if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
02191             continue;   /* keep trying */
02192          if (match == 2 && action == E_MATCHMORE) {
02193             /* We match an extension ending in '!'.
02194              * The decision in this case is final and is NULL (no match).
02195              */
02196             return NULL;
02197          }
02198          /* found entry, now look for the right priority */
02199          if (q->status < STATUS_NO_PRIORITY)
02200             q->status = STATUS_NO_PRIORITY;
02201          e = NULL;
02202          if (action == E_FINDLABEL && label ) {
02203             if (q->status < STATUS_NO_LABEL)
02204                q->status = STATUS_NO_LABEL;
02205             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02206          } else {
02207             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02208          }
02209 #ifdef NOTNOW
02210          while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
02211             /* Match label or priority */
02212             if (action == E_FINDLABEL) {
02213                if (q->status < STATUS_NO_LABEL)
02214                   q->status = STATUS_NO_LABEL;
02215                if (label && e->label && !strcmp(label, e->label))
02216                   break;   /* found it */
02217             } else if (e->priority == priority) {
02218                break;   /* found it */
02219             } /* else keep searching */
02220          }
02221 #endif
02222          if (e) { /* found a valid match */
02223             q->status = STATUS_SUCCESS;
02224             q->foundcontext = context;
02225             return e;
02226          }
02227       }
02228    }
02229    
02230    
02231    /* Check alternative switches */
02232    AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
02233       struct ast_switch *asw = pbx_findswitch(sw->name);
02234       ast_switch_f *aswf = NULL;
02235       char *datap;
02236 
02237       if (!asw) {
02238          ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
02239          continue;
02240       }
02241       /* Substitute variables now */
02242       
02243       if (sw->eval) {
02244          if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02245             ast_log(LOG_WARNING, "Can't evaluate switch?!");
02246             continue;
02247          }
02248          pbx_substitute_variables_helper(chan, sw->data, tmpdata->str, tmpdata->len);
02249       }
02250 
02251       /* equivalent of extension_match_core() at the switch level */
02252       if (action == E_CANMATCH)
02253          aswf = asw->canmatch;
02254       else if (action == E_MATCHMORE)
02255          aswf = asw->matchmore;
02256       else /* action == E_MATCH */
02257          aswf = asw->exists;
02258       datap = sw->eval ? tmpdata->str : sw->data;
02259       if (!aswf)
02260          res = 0;
02261       else {
02262          if (chan)
02263             ast_autoservice_start(chan);
02264          res = aswf(chan, context, exten, priority, callerid, datap);
02265          if (chan)
02266             ast_autoservice_stop(chan);
02267       }
02268       if (res) {  /* Got a match */
02269          q->swo = asw;
02270          q->data = datap;
02271          q->foundcontext = context;
02272          /* XXX keep status = STATUS_NO_CONTEXT ? */
02273          return NULL;
02274       }
02275    }
02276    q->incstack[q->stacklen++] = tmp->name;   /* Setup the stack */
02277    /* Now try any includes we have in this context */
02278    for (i = tmp->includes; i; i = i->next) {
02279       if (include_valid(i)) {
02280          if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
02281 #ifdef NEED_DEBUG_HERE
02282             ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
02283 #endif
02284             return e;
02285          }
02286          if (q->swo)
02287             return NULL;
02288       }
02289    }
02290    return NULL;
02291 }

struct ast_app* pbx_findapp ( const char *  app  ) 

Look up an application.

Parameters:
app name of the app
This function searches for the ast_app structure within the apps that are registered for the one with the name you passed in.

Returns:
the ast_app structure that matches on success, or NULL on failure

Definition at line 966 of file pbx.c.

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

Referenced by answer_exec_run(), ast_bridge_call(), ast_pbx_run_app(), async_wait(), builtin_automixmonitor(), builtin_automonitor(), conf_run(), dial_exec_full(), dundi_exec(), exec_exec(), execif_exec(), feature_exec_app(), forward_message(), handle_exec(), handle_gosub(), iax2_exec(), lua_pbx_exec(), milliwatt_exec(), page_exec(), pbx_builtin_execiftime(), pbx_extension_helper(), and tryexec_exec().

00967 {
00968    struct ast_app *tmp;
00969 
00970    AST_RWLIST_RDLOCK(&apps);
00971    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
00972       if (!strcasecmp(tmp->name, app))
00973          break;
00974    }
00975    AST_RWLIST_UNLOCK(&apps);
00976 
00977    return tmp;
00978 }

static struct ast_switch* pbx_findswitch ( const char *  sw  )  [static]

Definition at line 980 of file pbx.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_switch::list, and ast_switch::name.

Referenced by pbx_find_extension().

00981 {
00982    struct ast_switch *asw;
00983 
00984    AST_RWLIST_RDLOCK(&switches);
00985    AST_RWLIST_TRAVERSE(&switches, asw, list) {
00986       if (!strcasecmp(asw->name, sw))
00987          break;
00988    }
00989    AST_RWLIST_UNLOCK(&switches);
00990 
00991    return asw;
00992 }

static int pbx_parseable_goto ( struct ast_channel chan,
const char *  goto_string,
int  async 
) [static]

Definition at line 8635 of file pbx.c.

References ast_async_goto(), ast_explicit_goto(), ast_findlabel_extension(), ast_log(), ast_strdupa, ast_strlen_zero(), chan, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, exten, LOG_WARNING, ast_channel::priority, and strsep().

Referenced by ast_async_parseable_goto(), and ast_parseable_goto().

08636 {
08637    char *exten, *pri, *context;
08638    char *stringp;
08639    int ipri;
08640    int mode = 0;
08641 
08642    if (ast_strlen_zero(goto_string)) {
08643       ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
08644       return -1;
08645    }
08646    stringp = ast_strdupa(goto_string);
08647    context = strsep(&stringp, ","); /* guaranteed non-null */
08648    exten = strsep(&stringp, ",");
08649    pri = strsep(&stringp, ",");
08650    if (!exten) {  /* Only a priority in this one */
08651       pri = context;
08652       exten = NULL;
08653       context = NULL;
08654    } else if (!pri) {   /* Only an extension and priority in this one */
08655       pri = exten;
08656       exten = context;
08657       context = NULL;
08658    }
08659    if (*pri == '+') {
08660       mode = 1;
08661       pri++;
08662    } else if (*pri == '-') {
08663       mode = -1;
08664       pri++;
08665    }
08666    if (sscanf(pri, "%d", &ipri) != 1) {
08667       if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
08668          pri, chan->cid.cid_num)) < 1) {
08669          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
08670          return -1;
08671       } else
08672          mode = 0;
08673    }
08674    /* At this point we have a priority and maybe an extension and a context */
08675 
08676    if (mode)
08677       ipri = chan->priority + (ipri * mode);
08678 
08679    if (async)
08680       ast_async_goto(chan, context, exten, ipri);
08681    else
08682       ast_explicit_goto(chan, context, exten, ipri);
08683    
08684    return 0;
08685 
08686 }

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.

Note:
See also

Definition at line 2373 of file pbx.c.

References ARRAY_LEN, ast_channel_lock, ast_channel_unlock, ast_config_AST_SYSTEM_NAME, ast_copy_string(), ast_get_hint(), AST_LIST_TRAVERSE, ast_rwlock_rdlock(), ast_rwlock_unlock(), 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_channel::exten, globals, globalslock, ast_channel::hangupcause, ast_channel::name, parse_variable_name(), ast_channel::priority, s, substring(), and ast_channel::uniqueid.

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

02374 {
02375    const char not_found = '\0';
02376    char *tmpvar;
02377    const char *s; /* the result */
02378    int offset, length;
02379    int i, need_substring;
02380    struct varshead *places[2] = { headp, &globals };  /* list of places where we may look */
02381 
02382    if (c) {
02383       ast_channel_lock(c);
02384       places[0] = &c->varshead;
02385    }
02386    /*
02387     * Make a copy of var because parse_variable_name() modifies the string.
02388     * Then if called directly, we might need to run substring() on the result;
02389     * remember this for later in 'need_substring', 'offset' and 'length'
02390     */
02391    tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
02392    need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
02393 
02394    /*
02395     * Look first into predefined variables, then into variable lists.
02396     * Variable 's' points to the result, according to the following rules:
02397     * s == &not_found (set at the beginning) means that we did not find a
02398     * matching variable and need to look into more places.
02399     * If s != &not_found, s is a valid result string as follows:
02400     * s = NULL if the variable does not have a value;
02401     * you typically do this when looking for an unset predefined variable.
02402     * s = workspace if the result has been assembled there;
02403     * typically done when the result is built e.g. with an snprintf(),
02404     * so we don't need to do an additional copy.
02405     * s != workspace in case we have a string, that needs to be copied
02406     * (the ast_copy_string is done once for all at the end).
02407     * Typically done when the result is already available in some string.
02408     */
02409    s = &not_found;   /* default value */
02410    if (c) { /* This group requires a valid channel */
02411       /* Names with common parts are looked up a piece at a time using strncmp. */
02412       if (!strncmp(var, "CALL", 4)) {
02413          if (!strncmp(var + 4, "ING", 3)) {
02414             if (!strcmp(var + 7, "PRES")) {        /* CALLINGPRES */
02415                snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
02416                s = workspace;
02417             } else if (!strcmp(var + 7, "ANI2")) {    /* CALLINGANI2 */
02418                snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
02419                s = workspace;
02420             } else if (!strcmp(var + 7, "TON")) {     /* CALLINGTON */
02421                snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
02422                s = workspace;
02423             } else if (!strcmp(var + 7, "TNS")) {     /* CALLINGTNS */
02424                snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
02425                s = workspace;
02426             }
02427          }
02428       } else if (!strcmp(var, "HINT")) {
02429          s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
02430       } else if (!strcmp(var, "HINTNAME")) {
02431          s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
02432       } else if (!strcmp(var, "EXTEN")) {
02433          s = c->exten;
02434       } else if (!strcmp(var, "CONTEXT")) {
02435          s = c->context;
02436       } else if (!strcmp(var, "PRIORITY")) {
02437          snprintf(workspace, workspacelen, "%d", c->priority);
02438          s = workspace;
02439       } else if (!strcmp(var, "CHANNEL")) {
02440          s = c->name;
02441       } else if (!strcmp(var, "UNIQUEID")) {
02442          s = c->uniqueid;
02443       } else if (!strcmp(var, "HANGUPCAUSE")) {
02444          snprintf(workspace, workspacelen, "%d", c->hangupcause);
02445          s = workspace;
02446       }
02447    }
02448    if (s == &not_found) { /* look for more */
02449       if (!strcmp(var, "EPOCH")) {
02450          snprintf(workspace, workspacelen, "%u",(int)time(NULL));
02451          s = workspace;
02452       } else if (!strcmp(var, "SYSTEMNAME")) {
02453          s = ast_config_AST_SYSTEM_NAME;
02454       }
02455    }
02456    /* if not found, look into chanvars or global vars */
02457    for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
02458       struct ast_var_t *variables;
02459       if (!places[i])
02460          continue;
02461       if (places[i] == &globals)
02462          ast_rwlock_rdlock(&globalslock);
02463       AST_LIST_TRAVERSE(places[i], variables, entries) {
02464          if (!strcasecmp(ast_var_name(variables), var)) {
02465             s = ast_var_value(variables);
02466             break;
02467          }
02468       }
02469       if (places[i] == &globals)
02470          ast_rwlock_unlock(&globalslock);
02471    }
02472    if (s == &not_found || s == NULL)
02473       *ret = NULL;
02474    else {
02475       if (s != workspace)
02476          ast_copy_string(workspace, s, workspacelen);
02477       *ret = workspace;
02478       if (need_substring)
02479          *ret = substring(*ret, offset, length, workspace, workspacelen);
02480    }
02481 
02482    if (c)
02483       ast_channel_unlock(c);
02484 }

int pbx_set_autofallthrough ( int  newval  ) 

Set "autofallthrough" flag, if newval is <0, does not acutally set. If set to 1, sets to auto fall through. If newval set to 0, sets to no auto fall through (reads extension instead). Returns previous value.

Definition at line 4036 of file pbx.c.

Referenced by pbx_load_module().

04037 {
04038    int oldval = autofallthrough;
04039    autofallthrough = newval;
04040    return oldval;
04041 }

int pbx_set_extenpatternmatchnew ( int  newval  ) 

Set "extenpatternmatchnew" flag, if newval is <0, does not acutally set. If set to 1, sets to use the new Trie-based pattern matcher. If newval set to 0, sets to use the old linear-search algorithm. Returns previous value.

Definition at line 4043 of file pbx.c.

Referenced by handle_set_extenpatternmatchnew(), handle_unset_extenpatternmatchnew(), and pbx_load_module().

04044 {
04045    int oldval = extenpatternmatchnew;
04046    extenpatternmatchnew = newval;
04047    return oldval;
04048 }

static void pbx_substitute_variables ( char *  passdata,
int  datalen,
struct ast_channel c,
struct ast_exten e 
) [static]

Definition at line 3021 of file pbx.c.

References ast_copy_string(), ast_exten::data, and pbx_substitute_variables_helper().

Referenced by pbx_extension_helper().

03022 {
03023    const char *tmp;
03024 
03025    /* Nothing more to do */
03026    if (!e->data)
03027       return;
03028 
03029    /* No variables or expressions in e->data, so why scan it? */
03030    if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
03031       ast_copy_string(passdata, e->data, datalen);
03032       return;
03033    }
03034 
03035    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
03036 }

void pbx_substitute_variables_helper ( struct ast_channel c,
const char *  cp1,
char *  cp2,
int  count 
)

Definition at line 3011 of file pbx.c.

References pbx_substitute_variables_helper_full(), and ast_channel::varshead.

Referenced by _macro_exec(), acf_import(), acf_odbc_read(), acf_odbc_write(), config_curl(), custom_log(), cut_internal(), destroy_curl(), exec_exec(), function_eval(), function_fieldqty(), get_mapping_weight(), handle_cli_rpt_lstats(), handle_getvariablefull(), launch_monitor_thread(), make_email_file(), manager_log(), pbx_builtin_importvar(), pbx_find_extension(), pbx_load_config(), pbx_substitute_variables(), realtime_curl(), realtime_multi_curl(), rotate_file(), sendmail(), sendpage(), sqlite3_log(), store_curl(), substituted(), tryexec_exec(), and update_curl().

03012 {
03013    pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
03014 }

static void pbx_substitute_variables_helper_full ( struct ast_channel c,
struct varshead headp,
const char *  cp1,
char *  cp2,
int  count 
) [static]

Definition at line 2819 of file pbx.c.

References ast_channel_alloc, ast_channel_free(), ast_copy_string(), ast_debug, ast_expr(), ast_func_read(), ast_log(), ast_strlen_zero(), len(), LOG_ERROR, LOG_WARNING, parse_variable_name(), pbx_retrieve_variable(), substring(), var, VAR_BUF_SIZE, and ast_channel::varshead.

Referenced by pbx_substitute_variables_helper(), and pbx_substitute_variables_varshead().

02820 {
02821    /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
02822    char *cp4;
02823    const char *tmp, *whereweare;
02824    int length, offset, offset2, isfunction;
02825    char *workspace = NULL;
02826    char *ltmp = NULL, *var = NULL;
02827    char *nextvar, *nextexp, *nextthing;
02828    char *vars, *vare;
02829    int pos, brackets, needsub, len;
02830    
02831    *cp2 = 0; /* just in case nothing ends up there */
02832    whereweare=tmp=cp1;
02833    while (!ast_strlen_zero(whereweare) && count) {
02834       /* Assume we're copying the whole remaining string */
02835       pos = strlen(whereweare);
02836       nextvar = NULL;
02837       nextexp = NULL;
02838       nextthing = strchr(whereweare, '$');
02839       if (nextthing) {
02840          switch (nextthing[1]) {
02841          case '{':
02842             nextvar = nextthing;
02843             pos = nextvar - whereweare;
02844             break;
02845          case '[':
02846             nextexp = nextthing;
02847             pos = nextexp - whereweare;
02848             break;
02849          default:
02850             pos = 1;
02851          }
02852       }
02853 
02854       if (pos) {
02855          /* Can't copy more than 'count' bytes */
02856          if (pos > count)
02857             pos = count;
02858 
02859          /* Copy that many bytes */
02860          memcpy(cp2, whereweare, pos);
02861 
02862          count -= pos;
02863          cp2 += pos;
02864          whereweare += pos;
02865          *cp2 = 0;
02866       }
02867 
02868       if (nextvar) {
02869          /* We have a variable.  Find the start and end, and determine
02870             if we are going to have to recursively call ourselves on the
02871             contents */
02872          vars = vare = nextvar + 2;
02873          brackets = 1;
02874          needsub = 0;
02875 
02876          /* Find the end of it */
02877          while (brackets && *vare) {
02878             if ((vare[0] == '$') && (vare[1] == '{')) {
02879                needsub++;
02880             } else if (vare[0] == '{') {
02881                brackets++;
02882             } else if (vare[0] == '}') {
02883                brackets--;
02884             } else if ((vare[0] == '$') && (vare[1] == '['))
02885                needsub++;
02886             vare++;
02887          }
02888          if (brackets)
02889             ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
02890          len = vare - vars - 1;
02891 
02892          /* Skip totally over variable string */
02893          whereweare += (len + 3);
02894 
02895          if (!var)
02896             var = alloca(VAR_BUF_SIZE);
02897 
02898          /* Store variable name (and truncate) */
02899          ast_copy_string(var, vars, len + 1);
02900 
02901          /* Substitute if necessary */
02902          if (needsub) {
02903             if (!ltmp)
02904                ltmp = alloca(VAR_BUF_SIZE);
02905 
02906             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
02907             vars = ltmp;
02908          } else {
02909             vars = var;
02910          }
02911 
02912          if (!workspace)
02913             workspace = alloca(VAR_BUF_SIZE);
02914 
02915          workspace[0] = '\0';
02916 
02917          parse_variable_name(vars, &offset, &offset2, &isfunction);
02918          if (isfunction) {
02919             /* Evaluate function */
02920             if (c || !headp)
02921                cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
02922             else {
02923                struct varshead old;
02924                struct ast_channel *c = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
02925                if (c) {
02926                   memcpy(&old, &c->varshead, sizeof(old));
02927                   memcpy(&c->varshead, headp, sizeof(c->varshead));
02928                   cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
02929                   /* Don't deallocate the varshead that was passed in */
02930                   memcpy(&c->varshead, &old, sizeof(c->varshead));
02931                   ast_channel_free(c);
02932                } else
02933                   ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
02934             }
02935             ast_debug(1, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
02936          } else {
02937             /* Retrieve variable value */
02938             pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
02939          }
02940          if (cp4) {
02941             cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
02942 
02943             length = strlen(cp4);
02944             if (length > count)
02945                length = count;
02946             memcpy(cp2, cp4, length);
02947             count -= length;
02948             cp2 += length;
02949             *cp2 = 0;
02950          }
02951       } else if (nextexp) {
02952          /* We have an expression.  Find the start and end, and determine
02953             if we are going to have to recursively call ourselves on the
02954             contents */
02955          vars = vare = nextexp + 2;
02956          brackets = 1;
02957          needsub = 0;
02958 
02959          /* Find the end of it */
02960          while (brackets && *vare) {
02961             if ((vare[0] == '$') && (vare[1] == '[')) {
02962                needsub++;
02963                brackets++;
02964                vare++;
02965             } else if (vare[0] == '[') {
02966                brackets++;
02967             } else if (vare[0] == ']') {
02968                brackets--;
02969             } else if ((vare[0] == '$') && (vare[1] == '{')) {
02970                needsub++;
02971                vare++;
02972             }
02973             vare++;
02974          }
02975          if (brackets)
02976             ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
02977          len = vare - vars - 1;
02978 
02979          /* Skip totally over expression */
02980          whereweare += (len + 3);
02981 
02982          if (!var)
02983             var = alloca(VAR_BUF_SIZE);
02984 
02985          /* Store variable name (and truncate) */
02986          ast_copy_string(var, vars, len + 1);
02987 
02988          /* Substitute if necessary */
02989          if (needsub) {
02990             if (!ltmp)
02991                ltmp = alloca(VAR_BUF_SIZE);
02992 
02993             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
02994             vars = ltmp;
02995          } else {
02996             vars = var;
02997          }
02998 
02999          length = ast_expr(vars, cp2, count, c);
03000 
03001          if (length) {
03002             ast_debug(1, "Expression result is '%s'\n", cp2);
03003             count -= length;
03004             cp2 += length;
03005             *cp2 = 0;
03006          }
03007       }
03008    }
03009 }

void pbx_substitute_variables_varshead ( struct varshead headp,
const char *  cp1,
char *  cp2,
int  count 
)

Definition at line 3016 of file pbx.c.

References pbx_substitute_variables_helper_full().

Referenced by ast_add_extension2_lockopt(), build_user_routes(), dundi_lookup_local(), loopback_subst(), phoneprov_callback(), and pp_each_user_exec().

03017 {
03018    pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
03019 }

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

Definition at line 3964 of file pbx.c.

References __ast_pbx_run(), and decrease_call_count().

Referenced by ast_pbx_start().

03965 {
03966    /* Oh joyeous kernel, we're a new thread, with nothing to do but
03967       answer this channel and get it going.
03968    */
03969    /* NOTE:
03970       The launcher of this function _MUST_ increment 'countcalls'
03971       before invoking the function; it will be decremented when the
03972       PBX has finished running on the channel
03973     */
03974    struct ast_channel *c = data;
03975 
03976    __ast_pbx_run(c, NULL);
03977    decrease_call_count();
03978 
03979    pthread_exit(NULL);
03980 
03981    return NULL;
03982 }

static void print_ext ( struct ast_exten e,
char *  buf,
int  buflen 
) [static]

helper function to print an extension

Definition at line 4918 of file pbx.c.

References ast_get_extension_app(), ast_get_extension_app_data(), ast_get_extension_priority(), ast_strlen_zero(), and PRIORITY_HINT.

Referenced by show_dialplan_helper().

04919 {
04920    int prio = ast_get_extension_priority(e);
04921    if (prio == PRIORITY_HINT) {
04922       snprintf(buf, buflen, "hint: %s",
04923          ast_get_extension_app(e));
04924    } else {
04925       snprintf(buf, buflen, "%d. %s(%s)",
04926          prio, ast_get_extension_app(e),
04927          (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
04928    }
04929 }

static void set_ext_pri ( struct ast_channel c,
const char *  exten,
int  pri 
) [static]

helper function to set extension and priority

Definition at line 3620 of file pbx.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_channel::exten, and ast_channel::priority.

Referenced by __ast_pbx_run(), ast_pbx_outgoing_exten(), pbx_builtin_raise_exception(), and pbx_builtin_waitexten().

03621 {
03622    ast_channel_lock(c);
03623    ast_copy_string(c->exten, exten, sizeof(c->exten));
03624    c->priority = pri;
03625    ast_channel_unlock(c);
03626 }

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]

Definition at line 4932 of file pbx.c.

References ast_cli(), ast_extension_match(), ast_get_context_name(), ast_get_context_registrar(), ast_get_extension_label(), ast_get_extension_name(), ast_get_extension_registrar(), ast_get_ignorepat_name(), ast_get_ignorepat_registrar(), ast_get_include_name(), ast_get_include_registrar(), ast_get_switch_data(), ast_get_switch_name(), ast_get_switch_registrar(), ast_log(), AST_MAX_EXTENSION, AST_PBX_MAX_STACK, ast_rdlock_context(), ast_rdlock_contexts(), ast_unlock_context(), ast_unlock_contexts(), ast_walk_context_extensions(), ast_walk_context_ignorepats(), ast_walk_context_includes(), ast_walk_context_switches(), ast_walk_contexts(), ast_walk_extension_priorities(), buf, ast_exten::cidmatch, cli_match_char_tree(), dialplan_counters::context_existence, el, dialplan_counters::extension_existence, LOG_WARNING, ast_exten::matchcid, option_debug, ast_context::pattern_tree, print_ext(), dialplan_counters::total_context, dialplan_counters::total_exten, and dialplan_counters::total_prio.

Referenced by handle_show_dialplan().

04933 {
04934    struct ast_context *c = NULL;
04935    int res = 0, old_total_exten = dpc->total_exten;
04936 
04937    ast_rdlock_contexts();
04938 
04939    /* walk all contexts ... */
04940    while ( (c = ast_walk_contexts(c)) ) {
04941       struct ast_exten *e;
04942       struct ast_include *i;
04943       struct ast_ignorepat *ip;
04944       char buf[256], buf2[256];
04945       int context_info_printed = 0;
04946 
04947       if (context && strcmp(ast_get_context_name(c), context))
04948          continue;   /* skip this one, name doesn't match */
04949 
04950       dpc->context_existence = 1;
04951 
04952       ast_rdlock_context(c);
04953 
04954       /* are we looking for exten too? if yes, we print context
04955        * only if we find our extension.
04956        * Otherwise print context even if empty ?
04957        * XXX i am not sure how the rinclude is handled.
04958        * I think it ought to go inside.
04959        */
04960       if (!exten) {
04961          dpc->total_context++;
04962          ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
04963             ast_get_context_name(c), ast_get_context_registrar(c));
04964          context_info_printed = 1;
04965       }
04966 
04967       /* walk extensions ... */
04968       e = NULL;
04969       while ( (e = ast_walk_context_extensions(c, e)) ) {
04970          struct ast_exten *p;
04971 
04972          if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
04973             continue;   /* skip, extension match failed */
04974 
04975          dpc->extension_existence = 1;
04976 
04977          /* may we print context info? */
04978          if (!context_info_printed) {
04979             dpc->total_context++;
04980             if (rinclude) { /* TODO Print more info about rinclude */
04981                ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
04982                   ast_get_context_name(c), ast_get_context_registrar(c));
04983             } else {
04984                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
04985                   ast_get_context_name(c), ast_get_context_registrar(c));
04986             }
04987             context_info_printed = 1;
04988          }
04989          dpc->total_prio++;
04990 
04991          /* write extension name and first peer */
04992          if (e->matchcid)
04993             snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
04994          else
04995             snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
04996 
04997          print_ext(e, buf2, sizeof(buf2));
04998 
04999          ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
05000             ast_get_extension_registrar(e));
05001 
05002          dpc->total_exten++;
05003          /* walk next extension peers */
05004          p = e;   /* skip the first one, we already got it */
05005          while ( (p = ast_walk_extension_priorities(e, p)) ) {
05006             const char *el = ast_get_extension_label(p);
05007             dpc->total_prio++;
05008             if (el)
05009                snprintf(buf, sizeof(buf), "   [%s]", el);
05010             else
05011                buf[0] = '\0';
05012             print_ext(p, buf2, sizeof(buf2));
05013 
05014             ast_cli(fd,"  %-17s %-45s [%s]\n", buf, buf2,
05015                ast_get_extension_registrar(p));
05016          }
05017       }
05018 
05019       /* walk included and write info ... */
05020       i = NULL;
05021       while ( (i = ast_walk_context_includes(c, i)) ) {
05022          snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
05023          if (exten) {
05024             /* Check all includes for the requested extension */
05025             if (includecount >= AST_PBX_MAX_STACK) {
05026                ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
05027             } else {
05028                int dupe = 0;
05029                int x;
05030                for (x = 0; x < includecount; x++) {
05031                   if (!strcasecmp(includes[x], ast_get_include_name(i))) {
05032                      dupe++;
05033                      break;
05034                   }
05035                }
05036                if (!dupe) {
05037                   includes[includecount] = ast_get_include_name(i);
05038                   show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
05039                } else {
05040                   ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
05041                }
05042             }
05043          } else {
05044             ast_cli(fd, "  Include =>        %-45s [%s]\n",
05045                buf, ast_get_include_registrar(i));
05046          }
05047       }
05048 
05049       /* walk ignore patterns and write info ... */
05050       ip = NULL;
05051       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05052          const char *ipname = ast_get_ignorepat_name(ip);
05053          char ignorepat[AST_MAX_EXTENSION];
05054          snprintf(buf, sizeof(buf), "'%s'", ipname);
05055          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05056          if (!exten || ast_extension_match(ignorepat, exten)) {
05057             ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
05058                buf, ast_get_ignorepat_registrar(ip));
05059          }
05060       }
05061       if (!rinclude) {
05062          struct ast_sw *sw = NULL;
05063          while ( (sw = ast_walk_context_switches(c, sw)) ) {
05064             snprintf(buf, sizeof(buf), "'%s/%s'",
05065                ast_get_switch_name(sw),
05066                ast_get_switch_data(sw));
05067             ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
05068                buf, ast_get_switch_registrar(sw));
05069          }
05070       }
05071       
05072       if (option_debug && c->pattern_tree)
05073       {
05074          ast_cli(fd,"\n     In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
05075 
05076          ast_cli(fd,"\n           Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
05077          ast_cli(fd,    "                        Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
05078          ast_cli(fd,    "                              <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
05079          ast_cli(fd,    "                              <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
05080          ast_cli(fd,    "                              [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
05081          ast_cli(fd,    "                        In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
05082          ast_cli(fd,    "                        are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
05083          cli_match_char_tree(c->pattern_tree, " ", fd);
05084       }
05085 
05086       ast_unlock_context(c);
05087 
05088       /* if we print something in context, make an empty line */
05089       if (context_info_printed)
05090          ast_cli(fd, "\n");
05091    }
05092    ast_unlock_contexts();
05093 
05094    return (dpc->total_exten == old_total_exten) ? -1 : res;
05095 }

static int statechange_queue ( const char *  dev  )  [static]

Definition at line 3322 of file pbx.c.

References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), device_state, and statechange::entry.

Referenced by device_state_cb().

03323 {
03324    struct statechange *sc;
03325 
03326    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
03327       return 0;
03328 
03329    strcpy(sc->dev, dev);
03330 
03331    ast_mutex_lock(&device_state.lock);
03332    AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
03333    ast_cond_signal(&device_state.cond);
03334    ast_mutex_unlock(&device_state.lock);
03335 
03336    return 0;
03337 }

static char* substring ( const char *  value,
int  offset,
int  length,
char *  workspace,
size_t  workspace_len 
) [static]

takes a substring. It is ok to call with value == workspace.

Parameters:
value 
offset < 0 means start from the end of the string and set the beginning to be that many characters back.
length is the length of the substring, a value less than 0 means to leave that many off the end.
workspace 
workspace_len Always return a copy in workspace.

Definition at line 2331 of file pbx.c.

References ast_copy_string().

Referenced by pbx_retrieve_variable(), and pbx_substitute_variables_helper_full().

02332 {
02333    char *ret = workspace;
02334    int lr;  /* length of the input string after the copy */
02335 
02336    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
02337 
02338    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
02339 
02340    /* Quick check if no need to do anything */
02341    if (offset == 0 && length >= lr) /* take the whole string */
02342       return ret;
02343 
02344    if (offset < 0)   {  /* translate negative offset into positive ones */
02345       offset = lr + offset;
02346       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
02347          offset = 0;
02348    }
02349 
02350    /* too large offset result in empty string so we know what to return */
02351    if (offset >= lr)
02352       return ret + lr;  /* the final '\0' */
02353 
02354    ret += offset;    /* move to the start position */
02355    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
02356       ret[length] = '\0';
02357    else if (length < 0) {
02358       if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
02359          ret[lr + length - offset] = '\0';
02360       else
02361          ret[0] = '\0';
02362    }
02363 
02364    return ret;
02365 }

static struct ast_exten* trie_find_next_match ( struct match_char node  )  [static]

Definition at line 1174 of file pbx.c.

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

Referenced by pbx_find_extension().

01175 {
01176    struct match_char *m3;
01177    struct match_char *m4;
01178    struct ast_exten *e3;
01179    
01180    if (node && node->x[0] == '.' && !node->x[1]) /* dot and ! will ALWAYS be next match in a matchmore */
01181       return node->exten;
01182    
01183    if (node && node->x[0] == '!' && !node->x[1])
01184       return node->exten;
01185    
01186    if (!node || !node->next_char)
01187       return NULL;
01188    
01189    m3 = node->next_char;
01190 
01191    if (m3->exten)
01192       return m3->exten;
01193    for(m4=m3->alt_char; m4; m4 = m4->alt_char) {
01194       if (m4->exten)
01195          return m4->exten;
01196    }
01197    for(m4=m3; m4; m4 = m4->alt_char) {
01198       e3 = trie_find_next_match(m3);
01199       if (e3)
01200          return e3;
01201    }
01202    return NULL;
01203 }

static void unreference_cached_app ( struct ast_app app  )  [static]

Definition at line 5536 of file pbx.c.

References app, ast_rdlock_contexts(), ast_unlock_contexts(), ast_walk_context_extensions(), ast_walk_contexts(), ast_walk_extension_priorities(), and context.

Referenced by ast_unregister_application().

05537 {
05538    struct ast_context *context = NULL;
05539    struct ast_exten *eroot = NULL, *e = NULL;
05540 
05541    ast_rdlock_contexts();
05542    while ((context = ast_walk_contexts(context))) {
05543       while ((eroot = ast_walk_context_extensions(context, eroot))) {
05544          while ((e = ast_walk_extension_priorities(eroot, e))) {
05545             if (e->cached_app == app)
05546                e->cached_app = NULL;
05547          }
05548       }
05549    }
05550    ast_unlock_contexts();
05551 
05552    return;
05553 }

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]

Definition at line 1081 of file pbx.c.

References ast_log(), exten, scoreboard::exten, scoreboard::last_char, LOG_NOTICE, scoreboard::node, scoreboard::total_length, and scoreboard::total_specificity.

Referenced by new_find_extension().

01082 {
01083    /* if this extension is marked as deleted, then skip this -- if it never shows
01084       on the scoreboard, it will never be found, nor will halt the traversal. */
01085    if (deleted)
01086       return;
01087    board->total_specificity = spec;
01088    board->total_length = length;
01089    board->exten = exten;
01090    board->last_char = last;
01091    board->node = node;
01092 #ifdef NEED_DEBUG_HERE
01093    ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
01094 #endif
01095 }

static void wait_for_hangup ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 7544 of file pbx.c.

References ast_frfree, ast_read(), ast_safe_sleep(), ast_strlen_zero(), ast_waitfor(), chan, and f.

Referenced by pbx_builtin_busy(), and pbx_builtin_congestion().

07545 {
07546    int res;
07547    struct ast_frame *f;
07548    double waitsec;
07549    int waittime;
07550 
07551    if (ast_strlen_zero(data) || (sscanf(data, "%lg", &waitsec) != 1) || (waitsec < 0))
07552       waitsec = -1;
07553    if (waitsec > -1) {
07554       waittime = waitsec * 1000.0;
07555       ast_safe_sleep(chan, waittime);
07556    } else do {
07557       res = ast_waitfor(chan, -1);
07558       if (res < 0)
07559          return;
07560       f = ast_read(chan);
07561       if (f)
07562          ast_frfree(f);
07563    } while(f);
07564 }


Variable Documentation

int autofallthrough = 1 [static]

Definition at line 438 of file pbx.c.

struct ast_app_option background_opts[128] = { [ 's' ] = { .flag = (1 << 0) }, [ 'n' ] = { .flag = (1 << 1) }, [ 'm' ] = { .flag = (1 << 2) }, [ 'p' ] = { .flag = (1 << 3) },} [static]

Definition at line 113 of file pbx.c.

Referenced by pbx_builtin_background().

struct pbx_builtin builtins[] [static]

Declaration of builtin applications.

Referenced by load_pbx().

ast_cond_t cond

Condition for the state change queue

Definition at line 282 of file pbx.c.

ast_rwlock_t conlock = PTHREAD_RWLOCK_INITIALIZER [static]

Lock for the ast_context list

Definition at line 727 of file pbx.c.

Referenced by ast_rdlock_contexts(), ast_unlock_contexts(), and ast_wrlock_contexts().

int conlock_wrlock_version = 0 [static]

Definition at line 8390 of file pbx.c.

struct ast_context* contexts [static]

Definition at line 724 of file pbx.c.

Referenced by __ast_context_destroy(), ast_context_destroy(), ast_context_find_or_create(), ast_merge_contexts_and_delete(), and ast_walk_contexts().

struct ast_hashtab* contexts_table = NULL [static]

Definition at line 725 of file pbx.c.

Referenced by ast_context_destroy(), ast_context_find(), ast_context_find_or_create(), ast_context_lockmacro(), ast_context_unlockmacro(), ast_merge_contexts_and_delete(), find_context_locked(), and pbx_find_extension().

int countcalls [static]

Definition at line 445 of file pbx.c.

char* days[] [static]

Definition at line 6081 of file pbx.c.

Referenced by ast_build_timing().

struct { ... } device_state [static]

Data used by the device state thread.

Referenced by device_state_thread(), load_module(), load_pbx(), statechange_queue(), and unload_module().

struct ast_event_sub* device_state_sub [static]

Subscription for device state change events.

Definition at line 442 of file pbx.c.

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

struct ast_custom_function exception_function [static]

Definition at line 2551 of file pbx.c.

Referenced by load_pbx().

struct ast_datastore_info exception_store_info [static]

Initial value:

 {
   .type = "EXCEPTION",
   .destroy = exception_store_free,
}

Definition at line 2493 of file pbx.c.

Referenced by acf_exception_read(), and pbx_builtin_raise_exception().

int extenpatternmatchnew = 0 [static]

Definition at line 439 of file pbx.c.

struct cfextension_states extension_states[] [static]

Referenced by ast_extension_state2str().

struct statechange* first

Definition at line 284 of file pbx.c.

struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE [static]

Definition at line 436 of file pbx.c.

Referenced by ast_add_extension2_lockopt(), handle_show_globals(), load_config(), load_module(), pbx_builtin_clear_globals(), pbx_builtin_getvar_helper(), pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), pbx_retrieve_variable(), set_active(), set_pvt_defaults(), store_config_core(), and unload_module().

ast_rwlock_t globalslock = PTHREAD_RWLOCK_INITIALIZER [static]

Definition at line 435 of file pbx.c.

Referenced by ast_add_extension2_lockopt(), handle_show_globals(), pbx_builtin_clear_globals(), pbx_builtin_getvar_helper(), pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), and pbx_retrieve_variable().

struct statechange* last

Definition at line 284 of file pbx.c.

ast_mutex_t lock

Lock for the state change queue

Definition at line 280 of file pbx.c.

char mandescr_show_dialplan[] [static]

Definition at line 5363 of file pbx.c.

ast_mutex_t maxcalllock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]

Definition at line 444 of file pbx.c.

Referenced by decrease_call_count(), and increase_call_count().

char* months[] [static]

Definition at line 6093 of file pbx.c.

Referenced by ast_build_timing().

struct ast_cli_entry pbx_cli[] [static]

Definition at line 5520 of file pbx.c.

Referenced by load_pbx().

struct ast_app_option resetcdr_opts[128] = { [ 'w' ] = { .flag = (1 << 1) }, [ 'a' ] = { .flag = (1 << 2) }, [ 'v' ] = { .flag = (1 << 0) }, [ 'e' ] = { .flag = (1 << 10) },} [static]

Definition at line 7645 of file pbx.c.

Referenced by pbx_builtin_resetcdr().

struct { ... } state_change_q

Queue of state changes

struct ast_state_cb* statecbs

Definition at line 741 of file pbx.c.

Referenced by ast_extension_state_add(), ast_extension_state_del(), and handle_statechange().

int stateid = 1 [static]

Definition at line 733 of file pbx.c.

unsigned int stop

Set to 1 to stop the thread

Definition at line 276 of file pbx.c.

Referenced by controlplayback_exec(), handle_controlstreamfile(), and queue_exec().

struct ast_threadstorage switch_data = { .once = PTHREAD_ONCE_INIT, .key_init = __init_switch_data , .custom_init = NULL , } [static]

Definition at line 126 of file pbx.c.

Referenced by pbx_find_extension().

pthread_t thread

The device state monitoring thread

Definition at line 278 of file pbx.c.

Referenced by __schedule_action(), __unload_module(), ast_bridge_call_thread_launch(), find_idle_thread(), handle_cli_iax2_show_threads(), handle_deferred_full_frames(), iax2_process_thread(), iax2_process_thread_cleanup(), insert_idle_thread(), launch_monitor_thread(), load_module(), socket_process(), socket_read(), start_network_thread(), and unload_module().

int totalcalls [static]

Definition at line 446 of file pbx.c.

Referenced by timing_read().

struct ast_app_option waitexten_opts[128] = { [ 'm' ] = { .flag = (1 << 0) , .arg_index = 0 + 1 }, [ 'd' ] = { .flag = (1 << 1) , .arg_index = 0 + 1 },} [static]

Definition at line 121 of file pbx.c.

Referenced by pbx_builtin_waitexten().


Generated on Thu Jul 9 13:41:26 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7