Tue Mar 2 17:34:05 2010

Asterisk developer's documentation


pbx.c File Reference

Core PBX routines. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/callerid.h"
#include "asterisk/cdr.h"
#include "asterisk/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"
#include "asterisk/taskprocessor.h"
Include dependency graph for pbx.c:

Go to the source code of this file.

Data Structures

struct  app_tmp
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  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

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 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)
 Main interface to add extensions to the list for out context.
static int ast_add_extension2_lockopt (struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, int lockconts, int lockhints)
 Does all the work of ast_add_extension2, but adds two args, to determine if context and hint locking should be done. In merge_and_delete, we need to do this without locking, as the locks are already held.
static int ast_add_extension_nolock (const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
static int ast_add_hint (struct ast_exten *e)
 Add hint to hint list, check initial extension state.
static int ast_add_hint_nolock (struct ast_exten *e)
 Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already!
 AST_APP_OPTIONS (resetcdr_opts,{AST_APP_OPTION('w', AST_CDR_FLAG_POSTED), AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED), AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS), AST_APP_OPTION('e', AST_CDR_FLAG_POST_ENABLE),})
 AST_APP_OPTIONS (waitexten_opts,{AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0), AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),})
 AST_APP_OPTIONS (background_opts,{AST_APP_OPTION('s', BACKGROUND_SKIP), AST_APP_OPTION('n', BACKGROUND_NOANSWER), AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN), AST_APP_OPTION('p', BACKGROUND_PLAYBACK),})
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).
struct ast_contextast_context_find (const char *name)
 Find a context.
struct ast_contextast_context_find_or_create (struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
 Register a new context or find an existing one.
int ast_context_lockmacro (const char *context)
 locks the macrolock in the given given context
int ast_context_remove_extension (const char *context, const char *extension, int priority, const char *registrar)
 Simply remove extension from context.
int ast_context_remove_extension2 (struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
 This functionc locks given context, search for the right extension and fires out all peer in this extensions with given priority. If priority is set to 0, all peers are removed. After that, unlock context and return.
int ast_context_remove_extension_callerid (const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
int ast_context_remove_extension_callerid2 (struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar, int already_locked)
int ast_context_remove_ignorepat (const char *context, const char *ignorepat, const char *registrar)
int ast_context_remove_ignorepat2 (struct ast_context *con, const char *ignorepat, const char *registrar)
int ast_context_remove_include (const char *context, const char *include, const char *registrar)
 Remove included contexts. This function locks contexts list by &conlist, search for the right context structure, leave context list locked and call ast_context_remove_include2 which removes include, unlock contexts list and return ...
int ast_context_remove_include2 (struct ast_context *con, const char *include, const char *registrar)
 Locks context, remove included contexts, unlocks context. When we call this function, &conlock lock must be locked, because when we giving *con argument, some process can remove/change this context and after that there can be segfault.
int ast_context_remove_switch (const char *context, const char *sw, const char *data, const char *registrar)
 Remove a switch.
int ast_context_remove_switch2 (struct ast_context *con, const char *sw, const char *data, const char *registrar)
 This function locks given context, removes switch, unlock context and return.
int ast_context_unlockmacro (const char *context)
 Unlocks the macrolock in the given context.
int ast_context_verify_includes (struct ast_context *con)
 Verifies includes in an ast_contect structure.
struct ast_custom_functionast_custom_function_find (const char *name)
int ast_custom_function_unregister (struct ast_custom_function *acf)
 Unregister a custom function.
enum ast_extension_states ast_devstate_to_extenstate (enum ast_device_state devstate)
 Map devstate to an extension state.
int ast_exists_extension (struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
 Determine whether an extension exists.
int ast_explicit_goto (struct ast_channel *chan, const char *context, const char *exten, int priority)
int ast_extension_close (const char *pattern, const char *data, int needmore)
int ast_extension_cmp (const char *a, const char *b)
 Determine if one extension should match before another.
int ast_extension_match (const char *pattern, const char *data)
 Determine if a given extension matches a given pattern (in NXX format).
int ast_extension_state (struct ast_channel *c, const char *context, const char *exten)
 Check extension state for an extension by using hint.
static int ast_extension_state2 (struct ast_exten *e)
 Check state of extension by using hints.
const char * ast_extension_state2str (int extension_state)
 Return extension_state as string.
int ast_extension_state_add (const char *context, const char *exten, ast_state_cb_type callback, void *data)
 Add watcher for extension states.
int ast_extension_state_del (int id, ast_state_cb_type callback)
 Remove a watcher from the callback list.
int ast_findlabel_extension (struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
 Find the priority of an extension that has the specified label.
int ast_findlabel_extension2 (struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
 Find the priority of an extension that has the specified label.
int ast_func_read (struct ast_channel *chan, const char *function, char *workspace, size_t len)
 executes a read operation on a function
int ast_func_write (struct ast_channel *chan, const char *function, const char *value)
 executes a write operation on a function
const char * ast_get_context_name (struct ast_context *con)
const char * ast_get_context_registrar (struct ast_context *c)
const char * ast_get_extension_app (struct ast_exten *e)
void * ast_get_extension_app_data (struct ast_exten *e)
const char * ast_get_extension_cidmatch (struct ast_exten *e)
struct ast_contextast_get_extension_context (struct ast_exten *exten)
const char * ast_get_extension_label (struct ast_exten *exten)
int ast_get_extension_matchcid (struct ast_exten *e)
const char * ast_get_extension_name (struct ast_exten *exten)
int ast_get_extension_priority (struct ast_exten *exten)
const char * ast_get_extension_registrar (struct ast_exten *e)
int ast_get_hint (char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
 Get hint for channel.
const char * ast_get_ignorepat_name (struct ast_ignorepat *ip)
const char * ast_get_ignorepat_registrar (struct ast_ignorepat *ip)
const char * ast_get_include_name (struct ast_include *inc)
const char * ast_get_include_registrar (struct ast_include *i)
const char * ast_get_switch_data (struct ast_sw *sw)
int ast_get_switch_eval (struct ast_sw *sw)
const char * ast_get_switch_name (struct ast_sw *sw)
const char * ast_get_switch_registrar (struct ast_sw *sw)
int ast_goto_if_exists (struct ast_channel *chan, const char *context, const char *exten, int priority)
int ast_hashtab_compare_contexts (const void *ah_a, const void *ah_b)
unsigned int ast_hashtab_hash_contexts (const void *obj)
static struct ast_extenast_hint_extension (struct ast_channel *c, const char *context, const char *exten)
static struct ast_extenast_hint_extension_nolock (struct ast_channel *c, const char *context, const char *exten)
 Find hint for given extension in context.
int ast_ignore_pattern (const char *context, const char *pattern)
 Checks to see if a number should be ignored.
 AST_LIST_HEAD (store_hints, store_hint)
static AST_LIST_HEAD_NOLOCK_STATIC (statecbs, ast_state_cb)
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.
 AST_MUTEX_DEFINE_STATIC (maxcalllock)
int ast_parseable_goto (struct ast_channel *chan, const char *goto_string)
int ast_pbx_outgoing_app (const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
static int ast_pbx_outgoing_cdr_failed (void)
 Function to post an empty cdr after a spool call fails.
int ast_pbx_outgoing_exten (const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
enum ast_pbx_result ast_pbx_run (struct ast_channel *c)
 Execute the PBX in the current thread.
static void * ast_pbx_run_app (void *data)
 run the application and free the descriptor once done
enum ast_pbx_result ast_pbx_run_args (struct ast_channel *c, struct ast_pbx_args *args)
 Execute the PBX in the current thread.
enum ast_pbx_result ast_pbx_start (struct ast_channel *c)
 Create a new thread and start the PBX.
int ast_processed_calls (void)
 Retrieve the total number of calls processed through the PBX since last restart.
int ast_rdlock_context (struct ast_context *con)
 Read locks a given context.
int ast_rdlock_contexts ()
 Read locks the context list.
int ast_register_application2 (const char *app, int(*execute)(struct ast_channel *, void *), const char *synopsis, const char *description, void *mod)
 Dynamically register a new dial plan application.
int ast_register_switch (struct ast_switch *sw)
 Register an alternative dialplan switch.
static int ast_remove_hint (struct ast_exten *e)
 Remove hint from extension.
static AST_RWLIST_HEAD_STATIC (hints, ast_hint)
static AST_RWLIST_HEAD_STATIC (switches, ast_switch)
static AST_RWLIST_HEAD_STATIC (apps, ast_app)
static AST_RWLIST_HEAD_STATIC (acf_root, ast_custom_function)
 AST_RWLOCK_DEFINE_STATIC (conlock)
 AST_RWLOCK_DEFINE_STATIC (globalslock)
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).
 AST_THREADSTORAGE (switch_data)
int ast_unlock_context (struct ast_context *con)
int ast_unlock_contexts ()
 Unlocks contexts.
int ast_unregister_application (const char *app)
 Unregister an application.
void ast_unregister_switch (struct ast_switch *sw)
 Unregister an alternative switch.
struct ast_extenast_walk_context_extensions (struct ast_context *con, struct ast_exten *exten)
struct ast_ignorepatast_walk_context_ignorepats (struct ast_context *con, struct ast_ignorepat *ip)
struct ast_includeast_walk_context_includes (struct ast_context *con, struct ast_include *inc)
struct ast_swast_walk_context_switches (struct ast_context *con, struct ast_sw *sw)
struct ast_contextast_walk_contexts (struct ast_context *con)
struct ast_extenast_walk_extension_priorities (struct ast_exten *exten, struct ast_exten *priority)
int ast_wrlock_context (struct ast_context *con)
 Write locks a given context.
int ast_wrlock_contexts ()
 Write locks the context list.
int ast_wrlock_contexts_version (void)
static void * async_wait (void *data)
static void cli_match_char_tree (struct match_char *node, char *prefix, int fd)
static int collect_digits (struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
 collect digits from the channel into the buffer.
static int compare_char (const void *a, const void *b)
static char * complete_core_show_hint (const char *line, const char *word, int pos, int state)
 autocomplete for CLI command 'core show hint'
static char * complete_show_dialplan_context (const char *line, const char *word, int pos, int state)
static void context_merge (struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
static void context_merge_incls_swits_igps_other_registrars (struct ast_context *new, struct ast_context *old, const char *registrar)
static void create_match_char_tree (struct ast_context *con)
static void decrease_call_count (void)
static void destroy_exten (struct ast_exten *e)
static void destroy_pattern_tree (struct match_char *pattern_tree)
static void device_state_cb (const struct ast_event *event, void *unused)
static void exception_store_free (void *data)
static int ext_cmp (const char *a, const char *b)
 the full routine to compare extensions in rules.
static int ext_cmp1 (const char **p, unsigned char *bitwise)
 helper functions to sort extensions and patterns in the desired way, so that more specific patterns appear first.
static int ext_strncpy (char *dst, const char *src, int len)
 copy a string skipping whitespace
static int extension_match_core (const char *pattern, const char *data, enum ext_match_t mode)
static struct ast_contextfind_context (const char *context)
 lookup for a context with a given name,
static struct ast_contextfind_context_locked (const char *context)
 lookup for a context with a given name,
static char * func_args (char *function)
 return a pointer to the arguments of the function, and terminates the function name with '\0'
static struct ast_extenget_canmatch_exten (struct match_char *node)
static unsigned get_range (char *src, int max, 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_debug_dialplan (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Send ack once.
static char * handle_set_chanvar (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_set_chanvar_deprecated (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_set_global_deprecated (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_application (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_applications (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_chanvar (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI support for listing chanvar's variables in a parseable way.
static char * handle_show_dialplan (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_function (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_functions (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_globals (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI support for listing global variables in a parseable way.
static char * handle_show_globals_deprecated (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_hint (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 handle_show_hint: CLI support for listing registered dial plan hint
static char * handle_show_hints (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 handle_show_hints: CLI support for listing registered dial plan hints
static char * handle_show_switches (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 handle_show_switches: CLI support for listing registered dial plan switches
static int handle_statechange (void *datap)
static char * handle_unset_extenpatternmatchnew (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int hashtab_compare_exten_labels (const void *ah_a, const void *ah_b)
static int hashtab_compare_exten_numbers (const void *ah_a, const void *ah_b)
static int hashtab_compare_extens (const void *ha_a, const void *ah_b)
static unsigned int hashtab_hash_extens (const void *obj)
static unsigned int hashtab_hash_labels (const void *obj)
static unsigned int hashtab_hash_priority (const void *obj)
static int include_valid (struct ast_include *i)
static int increase_call_count (const struct ast_channel *c)
 Increase call count for channel.
static void insert_in_next_chars_alt_char_list (struct match_char **parent_ptr, struct match_char *node)
int load_pbx (void)
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_incomplete (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:.
struct ast_extenpbx_find_extension (struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
struct ast_apppbx_findapp (const char *app)
 Find application handle in linked list.
static struct ast_switchpbx_findswitch (const char *sw)
static int pbx_parseable_goto (struct ast_channel *chan, const char *goto_string, int async)
void pbx_retrieve_variable (struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
 Support for Asterisk built-in variables in the dialplan.
int pbx_set_autofallthrough (int newval)
int pbx_set_extenpatternmatchnew (int newval)
void pbx_set_overrideswitch (const char *newval)
static void pbx_substitute_variables (char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
void pbx_substitute_variables_helper (struct ast_channel *c, const char *cp1, char *cp2, int count)
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_debug_helper (int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
static int show_dialplan_helper (int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
static char * substring (const char *value, int offset, int length, char *workspace, size_t workspace_len)
 takes a substring. It is ok to call with value == workspace.
static struct ast_extentrie_find_next_match (struct match_char *node)
static void unreference_cached_app (struct ast_app *app)
static void update_scoreboard (struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
static void wait_for_hangup (struct ast_channel *chan, void *data)

Variables

static int autofallthrough = 1
static struct pbx_builtin builtins []
 Declaration of builtin applications.
static struct ast_cli_entry cli_set_chanvar_deprecated = AST_CLI_DEFINE(handle_set_chanvar_deprecated, "Set a channel variable.")
static struct ast_cli_entry cli_set_global_deprecated = AST_CLI_DEFINE(handle_set_global_deprecated, "Set global dialplan variable.")
static struct ast_cli_entry cli_show_globals_deprecated = AST_CLI_DEFINE(handle_show_globals_deprecated, "Show global dialplan variables.")
static int conlock_wrlock_version = 0
static struct ast_contextcontexts
static struct ast_hashtabcontexts_table = NULL
static int countcalls
static char * days []
static struct ast_event_subdevice_state_sub
 Subscription for device state change events.
static struct ast_taskprocessordevice_state_tps
static struct ast_custom_function exception_function
static struct ast_datastore_info exception_store_info
static int extenpatternmatchnew = 0
static struct cfextension_states extension_states []
static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
static char mandescr_show_dialplan []
static char * months []
static char * overrideswitch = NULL
static struct ast_cli_entry pbx_cli []
static int stateid = 1
static int totalcalls

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

Referenced by handle_debug_dialplan(), 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(), and realtime_exec().

#define NEW_MATCHER_CHK_MATCH

Referenced by new_find_extension().

#define NEW_MATCHER_RECURSE

Referenced by new_find_extension().

#define SAY_STUBS

Definition at line 54 of file pbx.c.

#define STATUS_NO_CONTEXT   1

Definition at line 2051 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_NO_EXTENSION   2

Definition at line 2052 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_NO_LABEL   4

Definition at line 2054 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_NO_PRIORITY   3

Definition at line 2053 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_SUCCESS   5

Definition at line 2055 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
#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 7718 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, ast_exten::exten, ast_context::ignorepats, ast_context::includes, ast_include::next, ast_ignorepat::next, ast_context::next, ast_exten::peer_table, ast_exten::priority, ast_context::refcount, ast_exten::registrar, ast_sw::registrar, ast_include::registrar, ast_ignorepat::registrar, ast_context::registrar, ast_context::root, and ast_context::root_table.

Referenced by ast_context_destroy().

07719 {
07720    struct ast_context *tmp, *tmpl=NULL;
07721    struct ast_exten *exten_item, *prio_item;
07722 
07723    for (tmp = list; tmp; ) {
07724       struct ast_context *next = NULL; /* next starting point */
07725          /* The following code used to skip forward to the next
07726             context with matching registrar, but this didn't
07727             make sense; individual priorities registrar'd to 
07728             the matching registrar could occur in any context! */
07729       ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
07730       if (con) {
07731          for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
07732             ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
07733             if ( !strcasecmp(tmp->name, con->name) ) {
07734                break;   /* found it */
07735             }
07736          }
07737       }
07738       
07739       if (!tmp)   /* not found, we are done */
07740          break;
07741       ast_wrlock_context(tmp);
07742 
07743       if (registrar) {
07744          /* then search thru and remove any extens that match registrar. */
07745          struct ast_hashtab_iter *exten_iter;
07746          struct ast_hashtab_iter *prio_iter;
07747          struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
07748          struct ast_include *i, *pi = NULL, *ni = NULL;
07749          struct ast_sw *sw = NULL;
07750 
07751          /* remove any ignorepats whose registrar matches */
07752          for (ip = tmp->ignorepats; ip; ip = ipn) {
07753             ipn = ip->next;
07754             if (!strcmp(ip->registrar, registrar)) {
07755                if (ipl) {
07756                   ipl->next = ip->next;
07757                   ast_free(ip);
07758                   continue; /* don't change ipl */
07759                } else {
07760                   tmp->ignorepats = ip->next;
07761                   ast_free(ip);
07762                   continue; /* don't change ipl */
07763                }
07764             }
07765             ipl = ip;
07766          }
07767          /* remove any includes whose registrar matches */
07768          for (i = tmp->includes; i; i = ni) {
07769             ni = i->next;
07770             if (strcmp(i->registrar, registrar) == 0) {
07771                /* remove from list */
07772                if (pi) {
07773                   pi->next = i->next;
07774                   /* free include */
07775                   ast_free(i);
07776                   continue; /* don't change pi */
07777                } else {
07778                   tmp->includes = i->next;
07779                   /* free include */
07780                   ast_free(i);
07781                   continue; /* don't change pi */
07782                }
07783             }
07784             pi = i;
07785          }
07786          /* remove any switches whose registrar matches */
07787          AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
07788             if (strcmp(sw->registrar,registrar) == 0) {
07789                AST_LIST_REMOVE_CURRENT(list);
07790                ast_free(sw);
07791             }
07792          }
07793          AST_LIST_TRAVERSE_SAFE_END;
07794 
07795          if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
07796             exten_iter = ast_hashtab_start_traversal(tmp->root_table);
07797             while ((exten_item=ast_hashtab_next(exten_iter))) {
07798                prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
07799                while ((prio_item=ast_hashtab_next(prio_iter))) {
07800                   if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
07801                      continue;
07802                   }
07803                   ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
07804                          tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
07805                   /* set matchcid to 1 to insure we get a direct match, and NULL registrar to make sure no wildcarding is done */
07806                   ast_context_remove_extension_callerid2(tmp, prio_item->exten, prio_item->priority, prio_item->cidmatch, 1, NULL, 1);
07807                }
07808                ast_hashtab_end_traversal(prio_iter);
07809             }
07810             ast_hashtab_end_traversal(exten_iter);
07811          }
07812    
07813          /* delete the context if it's registrar matches, is empty, has refcount of 1, */
07814          /* it's not empty, if it has includes, ignorepats, or switches that are registered from
07815             another registrar. It's not empty if there are any extensions */
07816          if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
07817             ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
07818             ast_hashtab_remove_this_object(contexttab, tmp);
07819             
07820             next = tmp->next;
07821             if (tmpl)
07822                tmpl->next = next;
07823             else
07824                contexts = next;
07825             /* Okay, now we're safe to let it go -- in a sense, we were
07826                ready to let it go as soon as we locked it. */
07827             ast_unlock_context(tmp);
07828             __ast_internal_context_destroy(tmp);
07829          } else {
07830             ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
07831                     tmp->refcount, tmp->root);
07832             ast_unlock_context(tmp);
07833             next = tmp->next;
07834             tmpl = tmp;
07835          }
07836       } else if (con) {
07837          ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
07838          ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
07839          ast_hashtab_remove_this_object(contexttab, tmp);
07840          
07841          next = tmp->next;
07842          if (tmpl)
07843             tmpl->next = next;
07844          else
07845             contexts = next;
07846          /* Okay, now we're safe to let it go -- in a sense, we were
07847             ready to let it go as soon as we locked it. */
07848          ast_unlock_context(tmp);
07849          __ast_internal_context_destroy(tmp);
07850       }
07851 
07852       /* if we have a specific match, we are done, otherwise continue */
07853       tmp = con ? NULL : next;
07854    }
07855 }

int __ast_custom_function_register ( struct ast_custom_function acf,
struct ast_module mod 
)

Register a custom function.

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

02812 {
02813    struct ast_custom_function *cur;
02814    char tmps[80];
02815 
02816    if (!acf)
02817       return -1;
02818 
02819    acf->mod = mod;
02820 
02821    AST_RWLIST_WRLOCK(&acf_root);
02822 
02823    AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
02824       if (!strcmp(acf->name, cur->name)) {
02825          ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
02826          AST_RWLIST_UNLOCK(&acf_root);
02827          return -1;
02828       }
02829    }
02830 
02831    /* Store in alphabetical order */
02832    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
02833       if (strcasecmp(acf->name, cur->name) < 0) {
02834          AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
02835          break;
02836       }
02837    }
02838    AST_RWLIST_TRAVERSE_SAFE_END;
02839    if (!cur)
02840       AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
02841 
02842    AST_RWLIST_UNLOCK(&acf_root);
02843 
02844    ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02845 
02846    return 0;
02847 }

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

Definition at line 8968 of file pbx.c.

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

08969 {
08970    int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
08971 
08972    if (!chan)
08973       return -2;
08974 
08975    if (context == NULL)
08976       context = chan->context;
08977    if (exten == NULL)
08978       exten = chan->exten;
08979 
08980    goto_func = (async) ? ast_async_goto : ast_explicit_goto;
08981    if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
08982       return goto_func(chan, context, exten, priority);
08983    else
08984       return -3;
08985 }

static void __ast_internal_context_destroy ( struct ast_context con  )  [static]

Definition at line 7671 of file pbx.c.

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

07672 {
07673    struct ast_include *tmpi;
07674    struct ast_sw *sw;
07675    struct ast_exten *e, *el, *en;
07676    struct ast_ignorepat *ipi;
07677    struct ast_context *tmp = con;
07678    
07679    for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
07680       struct ast_include *tmpil = tmpi;
07681       tmpi = tmpi->next;
07682       ast_free(tmpil);
07683    }
07684    for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
07685       struct ast_ignorepat *ipl = ipi;
07686       ipi = ipi->next;
07687       ast_free(ipl);
07688    }
07689    if (tmp->registrar)
07690       ast_free(tmp->registrar);
07691    
07692    /* destroy the hash tabs */
07693    if (tmp->root_table) {
07694       ast_hashtab_destroy(tmp->root_table, 0);
07695    }
07696    /* and destroy the pattern tree */
07697    if (tmp->pattern_tree)
07698       destroy_pattern_tree(tmp->pattern_tree);
07699    
07700    while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
07701       ast_free(sw);
07702    for (e = tmp->root; e;) {
07703       for (en = e->peer; en;) {
07704          el = en;
07705          en = en->peer;
07706          destroy_exten(el);
07707       }
07708       el = e;
07709       e = e->next;
07710       destroy_exten(el);
07711    }
07712    tmp->root = NULL;
07713    ast_rwlock_destroy(&tmp->lock);
07714    ast_free(tmp);
07715 }

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

Note:
We get here on a failure of some kind: non-existing extension or hangup. We have options, here. We can either catch the failure and continue, or we can drop out entirely.
If there is no match at priority 1, it is not a valid extension anymore. Try to continue at "i" (for invalid) or "e" (for exception) or exit if neither exist.

Definition at line 3716 of file pbx.c.

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

Referenced by ast_pbx_run_args(), and pbx_thread().

03718 {
03719    int found = 0; /* set if we find at least one match */
03720    int res = 0;
03721    int autoloopflag;
03722    int error = 0;    /* set an error conditions */
03723 
03724    /* A little initial setup here */
03725    if (c->pbx) {
03726       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
03727       /* XXX and now what ? */
03728       ast_free(c->pbx);
03729    }
03730    if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
03731       return -1;
03732    /* Set reasonable defaults */
03733    c->pbx->rtimeoutms = 10000;
03734    c->pbx->dtimeoutms = 5000;
03735 
03736    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);   /* save value to restore at the end */
03737    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
03738 
03739    /* Start by trying whatever the channel is set to */
03740    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03741       /* If not successful fall back to 's' */
03742       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);
03743       /* XXX the original code used the existing priority in the call to
03744        * ast_exists_extension(), and reset it to 1 afterwards.
03745        * I believe the correct thing is to set it to 1 immediately.
03746        */
03747       set_ext_pri(c, "s", 1);
03748       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03749          /* JK02: And finally back to default if everything else failed */
03750          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);
03751          ast_copy_string(c->context, "default", sizeof(c->context));
03752       }
03753    }
03754    for (;;) {
03755       char dst_exten[256]; /* buffer to accumulate digits */
03756       int pos = 0;      /* XXX should check bounds */
03757       int digit = 0;
03758       int invalid = 0;
03759       int timeout = 0;
03760 
03761       /* loop on priorities in this context/exten */
03762       while ( !(res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found,1))) {
03763          if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03764             set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
03765             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03766             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03767             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03768          } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03769             pbx_builtin_raise_exception(c, "ABSOLUTETIMEOUT");
03770             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03771             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03772             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03773          } else if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03774             c->_softhangup = 0;
03775             continue;
03776          } else if (ast_check_hangup(c)) {
03777             ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
03778                c->exten, c->priority);
03779             error = 1;
03780             break;
03781          }
03782          c->priority++;
03783       } /* end while  - from here on we can use 'break' to go out */
03784       if (found && res) {
03785          /* Something bad happened, or a hangup has been requested. */
03786          if (strchr("0123456789ABCDEF*#", res)) {
03787             ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
03788             pos = 0;
03789             dst_exten[pos++] = digit = res;
03790             dst_exten[pos] = '\0';
03791          } else if (res == AST_PBX_INCOMPLETE) {
03792             ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
03793             ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
03794 
03795             /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
03796             if (!ast_matchmore_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
03797                invalid = 1;
03798             } else {
03799                ast_copy_string(dst_exten, c->exten, sizeof(dst_exten));
03800                digit = 1;
03801                pos = strlen(dst_exten);
03802             }
03803          } else {
03804             ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03805             ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03806             
03807             if ((res == AST_PBX_ERROR) && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03808                /* if we are already on the 'e' exten, don't jump to it again */
03809                if (!strcmp(c->exten, "e")) {
03810                   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);
03811                   error = 1;
03812                } else {
03813                   pbx_builtin_raise_exception(c, "ERROR");
03814                   continue;
03815                }
03816             }
03817             
03818             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03819                c->_softhangup = 0;
03820                continue;
03821             } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03822                set_ext_pri(c, "T", 1); 
03823                /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03824                memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03825                c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03826                continue;
03827             } else {
03828                if (c->cdr)
03829                   ast_cdr_update(c);
03830                error = 1;
03831                break;
03832             }
03833          }
03834       }
03835       if (error)
03836          break;
03837 
03838       /*!\note
03839        * We get here on a failure of some kind:  non-existing extension or
03840        * hangup.  We have options, here.  We can either catch the failure
03841        * and continue, or we can drop out entirely. */
03842 
03843       if (invalid || !ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
03844          /*!\note
03845           * If there is no match at priority 1, it is not a valid extension anymore.
03846           * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
03847           * neither exist.
03848           */
03849          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03850             ast_verb(3, "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
03851             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
03852             set_ext_pri(c, "i", 1);
03853          } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03854             pbx_builtin_raise_exception(c, "INVALID");
03855          } else {
03856             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
03857                c->name, c->exten, c->context);
03858             error = 1; /* we know what to do with it */
03859             break;
03860          }
03861       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
03862          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
03863          c->_softhangup = 0;
03864       } else { /* keypress received, get more digits for a full extension */
03865          int waittime = 0;
03866          if (digit)
03867             waittime = c->pbx->dtimeoutms;
03868          else if (!autofallthrough)
03869             waittime = c->pbx->rtimeoutms;
03870          if (!waittime) {
03871             const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
03872             if (!status)
03873                status = "UNKNOWN";
03874             ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
03875             if (!strcasecmp(status, "CONGESTION"))
03876                res = pbx_builtin_congestion(c, "10");
03877             else if (!strcasecmp(status, "CHANUNAVAIL"))
03878                res = pbx_builtin_congestion(c, "10");
03879             else if (!strcasecmp(status, "BUSY"))
03880                res = pbx_builtin_busy(c, "10");
03881             error = 1; /* XXX disable message */
03882             break;   /* exit from the 'for' loop */
03883          }
03884 
03885          if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
03886             break;
03887          if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
03888             timeout = 1;
03889          if (!timeout && ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
03890             set_ext_pri(c, dst_exten, 1);
03891          else {
03892             /* No such extension */
03893             if (!timeout && !ast_strlen_zero(dst_exten)) {
03894                /* An invalid extension */
03895                if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03896                   ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
03897                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
03898                   set_ext_pri(c, "i", 1);
03899                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03900                   pbx_builtin_raise_exception(c, "INVALID");
03901                } else {
03902                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
03903                   found = 1; /* XXX disable message */
03904                   break;
03905                }
03906             } else {
03907                /* A simple timeout */
03908                if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
03909                   ast_verb(3, "Timeout on %s\n", c->name);
03910                   set_ext_pri(c, "t", 1);
03911                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03912                   pbx_builtin_raise_exception(c, "RESPONSETIMEOUT");
03913                } else {
03914                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
03915                   found = 1; /* XXX disable message */
03916                   break;
03917                }
03918             }
03919          }
03920          if (c->cdr) {
03921             ast_verb(2, "CDR updated on %s\n",c->name);
03922             ast_cdr_update(c);
03923          }
03924       }
03925    }
03926 
03927    if (!found && !error) {
03928       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
03929    }
03930 
03931    if (!args || !args->no_hangup_chan) {
03932       ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
03933    }
03934 
03935    if ((!args || !args->no_hangup_chan) &&
03936          !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) && 
03937          ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
03938       set_ext_pri(c, "h", 1);
03939       if (c->cdr && ast_opt_end_cdr_before_h_exten) {
03940          ast_cdr_end(c->cdr);
03941       }
03942       while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found, 1)) == 0) {
03943          c->priority++;
03944       }
03945       if (found && res) {
03946          /* Something bad happened, or a hangup has been requested. */
03947          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03948          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03949       }
03950    }
03951    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03952    ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
03953    pbx_destroy(c->pbx);
03954    c->pbx = NULL;
03955 
03956    if (!args || !args->no_hangup_chan) {
03957       ast_hangup(c);
03958    }
03959 
03960    return 0;
03961 }

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

Definition at line 1827 of file pbx.c.

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

Referenced by extension_match_core().

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

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

Definition at line 2628 of file pbx.c.

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

02629 {
02630    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02631    struct pbx_exception *exception = NULL;
02632    if (!ds || !ds->data)
02633       return -1;
02634    exception = ds->data;
02635    if (!strcasecmp(data, "REASON"))
02636       ast_copy_string(buf, exception->reason, buflen);
02637    else if (!strcasecmp(data, "CONTEXT"))
02638       ast_copy_string(buf, exception->context, buflen);
02639    else if (!strncasecmp(data, "EXTEN", 5))
02640       ast_copy_string(buf, exception->exten, buflen);
02641    else if (!strcasecmp(data, "PRIORITY"))
02642       snprintf(buf, buflen, "%d", exception->priority);
02643    else
02644       return -1;
02645    return 0;
02646 }

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

Definition at line 1478 of file pbx.c.

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

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

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

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

Definition at line 1437 of file pbx.c.

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

Referenced by add_exten_to_pattern_tree().

01438 {
01439    struct match_char *m;
01440    
01441    if (!(m = ast_calloc(1, sizeof(*m))))
01442       return NULL;
01443 
01444    if (!(m->x = ast_strdup(pattern))) {
01445       ast_free(m);
01446       return NULL;
01447    }
01448 
01449    /* the specificity scores are the same as used in the old
01450       pattern matcher. */
01451    m->is_pattern = is_pattern;
01452    if (specificity == 1 && is_pattern && pattern[0] == 'N')
01453       m->specificity = 0x0802;
01454    else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
01455       m->specificity = 0x0901;
01456    else if (specificity == 1 && is_pattern && pattern[0] == 'X')
01457       m->specificity = 0x0a00;
01458    else if (specificity == 1 && is_pattern && pattern[0] == '.')
01459       m->specificity = 0x10000;
01460    else if (specificity == 1 && is_pattern && pattern[0] == '!')
01461       m->specificity = 0x20000;
01462    else
01463       m->specificity = specificity;
01464    
01465    if (!con->pattern_tree) {
01466       insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
01467    } else {
01468       if (already) { /* switch to the new regime (traversing vs appending)*/
01469          insert_in_next_chars_alt_char_list(nextcharptr, m);
01470       } else {
01471          insert_in_next_chars_alt_char_list(&current->next_char, m);
01472       }
01473    }
01474 
01475    return m;
01476 }

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

References add_pri_lockopt().

Referenced by ast_add_extension2_lockopt().

06886 {
06887    return add_pri_lockopt(con, tmp, el, e, replace, 1);
06888 }

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

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

Referenced by add_pri().

06897 {
06898    struct ast_exten *ep;
06899    struct ast_exten *eh=e;
06900 
06901    for (ep = NULL; e ; ep = e, e = e->peer) {
06902       if (e->priority >= tmp->priority)
06903          break;
06904    }
06905    if (!e) {   /* go at the end, and ep is surely set because the list is not empty */
06906       ast_hashtab_insert_safe(eh->peer_table, tmp);
06907       
06908       if (tmp->label) {
06909          ast_hashtab_insert_safe(eh->peer_label_table, tmp);
06910       }
06911       ep->peer = tmp;
06912       return 0;   /* success */
06913    }
06914    if (e->priority == tmp->priority) {
06915       /* Can't have something exactly the same.  Is this a
06916          replacement?  If so, replace, otherwise, bonk. */
06917       if (!replace) {
06918          ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
06919          if (tmp->datad) {
06920             tmp->datad(tmp->data);
06921             /* if you free this, null it out */
06922             tmp->data = NULL;
06923          }
06924          
06925          ast_free(tmp);
06926          return -1;
06927       }
06928       /* we are replacing e, so copy the link fields and then update
06929        * whoever pointed to e to point to us
06930        */
06931       tmp->next = e->next; /* not meaningful if we are not first in the peer list */
06932       tmp->peer = e->peer; /* always meaningful */
06933       if (ep)  {     /* We're in the peer list, just insert ourselves */
06934          ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
06935 
06936          if (e->label) {
06937             ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
06938          }
06939          
06940          ast_hashtab_insert_safe(eh->peer_table,tmp);
06941          if (tmp->label) {
06942             ast_hashtab_insert_safe(eh->peer_label_table,tmp);
06943          }
06944          
06945          ep->peer = tmp;
06946       } else if (el) {     /* We're the first extension. Take over e's functions */
06947          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
06948          tmp->peer_table = e->peer_table;
06949          tmp->peer_label_table = e->peer_label_table;
06950          ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
06951          ast_hashtab_insert_safe(tmp->peer_table,tmp);
06952          if (e->label) {
06953             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
06954          }
06955          if (tmp->label) {
06956             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06957          }
06958          
06959          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06960          ast_hashtab_insert_safe(con->root_table, tmp);
06961          el->next = tmp;
06962          /* The pattern trie points to this exten; replace the pointer,
06963             and all will be well */
06964          if (x) { /* if the trie isn't formed yet, don't sweat this */
06965             if (x->exten) { /* this test for safety purposes */
06966                x->exten = tmp; /* replace what would become a bad pointer */
06967             } else {
06968                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
06969             }
06970          }
06971       } else {       /* We're the very first extension.  */
06972          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
06973          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06974          ast_hashtab_insert_safe(con->root_table, tmp);
06975          tmp->peer_table = e->peer_table;
06976          tmp->peer_label_table = e->peer_label_table;
06977          ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
06978          ast_hashtab_insert_safe(tmp->peer_table, tmp);
06979          if (e->label) {
06980             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
06981          }
06982          if (tmp->label) {
06983             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06984          }
06985          
06986          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06987          ast_hashtab_insert_safe(con->root_table, tmp);
06988          con->root = tmp;
06989          /* The pattern trie points to this exten; replace the pointer,
06990             and all will be well */
06991          if (x) { /* if the trie isn't formed yet; no problem */
06992             if (x->exten) { /* this test for safety purposes */
06993                x->exten = tmp; /* replace what would become a bad pointer */
06994             } else {
06995                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
06996             }
06997          }
06998       }
06999       if (tmp->priority == PRIORITY_HINT)
07000          ast_change_hint(e,tmp);
07001       /* Destroy the old one */
07002       if (e->datad)
07003          e->datad(e->data);
07004       ast_free(e);
07005    } else { /* Slip ourselves in just before e */
07006       tmp->peer = e;
07007       tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
07008       if (ep) {         /* Easy enough, we're just in the peer list */
07009          if (tmp->label) {
07010             ast_hashtab_insert_safe(eh->peer_label_table, tmp);
07011          }
07012          ast_hashtab_insert_safe(eh->peer_table, tmp);
07013          ep->peer = tmp;
07014       } else {       /* we are the first in some peer list, so link in the ext list */
07015          tmp->peer_table = e->peer_table;
07016          tmp->peer_label_table = e->peer_label_table;
07017          e->peer_table = 0;
07018          e->peer_label_table = 0;
07019          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07020          if (tmp->label) {
07021             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07022          }
07023          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07024          ast_hashtab_insert_safe(con->root_table, tmp);
07025          if (el)
07026             el->next = tmp;   /* in the middle... */
07027          else
07028             con->root = tmp; /* ... or at the head */
07029          e->next = NULL;   /* e is no more at the head, so e->next must be reset */
07030       }
07031       /* And immediately return success. */
07032       if (tmp->priority == PRIORITY_HINT) {
07033          if (lockhints) {
07034             ast_add_hint(tmp);
07035          } else {
07036             ast_add_hint_nolock(tmp);
07037          }
07038       }
07039    }
07040    return 0;
07041 }

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

Definition at line 1385 of file pbx.c.

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

Referenced by add_exten_to_pattern_tree().

01386 {
01387    struct match_char *t;
01388 
01389    if (!current)
01390       return 0;
01391 
01392    for (t = current; t; t = t->alt_char) {
01393       if (!strcmp(pat, t->x)) /* uh, we may want to sort exploded [] contents to make matching easy */
01394          return t;
01395    }
01396 
01397    return 0;
01398 }

int ast_active_calls ( void   ) 

Retrieve the number of active calls.

Definition at line 4099 of file pbx.c.

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

04100 {
04101    return countcalls;
04102 }

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

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

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

06753 {
06754    int ret = -1;
06755    struct ast_context *c = find_context_locked(context);
06756 
06757    if (c) {
06758       ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
06759          application, data, datad, registrar);
06760       ast_unlock_contexts();
06761    }
06762    
06763    return ret;
06764 }

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

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

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

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

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

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

Definition at line 7068 of file pbx.c.

References ast_add_extension2_lockopt().

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

07072 {
07073    return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
07074 }

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 7081 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_copy_string(), ast_debug, ast_hashtab_create(), ast_hashtab_insert_safe(), ast_hashtab_lookup(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), ast_log(), ast_strlen_zero(), ast_unlock_context(), ast_verb, ast_wrlock_context(), ast_exten::cidmatch, ast_channel::context, ast_exten::data, ast_exten::datad, el, errno, ext_cmp(), ext_strncpy(), ast_exten::exten, ast_channel::exten, hashtab_compare_exten_labels(), hashtab_compare_exten_numbers(), hashtab_compare_extens(), hashtab_hash_extens(), hashtab_hash_labels(), hashtab_hash_priority(), ast_exten::label, LOG_ERROR, ast_exten::matchcid, ast_exten::next, option_debug, ast_exten::parent, ast_context::pattern_tree, pbx_substitute_variables_helper(), ast_exten::peer_label_table, ast_exten::peer_table, ast_exten::priority, PRIORITY_HINT, ast_exten::registrar, ast_context::root, ast_context::root_table, ast_exten::stuff, and VAR_BUF_SIZE.

Referenced by ast_add_extension2(), and ast_add_extension_nolock().

07085 {
07086    /*
07087     * Sort extensions (or patterns) according to the rules indicated above.
07088     * These are implemented by the function ext_cmp()).
07089     * All priorities for the same ext/pattern/cid are kept in a list,
07090     * using the 'peer' field  as a link field..
07091     */
07092    struct ast_exten *tmp, *tmp2, *e, *el = NULL;
07093    int res;
07094    int length;
07095    char *p;
07096    char expand_buf[VAR_BUF_SIZE];
07097    struct ast_exten dummy_exten = {0};
07098    char dummy_name[1024];
07099 
07100    if (ast_strlen_zero(extension)) {
07101       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",
07102             con->name);
07103       return -1;
07104    }
07105    
07106    /* If we are adding a hint evalulate in variables and global variables */
07107    if (priority == PRIORITY_HINT && strstr(application, "${") && !strstr(extension, "_")) {
07108       struct ast_channel c = {0, };
07109 
07110       ast_copy_string(c.exten, extension, sizeof(c.exten));
07111       ast_copy_string(c.context, con->name, sizeof(c.context));
07112       pbx_substitute_variables_helper(&c, application, expand_buf, sizeof(expand_buf));
07113       application = expand_buf;
07114    }
07115 
07116    length = sizeof(struct ast_exten);
07117    length += strlen(extension) + 1;
07118    length += strlen(application) + 1;
07119    if (label)
07120       length += strlen(label) + 1;
07121    if (callerid)
07122       length += strlen(callerid) + 1;
07123    else
07124       length ++;  /* just the '\0' */
07125 
07126    /* Be optimistic:  Build the extension structure first */
07127    if (!(tmp = ast_calloc(1, length)))
07128       return -1;
07129 
07130    if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
07131       label = 0;
07132 
07133    /* use p as dst in assignments, as the fields are const char * */
07134    p = tmp->stuff;
07135    if (label) {
07136       tmp->label = p;
07137       strcpy(p, label);
07138       p += strlen(label) + 1;
07139    }
07140    tmp->exten = p;
07141    p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
07142    tmp->priority = priority;
07143    tmp->cidmatch = p;   /* but use p for assignments below */
07144    if (!ast_strlen_zero(callerid)) {
07145       p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
07146       tmp->matchcid = 1;
07147    } else {
07148       *p++ = '\0';
07149       tmp->matchcid = 0;
07150    }
07151    tmp->app = p;
07152    strcpy(p, application);
07153    tmp->parent = con;
07154    tmp->data = data;
07155    tmp->datad = datad;
07156    tmp->registrar = registrar;
07157 
07158    if (lockconts) {
07159       ast_wrlock_context(con);
07160    }
07161    
07162    if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
07163                         an extension, and the trie exists, then we need to incrementally add this pattern to it. */
07164       ast_copy_string(dummy_name, extension, sizeof(dummy_name));
07165       dummy_exten.exten = dummy_name;
07166       dummy_exten.matchcid = 0;
07167       dummy_exten.cidmatch = 0;
07168       tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
07169       if (!tmp2) {
07170          /* hmmm, not in the trie; */
07171          add_exten_to_pattern_tree(con, tmp, 0);
07172          ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
07173       }
07174    }
07175    res = 0; /* some compilers will think it is uninitialized otherwise */
07176    for (e = con->root; e; el = e, e = e->next) {   /* scan the extension list */
07177       res = ext_cmp(e->exten, tmp->exten);
07178       if (res == 0) { /* extension match, now look at cidmatch */
07179          if (!e->matchcid && !tmp->matchcid)
07180             res = 0;
07181          else if (tmp->matchcid && !e->matchcid)
07182             res = 1;
07183          else if (e->matchcid && !tmp->matchcid)
07184             res = -1;
07185          else
07186             res = ext_cmp(e->cidmatch, tmp->cidmatch);
07187       }
07188       if (res >= 0)
07189          break;
07190    }
07191    if (e && res == 0) { /* exact match, insert in the pri chain */
07192       res = add_pri(con, tmp, el, e, replace);
07193       if (lockconts) {
07194          ast_unlock_context(con);
07195       }
07196       if (res < 0) {
07197          errno = EEXIST;   /* XXX do we care ? */
07198          return 0; /* XXX should we return -1 maybe ? */
07199       }
07200    } else {
07201       /*
07202        * not an exact match, this is the first entry with this pattern,
07203        * so insert in the main list right before 'e' (if any)
07204        */
07205       tmp->next = e;
07206       if (el) {  /* there is another exten already in this context */
07207          el->next = tmp;
07208          tmp->peer_table = ast_hashtab_create(13,
07209                      hashtab_compare_exten_numbers,
07210                      ast_hashtab_resize_java,
07211                      ast_hashtab_newsize_java,
07212                      hashtab_hash_priority,
07213                      0);
07214          tmp->peer_label_table = ast_hashtab_create(7,
07215                         hashtab_compare_exten_labels,
07216                         ast_hashtab_resize_java,
07217                         ast_hashtab_newsize_java,
07218                         hashtab_hash_labels,
07219                         0);
07220          if (label) {
07221             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07222          }
07223          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07224       } else {  /* this is the first exten in this context */
07225          if (!con->root_table)
07226             con->root_table = ast_hashtab_create(27,
07227                                        hashtab_compare_extens,
07228                                        ast_hashtab_resize_java,
07229                                        ast_hashtab_newsize_java,
07230                                        hashtab_hash_extens,
07231                                        0);
07232          con->root = tmp;
07233          con->root->peer_table = ast_hashtab_create(13,
07234                         hashtab_compare_exten_numbers,
07235                         ast_hashtab_resize_java,
07236                         ast_hashtab_newsize_java,
07237                         hashtab_hash_priority,
07238                         0);
07239          con->root->peer_label_table = ast_hashtab_create(7,
07240                            hashtab_compare_exten_labels,
07241                            ast_hashtab_resize_java,
07242                            ast_hashtab_newsize_java,
07243                            hashtab_hash_labels,
07244                            0);
07245          if (label) {
07246             ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
07247          }
07248          ast_hashtab_insert_safe(con->root->peer_table, tmp);
07249             
07250       }
07251       ast_hashtab_insert_safe(con->root_table, tmp);
07252       if (lockconts) {
07253          ast_unlock_context(con);
07254       }
07255       if (tmp->priority == PRIORITY_HINT) {
07256          if (lockhints) {
07257             ast_add_hint(tmp);
07258          } else {
07259             ast_add_hint_nolock(tmp);
07260          }
07261       }
07262    }
07263    if (option_debug) {
07264       if (tmp->matchcid) {
07265          ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
07266                  tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
07267       } else {
07268          ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
07269                  tmp->exten, tmp->priority, con->name, con);
07270       }
07271    }
07272 
07273    if (tmp->matchcid) {
07274       ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
07275              tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
07276    } else {
07277       ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n",
07278              tmp->exten, tmp->priority, con->name, con);
07279    }
07280    
07281    return 0;
07282 }

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

Definition at line 6731 of file pbx.c.

References ast_add_extension2_lockopt(), and find_context().

Referenced by ast_merge_contexts_and_delete().

06734 {
06735    int ret = -1;
06736    struct ast_context *c = find_context(context);
06737 
06738    if (c) {
06739       ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
06740          application, data, datad, registrar, 0, 0);
06741    }
06742    
06743    return ret;
06744 }

static int ast_add_hint ( struct ast_exten e  )  [static]

Add hint to hint list, check initial extension state.

Definition at line 3563 of file pbx.c.

References ast_add_hint_nolock(), AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by add_pri_lockopt(), and ast_add_extension2_lockopt().

03564 {
03565    int ret;
03566 
03567    AST_RWLIST_WRLOCK(&hints);
03568    ret = ast_add_hint_nolock(e);
03569    AST_RWLIST_UNLOCK(&hints);
03570    
03571    return ret;
03572 }

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

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

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

03535 {
03536    struct ast_hint *hint;
03537 
03538    if (!e)
03539       return -1;
03540 
03541    /* Search if hint exists, do nothing */
03542    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03543       if (hint->exten == e) {
03544          ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03545          return -1;
03546       }
03547    }
03548 
03549    ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03550 
03551    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
03552       return -1;
03553    }
03554    /* Initialize and insert new item at the top */
03555    hint->exten = e;
03556    hint->laststate = ast_extension_state2(e);
03557    AST_RWLIST_INSERT_HEAD(&hints, hint, list);
03558 
03559    return 0;
03560 }

AST_APP_OPTIONS ( resetcdr_opts   ) 
AST_APP_OPTIONS ( waitexten_opts   ) 
AST_APP_OPTIONS ( background_opts   ) 
int ast_async_goto ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority 
)

Definition at line 6789 of file pbx.c.

References ast_channel::_state, ast_channel::amaflags, ast_cdr_discard(), ast_cdr_dup(), ast_channel_alloc, ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_explicit_goto(), ast_hangup(), ast_log(), ast_pbx_start(), AST_SOFTHANGUP_ASYNCGOTO, ast_softhangup_nolock(), ast_channel::cdr, ast_channel::context, ast_channel::exten, LOG_WARNING, 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(), sip_read(), and socket_process().

06790 {
06791    int res = 0;
06792 
06793    ast_channel_lock(chan);
06794 
06795    if (chan->pbx) { /* This channel is currently in the PBX */
06796       ast_explicit_goto(chan, context, exten, priority + 1);
06797       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
06798    } else {
06799       /* In order to do it when the channel doesn't really exist within
06800          the PBX, we have to make a new channel, masquerade, and start the PBX
06801          at the new location */
06802       struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
06803       if (!tmpchan) {
06804          res = -1;
06805       } else {
06806          if (chan->cdr) {
06807             ast_cdr_discard(tmpchan->cdr);
06808             tmpchan->cdr = ast_cdr_dup(chan->cdr);  /* share the love */
06809          }
06810          /* Make formats okay */
06811          tmpchan->readformat = chan->readformat;
06812          tmpchan->writeformat = chan->writeformat;
06813          /* Setup proper location */
06814          ast_explicit_goto(tmpchan,
06815             S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
06816 
06817          /* Masquerade into temp channel */
06818          if (ast_channel_masquerade(tmpchan, chan)) {
06819             /* Failed to set up the masquerade.  It's probably chan_local
06820              * in the middle of optimizing itself out.  Sad. :( */
06821             ast_hangup(tmpchan);
06822             tmpchan = NULL;
06823             res = -1;
06824          } else {
06825             /* Grab the locks and get going */
06826             ast_channel_lock(tmpchan);
06827             ast_do_masquerade(tmpchan);
06828             ast_channel_unlock(tmpchan);
06829             /* Start the PBX going on our stolen channel */
06830             if (ast_pbx_start(tmpchan)) {
06831                ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
06832                ast_hangup(tmpchan);
06833                res = -1;
06834             }
06835          }
06836       }
06837    }
06838    ast_channel_unlock(chan);
06839    return res;
06840 }

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

Definition at line 6842 of file pbx.c.

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

06843 {
06844    struct ast_channel *chan;
06845    int res = -1;
06846 
06847    chan = ast_get_channel_by_name_locked(channame);
06848    if (chan) {
06849       res = ast_async_goto(chan, context, exten, priority);
06850       ast_channel_unlock(chan);
06851    }
06852    return res;
06853 }

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

References __ast_goto_if_exists().

08993 {
08994    return __ast_goto_if_exists(chan, context, exten, priority, 1);
08995 }

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

References pbx_parseable_goto().

Referenced by asyncgoto_exec().

09056 {
09057    return pbx_parseable_goto(chan, goto_string, 1);
09058 }

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

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

06411 {
06412    char info_save[256];
06413    char *info;
06414 
06415    /* Check for empty just in case */
06416    if (ast_strlen_zero(info_in))
06417       return 0;
06418    /* make a copy just in case we were passed a static string */
06419    ast_copy_string(info_save, info_in, sizeof(info_save));
06420    info = info_save;
06421    /* Assume everything except time */
06422    i->monthmask = 0xfff;   /* 12 bits */
06423    i->daymask = 0x7fffffffU; /* 31 bits */
06424    i->dowmask = 0x7f; /* 7 bits */
06425    /* on each call, use strsep() to move info to the next argument */
06426    get_timerange(i, strsep(&info, "|,"));
06427    if (info)
06428       i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
06429    if (info)
06430       i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
06431    if (info)
06432       i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
06433    return 1;
06434 }

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 3661 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(), pbx_builtin_background(), phone_check_exception(), pri_dchannel(), skinny_ss(), ss_thread(), and valid_exit().

03662 {
03663    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
03664 }

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

Change hint for an extension.

Definition at line 3575 of file pbx.c.

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

Referenced by add_pri_lockopt().

03576 {
03577    struct ast_hint *hint;
03578    int res = -1;
03579 
03580    AST_RWLIST_WRLOCK(&hints);
03581    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03582       if (hint->exten == oe) {
03583             hint->exten = ne;
03584          res = 0;
03585          break;
03586       }
03587    }
03588    AST_RWLIST_UNLOCK(&hints);
03589 
03590    return res;
03591 }

int ast_check_timing ( const struct ast_timing i  ) 

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

06437 {
06438    struct ast_tm tm;
06439    struct timeval now = ast_tvnow();
06440 
06441    ast_localtime(&now, &tm, NULL);
06442 
06443    /* If it's not the right month, return */
06444    if (!(i->monthmask & (1 << tm.tm_mon)))
06445       return 0;
06446 
06447    /* If it's not that time of the month.... */
06448    /* Warning, tm_mday has range 1..31! */
06449    if (!(i->daymask & (1 << (tm.tm_mday-1))))
06450       return 0;
06451 
06452    /* If it's not the right day of the week */
06453    if (!(i->dowmask & (1 << tm.tm_wday)))
06454       return 0;
06455 
06456    /* Sanity check the hour just to be safe */
06457    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
06458       ast_log(LOG_WARNING, "Insane time...\n");
06459       return 0;
06460    }
06461 
06462    /* Now the tough part, we calculate if it fits
06463       in the right time based on min/hour */
06464    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
06465       return 0;
06466 
06467    /* If we got this far, then we're good */
06468    return 1;
06469 }

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

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

Referenced by handle_cli_dialplan_add_ignorepat().

06663 {
06664    int ret = -1;
06665    struct ast_context *c = find_context_locked(context);
06666 
06667    if (c) {
06668       ret = ast_context_add_ignorepat2(c, value, registrar);
06669       ast_unlock_contexts();
06670    }
06671    return ret;
06672 }

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

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

06675 {
06676    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
06677    int length;
06678    char *pattern;
06679    length = sizeof(struct ast_ignorepat);
06680    length += strlen(value) + 1;
06681    if (!(ignorepat = ast_calloc(1, length)))
06682       return -1;
06683    /* The cast to char * is because we need to write the initial value.
06684     * The field is not supposed to be modified otherwise.  Also, gcc 4.2
06685     * sees the cast as dereferencing a type-punned pointer and warns about
06686     * it.  This is the workaround (we're telling gcc, yes, that's really
06687     * what we wanted to do).
06688     */
06689    pattern = (char *) ignorepat->pattern;
06690    strcpy(pattern, value);
06691    ignorepat->next = NULL;
06692    ignorepat->registrar = registrar;
06693    ast_wrlock_context(con);
06694    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
06695       ignorepatl = ignorepatc;
06696       if (!strcasecmp(ignorepatc->pattern, value)) {
06697          /* Already there */
06698          ast_unlock_context(con);
06699          errno = EEXIST;
06700          return -1;
06701       }
06702    }
06703    if (ignorepatl)
06704       ignorepatl->next = ignorepat;
06705    else
06706       con->ignorepats = ignorepat;
06707    ast_unlock_context(con);
06708    return 0;
06709 
06710 }

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

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

Referenced by handle_cli_dialplan_add_include().

06217 {
06218    int ret = -1;
06219    struct ast_context *c = find_context_locked(context);
06220 
06221    if (c) {
06222       ret = ast_context_add_include2(c, include, registrar);
06223       ast_unlock_contexts();
06224    }
06225    return ret;
06226 }

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

06480 {
06481    struct ast_include *new_include;
06482    char *c;
06483    struct ast_include *i, *il = NULL; /* include, include_last */
06484    int length;
06485    char *p;
06486 
06487    length = sizeof(struct ast_include);
06488    length += 2 * (strlen(value) + 1);
06489 
06490    /* allocate new include structure ... */
06491    if (!(new_include = ast_calloc(1, length)))
06492       return -1;
06493    /* Fill in this structure. Use 'p' for assignments, as the fields
06494     * in the structure are 'const char *'
06495     */
06496    p = new_include->stuff;
06497    new_include->name = p;
06498    strcpy(p, value);
06499    p += strlen(value) + 1;
06500    new_include->rname = p;
06501    strcpy(p, value);
06502    /* Strip off timing info, and process if it is there */
06503    if ( (c = strchr(p, ',')) ) {
06504       *c++ = '\0';
06505            new_include->hastime = ast_build_timing(&(new_include->timing), c);
06506    }
06507    new_include->next      = NULL;
06508    new_include->registrar = registrar;
06509 
06510    ast_wrlock_context(con);
06511 
06512    /* ... go to last include and check if context is already included too... */
06513    for (i = con->includes; i; i = i->next) {
06514       if (!strcasecmp(i->name, new_include->name)) {
06515          ast_free(new_include);
06516          ast_unlock_context(con);
06517          errno = EEXIST;
06518          return -1;
06519       }
06520       il = i;
06521    }
06522 
06523    /* ... include new context into context list, unlock, return */
06524    if (il)
06525       il->next = new_include;
06526    else
06527       con->includes = new_include;
06528    ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
06529 
06530    ast_unlock_context(con);
06531 
06532    return 0;
06533 }

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

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

06541 {
06542    int ret = -1;
06543    struct ast_context *c = find_context_locked(context);
06544 
06545    if (c) { /* found, add switch to this context */
06546       ret = ast_context_add_switch2(c, sw, data, eval, registrar);
06547       ast_unlock_contexts();
06548    }
06549    return ret;
06550 }

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

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

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

06561 {
06562    struct ast_sw *new_sw;
06563    struct ast_sw *i;
06564    int length;
06565    char *p;
06566 
06567    length = sizeof(struct ast_sw);
06568    length += strlen(value) + 1;
06569    if (data)
06570       length += strlen(data);
06571    length++;
06572 
06573    /* allocate new sw structure ... */
06574    if (!(new_sw = ast_calloc(1, length)))
06575       return -1;
06576    /* ... fill in this structure ... */
06577    p = new_sw->stuff;
06578    new_sw->name = p;
06579    strcpy(new_sw->name, value);
06580    p += strlen(value) + 1;
06581    new_sw->data = p;
06582    if (data) {
06583       strcpy(new_sw->data, data);
06584       p += strlen(data) + 1;
06585    } else {
06586       strcpy(new_sw->data, "");
06587       p++;
06588    }
06589    new_sw->eval     = eval;
06590    new_sw->registrar = registrar;
06591 
06592    /* ... try to lock this context ... */
06593    ast_wrlock_context(con);
06594 
06595    /* ... go to last sw and check if context is already swd too... */
06596    AST_LIST_TRAVERSE(&con->alts, i, list) {
06597       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
06598          ast_free(new_sw);
06599          ast_unlock_context(con);
06600          errno = EEXIST;
06601          return -1;
06602       }
06603    }
06604 
06605    /* ... sw new context into context list, unlock, return */
06606    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
06607 
06608    ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
06609 
06610    ast_unlock_context(con);
06611 
06612    return 0;
06613 }

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

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

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

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

Find a context.

Parameters:
name name of the context to find

Will search for the context with the given name.

Returns:
the ast_context on success, NULL on failure.

Definition at line 2031 of file pbx.c.

References ast_copy_string(), ast_hashtab_lookup(), ast_rdlock_contexts(), ast_unlock_contexts(), and ast_walk_contexts().

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

02032 {
02033    struct ast_context *tmp = NULL;
02034    struct fake_context item;
02035 
02036    ast_copy_string(item.name, name, sizeof(item.name));
02037 
02038    ast_rdlock_contexts();
02039    if( contexts_table ) {
02040       tmp = ast_hashtab_lookup(contexts_table,&item);
02041    } else {
02042       while ( (tmp = ast_walk_contexts(tmp)) ) {
02043          if (!name || !strcasecmp(name, tmp->name))
02044             break;
02045       }
02046    }
02047    ast_unlock_contexts();
02048    return tmp;
02049 }

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

Register a new context or find an existing one.

Parameters:
extcontexts pointer to the ast_context structure pointer
exttable pointer to the hashtable that contains all the elements in extcontexts
name name of the new context
registrar registrar of the context

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

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

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

Definition at line 5872 of file pbx.c.

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

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

05873 {
05874    struct ast_context *tmp, **local_contexts;
05875    struct fake_context search;
05876    int length = sizeof(struct ast_context) + strlen(name) + 1;
05877 
05878    if (!contexts_table) {
05879       contexts_table = ast_hashtab_create(17,
05880                                  ast_hashtab_compare_contexts, 
05881                                  ast_hashtab_resize_java,
05882                                  ast_hashtab_newsize_java,
05883                                  ast_hashtab_hash_contexts,
05884                                  0);
05885    }
05886    
05887    ast_copy_string(search.name, name, sizeof(search.name));
05888    if (!extcontexts) {
05889       ast_rdlock_contexts();
05890       local_contexts = &contexts;
05891       tmp = ast_hashtab_lookup(contexts_table, &search);
05892       ast_unlock_contexts();
05893       if (tmp) {
05894          tmp->refcount++;
05895          return tmp;
05896       }
05897    } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
05898       local_contexts = extcontexts;
05899       tmp = ast_hashtab_lookup(exttable, &search);
05900       if (tmp) {
05901          tmp->refcount++;
05902          return tmp;
05903       }
05904    }
05905    
05906    if ((tmp = ast_calloc(1, length))) {
05907       ast_rwlock_init(&tmp->lock);
05908       ast_mutex_init(&tmp->macrolock);
05909       strcpy(tmp->name, name);
05910       tmp->root = NULL;
05911       tmp->root_table = NULL;
05912       tmp->registrar = ast_strdup(registrar);
05913       tmp->includes = NULL;
05914       tmp->ignorepats = NULL;
05915       tmp->refcount = 1;
05916    } else {
05917       ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
05918       return NULL;
05919    }
05920    
05921    if (!extcontexts) {
05922       ast_wrlock_contexts();
05923       tmp->next = *local_contexts;
05924       *local_contexts = tmp;
05925       ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
05926       ast_unlock_contexts();
05927       ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05928       ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05929    } else {
05930       tmp->next = *local_contexts;
05931       if (exttable)
05932          ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
05933       
05934       *local_contexts = tmp;
05935       ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05936       ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05937    }
05938    return tmp;
05939 }

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

References ast_copy_string(), ast_get_context_name(), ast_hashtab_lookup(), ast_mutex_lock(), ast_rdlock_contexts(), ast_unlock_contexts(), and ast_walk_contexts().

Referenced by _macro_exec().

04487 {
04488    struct ast_context *c = NULL;
04489    int ret = -1;
04490    struct fake_context item;
04491 
04492    ast_rdlock_contexts();
04493 
04494    ast_copy_string(item.name, context, sizeof(item.name));
04495 
04496    c = ast_hashtab_lookup(contexts_table,&item);
04497    if (c)
04498       ret = 0;
04499 
04500 
04501 #ifdef NOTNOW
04502 
04503    while ((c = ast_walk_contexts(c))) {
04504       if (!strcmp(ast_get_context_name(c), context)) {
04505          ret = 0;
04506          break;
04507       }
04508    }
04509 
04510 #endif
04511    ast_unlock_contexts();
04512 
04513    /* if we found context, lock macrolock */
04514    if (ret == 0) 
04515       ret = ast_mutex_lock(&c->macrolock);
04516 
04517    return ret;
04518 }

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

References ast_context_remove_extension_callerid().

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

04294 {
04295    return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
04296 }

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

References ast_context_remove_extension_callerid2().

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

04321 {
04322    return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked);
04323 }

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

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

04299 {
04300    int ret = -1; /* default error return */
04301    struct ast_context *c = find_context_locked(context);
04302 
04303    if (c) { /* ... remove extension ... */
04304       ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcallerid, registrar, 1);
04305       ast_unlock_contexts();
04306    }
04307    return ret;
04308 }

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

Definition at line 4325 of file pbx.c.

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

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

04326 {
04327    struct ast_exten *exten, *prev_exten = NULL;
04328    struct ast_exten *peer;
04329    struct ast_exten ex, *exten2, *exten3;
04330    char dummy_name[1024];
04331    struct ast_exten *previous_peer = NULL;
04332    struct ast_exten *next_peer = NULL;
04333    int found = 0;
04334 
04335    if (!already_locked)
04336       ast_wrlock_context(con);
04337 
04338    /* Handle this is in the new world */
04339 
04340    /* FIXME For backwards compatibility, if callerid==NULL, then remove ALL
04341     * peers, not just those matching the callerid. */
04342 #ifdef NEED_DEBUG
04343    ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
04344 #endif
04345 #ifdef CONTEXT_DEBUG
04346    check_contexts(__FILE__, __LINE__);
04347 #endif
04348    /* find this particular extension */
04349    ex.exten = dummy_name;
04350    ex.matchcid = matchcallerid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */
04351    ex.cidmatch = callerid;
04352    ast_copy_string(dummy_name, extension, sizeof(dummy_name));
04353    exten = ast_hashtab_lookup(con->root_table, &ex);
04354    if (exten) {
04355       if (priority == 0) {
04356          exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04357          if (!exten2)
04358             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);
04359          if (con->pattern_tree) {
04360             
04361             struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04362             
04363             if (x->exten) { /* this test for safety purposes */
04364                x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04365                x->exten = 0; /* get rid of what will become a bad pointer */
04366             } else {
04367                ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
04368             }
04369          }
04370       } else {
04371          ex.priority = priority;
04372          exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
04373          if (exten2) {
04374             
04375             if (exten2->label) { /* if this exten has a label, remove that, too */
04376                exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
04377                if (!exten3)
04378                   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);
04379             }
04380          
04381             exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
04382             if (!exten3)
04383                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);
04384             if (exten2 == exten && exten2->peer) {
04385                exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04386                ast_hashtab_insert_immediate(con->root_table, exten2->peer);
04387             }
04388             if (ast_hashtab_size(exten->peer_table) == 0) {
04389                /* well, if the last priority of an exten is to be removed,
04390                   then, the extension is removed, too! */
04391                exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
04392                if (!exten3)
04393                   ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
04394                if (con->pattern_tree) {
04395                   struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04396                   if (x->exten) { /* this test for safety purposes */
04397                      x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04398                      x->exten = 0; /* get rid of what will become a bad pointer */
04399                   }
04400                }
04401             }
04402          } else {
04403             ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
04404                   priority, exten->exten, con->name);
04405          }
04406       }
04407    } else {
04408       /* hmmm? this exten is not in this pattern tree? */
04409       ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
04410             extension, con->name);
04411    }
04412 #ifdef NEED_DEBUG
04413    if (con->pattern_tree) {
04414       ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
04415       log_match_char_tree(con->pattern_tree, " ");
04416    }
04417 #endif
04418 
04419    /* scan the extension list to find first matching extension-registrar */
04420    for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
04421       if (!strcmp(exten->exten, extension) &&
04422          (!registrar || !strcmp(exten->registrar, registrar)) &&
04423          (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
04424          break;
04425    }
04426    if (!exten) {
04427       /* we can't find right extension */
04428       if (!already_locked)
04429          ast_unlock_context(con);
04430       return -1;
04431    }
04432 
04433    /* scan the priority list to remove extension with exten->priority == priority */
04434    for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
04435        peer && !strcmp(peer->exten, extension) && (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(peer->cidmatch) && !strcmp(peer->cidmatch,callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(peer->cidmatch)));
04436          peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
04437       if ((priority == 0 || peer->priority == priority) &&
04438             (!callerid || !matchcallerid || (matchcallerid && !strcmp(peer->cidmatch, callerid))) &&
04439             (!registrar || !strcmp(peer->registrar, registrar) )) {
04440          found = 1;
04441 
04442          /* we are first priority extension? */
04443          if (!previous_peer) {
04444             /*
04445              * We are first in the priority chain, so must update the extension chain.
04446              * The next node is either the next priority or the next extension
04447              */
04448             struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
04449             if (peer->peer) {
04450                /* move the peer_table and peer_label_table down to the next peer, if
04451                   it is there */
04452                peer->peer->peer_table = peer->peer_table;
04453                peer->peer->peer_label_table = peer->peer_label_table;
04454                peer->peer_table = NULL;
04455                peer->peer_label_table = NULL;
04456             }
04457             if (!prev_exten) {   /* change the root... */
04458                con->root = next_node;
04459             } else {
04460                prev_exten->next = next_node; /* unlink */
04461             }
04462             if (peer->peer)   { /* update the new head of the pri list */
04463                peer->peer->next = peer->next;
04464             }
04465          } else { /* easy, we are not first priority in extension */
04466             previous_peer->peer = peer->peer;
04467          }
04468 
04469          /* now, free whole priority extension */
04470          destroy_exten(peer);
04471       } else {
04472          previous_peer = peer;
04473       }
04474    }
04475    if (!already_locked)
04476       ast_unlock_context(con);
04477    return found ? 0 : -1;
04478 }

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

Definition at line 6619 of file pbx.c.

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

Referenced by handle_cli_dialplan_remove_ignorepat().

06620 {
06621    int ret = -1;
06622    struct ast_context *c = find_context_locked(context);
06623 
06624    if (c) {
06625       ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
06626       ast_unlock_contexts();
06627    }
06628    return ret;
06629 }

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

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

06632 {
06633    struct ast_ignorepat *ip, *ipl = NULL;
06634 
06635    ast_wrlock_context(con);
06636 
06637    for (ip = con->ignorepats; ip; ip = ip->next) {
06638       if (!strcmp(ip->pattern, ignorepat) &&
06639          (!registrar || (registrar == ip->registrar))) {
06640          if (ipl) {
06641             ipl->next = ip->next;
06642             ast_free(ip);
06643          } else {
06644             con->ignorepats = ip->next;
06645             ast_free(ip);
06646          }
06647          ast_unlock_context(con);
06648          return 0;
06649       }
06650       ipl = ip;
06651    }
06652 
06653    ast_unlock_context(con);
06654    errno = EINVAL;
06655    return -1;
06656 }

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

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

Remove a context include.

Definition at line 4185 of file pbx.c.

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

Referenced by handle_cli_dialplan_remove_include().

04186 {
04187    int ret = -1;
04188    struct ast_context *c = find_context_locked(context);
04189 
04190    if (c) {
04191       /* found, remove include from this context ... */
04192       ret = ast_context_remove_include2(c, include, registrar);
04193       ast_unlock_contexts();
04194    }
04195    return ret;
04196 }

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

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

Removes an include by an ast_context structure.

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

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

04208 {
04209    struct ast_include *i, *pi = NULL;
04210    int ret = -1;
04211 
04212    ast_wrlock_context(con);
04213 
04214    /* find our include */
04215    for (i = con->includes; i; pi = i, i = i->next) {
04216       if (!strcmp(i->name, include) &&
04217             (!registrar || !strcmp(i->registrar, registrar))) {
04218          /* remove from list */
04219          ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
04220          if (pi)
04221             pi->next = i->next;
04222          else
04223             con->includes = i->next;
04224          /* free include and return */
04225          ast_free(i);
04226          ret = 0;
04227          break;
04228       }
04229    }
04230 
04231    ast_unlock_context(con);
04232 
04233    return ret;
04234 }

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

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

04242 {
04243    int ret = -1; /* default error return */
04244    struct ast_context *c = find_context_locked(context);
04245 
04246    if (c) {
04247       /* remove switch from this context ... */
04248       ret = ast_context_remove_switch2(c, sw, data, registrar);
04249       ast_unlock_contexts();
04250    }
04251    return ret;
04252 }

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

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

Referenced by ast_context_remove_switch().

04263 {
04264    struct ast_sw *i;
04265    int ret = -1;
04266 
04267    ast_wrlock_context(con);
04268 
04269    /* walk switches */
04270    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
04271       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
04272          (!registrar || !strcmp(i->registrar, registrar))) {
04273          /* found, remove from list */
04274          ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
04275          AST_LIST_REMOVE_CURRENT(list);
04276          ast_free(i); /* free switch and return */
04277          ret = 0;
04278          break;
04279       }
04280    }
04281    AST_LIST_TRAVERSE_SAFE_END;
04282 
04283    ast_unlock_context(con);
04284 
04285    return ret;
04286 }

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

References ast_copy_string(), ast_get_context_name(), ast_hashtab_lookup(), ast_mutex_unlock(), ast_rdlock_contexts(), ast_unlock_contexts(), and ast_walk_contexts().

Referenced by _macro_exec().

04526 {
04527    struct ast_context *c = NULL;
04528    int ret = -1;
04529    struct fake_context item;
04530 
04531    ast_rdlock_contexts();
04532 
04533    ast_copy_string(item.name, context, sizeof(item.name));
04534 
04535    c = ast_hashtab_lookup(contexts_table,&item);
04536    if (c)
04537       ret = 0;
04538 #ifdef NOTNOW
04539 
04540    while ((c = ast_walk_contexts(c))) {
04541       if (!strcmp(ast_get_context_name(c), context)) {
04542          ret = 0;
04543          break;
04544       }
04545    }
04546 
04547 #endif
04548    ast_unlock_contexts();
04549 
04550    /* if we found context, unlock macrolock */
04551    if (ret == 0) 
04552       ret = ast_mutex_unlock(&c->macrolock);
04553 
04554    return ret;
04555 }

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

08950 {
08951    struct ast_include *inc = NULL;
08952    int res = 0;
08953 
08954    while ( (inc = ast_walk_context_includes(con, inc)) ) {
08955       if (ast_context_find(inc->rname))
08956          continue;
08957 
08958       res = -1;
08959       ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
08960          ast_get_context_name(con), inc->rname);
08961       break;
08962    }
08963 
08964    return res;
08965 }

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

Definition at line 2782 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(), require_curl(), store_curl(), and update_curl().

02783 {
02784    struct ast_custom_function *acf = NULL;
02785 
02786    AST_RWLIST_RDLOCK(&acf_root);
02787    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02788       if (!strcmp(name, acf->name))
02789          break;
02790    }
02791    AST_RWLIST_UNLOCK(&acf_root);
02792 
02793    return acf;
02794 }

int ast_custom_function_unregister ( struct ast_custom_function acf  ) 

Unregister a custom function.

Definition at line 2796 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 load_module(), reload(), and unload_module().

02797 {
02798    struct ast_custom_function *cur;
02799 
02800    if (!acf)
02801       return -1;
02802 
02803    AST_RWLIST_WRLOCK(&acf_root);
02804    if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist)))
02805       ast_verb(2, "Unregistered custom function %s\n", cur->name);
02806    AST_RWLIST_UNLOCK(&acf_root);
02807 
02808    return cur ? 0 : -1;
02809 }

enum ast_extension_states ast_devstate_to_extenstate ( enum ast_device_state  devstate  ) 

Map devstate to an extension state.

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

Definition at line 3276 of file pbx.c.

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

Referenced by ast_extension_state2().

03277 {
03278    switch (devstate) {
03279    case AST_DEVICE_ONHOLD:
03280       return AST_EXTENSION_ONHOLD;
03281    case AST_DEVICE_BUSY:
03282       return AST_EXTENSION_BUSY;
03283    case AST_DEVICE_UNAVAILABLE:
03284    case AST_DEVICE_UNKNOWN:
03285    case AST_DEVICE_INVALID:
03286       return AST_EXTENSION_UNAVAILABLE;
03287    case AST_DEVICE_RINGINUSE:
03288       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
03289    case AST_DEVICE_RINGING:
03290       return AST_EXTENSION_RINGING;
03291    case AST_DEVICE_INUSE:
03292       return AST_EXTENSION_INUSE;
03293    case AST_DEVICE_NOT_INUSE:
03294       return AST_EXTENSION_NOT_INUSE;
03295    case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
03296       break;
03297    }
03298 
03299    return AST_EXTENSION_NOT_INUSE;
03300 }

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 3646 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_call(), 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(), privacy_exec(), process_ast_dsp(), readexten_exec(), register_peer_exten(), rpt_exec(), show_debug_helper(), sip_read(), skinny_ss(), socket_process(), ss7_linkset(), ss_thread(), and waitstream_core().

03647 {
03648    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
03649 }

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

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

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

06767 {
06768    if (!chan)
06769       return -1;
06770 
06771    ast_channel_lock(chan);
06772 
06773    if (!ast_strlen_zero(context))
06774       ast_copy_string(chan->context, context, sizeof(chan->context));
06775    if (!ast_strlen_zero(exten))
06776       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06777    if (priority > -1) {
06778       chan->priority = priority;
06779       /* see flag description in channel.h for explanation */
06780       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
06781          chan->priority--;
06782    }
06783 
06784    ast_channel_unlock(chan);
06785 
06786    return 0;
06787 }

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

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

02009 {
02010    if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
02011       ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
02012    return extension_match_core(pattern, data, needmore);
02013 }

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

References ext_cmp().

Referenced by lua_extension_cmp().

01811 {
01812    return ext_cmp(a, b);
01813 }

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

02004 {
02005    return extension_match_core(pattern, data, E_MATCH);
02006 }

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

Check extension state for an extension by using hint.

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

Definition at line 3338 of file pbx.c.

References ast_extension_state2(), and ast_hint_extension().

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

03339 {
03340    struct ast_exten *e;
03341 
03342    e = ast_hint_extension(c, context, exten);   /* Do we have a hint for this extension ? */
03343    if (!e)
03344       return -1;           /* No hint, return -1 */
03345 
03346    return ast_extension_state2(e);        /* Check all devices in the hint */
03347 }

static int ast_extension_state2 ( struct ast_exten e  )  [static]

Check state of extension by using hints.

Definition at line 3303 of file pbx.c.

References ast_copy_string(), ast_devstate_aggregate_add(), ast_devstate_aggregate_init(), ast_devstate_aggregate_result(), ast_devstate_to_extenstate(), ast_get_extension_app(), AST_MAX_EXTENSION, and strsep().

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

03304 {
03305    char hint[AST_MAX_EXTENSION] = "";
03306    char *cur, *rest;
03307    struct ast_devstate_aggregate agg;
03308 
03309    if (!e)
03310       return -1;
03311 
03312    ast_devstate_aggregate_init(&agg);
03313 
03314    ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
03315 
03316    rest = hint;   /* One or more devices separated with a & character */
03317 
03318    while ( (cur = strsep(&rest, "&")) ) {
03319       ast_devstate_aggregate_add(&agg, ast_device_state(cur));
03320    }
03321 
03322    return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
03323 }

const char* ast_extension_state2str ( int  extension_state  ) 

Return extension_state as string.

Return string representation of the state of an extension.

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

03327 {
03328    int i;
03329 
03330    for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
03331       if (extension_states[i].extension_state == extension_state)
03332          return extension_states[i].text;
03333    }
03334    return "Unknown";
03335 }

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

Add watcher for extension states.

Registers a state change callback.

Definition at line 3399 of file pbx.c.

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

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

03401 {
03402    struct ast_hint *hint;
03403    struct ast_state_cb *cblist;
03404    struct ast_exten *e;
03405 
03406    /* If there's no context and extension:  add callback to statecbs list */
03407    if (!context && !exten) {
03408       AST_RWLIST_WRLOCK(&hints);
03409 
03410       AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
03411          if (cblist->callback == callback) {
03412             cblist->data = data;
03413             AST_RWLIST_UNLOCK(&hints);
03414             return 0;
03415          }
03416       }
03417 
03418       /* Now insert the callback */
03419       if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03420          AST_RWLIST_UNLOCK(&hints);
03421          return -1;
03422       }
03423       cblist->id = 0;
03424       cblist->callback = callback;
03425       cblist->data = data;
03426 
03427       AST_LIST_INSERT_HEAD(&statecbs, cblist, entry);
03428 
03429       AST_RWLIST_UNLOCK(&hints);
03430 
03431       return 0;
03432    }
03433 
03434    if (!context || !exten)
03435       return -1;
03436 
03437    /* This callback type is for only one hint, so get the hint */
03438    e = ast_hint_extension(NULL, context, exten);
03439    if (!e) {
03440       return -1;
03441    }
03442 
03443    /* If this is a pattern, dynamically create a new extension for this
03444     * particular match.  Note that this will only happen once for each
03445     * individual extension, because the pattern will no longer match first.
03446     */
03447    if (e->exten[0] == '_') {
03448       ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
03449          e->cidmatch, e->app, ast_strdup(e->data), ast_free_ptr,
03450          e->registrar);
03451       e = ast_hint_extension(NULL, context, exten);
03452       if (!e || e->exten[0] == '_') {
03453          return -1;
03454       }
03455    }
03456 
03457    /* Find the hint in the list of hints */
03458    AST_RWLIST_WRLOCK(&hints);
03459 
03460    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03461       if (hint->exten == e)
03462          break;
03463    }
03464 
03465    if (!hint) {
03466       /* We have no hint, sorry */
03467       AST_RWLIST_UNLOCK(&hints);
03468       return -1;
03469    }
03470 
03471    /* Now insert the callback in the callback list  */
03472    if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03473       AST_RWLIST_UNLOCK(&hints);
03474       return -1;
03475    }
03476 
03477    cblist->id = stateid++;    /* Unique ID for this callback */
03478    cblist->callback = callback;  /* Pointer to callback routine */
03479    cblist->data = data;    /* Data for the callback */
03480 
03481    AST_LIST_INSERT_HEAD(&hint->callbacks, cblist, entry);
03482 
03483    AST_RWLIST_UNLOCK(&hints);
03484 
03485    return cblist->id;
03486 }

int ast_extension_state_del ( int  id,
ast_state_cb_type  callback 
)

Remove a watcher from the callback list.

Deletes a registered state change callback by ID.

Definition at line 3489 of file pbx.c.

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

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

03490 {
03491    struct ast_state_cb *p_cur = NULL;
03492    int ret = -1;
03493 
03494    if (!id && !callback)
03495       return -1;
03496 
03497    AST_RWLIST_WRLOCK(&hints);
03498 
03499    if (!id) {  /* id == 0 is a callback without extension */
03500       AST_LIST_TRAVERSE_SAFE_BEGIN(&statecbs, p_cur, entry) {
03501          if (p_cur->callback == callback) {
03502             AST_LIST_REMOVE_CURRENT(entry);
03503             break;
03504          }
03505       }
03506       AST_LIST_TRAVERSE_SAFE_END;
03507    } else { /* callback with extension, find the callback based on ID */
03508       struct ast_hint *hint;
03509       AST_RWLIST_TRAVERSE(&hints, hint, list) {
03510          AST_LIST_TRAVERSE_SAFE_BEGIN(&hint->callbacks, p_cur, entry) {
03511             if (p_cur->id == id) {
03512                AST_LIST_REMOVE_CURRENT(entry);
03513                break;
03514             }
03515          }
03516          AST_LIST_TRAVERSE_SAFE_END;
03517 
03518          if (p_cur)
03519             break;
03520       }
03521    }
03522 
03523    if (p_cur) {
03524       ast_free(p_cur);
03525    }
03526 
03527    AST_RWLIST_UNLOCK(&hints);
03528 
03529    return ret;
03530 }

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

03652 {
03653    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03654 }

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

References E_FINDLABEL, and pbx_extension_helper().

Referenced by pbx_load_config().

03657 {
03658    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03659 }

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

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

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

02870 {
02871    char *copy = ast_strdupa(function);
02872    char *args = func_args(copy);
02873    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02874 
02875    if (acfptr == NULL)
02876       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02877    else if (!acfptr->read)
02878       ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
02879    else {
02880       int res;
02881       struct ast_module_user *u = NULL;
02882       if (acfptr->mod)
02883          u = __ast_module_user_add(acfptr->mod, chan);
02884       res = acfptr->read(chan, copy, args, workspace, len);
02885       if (acfptr->mod && u)
02886          __ast_module_user_remove(acfptr->mod, u);
02887       return res;
02888    }
02889    return -1;
02890 }

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

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

Referenced by pbx_builtin_pushvar_helper(), and pbx_builtin_setvar_helper().

02893 {
02894    char *copy = ast_strdupa(function);
02895    char *args = func_args(copy);
02896    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02897 
02898    if (acfptr == NULL)
02899       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02900    else if (!acfptr->write)
02901       ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
02902    else {
02903       int res;
02904       struct ast_module_user *u = NULL;
02905       if (acfptr->mod)
02906          u = __ast_module_user_add(acfptr->mod, chan);
02907       res = acfptr->write(chan, copy, args, value);
02908       if (acfptr->mod && u)
02909          __ast_module_user_remove(acfptr->mod, u);
02910       return res;
02911    }
02912 
02913    return -1;
02914 }

const char* ast_get_context_name ( struct ast_context con  ) 
const char* ast_get_context_registrar ( struct ast_context c  ) 

Definition at line 8839 of file pbx.c.

References ast_context::registrar.

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

08840 {
08841    return c ? c->registrar : NULL;
08842 }

const char* ast_get_extension_app ( struct ast_exten e  ) 
void* ast_get_extension_app_data ( struct ast_exten e  ) 

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

08875 {
08876    return e ? e->data : NULL;
08877 }

const char* ast_get_extension_cidmatch ( struct ast_exten e  ) 

Definition at line 8864 of file pbx.c.

References ast_exten::cidmatch.

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

08865 {
08866    return e ? e->cidmatch : NULL;
08867 }

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

Definition at line 8806 of file pbx.c.

References ast_exten::parent.

Referenced by handle_show_hint(), and handle_show_hints().

08807 {
08808    return exten ? exten->parent : NULL;
08809 }

const char* ast_get_extension_label ( struct ast_exten exten  ) 

Definition at line 8816 of file pbx.c.

References ast_exten::label.

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

08817 {
08818    return exten ? exten->label : NULL;
08819 }

int ast_get_extension_matchcid ( struct ast_exten e  ) 

Definition at line 8859 of file pbx.c.

References ast_exten::matchcid.

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

08860 {
08861    return e ? e->matchcid : 0;
08862 }

const char* ast_get_extension_name ( struct ast_exten exten  ) 
int ast_get_extension_priority ( struct ast_exten exten  ) 

Definition at line 8831 of file pbx.c.

References ast_exten::priority.

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

08832 {
08833    return exten ? exten->priority : -1;
08834 }

const char* ast_get_extension_registrar ( struct ast_exten e  ) 

Definition at line 8844 of file pbx.c.

References ast_exten::registrar.

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

08845 {
08846    return e ? e->registrar : NULL;
08847 }

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

Get hint for channel.

If an extension hint exists, return non-zero.

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

03630 {
03631    struct ast_exten *e = ast_hint_extension(c, context, exten);
03632 
03633    if (e) {
03634       if (hint)
03635          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
03636       if (name) {
03637          const char *tmp = ast_get_extension_app_data(e);
03638          if (tmp)
03639             ast_copy_string(name, tmp, namesize);
03640       }
03641       return -1;
03642    }
03643    return 0;
03644 }

const char* ast_get_ignorepat_name ( struct ast_ignorepat ip  ) 
const char* ast_get_ignorepat_registrar ( struct ast_ignorepat ip  ) 

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

08855 {
08856    return ip ? ip->registrar : NULL;
08857 }

const char* ast_get_include_name ( struct ast_include inc  ) 
const char* ast_get_include_registrar ( struct ast_include i  ) 

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

08850 {
08851    return i ? i->registrar : NULL;
08852 }

const char* ast_get_switch_data ( struct ast_sw sw  ) 

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

08885 {
08886    return sw ? sw->data : NULL;
08887 }

int ast_get_switch_eval ( struct ast_sw sw  ) 

Definition at line 8889 of file pbx.c.

References ast_sw::eval.

Referenced by context_merge_incls_swits_igps_other_registrars().

08890 {
08891    return sw->eval;
08892 }

const char* ast_get_switch_name ( struct ast_sw sw  ) 

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

08880 {
08881    return sw ? sw->name : NULL;
08882 }

const char* ast_get_switch_registrar ( struct ast_sw sw  ) 

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

08895 {
08896    return sw ? sw->registrar : NULL;
08897 }

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

References __ast_goto_if_exists().

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

08988 {
08989    return __ast_goto_if_exists(chan, context, exten, priority, 0);
08990 }

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

Definition at line 351 of file pbx.c.

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

00352 {
00353    const struct ast_context *ac = ah_a;
00354    const struct ast_context *bc = ah_b;
00355    if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
00356       return 1;
00357    /* assume context names are registered in a string table! */
00358    return strcmp(ac->name, bc->name);
00359 }

unsigned int ast_hashtab_hash_contexts ( const void *  obj  ) 

Definition at line 394 of file pbx.c.

References ast_hashtab_hash_string().

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

00395 {
00396    const struct ast_context *ac = obj;
00397    return ast_hashtab_hash_string(ac->name);
00398 }

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

Definition at line 3267 of file pbx.c.

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

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

03268 {
03269    struct ast_exten *e;
03270    ast_rdlock_contexts();
03271    e = ast_hint_extension_nolock(c, context, exten);
03272    ast_unlock_contexts();
03273    return e;
03274 }

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

Find hint for given extension in context.

Definition at line 3261 of file pbx.c.

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

Referenced by ast_hint_extension(), and ast_merge_contexts_and_delete().

03262 {
03263    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
03264    return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
03265 }

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

06713 {
06714    struct ast_context *con = ast_context_find(context);
06715    if (con) {
06716       struct ast_ignorepat *pat;
06717       for (pat = con->ignorepats; pat; pat = pat->next) {
06718          if (ast_extension_match(pat->pattern, pattern))
06719             return 1;
06720       }
06721    }
06722 
06723    return 0;
06724 }

AST_LIST_HEAD ( store_hints  ,
store_hint   
)
static AST_LIST_HEAD_NOLOCK_STATIC ( statecbs  ,
ast_state_cb   
) [static]
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 3666 of file pbx.c.

References E_MATCHMORE, and pbx_extension_helper().

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

03667 {
03668    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
03669 }

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

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

Referenced by lua_reload_extensions(), and pbx_load_module().

06072 {
06073    double ft;
06074    struct ast_context *tmp, *oldcontextslist;
06075    struct ast_hashtab *oldtable;
06076    struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
06077    struct store_hint *this;
06078    struct ast_hint *hint;
06079    struct ast_exten *exten;
06080    int length;
06081    struct ast_state_cb *thiscb;
06082    struct ast_hashtab_iter *iter;
06083    
06084    /* it is very important that this function hold the hint list lock _and_ the conlock
06085       during its operation; not only do we need to ensure that the list of contexts
06086       and extensions does not change, but also that no hint callbacks (watchers) are
06087       added or removed during the merge/delete process
06088 
06089       in addition, the locks _must_ be taken in this order, because there are already
06090       other code paths that use this order
06091    */
06092    
06093    struct timeval begintime, writelocktime, endlocktime, enddeltime;
06094    int wrlock_ver;
06095    
06096    begintime = ast_tvnow();
06097    ast_rdlock_contexts();
06098    iter = ast_hashtab_start_traversal(contexts_table);
06099    while ((tmp = ast_hashtab_next(iter))) {
06100       context_merge(extcontexts, exttable, tmp, registrar);
06101    }
06102    ast_hashtab_end_traversal(iter);
06103    wrlock_ver = ast_wrlock_contexts_version();
06104    
06105    ast_unlock_contexts(); /* this feels real retarded, but you must do
06106                        what you must do If this isn't done, the following 
06107                         wrlock is a guraranteed deadlock */
06108    ast_wrlock_contexts();
06109    if (ast_wrlock_contexts_version() > wrlock_ver+1) {
06110       ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
06111    }
06112    
06113    AST_RWLIST_WRLOCK(&hints);
06114    writelocktime = ast_tvnow();
06115 
06116    /* preserve all watchers for hints */
06117    AST_RWLIST_TRAVERSE(&hints, hint, list) {
06118       if (!AST_LIST_EMPTY(&hint->callbacks)) {
06119          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
06120          if (!(this = ast_calloc(1, length)))
06121             continue;
06122          /* this removes all the callbacks from the hint into this. */
06123          AST_LIST_APPEND_LIST(&this->callbacks, &hint->callbacks, entry);
06124          this->laststate = hint->laststate;
06125          this->context = this->data;
06126          strcpy(this->data, hint->exten->parent->name);
06127          this->exten = this->data + strlen(this->context) + 1;
06128          strcpy(this->exten, hint->exten->exten);
06129          AST_LIST_INSERT_HEAD(&store, this, list);
06130       }
06131    }
06132 
06133    /* save the old table and list */
06134    oldtable = contexts_table;
06135    oldcontextslist = contexts;
06136 
06137    /* move in the new table and list */
06138    contexts_table = exttable;
06139    contexts = *extcontexts;
06140    
06141    /* restore the watchers for hints that can be found; notify those that
06142       cannot be restored
06143    */
06144    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
06145       struct pbx_find_info q = { .stacklen = 0 };
06146       exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH);
06147       /* If this is a pattern, dynamically create a new extension for this
06148        * particular match.  Note that this will only happen once for each
06149        * individual extension, because the pattern will no longer match first.
06150        */
06151       if (exten && exten->exten[0] == '_') {
06152          ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
06153             0, exten->app, ast_strdup(exten->data), ast_free_ptr, exten->registrar);
06154          /* rwlocks are not recursive locks */
06155          exten = ast_hint_extension_nolock(NULL, this->context, this->exten);
06156       }
06157 
06158       /* Find the hint in the list of hints */
06159       AST_RWLIST_TRAVERSE(&hints, hint, list) {
06160          if (hint->exten == exten)
06161             break;
06162       }
06163       if (!exten || !hint) {
06164          /* this hint has been removed, notify the watchers */
06165          while ((thiscb = AST_LIST_REMOVE_HEAD(&this->callbacks, entry))) {
06166             thiscb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, thiscb->data);
06167             ast_free(thiscb);
06168          }
06169       } else {
06170          AST_LIST_APPEND_LIST(&hint->callbacks, &this->callbacks, entry);
06171          hint->laststate = this->laststate;
06172       }
06173       ast_free(this);
06174    }
06175 
06176    AST_RWLIST_UNLOCK(&hints);
06177    ast_unlock_contexts();
06178    endlocktime = ast_tvnow();
06179    
06180    /* the old list and hashtab no longer are relevant, delete them while the rest of asterisk
06181       is now freely using the new stuff instead */
06182    
06183    ast_hashtab_destroy(oldtable, NULL);
06184    
06185    for (tmp = oldcontextslist; tmp; ) {
06186       struct ast_context *next;  /* next starting point */
06187       next = tmp->next;
06188       __ast_internal_context_destroy(tmp);
06189       tmp = next;
06190    }
06191    enddeltime = ast_tvnow();
06192    
06193    ft = ast_tvdiff_us(writelocktime, begintime);
06194    ft /= 1000000.0;
06195    ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
06196    
06197    ft = ast_tvdiff_us(endlocktime, writelocktime);
06198    ft /= 1000000.0;
06199    ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
06200 
06201    ft = ast_tvdiff_us(enddeltime, endlocktime);
06202    ft /= 1000000.0;
06203    ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
06204 
06205    ft = ast_tvdiff_us(enddeltime, begintime);
06206    ft /= 1000000.0;
06207    ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
06208    return;
06209 }

AST_MUTEX_DEFINE_STATIC ( maxcalllock   ) 
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 9050 of file pbx.c.

References pbx_parseable_goto().

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

09051 {
09052    return pbx_parseable_goto(chan, goto_string, 0);
09053 }

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

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

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

07549 {
07550    struct ast_channel *chan;
07551    struct app_tmp *tmp;
07552    int res = -1, cdr_res = -1;
07553    struct outgoing_helper oh;
07554 
07555    memset(&oh, 0, sizeof(oh));
07556    oh.vars = vars;
07557    oh.account = account;
07558 
07559    if (locked_channel)
07560       *locked_channel = NULL;
07561    if (ast_strlen_zero(app)) {
07562       res = -1;
07563       goto outgoing_app_cleanup;
07564    }
07565    if (synchronous) {
07566       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07567       if (chan) {
07568          ast_set_variables(chan, vars);
07569          if (account)
07570             ast_cdr_setaccount(chan, account);
07571          if (chan->_state == AST_STATE_UP) {
07572             res = 0;
07573             ast_verb(4, "Channel %s was answered.\n", chan->name);
07574             tmp = ast_calloc(1, sizeof(*tmp));
07575             if (!tmp)
07576                res = -1;
07577             else {
07578                ast_copy_string(tmp->app, app, sizeof(tmp->app));
07579                if (appdata)
07580                   ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
07581                tmp->chan = chan;
07582                if (synchronous > 1) {
07583                   if (locked_channel)
07584                      ast_channel_unlock(chan);
07585                   ast_pbx_run_app(tmp);
07586                } else {
07587                   if (locked_channel)
07588                      ast_channel_lock(chan);
07589                   if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
07590                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
07591                      ast_free(tmp);
07592                      if (locked_channel)
07593                         ast_channel_unlock(chan);
07594                      ast_hangup(chan);
07595                      res = -1;
07596                   } else {
07597                      if (locked_channel)
07598                         *locked_channel = chan;
07599                   }
07600                }
07601             }
07602          } else {
07603             ast_verb(4, "Channel %s was never answered.\n", chan->name);
07604             if (chan->cdr) { /* update the cdr */
07605                /* here we update the status of the call, which sould be busy.
07606                 * if that fails then we set the status to failed */
07607                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
07608                   ast_cdr_failed(chan->cdr);
07609             }
07610             ast_hangup(chan);
07611          }
07612       }
07613 
07614       if (res < 0) { /* the call failed for some reason */
07615          if (*reason == 0) { /* if the call failed (not busy or no answer)
07616                         * update the cdr with the failed message */
07617             cdr_res = ast_pbx_outgoing_cdr_failed();
07618             if (cdr_res != 0) {
07619                res = cdr_res;
07620                goto outgoing_app_cleanup;
07621             }
07622          }
07623       }
07624 
07625    } else {
07626       struct async_stat *as;
07627       if (!(as = ast_calloc(1, sizeof(*as)))) {
07628          res = -1;
07629          goto outgoing_app_cleanup;
07630       }
07631       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07632       if (!chan) {
07633          ast_free(as);
07634          res = -1;
07635          goto outgoing_app_cleanup;
07636       }
07637       as->chan = chan;
07638       ast_copy_string(as->app, app, sizeof(as->app));
07639       if (appdata)
07640          ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
07641       as->timeout = timeout;
07642       ast_set_variables(chan, vars);
07643       if (account)
07644          ast_cdr_setaccount(chan, account);
07645       /* Start a new thread, and get something handling this channel. */
07646       if (locked_channel)
07647          ast_channel_lock(chan);
07648       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
07649          ast_log(LOG_WARNING, "Failed to start async wait\n");
07650          ast_free(as);
07651          if (locked_channel)
07652             ast_channel_unlock(chan);
07653          ast_hangup(chan);
07654          res = -1;
07655          goto outgoing_app_cleanup;
07656       } else {
07657          if (locked_channel)
07658             *locked_channel = chan;
07659       }
07660       res = 0;
07661    }
07662 outgoing_app_cleanup:
07663    ast_variables_destroy(vars);
07664    return res;
07665 }

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 7356 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, and ast_channel::cdr.

Referenced by ast_pbx_outgoing_app(), and ast_pbx_outgoing_exten().

07357 {
07358    /* allocate a channel */
07359    struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");
07360 
07361    if (!chan)
07362       return -1;  /* failure */
07363 
07364    if (!chan->cdr) {
07365       /* allocation of the cdr failed */
07366       ast_channel_free(chan);   /* free the channel */
07367       return -1;                /* return failure */
07368    }
07369 
07370    /* allocation of the cdr was successful */
07371    ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
07372    ast_cdr_start(chan->cdr);       /* record the start and stop time */
07373    ast_cdr_end(chan->cdr);
07374    ast_cdr_failed(chan->cdr);      /* set the status to failed */
07375    ast_cdr_detach(chan->cdr);      /* post and free the record */
07376    chan->cdr = NULL;
07377    ast_channel_free(chan);         /* free the channel */
07378 
07379    return 0;  /* success */
07380 }

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

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

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

07383 {
07384    struct ast_channel *chan;
07385    struct async_stat *as;
07386    int res = -1, cdr_res = -1;
07387    struct outgoing_helper oh;
07388 
07389    if (synchronous) {
07390       oh.context = context;
07391       oh.exten = exten;
07392       oh.priority = priority;
07393       oh.cid_num = cid_num;
07394       oh.cid_name = cid_name;
07395       oh.account = account;
07396       oh.vars = vars;
07397       oh.parent_channel = NULL;
07398 
07399       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07400       if (channel) {
07401          *channel = chan;
07402          if (chan)
07403             ast_channel_lock(chan);
07404       }
07405       if (chan) {
07406          if (chan->_state == AST_STATE_UP) {
07407                res = 0;
07408             ast_verb(4, "Channel %s was answered.\n", chan->name);
07409 
07410             if (synchronous > 1) {
07411                if (channel)
07412                   ast_channel_unlock(chan);
07413                if (ast_pbx_run(chan)) {
07414                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
07415                   if (channel)
07416                      *channel = NULL;
07417                   ast_hangup(chan);
07418                   chan = NULL;
07419                   res = -1;
07420                }
07421             } else {
07422                if (ast_pbx_start(chan)) {
07423                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
07424                   if (channel) {
07425                      *channel = NULL;
07426                      ast_channel_unlock(chan);
07427                   }
07428                   ast_hangup(chan);
07429                   res = -1;
07430                }
07431                chan = NULL;
07432             }
07433          } else {
07434             ast_verb(4, "Channel %s was never answered.\n", chan->name);
07435 
07436             if (chan->cdr) { /* update the cdr */
07437                /* here we update the status of the call, which sould be busy.
07438                 * if that fails then we set the status to failed */
07439                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
07440                   ast_cdr_failed(chan->cdr);
07441             }
07442 
07443             if (channel) {
07444                *channel = NULL;
07445                ast_channel_unlock(chan);
07446             }
07447             ast_hangup(chan);
07448             chan = NULL;
07449          }
07450       }
07451 
07452       if (res < 0) { /* the call failed for some reason */
07453          if (*reason == 0) { /* if the call failed (not busy or no answer)
07454                         * update the cdr with the failed message */
07455             cdr_res = ast_pbx_outgoing_cdr_failed();
07456             if (cdr_res != 0) {
07457                res = cdr_res;
07458                goto outgoing_exten_cleanup;
07459             }
07460          }
07461 
07462          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
07463          /* check if "failed" exists */
07464          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
07465             chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
07466             if (chan) {
07467                char failed_reason[4] = "";
07468                if (!ast_strlen_zero(context))
07469                   ast_copy_string(chan->context, context, sizeof(chan->context));
07470                set_ext_pri(chan, "failed", 1);
07471                ast_set_variables(chan, vars);
07472                snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
07473                pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
07474                if (account)
07475                   ast_cdr_setaccount(chan, account);
07476                if (ast_pbx_run(chan)) {
07477                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
07478                   ast_hangup(chan);
07479                }
07480                chan = NULL;
07481             }
07482          }
07483       }
07484    } else {
07485       if (!(as = ast_calloc(1, sizeof(*as)))) {
07486          res = -1;
07487          goto outgoing_exten_cleanup;
07488       }
07489       chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
07490       if (channel) {
07491          *channel = chan;
07492          if (chan)
07493             ast_channel_lock(chan);
07494       }
07495       if (!chan) {
07496          ast_free(as);
07497          res = -1;
07498          goto outgoing_exten_cleanup;
07499       }
07500       as->chan = chan;
07501       ast_copy_string(as->context, context, sizeof(as->context));
07502       set_ext_pri(as->chan,  exten, priority);
07503       as->timeout = timeout;
07504       ast_set_variables(chan, vars);
07505       if (account)
07506          ast_cdr_setaccount(chan, account);
07507       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
07508          ast_log(LOG_WARNING, "Failed to start async wait\n");
07509          ast_free(as);
07510          if (channel) {
07511             *channel = NULL;
07512             ast_channel_unlock(chan);
07513          }
07514          ast_hangup(chan);
07515          res = -1;
07516          goto outgoing_exten_cleanup;
07517       }
07518       res = 0;
07519    }
07520 outgoing_exten_cleanup:
07521    ast_variables_destroy(vars);
07522    return res;
07523 }

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

04095 {
04096    return ast_pbx_run_args(c, NULL);
04097 }

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

run the application and free the descriptor once done

Definition at line 7533 of file pbx.c.

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

Referenced by ast_pbx_outgoing_app().

07534 {
07535    struct app_tmp *tmp = data;
07536    struct ast_app *app;
07537    app = pbx_findapp(tmp->app);
07538    if (app) {
07539       ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
07540       pbx_exec(tmp->chan, app, tmp->data);
07541    } else
07542       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
07543    ast_hangup(tmp->chan);
07544    ast_free(tmp);
07545    return NULL;
07546 }

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

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

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

04080 {
04081    enum ast_pbx_result res = AST_PBX_SUCCESS;
04082 
04083    if (increase_call_count(c)) {
04084       return AST_PBX_CALL_LIMIT;
04085    }
04086 
04087    res = __ast_pbx_run(c, args);
04088 
04089    decrease_call_count();
04090 
04091    return res;
04092 }

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 4057 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(), gtalk_new(), gtalk_newcall(), handle_request_invite(), jingle_new(), jingle_newcall(), local_call(), manage_parkinglot(), mgcp_new(), nbs_new(), oss_new(), pbx_start_chan(), phone_new(), pri_dchannel(), rpt_call(), sip_new(), skinny_new(), unistim_new(), and usbradio_new().

04058 {
04059    pthread_t t;
04060 
04061    if (!c) {
04062       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
04063       return AST_PBX_FAILED;
04064    }
04065 
04066    if (increase_call_count(c))
04067       return AST_PBX_CALL_LIMIT;
04068 
04069    /* Start a new thread, and get something handling this channel. */
04070    if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
04071       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
04072       decrease_call_count();
04073       return AST_PBX_FAILED;
04074    }
04075 
04076    return AST_PBX_SUCCESS;
04077 }

int ast_processed_calls ( void   ) 

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

Definition at line 4104 of file pbx.c.

Referenced by handle_chanlist(), and handle_showcalls().

04105 {
04106    return totalcalls;
04107 }

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

References ast_rwlock_rdlock(), and ast_context::lock.

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

08789 {
08790    return ast_rwlock_rdlock(&con->lock);
08791 }

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

Dynamically register a new dial plan application.

Register an application.

Definition at line 4558 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, LOG_WARNING, ast_app::synopsis, and term_color().

Referenced by ast_features_init(), and load_pbx().

04559 {
04560    struct ast_app *tmp, *cur = NULL;
04561    char tmps[80];
04562    int length, res;
04563 
04564    AST_RWLIST_WRLOCK(&apps);
04565    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
04566       if (!(res = strcasecmp(app, tmp->name))) {
04567          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
04568          AST_RWLIST_UNLOCK(&apps);
04569          return -1;
04570       } else if (res < 0)
04571          break;
04572    }
04573 
04574    length = sizeof(*tmp) + strlen(app) + 1;
04575 
04576    if (!(tmp = ast_calloc(1, length))) {
04577       AST_RWLIST_UNLOCK(&apps);
04578       return -1;
04579    }
04580 
04581    strcpy(tmp->name, app);
04582    tmp->execute = execute;
04583    tmp->synopsis = synopsis;
04584    tmp->description = description;
04585    tmp->module = mod;
04586 
04587    /* Store in alphabetical order */
04588    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
04589       if (strcasecmp(tmp->name, cur->name) < 0) {
04590          AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
04591          break;
04592       }
04593    }
04594    AST_RWLIST_TRAVERSE_SAFE_END;
04595    if (!cur)
04596       AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
04597 
04598    ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
04599 
04600    AST_RWLIST_UNLOCK(&apps);
04601 
04602    return 0;
04603 }

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

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

Referenced by load_module().

04610 {
04611    struct ast_switch *tmp;
04612 
04613    AST_RWLIST_WRLOCK(&switches);
04614    AST_RWLIST_TRAVERSE(&switches, tmp, list) {
04615       if (!strcasecmp(tmp->name, sw->name)) {
04616          AST_RWLIST_UNLOCK(&switches);
04617          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
04618          return -1;
04619       }
04620    }
04621    AST_RWLIST_INSERT_TAIL(&switches, sw, list);
04622    AST_RWLIST_UNLOCK(&switches);
04623 
04624    return 0;
04625 }

static int ast_remove_hint ( struct ast_exten e  )  [static]

Remove hint from extension.

Definition at line 3594 of file pbx.c.

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

Referenced by destroy_exten().

03595 {
03596    /* Cleanup the Notifys if hint is removed */
03597    struct ast_hint *hint;
03598    struct ast_state_cb *cblist;
03599    int res = -1;
03600 
03601    if (!e)
03602       return -1;
03603 
03604    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
03605       if (hint->exten != e)
03606          continue;
03607 
03608       while ((cblist = AST_LIST_REMOVE_HEAD(&hint->callbacks, entry))) {
03609          /* Notify with -1 and remove all callbacks */
03610          cblist->callback(hint->exten->parent->name, hint->exten->exten, 
03611             AST_EXTENSION_DEACTIVATED, cblist->data);
03612          ast_free(cblist);
03613       }
03614 
03615       AST_RWLIST_REMOVE_CURRENT(list);
03616       ast_free(hint);
03617 
03618          res = 0;
03619 
03620       break;
03621    }
03622    AST_RWLIST_TRAVERSE_SAFE_END;
03623 
03624    return res;
03625 }

static AST_RWLIST_HEAD_STATIC ( hints  ,
ast_hint   
) [static]
static AST_RWLIST_HEAD_STATIC ( switches  ,
ast_switch   
) [static]
static AST_RWLIST_HEAD_STATIC ( apps  ,
ast_app   
) [static]
static AST_RWLIST_HEAD_STATIC ( acf_root  ,
ast_custom_function   
) [static]
AST_RWLOCK_DEFINE_STATIC ( conlock   ) 

Lock for the ast_context list

AST_RWLOCK_DEFINE_STATIC ( globalslock   ) 
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 3671 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().

03672 {
03673    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
03674 }

AST_THREADSTORAGE ( switch_data   ) 
int ast_unlock_context ( struct ast_context con  ) 
int ast_unlock_contexts ( void   ) 
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 5852 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, and unreference_cached_app().

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

05853 {
05854    struct ast_app *tmp;
05855 
05856    AST_RWLIST_WRLOCK(&apps);
05857    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
05858       if (!strcasecmp(app, tmp->name)) {
05859          unreference_cached_app(tmp);
05860          AST_RWLIST_REMOVE_CURRENT(list);
05861          ast_verb(2, "Unregistered application '%s'\n", tmp->name);
05862          ast_free(tmp);
05863          break;
05864       }
05865    }
05866    AST_RWLIST_TRAVERSE_SAFE_END;
05867    AST_RWLIST_UNLOCK(&apps);
05868 
05869    return tmp ? 0 : -1;
05870 }

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

References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by __unload_module(), and unload_module().

04628 {
04629    AST_RWLIST_WRLOCK(&switches);
04630    AST_RWLIST_REMOVE(&switches, sw, list);
04631    AST_RWLIST_UNLOCK(&switches);
04632 }

struct ast_exten* ast_walk_context_extensions ( struct ast_context con,
struct ast_exten exten 
) [read]

Definition at line 8907 of file pbx.c.

References ast_exten::next, 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().

08909 {
08910    if (!exten)
08911       return con ? con->root : NULL;
08912    else
08913       return exten->next;
08914 }

struct ast_ignorepat* ast_walk_context_ignorepats ( struct ast_context con,
struct ast_ignorepat ip 
) [read]

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

08942 {
08943    if (!ip)
08944       return con ? con->ignorepats : NULL;
08945    else
08946       return ip->next;
08947 }

struct ast_include* ast_walk_context_includes ( struct ast_context con,
struct ast_include inc 
) [read]
struct ast_sw* ast_walk_context_switches ( struct ast_context con,
struct ast_sw sw 
) [read]

Definition at line 8916 of file pbx.c.

References AST_LIST_FIRST, and AST_LIST_NEXT.

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

08918 {
08919    if (!sw)
08920       return con ? AST_LIST_FIRST(&con->alts) : NULL;
08921    else
08922       return AST_LIST_NEXT(sw, list);
08923 }

struct ast_context* ast_walk_contexts ( struct ast_context con  )  [read]
struct ast_exten* ast_walk_extension_priorities ( struct ast_exten exten,
struct ast_exten priority 
) [read]
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 8783 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().

08784 {
08785    return ast_rwlock_wrlock(&con->lock);
08786 }

int ast_wrlock_contexts ( void   ) 

Write locks the context list.

Return values:
0 on success
-1 on error

Definition at line 8762 of file pbx.c.

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

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

08763 {
08764    int res = ast_rwlock_wrlock(&conlock);
08765    if (!res)
08766       ast_atomic_fetchadd_int(&conlock_wrlock_version, 1);
08767    return res;
08768 }

int ast_wrlock_contexts_version ( void   ) 

Definition at line 8754 of file pbx.c.

References conlock_wrlock_version.

Referenced by ast_merge_contexts_and_delete().

08755 {
08756    return conlock_wrlock_version;
08757 }

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

Definition at line 7295 of file pbx.c.

References ast_channel::_state, 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, ast_channel::context, async_stat::context, ast_channel::exten, async_stat::exten, f, ast_frame::frametype, LOG_ERROR, LOG_WARNING, pbx_exec(), pbx_findapp(), ast_channel::priority, async_stat::priority, ast_frame::subclass, and async_stat::timeout.

Referenced by ast_pbx_outgoing_app(), and ast_pbx_outgoing_exten().

07296 {
07297    struct async_stat *as = data;
07298    struct ast_channel *chan = as->chan;
07299    int timeout = as->timeout;
07300    int res;
07301    struct ast_frame *f;
07302    struct ast_app *app;
07303 
07304    while (timeout && (chan->_state != AST_STATE_UP)) {
07305       res = ast_waitfor(chan, timeout);
07306       if (res < 1)
07307          break;
07308       if (timeout > -1)
07309          timeout = res;
07310       f = ast_read(chan);
07311       if (!f)
07312          break;
07313       if (f->frametype == AST_FRAME_CONTROL) {
07314          if ((f->subclass == AST_CONTROL_BUSY)  ||
07315              (f->subclass == AST_CONTROL_CONGESTION) ) {
07316             ast_frfree(f);
07317             break;
07318          }
07319       }
07320       ast_frfree(f);
07321    }
07322    if (chan->_state == AST_STATE_UP) {
07323       if (!ast_strlen_zero(as->app)) {
07324          app = pbx_findapp(as->app);
07325          if (app) {
07326             ast_verb(3, "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
07327             pbx_exec(chan, app, as->appdata);
07328          } else
07329             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
07330       } else {
07331          if (!ast_strlen_zero(as->context))
07332             ast_copy_string(chan->context, as->context, sizeof(chan->context));
07333          if (!ast_strlen_zero(as->exten))
07334             ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
07335          if (as->priority > 0)
07336             chan->priority = as->priority;
07337          /* Run the PBX */
07338          if (ast_pbx_run(chan)) {
07339             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
07340          } else {
07341             /* PBX will have taken care of this */
07342             chan = NULL;
07343          }
07344       }
07345    }
07346    ast_free(as);
07347    if (chan)
07348       ast_hangup(chan);
07349    return NULL;
07350 }

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

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

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

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 3690 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::dtimeoutms, and ast_channel::pbx.

Referenced by __ast_pbx_run().

03691 {
03692    int digit;
03693 
03694    buf[pos] = '\0';  /* make sure it is properly terminated */
03695    while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
03696       /* As long as we're willing to wait, and as long as it's not defined,
03697          keep reading digits until we can't possibly get a right answer anymore.  */
03698       digit = ast_waitfordigit(c, waittime);
03699       if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03700          c->_softhangup = 0;
03701       } else {
03702          if (!digit) /* No entry */
03703             break;
03704          if (digit < 0) /* Error, maybe a  hangup */
03705             return -1;
03706          if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
03707             buf[pos++] = digit;
03708             buf[pos] = '\0';
03709          }
03710          waittime = c->pbx->dtimeoutms;
03711       }
03712    }
03713    return 0;
03714 }

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

Definition at line 338 of file pbx.c.

Referenced by add_exten_to_pattern_tree().

00339 {
00340    const char *ac = a;
00341    const char *bc = b;
00342    if ((*ac) < (*bc))
00343       return -1;
00344    else if ((*ac) == (*bc))
00345       return 0;
00346    else
00347       return 1;
00348 }

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

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

Referenced by handle_show_hint().

04788 {
04789    struct ast_hint *hint;
04790    char *ret = NULL;
04791    int which = 0;
04792    int wordlen;
04793 
04794    if (pos != 3)
04795       return NULL;
04796    
04797    wordlen = strlen(word);
04798 
04799    AST_RWLIST_RDLOCK(&hints);
04800    /* walk through all hints */
04801    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04802       if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
04803          ret = ast_strdup(ast_get_extension_name(hint->exten));
04804          break;
04805       }
04806    }
04807    AST_RWLIST_UNLOCK(&hints);
04808 
04809    return ret;
04810 }

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

Definition at line 4983 of file pbx.c.

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

Referenced by handle_debug_dialplan(), and handle_show_dialplan().

04985 {
04986    struct ast_context *c = NULL;
04987    char *ret = NULL;
04988    int which = 0;
04989    int wordlen;
04990 
04991    /* we are do completion of [exten@]context on second position only */
04992    if (pos != 2)
04993       return NULL;
04994 
04995    ast_rdlock_contexts();
04996 
04997    wordlen = strlen(word);
04998 
04999    /* walk through all contexts and return the n-th match */
05000    while ( (c = ast_walk_contexts(c)) ) {
05001       if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
05002          ret = ast_strdup(ast_get_context_name(c));
05003          break;
05004       }
05005    }
05006 
05007    ast_unlock_contexts();
05008 
05009    return ret;
05010 }

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

Definition at line 5987 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, 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, ast_context::refcount, ast_context::registrar, ast_exten::registrar, and ast_context::root_table.

Referenced by ast_merge_contexts_and_delete().

05988 {
05989    struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
05990    struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
05991    struct ast_hashtab_iter *exten_iter;
05992    struct ast_hashtab_iter *prio_iter;
05993    int insert_count = 0;
05994    int first = 1;
05995    
05996    /* We'll traverse all the extensions/prios, and see which are not registrar'd with
05997       the current registrar, and copy them to the new context. If the new context does not
05998       exist, we'll create it "on demand". If no items are in this context to copy, then we'll
05999       only create the empty matching context if the old one meets the criteria */
06000    
06001    if (context->root_table) {
06002       exten_iter = ast_hashtab_start_traversal(context->root_table);
06003       while ((exten_item=ast_hashtab_next(exten_iter))) {
06004          if (new) {
06005             new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
06006          } else {
06007             new_exten_item = NULL;
06008          }
06009          prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
06010          while ((prio_item=ast_hashtab_next(prio_iter))) {
06011             int res1;
06012             char *dupdstr;
06013             
06014             if (new_exten_item) {
06015                new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
06016             } else {
06017                new_prio_item = NULL;
06018             }
06019             if (strcmp(prio_item->registrar,registrar) == 0) {
06020                continue;
06021             }
06022             /* make sure the new context exists, so we have somewhere to stick this exten/prio */
06023             if (!new) {
06024                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 */
06025             }
06026 
06027             /* copy in the includes, switches, and ignorepats */
06028             if (first) { /* but, only need to do this once */
06029                context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06030                first = 0;
06031             }
06032             
06033             if (!new) {
06034                ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
06035                return; /* no sense continuing. */
06036             }
06037             /* we will not replace existing entries in the new context with stuff from the old context.
06038                but, if this is because of some sort of registrar conflict, we ought to say something... */
06039             
06040             dupdstr = ast_strdup(prio_item->data);
06041             
06042             res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label, 
06043                                 prio_item->cidmatch, prio_item->app, dupdstr, prio_item->datad, prio_item->registrar);
06044             if (!res1 && new_exten_item && new_prio_item){
06045                ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
06046                      context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
06047             } else {
06048                /* 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,
06049                 and no double frees take place, either! */
06050                insert_count++;
06051             }
06052          }
06053          ast_hashtab_end_traversal(prio_iter);
06054       }
06055       ast_hashtab_end_traversal(exten_iter);
06056    }
06057    
06058    if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
06059         (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
06060       /* we could have given it the registrar of the other module who incremented the refcount,
06061          but that's not available, so we give it the registrar we know about */
06062       new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
06063       
06064       /* copy in the includes, switches, and ignorepats */
06065       context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06066    }
06067 }

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

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

05955 {
05956    struct ast_include *i;
05957    struct ast_ignorepat *ip;
05958    struct ast_sw *sw;
05959    
05960    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);
05961    /* copy in the includes, switches, and ignorepats */
05962    /* walk through includes */
05963    for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
05964       if (strcmp(ast_get_include_registrar(i), registrar) == 0)
05965          continue; /* not mine */
05966       ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
05967    }
05968    
05969    /* walk through switches */
05970    for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
05971       if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
05972          continue; /* not mine */
05973       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));
05974    }
05975    
05976    /* walk thru ignorepats ... */
05977    for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
05978       if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
05979          continue; /* not mine */
05980       ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
05981    }
05982 }

static void create_match_char_tree ( struct ast_context con  )  [static]

Definition at line 1603 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, and ast_context::root_table.

Referenced by pbx_find_extension().

01604 {
01605    struct ast_hashtab_iter *t1;
01606    struct ast_exten *e1;
01607 #ifdef NEED_DEBUG
01608    int biggest_bucket, resizes, numobjs, numbucks;
01609    
01610    ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
01611    ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
01612    ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
01613          numobjs, numbucks, biggest_bucket, resizes);
01614 #endif
01615    t1 = ast_hashtab_start_traversal(con->root_table);
01616    while( (e1 = ast_hashtab_next(t1)) ) {
01617       if (e1->exten)
01618          add_exten_to_pattern_tree(con, e1, 0);
01619       else
01620          ast_log(LOG_ERROR,"Attempt to create extension with no extension name.\n");
01621    }
01622    ast_hashtab_end_traversal(t1);
01623 }

static void decrease_call_count ( void   )  [static]

Definition at line 4015 of file pbx.c.

References ast_mutex_lock(), and ast_mutex_unlock().

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

04016 {
04017    ast_mutex_lock(&maxcalllock);
04018    if (countcalls > 0)
04019       countcalls--;
04020    ast_mutex_unlock(&maxcalllock);
04021 }

static void destroy_exten ( struct ast_exten e  )  [static]
static void destroy_pattern_tree ( struct match_char pattern_tree  )  [static]

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

01626 {
01627    /* destroy all the alternates */
01628    if (pattern_tree->alt_char) {
01629       destroy_pattern_tree(pattern_tree->alt_char);
01630       pattern_tree->alt_char = 0;
01631    }
01632    /* destroy all the nexts */
01633    if (pattern_tree->next_char) {
01634       destroy_pattern_tree(pattern_tree->next_char);
01635       pattern_tree->next_char = 0;
01636    }
01637    pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
01638    if (pattern_tree->x)
01639       free(pattern_tree->x);
01640    free(pattern_tree);
01641 }

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

Definition at line 8700 of file pbx.c.

References ast_calloc, ast_event_get_ie_str(), AST_EVENT_IE_DEVICE, ast_free, ast_log(), ast_strlen_zero(), ast_taskprocessor_push(), statechange::dev, handle_statechange(), and LOG_ERROR.

Referenced by load_pbx().

08701 {
08702    const char *device;
08703    struct statechange *sc;
08704 
08705    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
08706    if (ast_strlen_zero(device)) {
08707       ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
08708       return;
08709    }
08710 
08711    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device) + 1)))
08712       return;
08713    strcpy(sc->dev, device);
08714    if (ast_taskprocessor_push(device_state_tps, handle_statechange, sc) < 0) {
08715       ast_free(sc);
08716    }
08717 }

static void exception_store_free ( void *  data  )  [static]

Definition at line 2583 of file pbx.c.

References ast_free, and ast_string_field_free_memory.

02584 {
02585    struct pbx_exception *exception = data;
02586    ast_string_field_free_memory(exception);
02587    ast_free(exception);
02588 }

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

the full routine to compare extensions in rules.

Definition at line 1777 of file pbx.c.

References ext_cmp1().

Referenced by ast_add_extension2_lockopt(), and ast_extension_cmp().

01778 {
01779    /* make sure non-patterns come first.
01780     * If a is not a pattern, it either comes first or
01781     * we do a more complex pattern comparison.
01782     */
01783    int ret = 0;
01784 
01785    if (a[0] != '_')
01786       return (b[0] == '_') ? -1 : strcmp(a, b);
01787 
01788    /* Now we know a is a pattern; if b is not, a comes first */
01789    if (b[0] != '_')
01790       return 1;
01791 
01792    /* ok we need full pattern sorting routine.
01793     * skip past the underscores */
01794    ++a; ++b;
01795    do {
01796       unsigned char bitwise[2][32] = { { 0, } };
01797       ret = ext_cmp1(&a, bitwise[0]) - ext_cmp1(&b, bitwise[1]);
01798       if (ret == 0) {
01799          /* Are the classes different, even though they score the same? */
01800          ret = memcmp(bitwise[0], bitwise[1], 32);
01801       }
01802    } while (!ret && a && b);
01803    if (ret == 0) {
01804       return 0;
01805    } else {
01806       return (ret > 0) ? 1 : -1;
01807    }
01808 }

static int ext_cmp1 ( const char **  p,
unsigned char *  bitwise 
) [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.

Note:
If two patterns score the same, the one with the lowest ascii values will compare as coming first.

Definition at line 1697 of file pbx.c.

References ast_log(), and LOG_WARNING.

Referenced by ext_cmp().

01698 {
01699    int c, cmin = 0xff, count = 0;
01700    const char *end;
01701 
01702    /* load value and advance pointer */
01703    c = *(*p)++;
01704 
01705    /* always return unless we have a set of chars */
01706    switch (toupper(c)) {
01707    default: /* ordinary character */
01708       bitwise[c / 8] = 1 << (c % 8);
01709       return 0x0100 | (c & 0xff);
01710 
01711    case 'N':   /* 2..9 */
01712       bitwise[6] = 0xfc;
01713       bitwise[7] = 0x03;
01714       return 0x0800 | '2';
01715 
01716    case 'X':   /* 0..9 */
01717       bitwise[6] = 0xff;
01718       bitwise[7] = 0x03;
01719       return 0x0A00 | '0';
01720 
01721    case 'Z':   /* 1..9 */
01722       bitwise[6] = 0xfe;
01723       bitwise[7] = 0x03;
01724       return 0x0900 | '1';
01725 
01726    case '.':   /* wildcard */
01727       return 0x10000;
01728 
01729    case '!':   /* earlymatch */
01730       return 0x20000;   /* less specific than NULL */
01731 
01732    case '\0':  /* empty string */
01733       *p = NULL;
01734       return 0x30000;
01735 
01736    case '[':   /* pattern */
01737       break;
01738    }
01739    /* locate end of set */
01740    end = strchr(*p, ']');  
01741 
01742    if (end == NULL) {
01743       ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
01744       return 0x40000;   /* XXX make this entry go last... */
01745    }
01746 
01747    for (; *p < end  ; (*p)++) {
01748       unsigned char c1, c2;   /* first-last char in range */
01749       c1 = (unsigned char)((*p)[0]);
01750       if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
01751          c2 = (unsigned char)((*p)[2]);
01752          *p += 2;    /* skip a total of 3 chars */
01753       } else {        /* individual character */
01754          c2 = c1;
01755       }
01756       if (c1 < cmin) {
01757          cmin = c1;
01758       }
01759       for (; c1 <= c2; c1++) {
01760          unsigned char mask = 1 << (c1 % 8);
01761          /*!\note If two patterns score the same, the one with the lowest
01762           * ascii values will compare as coming first. */
01763          /* Flag the character as included (used) and count it. */
01764          if (!(bitwise[ c1 / 8 ] & mask)) {
01765             bitwise[ c1 / 8 ] |= mask;
01766             count += 0x100;
01767          }
01768       }
01769    }
01770    (*p)++;
01771    return count == 0 ? 0x30000 : (count | cmin);
01772 }

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

copy a string skipping whitespace

Definition at line 6856 of file pbx.c.

Referenced by ast_add_extension2_lockopt().

06857 {
06858    int count = 0;
06859 
06860    while (*src && (count < len - 1)) {
06861       switch (*src) {
06862       case ' ':
06863          /* otherwise exten => [a-b],1,... doesn't work */
06864          /*    case '-': */
06865          /* Ignore */
06866          break;
06867       default:
06868          *dst = *src;
06869          dst++;
06870       }
06871       src++;
06872       count++;
06873    }
06874    *dst = '\0';
06875 
06876    return count;
06877 }

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

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

01992 {
01993    int i;
01994    static int prof_id = -2;   /* marker for 'unallocated' id */
01995    if (prof_id == -2)
01996       prof_id = ast_add_profile("ext_match", 0);
01997    ast_mark(prof_id, 1);
01998    i = _extension_match_core(pattern, data, mode);
01999    ast_mark(prof_id, 0);
02000    return i;
02001 }

static struct ast_context* find_context ( const char *  context  )  [static, read]

lookup for a context with a given name,

Return values:
found context or NULL if not found.

Definition at line 4139 of file pbx.c.

References ast_copy_string(), and ast_hashtab_lookup().

Referenced by ast_add_extension_nolock().

04140 {
04141    struct ast_context *c = NULL;
04142    struct fake_context item;
04143 
04144    ast_copy_string(item.name, context, sizeof(item.name));
04145 
04146    c = ast_hashtab_lookup(contexts_table,&item);
04147 
04148    return c;
04149 }

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

lookup for a context with a given name,

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

Definition at line 4156 of file pbx.c.

References ast_copy_string(), ast_get_context_name(), ast_hashtab_lookup(), ast_rdlock_contexts(), ast_unlock_contexts(), and ast_walk_contexts().

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

04157 {
04158    struct ast_context *c = NULL;
04159    struct fake_context item;
04160 
04161    ast_copy_string(item.name, context, sizeof(item.name));
04162 
04163    ast_rdlock_contexts();
04164    c = ast_hashtab_lookup(contexts_table,&item);
04165 
04166 #ifdef NOTNOW
04167 
04168    while ( (c = ast_walk_contexts(c)) ) {
04169       if (!strcmp(ast_get_context_name(c), context))
04170          return c;
04171    }
04172 #endif
04173    if (!c)
04174       ast_unlock_contexts();
04175 
04176    return c;
04177 }

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

References ast_log(), and LOG_WARNING.

Referenced by ast_func_read(), and ast_func_write().

02853 {
02854    char *args = strchr(function, '(');
02855 
02856    if (!args)
02857       ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses.  Assuming null argument.\n", function);
02858    else {
02859       char *p;
02860       *args++ = '\0';
02861       if ((p = strrchr(args, ')')) )
02862          *p = '\0';
02863       else
02864          ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
02865    }
02866    return args;
02867 }

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

Definition at line 1164 of file pbx.c.

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

01165 {
01166    /* find the exten at the end of the rope */
01167    struct match_char *node2 = node;
01168 
01169    for (node2 = node; node2; node2 = node2->next_char) {
01170       if (node2->exten) {
01171 #ifdef NEED_DEBUG_HERE
01172          ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
01173 #endif
01174          return node2->exten;
01175       }
01176    }
01177 #ifdef NEED_DEBUG_HERE
01178    ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
01179 #endif
01180    return 0;
01181 }

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

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

Referenced by ast_build_timing().

06251 {
06252    int s, e; /* start and ending position */
06253    unsigned int mask = 0;
06254 
06255    /* Check for whole range */
06256    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
06257       s = 0;
06258       e = max - 1;
06259    } else {
06260       /* Get start and ending position */
06261       char *c = strchr(src, '-');
06262       if (c)
06263          *c++ = '\0';
06264       /* Find the start */
06265       s = lookup_name(src, names, max);
06266       if (!s) {
06267          ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
06268          return 0;
06269       }
06270       s--;
06271       if (c) { /* find end of range */
06272          e = lookup_name(c, names, max);
06273          if (!e) {
06274             ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
06275             return 0;
06276          }
06277          e--;
06278       } else
06279          e = s;
06280    }
06281    /* Fill the mask. Remember that ranges are cyclic */
06282    mask = 1 << e; /* initialize with last element */
06283    while (s != e) {
06284       if (s >= max) {
06285          s = 0;
06286          mask |= (1 << s);
06287       } else {
06288          mask |= (1 << s);
06289          s++;
06290       }
06291    }
06292    return mask;
06293 }

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

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

Referenced by ast_build_timing().

06297 {
06298    char *e;
06299    int x;
06300    int s1, s2;
06301    int e1, e2;
06302    /* int cth, ctm; */
06303 
06304    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
06305    memset(i->minmask, 0, sizeof(i->minmask));
06306 
06307    /* 2-minutes per bit, since the mask has only 32 bits :( */
06308    /* Star is all times */
06309    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
06310       for (x = 0; x < 24; x++)
06311          i->minmask[x] = 0x3fffffff; /* 30 bits */
06312       return;
06313    }
06314    /* Otherwise expect a range */
06315    e = strchr(times, '-');
06316    if (!e) {
06317       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
06318       return;
06319    }
06320    *e++ = '\0';
06321    /* XXX why skip non digits ? */
06322    while (*e && !isdigit(*e))
06323       e++;
06324    if (!*e) {
06325       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
06326       return;
06327    }
06328    if (sscanf(times, "%2d:%2d", &s1, &s2) != 2) {
06329       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
06330       return;
06331    }
06332    if (sscanf(e, "%2d:%2d", &e1, &e2) != 2) {
06333       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
06334       return;
06335    }
06336    /* XXX this needs to be optimized */
06337 #if 1
06338    s1 = s1 * 30 + s2/2;
06339    if ((s1 < 0) || (s1 >= 24*30)) {
06340       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
06341       return;
06342    }
06343    e1 = e1 * 30 + e2/2;
06344    if ((e1 < 0) || (e1 >= 24*30)) {
06345       ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
06346       return;
06347    }
06348    /* Go through the time and enable each appropriate bit */
06349    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
06350       i->minmask[x/30] |= (1 << (x % 30));
06351    }
06352    /* Do the last one */
06353    i->minmask[x/30] |= (1 << (x % 30));
06354 #else
06355    for (cth = 0; cth < 24; cth++) {
06356       /* Initialize masks to blank */
06357       i->minmask[cth] = 0;
06358       for (ctm = 0; ctm < 30; ctm++) {
06359          if (
06360          /* First hour with more than one hour */
06361                (((cth == s1) && (ctm >= s2)) &&
06362                 ((cth < e1)))
06363          /* Only one hour */
06364          ||    (((cth == s1) && (ctm >= s2)) &&
06365                 ((cth == e1) && (ctm <= e2)))
06366          /* In between first and last hours (more than 2 hours) */
06367          ||    ((cth > s1) &&
06368                 (cth < e1))
06369          /* Last hour with more than one hour */
06370          ||    ((cth > s1) &&
06371                 ((cth == e1) && (ctm <= e2)))
06372          )
06373             i->minmask[cth] |= (1 << (ctm / 2));
06374       }
06375    }
06376 #endif
06377    /* All done */
06378    return;
06379 }

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

Send ack once.

Definition at line 5308 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(), dialplan_counters::context_existence, ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, show_debug_helper(), strsep(), dialplan_counters::total_context, ast_cli_entry::usage, and ast_cli_args::word.

05309 {
05310    char *exten = NULL, *context = NULL;
05311    /* Variables used for different counters */
05312    struct dialplan_counters counters;
05313    const char *incstack[AST_PBX_MAX_STACK];
05314 
05315    switch (cmd) {
05316    case CLI_INIT:
05317       e->command = "dialplan debug";
05318       e->usage = 
05319          "Usage: dialplan debug [context]\n"
05320          "       Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
05321       return NULL;
05322    case CLI_GENERATE:   
05323       return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05324    }
05325 
05326    memset(&counters, 0, sizeof(counters));
05327 
05328    if (a->argc != 2 && a->argc != 3)
05329       return CLI_SHOWUSAGE;
05330 
05331    /* we obtain [exten@]context? if yes, split them ... */
05332    /* note: we ignore the exten totally here .... */
05333    if (a->argc == 3) {
05334       if (strchr(a->argv[2], '@')) {   /* split into exten & context */
05335          context = ast_strdupa(a->argv[2]);
05336          exten = strsep(&context, "@");
05337          /* change empty strings to NULL */
05338          if (ast_strlen_zero(exten))
05339             exten = NULL;
05340       } else { /* no '@' char, only context given */
05341          context = a->argv[2];
05342       }
05343       if (ast_strlen_zero(context))
05344          context = NULL;
05345    }
05346    /* else Show complete dial plan, context and exten are NULL */
05347    show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05348 
05349    /* check for input failure and throw some error messages */
05350    if (context && !counters.context_existence) {
05351       ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05352       return CLI_FAILURE;
05353    }
05354 
05355 
05356    ast_cli(a->fd,"-= %d %s. =-\n",
05357          counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05358 
05359    /* everything ok */
05360    return CLI_SUCCESS;
05361 }

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

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

Referenced by handle_set_chanvar_deprecated().

05703 {
05704    struct ast_channel *chan;
05705    const char *chan_name, *var_name, *var_value;
05706 
05707    switch (cmd) {
05708    case CLI_INIT:
05709       e->command = "dialplan set chanvar";
05710       e->usage = 
05711          "Usage: dialplan set chanvar <channel> <varname> <value>\n"
05712          "       Set channel variable <varname> to <value>\n";
05713       return NULL;
05714    case CLI_GENERATE:
05715       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05716    }
05717 
05718    if (a->argc != e->args + 3)
05719       return CLI_SHOWUSAGE;
05720 
05721    chan_name = a->argv[e->args];
05722    var_name = a->argv[e->args + 1];
05723    var_value = a->argv[e->args + 2];
05724 
05725    if (!(chan = ast_get_channel_by_name_locked(chan_name))) {
05726       ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
05727       return CLI_FAILURE;
05728    }
05729 
05730    pbx_builtin_setvar_helper(chan, var_name, var_value);
05731    ast_channel_unlock(chan);
05732    ast_cli(a->fd, "\n    -- Channel variable '%s' set to '%s' for '%s'\n",  var_name, var_value, chan_name);
05733 
05734    return CLI_SUCCESS;
05735 }

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

Definition at line 5737 of file pbx.c.

References CLI_INIT, ast_cli_entry::command, and handle_set_chanvar().

05738 {
05739    char *res = handle_set_chanvar(e, cmd, a);
05740    if (cmd == CLI_INIT)
05741       e->command = "core set chanvar";
05742    return res;
05743 }

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

Definition at line 5745 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.

05746 {
05747    int oldval = 0;
05748    
05749    switch (cmd) {
05750    case CLI_INIT:
05751       e->command = "dialplan set extenpatternmatchnew true";
05752       e->usage = 
05753          "Usage: dialplan set extenpatternmatchnew true|false\n"
05754          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05755       return NULL;
05756    case CLI_GENERATE:
05757       return NULL;   
05758    }
05759 
05760    if (a->argc != 4)
05761       return CLI_SHOWUSAGE;
05762 
05763    oldval =  pbx_set_extenpatternmatchnew(1);
05764    
05765    if (oldval)
05766       ast_cli(a->fd, "\n    -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
05767    else
05768       ast_cli(a->fd, "\n    -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
05769 
05770    return CLI_SUCCESS;
05771 }

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

Definition at line 5672 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.

Referenced by handle_set_global_deprecated().

05673 {
05674    switch (cmd) {
05675    case CLI_INIT:
05676       e->command = "dialplan set global";
05677       e->usage = 
05678          "Usage: dialplan set global <name> <value>\n"
05679          "       Set global dialplan variable <name> to <value>\n";
05680       return NULL;
05681    case CLI_GENERATE:
05682       return NULL;   
05683    }
05684 
05685    if (a->argc != e->args + 2)
05686       return CLI_SHOWUSAGE;
05687 
05688    pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
05689    ast_cli(a->fd, "\n    -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
05690 
05691    return CLI_SUCCESS;
05692 }

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

Definition at line 5694 of file pbx.c.

References CLI_INIT, ast_cli_entry::command, and handle_set_global().

05695 {
05696    char *res = handle_set_global(e, cmd, a);
05697    if (cmd == CLI_INIT)
05698       e->command = "core set global";
05699    return res;
05700 }

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

Definition at line 4641 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_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, COLOR_CYAN, COLOR_MAGENTA, ast_cli_entry::command, ast_app::description, ast_cli_args::fd, ast_cli_args::n, ast_app::synopsis, term_color(), ast_cli_entry::usage, and ast_cli_args::word.

04642 {
04643    struct ast_app *aa;
04644    int app, no_registered_app = 1;
04645    char *ret = NULL;
04646    int which = 0;
04647    int wordlen;
04648 
04649    switch (cmd) {
04650    case CLI_INIT: 
04651       e->command = "core show application";
04652       e->usage = 
04653          "Usage: core show application <application> [<application> [<application> [...]]]\n"
04654          "       Describes a particular application.\n";
04655       return NULL;
04656    case CLI_GENERATE:
04657       /*
04658        * There is a possibility to show informations about more than one
04659        * application at one time. You can type 'show application Dial Echo' and
04660        * you will see informations about these two applications ...
04661        */
04662       wordlen = strlen(a->word);
04663       /* return the n-th [partial] matching entry */
04664       AST_RWLIST_RDLOCK(&apps);
04665       AST_RWLIST_TRAVERSE(&apps, aa, list) {
04666          if (!strncasecmp(a->word, aa->name, wordlen) && ++which > a->n) {
04667             ret = ast_strdup(aa->name);
04668             break;
04669          }
04670       }
04671       AST_RWLIST_UNLOCK(&apps);
04672 
04673       return ret;
04674    }
04675 
04676    if (a->argc < 4)
04677       return CLI_SHOWUSAGE;
04678 
04679    /* ... go through all applications ... */
04680    AST_RWLIST_RDLOCK(&apps);
04681    AST_RWLIST_TRAVERSE(&apps, aa, list) {
04682       /* ... compare this application name with all arguments given
04683        * to 'show application' command ... */
04684       for (app = 3; app < a->argc; app++) {
04685          if (!strcasecmp(aa->name, a->argv[app])) {
04686             /* Maximum number of characters added by terminal coloring is 22 */
04687             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
04688             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
04689             int synopsis_size, description_size;
04690 
04691             no_registered_app = 0;
04692 
04693             if (aa->synopsis)
04694                synopsis_size = strlen(aa->synopsis) + 23;
04695             else
04696                synopsis_size = strlen("Not available") + 23;
04697             synopsis = alloca(synopsis_size);
04698 
04699             if (aa->description)
04700                description_size = strlen(aa->description) + 23;
04701             else
04702                description_size = strlen("Not available") + 23;
04703             description = alloca(description_size);
04704 
04705             if (synopsis && description) {
04706                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", aa->name);
04707                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
04708                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
04709                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
04710                term_color(synopsis,
04711                            aa->synopsis ? aa->synopsis : "Not available",
04712                            COLOR_CYAN, 0, synopsis_size);
04713                term_color(description,
04714                            aa->description ? aa->description : "Not available",
04715                            COLOR_CYAN, 0, description_size);
04716 
04717                ast_cli(a->fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
04718             } else {
04719                /* ... one of our applications, show info ...*/
04720                ast_cli(a->fd,"\n  -= Info about application '%s' =- \n\n"
04721                   "[Synopsis]\n  %s\n\n"
04722                   "[Description]\n%s\n",
04723                   aa->name,
04724                   aa->synopsis ? aa->synopsis : "Not available",
04725                   aa->description ? aa->description : "Not available");
04726             }
04727          }
04728       }
04729    }
04730    AST_RWLIST_UNLOCK(&apps);
04731 
04732    /* we found at least one app? no? */
04733    if (no_registered_app) {
04734       ast_cli(a->fd, "Your application(s) is (are) not registered\n");
04735       return CLI_FAILURE;
04736    }
04737 
04738    return CLI_SUCCESS;
04739 }

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

Definition at line 4897 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_cli_args::n, ast_cli_args::pos, strcasestr(), ast_app::synopsis, ast_cli_entry::usage, and ast_cli_args::word.

04898 {
04899    struct ast_app *aa;
04900    int like = 0, describing = 0;
04901    int total_match = 0;    /* Number of matches in like clause */
04902    int total_apps = 0;  /* Number of apps registered */
04903    static char* choices[] = { "like", "describing", NULL };
04904 
04905    switch (cmd) {
04906    case CLI_INIT:
04907       e->command = "core show applications [like|describing]";
04908       e->usage = 
04909          "Usage: core show applications [{like|describing} <text>]\n"
04910          "       List applications which are currently available.\n"
04911          "       If 'like', <text> will be a substring of the app name\n"
04912          "       If 'describing', <text> will be a substring of the description\n";
04913       return NULL;
04914    case CLI_GENERATE:
04915       return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n);
04916    }
04917 
04918    AST_RWLIST_RDLOCK(&apps);
04919 
04920    if (AST_RWLIST_EMPTY(&apps)) {
04921       ast_cli(a->fd, "There are no registered applications\n");
04922       AST_RWLIST_UNLOCK(&apps);
04923       return CLI_SUCCESS;
04924    }
04925 
04926    /* core list applications like <keyword> */
04927    if ((a->argc == 5) && (!strcmp(a->argv[3], "like"))) {
04928       like = 1;
04929    } else if ((a->argc > 4) && (!strcmp(a->argv[3], "describing"))) {
04930       describing = 1;
04931    }
04932 
04933    /* core list applications describing <keyword1> [<keyword2>] [...] */
04934    if ((!like) && (!describing)) {
04935       ast_cli(a->fd, "    -= Registered Asterisk Applications =-\n");
04936    } else {
04937       ast_cli(a->fd, "    -= Matching Asterisk Applications =-\n");
04938    }
04939 
04940    AST_RWLIST_TRAVERSE(&apps, aa, list) {
04941       int printapp = 0;
04942       total_apps++;
04943       if (like) {
04944          if (strcasestr(aa->name, a->argv[4])) {
04945             printapp = 1;
04946             total_match++;
04947          }
04948       } else if (describing) {
04949          if (aa->description) {
04950             /* Match all words on command line */
04951             int i;
04952             printapp = 1;
04953             for (i = 4; i < a->argc; i++) {
04954                if (!strcasestr(aa->description, a->argv[i])) {
04955                   printapp = 0;
04956                } else {
04957                   total_match++;
04958                }
04959             }
04960          }
04961       } else {
04962          printapp = 1;
04963       }
04964 
04965       if (printapp) {
04966          ast_cli(a->fd,"  %20s: %s\n", aa->name, aa->synopsis ? aa->synopsis : "<Synopsis not available>");
04967       }
04968    }
04969    if ((!like) && (!describing)) {
04970       ast_cli(a->fd, "    -= %d Applications Registered =-\n",total_apps);
04971    } else {
04972       ast_cli(a->fd, "    -= %d Applications Matching =-\n",total_match);
04973    }
04974 
04975    AST_RWLIST_UNLOCK(&apps);
04976 
04977    return CLI_SUCCESS;
04978 }

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

CLI support for listing chanvar's variables in a parseable way.

Definition at line 5640 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(), ast_str_alloca, 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_serialize_variables(), ast_cli_args::pos, ast_str::str, ast_cli_entry::usage, and ast_cli_args::word.

05641 {
05642    struct ast_channel *chan = NULL;
05643    struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX large because we might have lots of channel vars */
05644 
05645    switch (cmd) {
05646    case CLI_INIT:
05647       e->command = "dialplan show chanvar";
05648       e->usage = 
05649          "Usage: dialplan show chanvar <channel>\n"
05650          "       List current channel variables and their values\n";
05651       return NULL;
05652    case CLI_GENERATE:
05653       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05654    }
05655 
05656    if (a->argc != e->args + 1)
05657       return CLI_SHOWUSAGE;
05658 
05659    if (!(chan = ast_get_channel_by_name_locked(a->argv[e->args]))) {
05660       ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
05661       return CLI_FAILURE;
05662    }
05663 
05664    pbx_builtin_serialize_variables(chan, &vars);
05665    if (vars->str) {
05666       ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], vars->str);
05667    }
05668    ast_channel_unlock(chan);
05669    return CLI_SUCCESS;
05670 }

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

Definition at line 5241 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(), dialplan_counters::context_existence, dialplan_counters::extension_existence, ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, show_dialplan_helper(), strsep(), dialplan_counters::total_context, dialplan_counters::total_exten, dialplan_counters::total_prio, ast_cli_entry::usage, and ast_cli_args::word.

05242 {
05243    char *exten = NULL, *context = NULL;
05244    /* Variables used for different counters */
05245    struct dialplan_counters counters;
05246    const char *incstack[AST_PBX_MAX_STACK];
05247 
05248    switch (cmd) {
05249    case CLI_INIT:
05250       e->command = "dialplan show";
05251       e->usage = 
05252          "Usage: dialplan show [[exten@]context]\n"
05253          "       Show dialplan\n";
05254       return NULL;
05255    case CLI_GENERATE:   
05256       return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05257    }
05258 
05259    memset(&counters, 0, sizeof(counters));
05260 
05261    if (a->argc != 2 && a->argc != 3)
05262       return CLI_SHOWUSAGE;
05263 
05264    /* we obtain [exten@]context? if yes, split them ... */
05265    if (a->argc == 3) {
05266       if (strchr(a->argv[2], '@')) {   /* split into exten & context */
05267          context = ast_strdupa(a->argv[2]);
05268          exten = strsep(&context, "@");
05269          /* change empty strings to NULL */
05270          if (ast_strlen_zero(exten))
05271             exten = NULL;
05272       } else { /* no '@' char, only context given */
05273          context = a->argv[2];
05274       }
05275       if (ast_strlen_zero(context))
05276          context = NULL;
05277    }
05278    /* else Show complete dial plan, context and exten are NULL */
05279    show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05280 
05281    /* check for input failure and throw some error messages */
05282    if (context && !counters.context_existence) {
05283       ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05284       return CLI_FAILURE;
05285    }
05286 
05287    if (exten && !counters.extension_existence) {
05288       if (context)
05289          ast_cli(a->fd, "There is no existence of %s@%s extension\n",
05290             exten, context);
05291       else
05292          ast_cli(a->fd,
05293             "There is no existence of '%s' extension in all contexts\n",
05294             exten);
05295       return CLI_FAILURE;
05296    }
05297 
05298    ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
05299             counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
05300             counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
05301             counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05302 
05303    /* everything ok */
05304    return CLI_SUCCESS;
05305 }

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

Definition at line 2701 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.

02702 {
02703    struct ast_custom_function *acf;
02704    /* Maximum number of characters added by terminal coloring is 22 */
02705    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
02706    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
02707    char stxtitle[40], *syntax = NULL;
02708    int synopsis_size, description_size, syntax_size;
02709    char *ret = NULL;
02710    int which = 0;
02711    int wordlen;
02712 
02713    switch (cmd) {
02714    case CLI_INIT:
02715       e->command = "core show function";
02716       e->usage = 
02717          "Usage: core show function <function>\n"
02718          "       Describe a particular dialplan function.\n";
02719       return NULL;
02720    case CLI_GENERATE:   
02721       wordlen = strlen(a->word);
02722       /* case-insensitive for convenience in this 'complete' function */
02723       AST_RWLIST_RDLOCK(&acf_root);
02724       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02725          if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
02726             ret = ast_strdup(acf->name);
02727             break;
02728          }
02729       }
02730       AST_RWLIST_UNLOCK(&acf_root);
02731 
02732       return ret;
02733    }
02734 
02735    if (a->argc < 4)
02736       return CLI_SHOWUSAGE;
02737 
02738    if (!(acf = ast_custom_function_find(a->argv[3]))) {
02739       ast_cli(a->fd, "No function by that name registered.\n");
02740       return CLI_FAILURE;
02741 
02742    }
02743 
02744    if (acf->synopsis)
02745       synopsis_size = strlen(acf->synopsis) + 23;
02746    else
02747       synopsis_size = strlen("Not available") + 23;
02748    synopsis = alloca(synopsis_size);
02749 
02750    if (acf->desc)
02751       description_size = strlen(acf->desc) + 23;
02752    else
02753       description_size = strlen("Not available") + 23;
02754    description = alloca(description_size);
02755 
02756    if (acf->syntax)
02757       syntax_size = strlen(acf->syntax) + 23;
02758    else
02759       syntax_size = strlen("Not available") + 23;
02760    syntax = alloca(syntax_size);
02761 
02762    snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
02763    term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
02764    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
02765    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
02766    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
02767    term_color(syntax,
02768          acf->syntax ? acf->syntax : "Not available",
02769          COLOR_CYAN, 0, syntax_size);
02770    term_color(synopsis,
02771          acf->synopsis ? acf->synopsis : "Not available",
02772          COLOR_CYAN, 0, synopsis_size);
02773    term_color(description,
02774          acf->desc ? acf->desc : "Not available",
02775          COLOR_CYAN, 0, description_size);
02776 
02777    ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
02778 
02779    return CLI_SUCCESS;
02780 }

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

Definition at line 2662 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.

02663 {
02664    struct ast_custom_function *acf;
02665    int count_acf = 0;
02666    int like = 0;
02667 
02668    switch (cmd) {
02669    case CLI_INIT:
02670       e->command = "core show functions [like]";
02671       e->usage = 
02672          "Usage: core show functions [like <text>]\n"
02673          "       List builtin functions, optionally only those matching a given string\n";
02674       return NULL;
02675    case CLI_GENERATE:
02676       return NULL;
02677    }
02678 
02679    if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
02680       like = 1;
02681    } else if (a->argc != 3) {
02682       return CLI_SHOWUSAGE;
02683    }
02684 
02685    ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
02686 
02687    AST_RWLIST_RDLOCK(&acf_root);
02688    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02689       if (!like || strstr(acf->name, a->argv[4])) {
02690          count_acf++;
02691          ast_cli(a->fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
02692       }
02693    }
02694    AST_RWLIST_UNLOCK(&acf_root);
02695 
02696    ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
02697 
02698    return CLI_SUCCESS;
02699 }

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 5573 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_cli_args::fd, and ast_cli_entry::usage.

Referenced by handle_show_globals_deprecated().

05574 {
05575    int i = 0;
05576    struct ast_var_t *newvariable;
05577 
05578    switch (cmd) {
05579    case CLI_INIT:
05580       e->command = "dialplan show globals";
05581       e->usage = 
05582          "Usage: dialplan show globals\n"
05583          "       List current global dialplan variables and their values\n";
05584       return NULL;
05585    case CLI_GENERATE:
05586       return NULL;
05587    }
05588 
05589    ast_rwlock_rdlock(&globalslock);
05590    AST_LIST_TRAVERSE (&globals, newvariable, entries) {
05591       i++;
05592       ast_cli(a->fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
05593    }
05594    ast_rwlock_unlock(&globalslock);
05595    ast_cli(a->fd, "\n    -- %d variable(s)\n", i);
05596 
05597    return CLI_SUCCESS;
05598 }

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

Definition at line 5600 of file pbx.c.

References CLI_INIT, ast_cli_entry::command, and handle_show_globals().

05601 {
05602 
05603    char *res = handle_show_globals(e, cmd, a);
05604    if (cmd == CLI_INIT)
05605       e->command = "core show globals";
05606    return res;
05607 }

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 4813 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_LIST_TRAVERSE, AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, 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, num, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

04814 {
04815    struct ast_hint *hint;
04816    int watchers;
04817    int num = 0, extenlen;
04818    struct ast_state_cb *watcher;
04819 
04820    switch (cmd) {
04821    case CLI_INIT:
04822       e->command = "core show hint";
04823       e->usage =
04824          "Usage: core show hint <exten>\n"
04825          "       List registered hint\n";
04826       return NULL;
04827    case CLI_GENERATE:
04828       return complete_core_show_hint(a->line, a->word, a->pos, a->n);
04829    }
04830 
04831    if (a->argc < 4)
04832       return CLI_SHOWUSAGE;
04833 
04834    AST_RWLIST_RDLOCK(&hints);
04835    if (AST_RWLIST_EMPTY(&hints)) {
04836       ast_cli(a->fd, "There are no registered dialplan hints\n");
04837       AST_RWLIST_UNLOCK(&hints);
04838       return CLI_SUCCESS;
04839    }
04840    extenlen = strlen(a->argv[3]);
04841    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04842       if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
04843          watchers = 0;
04844          AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04845             watchers++;
04846          }
04847          ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04848             ast_get_extension_name(hint->exten),
04849             ast_get_context_name(ast_get_extension_context(hint->exten)),
04850             ast_get_extension_app(hint->exten),
04851             ast_extension_state2str(hint->laststate), watchers);
04852          num++;
04853       }
04854    }
04855    AST_RWLIST_UNLOCK(&hints);
04856    if (!num)
04857       ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
04858    else
04859       ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
04860    return CLI_SUCCESS;
04861 }

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 4742 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_LIST_TRAVERSE, AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_hint::exten, ast_cli_args::fd, ast_hint::laststate, num, and ast_cli_entry::usage.

04743 {
04744    struct ast_hint *hint;
04745    int num = 0;
04746    int watchers;
04747    struct ast_state_cb *watcher;
04748 
04749    switch (cmd) {
04750    case CLI_INIT:
04751       e->command = "core show hints";
04752       e->usage = 
04753          "Usage: core show hints\n"
04754          "       List registered hints\n";
04755       return NULL;
04756    case CLI_GENERATE:
04757       return NULL;   
04758    }
04759 
04760    AST_RWLIST_RDLOCK(&hints);
04761    if (AST_RWLIST_EMPTY(&hints)) {
04762       ast_cli(a->fd, "There are no registered dialplan hints\n");
04763       AST_RWLIST_UNLOCK(&hints);
04764       return CLI_SUCCESS;
04765    }
04766    /* ... we have hints ... */
04767    ast_cli(a->fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
04768    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04769       watchers = 0;
04770       AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04771          watchers++;
04772       }
04773       ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04774          ast_get_extension_name(hint->exten),
04775          ast_get_context_name(ast_get_extension_context(hint->exten)),
04776          ast_get_extension_app(hint->exten),
04777          ast_extension_state2str(hint->laststate), watchers);
04778       num++;
04779    }
04780    ast_cli(a->fd, "----------------\n");
04781    ast_cli(a->fd, "- %d hints registered\n", num);
04782    AST_RWLIST_UNLOCK(&hints);
04783    return CLI_SUCCESS;
04784 }

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 4865 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::name, and ast_cli_entry::usage.

04866 {
04867    struct ast_switch *sw;
04868 
04869    switch (cmd) {
04870    case CLI_INIT:
04871       e->command = "core show switches";
04872       e->usage = 
04873          "Usage: core show switches\n"
04874          "       List registered switches\n";
04875       return NULL;
04876    case CLI_GENERATE:
04877       return NULL;   
04878    }
04879 
04880    AST_RWLIST_RDLOCK(&switches);
04881 
04882    if (AST_RWLIST_EMPTY(&switches)) {
04883       AST_RWLIST_UNLOCK(&switches);
04884       ast_cli(a->fd, "There are no registered alternative switches\n");
04885       return CLI_SUCCESS;
04886    }
04887 
04888    ast_cli(a->fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
04889    AST_RWLIST_TRAVERSE(&switches, sw, list)
04890       ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
04891 
04892    AST_RWLIST_UNLOCK(&switches);
04893 
04894    return CLI_SUCCESS;
04895 }

static int handle_statechange ( void *  datap  )  [static]

Definition at line 3349 of file pbx.c.

References ast_copy_string(), ast_extension_state2(), ast_free, ast_get_extension_app(), AST_LIST_TRAVERSE, AST_MAX_EXTENSION, ast_rdlock_contexts(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_unlock_contexts(), buf, ast_state_cb::callback, ast_state_cb::data, statechange::dev, ast_exten::exten, ast_hint::exten, ast_hint::laststate, ast_exten::parent, parse(), and strsep().

Referenced by device_state_cb().

03350 {
03351    struct ast_hint *hint;
03352    struct statechange *sc = datap;
03353 
03354    ast_rdlock_contexts();
03355    AST_RWLIST_RDLOCK(&hints);
03356 
03357    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03358       struct ast_state_cb *cblist;
03359       char buf[AST_MAX_EXTENSION];
03360       char *parse = buf;
03361       char *cur;
03362       int state;
03363 
03364       ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
03365       while ( (cur = strsep(&parse, "&")) ) {
03366          if (!strcasecmp(cur, sc->dev))
03367             break;
03368       }
03369       if (!cur)
03370          continue;
03371 
03372       /* Get device state for this hint */
03373       state = ast_extension_state2(hint->exten);
03374 
03375       if ((state == -1) || (state == hint->laststate))
03376          continue;
03377 
03378       /* Device state changed since last check - notify the watchers */
03379 
03380       /* For general callbacks */
03381       AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
03382          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03383       }
03384 
03385       /* For extension callbacks */
03386       AST_LIST_TRAVERSE(&hint->callbacks, cblist, entry) {
03387          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03388       }
03389 
03390       hint->laststate = state;   /* record we saw the change */
03391    }
03392    AST_RWLIST_UNLOCK(&hints);
03393    ast_unlock_contexts();
03394    ast_free(sc);
03395    return 0;
03396 }

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

Definition at line 5773 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.

05774 {
05775    int oldval = 0;
05776    
05777    switch (cmd) {
05778    case CLI_INIT:
05779       e->command = "dialplan set extenpatternmatchnew false";
05780       e->usage = 
05781          "Usage: dialplan set extenpatternmatchnew true|false\n"
05782          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05783       return NULL;
05784    case CLI_GENERATE:
05785       return NULL;   
05786    }
05787 
05788    if (a->argc != 4)
05789       return CLI_SHOWUSAGE;
05790 
05791    oldval =  pbx_set_extenpatternmatchnew(0);
05792    
05793    if (!oldval)
05794       ast_cli(a->fd, "\n    -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
05795    else
05796       ast_cli(a->fd, "\n    -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
05797 
05798    return CLI_SUCCESS;
05799 }

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

Definition at line 387 of file pbx.c.

References ast_exten::label, and S_OR.

Referenced by ast_add_extension2_lockopt().

00388 {
00389    const struct ast_exten *ac = ah_a;
00390    const struct ast_exten *bc = ah_b;
00391    return strcmp(S_OR(ac->label, ""), S_OR(bc->label, ""));
00392 }

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

Definition at line 380 of file pbx.c.

References ast_exten::priority.

Referenced by ast_add_extension2_lockopt().

00381 {
00382    const struct ast_exten *ac = ah_a;
00383    const struct ast_exten *bc = ah_b;
00384    return ac->priority != bc->priority;
00385 }

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

Definition at line 361 of file pbx.c.

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

Referenced by ast_add_extension2_lockopt().

00362 {
00363    const struct ast_exten *ac = ah_a;
00364    const struct ast_exten *bc = ah_b;
00365    int x = strcmp(ac->exten, bc->exten);
00366    if (x) { /* if exten names are diff, then return */
00367       return x;
00368    }
00369    
00370    /* but if they are the same, do the cidmatch values match? */
00371    if (ac->matchcid && bc->matchcid) {
00372       return strcmp(ac->cidmatch,bc->cidmatch);
00373    } else if (!ac->matchcid && !bc->matchcid) {
00374       return 0; /* if there's no matchcid on either side, then this is a match */
00375    } else {
00376       return 1; /* if there's matchcid on one but not the other, they are different */
00377    }
00378 }

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

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

00401 {
00402    const struct ast_exten *ac = obj;
00403    unsigned int x = ast_hashtab_hash_string(ac->exten);
00404    unsigned int y = 0;
00405    if (ac->matchcid)
00406       y = ast_hashtab_hash_string(ac->cidmatch);
00407    return x+y;
00408 }

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

Definition at line 416 of file pbx.c.

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

Referenced by ast_add_extension2_lockopt().

00417 {
00418    const struct ast_exten *ac = obj;
00419    return ast_hashtab_hash_string(S_OR(ac->label, ""));
00420 }

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

Definition at line 410 of file pbx.c.

References ast_hashtab_hash_int(), and ast_exten::priority.

Referenced by ast_add_extension2_lockopt().

00411 {
00412    const struct ast_exten *ac = obj;
00413    return ast_hashtab_hash_int(ac->priority);
00414 }

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

Definition at line 1003 of file pbx.c.

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

Referenced by pbx_find_extension().

01004 {
01005    if (!i->hastime)
01006       return 1;
01007 
01008    return ast_check_timing(&(i->timing));
01009 }

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

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), getloadavg(), LOG_WARNING, option_maxcalls, option_maxload, and option_minmemfree.

Referenced by ast_pbx_run_args(), and ast_pbx_start().

03969 {
03970    int failed = 0;
03971    double curloadavg;
03972 #if defined(HAVE_SYSINFO)
03973    long curfreemem;
03974    struct sysinfo sys_info;
03975 #endif
03976 
03977    ast_mutex_lock(&maxcalllock);
03978    if (option_maxcalls) {
03979       if (countcalls >= option_maxcalls) {
03980          ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
03981          failed = -1;
03982       }
03983    }
03984    if (option_maxload) {
03985       getloadavg(&curloadavg, 1);
03986       if (curloadavg >= option_maxload) {
03987          ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
03988          failed = -1;
03989       }
03990    }
03991 #if defined(HAVE_SYSINFO)
03992    if (option_minmemfree) {
03993       if (!sysinfo(&sys_info)) {
03994          /* make sure that the free system memory is above the configured low watermark
03995           * convert the amount of freeram from mem_units to MB */
03996          curfreemem = sys_info.freeram / sys_info.mem_unit; 
03997          curfreemem /= 1024*1024; 
03998          if (curfreemem < option_minmemfree) {
03999             ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
04000             failed = -1;
04001          }
04002       }
04003    }
04004 #endif
04005       
04006    if (!failed) {
04007       countcalls++;
04008       totalcalls++;
04009    }
04010    ast_mutex_unlock(&maxcalllock);
04011 
04012    return failed;
04013 }

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

Definition at line 1404 of file pbx.c.

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

Referenced by add_pattern_node().

01405 {
01406    struct match_char *curr, *lcurr;
01407    
01408    /* insert node into the tree at "current", so the alt_char list from current is
01409       sorted in increasing value as you go to the leaves */
01410    if (!(*parent_ptr)) {
01411       *parent_ptr = node;
01412    } else {
01413       if ((*parent_ptr)->specificity > node->specificity){
01414          /* insert at head */
01415          node->alt_char = (*parent_ptr);
01416          *parent_ptr = node;
01417       } else {
01418          lcurr = *parent_ptr;
01419          for (curr=(*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
01420             if (curr->specificity > node->specificity) {
01421                node->alt_char = curr;
01422                lcurr->alt_char = node;
01423                break;
01424             }
01425             lcurr = curr;
01426          }
01427          if (!curr)
01428          {
01429             lcurr->alt_char = node;
01430          }
01431       }
01432    }
01433 }

int load_pbx ( void   ) 

Provided by pbx.c

Definition at line 8719 of file pbx.c.

References __ast_custom_function_register(), ast_cli_register_multiple(), AST_EVENT_DEVICE_STATE, AST_EVENT_IE_END, ast_event_subscribe(), ast_log(), ast_manager_register2(), ast_register_application2(), ast_taskprocessor_get(), ast_verb, builtins, device_state_cb(), EVENT_FLAG_CONFIG, EVENT_FLAG_REPORTING, exception_function, LOG_ERROR, LOG_WARNING, manager_show_dialplan(), mandescr_show_dialplan, and pbx_cli.

Referenced by main().

08720 {
08721    int x;
08722 
08723    /* Initialize the PBX */
08724    ast_verb(1, "Asterisk PBX Core Initializing\n");
08725    if (!(device_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
08726       ast_log(LOG_WARNING, "failed to create pbx-core taskprocessor\n");
08727    }
08728 
08729    ast_verb(1, "Registering builtin applications:\n");
08730    ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
08731    __ast_custom_function_register(&exception_function, NULL);
08732 
08733    /* Register builtin applications */
08734    for (x = 0; x < sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
08735       ast_verb(1, "[%s]\n", builtins[x].name);
08736       if (ast_register_application2(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description, NULL)) {
08737          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
08738          return -1;
08739       }
08740    }
08741    
08742    /* Register manager application */
08743    ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
08744 
08745    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL,
08746          AST_EVENT_IE_END))) {
08747       return -1;
08748    }
08749 
08750    return 0;
08751 }

void log_match_char_tree ( struct match_char node,
char *  prefix 
)

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

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

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

Referenced by get_range().

06233 {
06234    int i;
06235 
06236    if (names) {
06237       for (i = 0; names[i]; i++) {
06238          if (!strcasecmp(s, names[i]))
06239             return i+1;
06240       }
06241    } else if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
06242       return i;
06243    }
06244    return 0; /* error return */
06245 }

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

Send ack once.

Definition at line 5364 of file pbx.c.

References astman_send_listack().

Referenced by manager_show_dialplan_helper().

05365 {
05366    astman_send_listack(s, m, "DialPlan list will follow", "start");
05367 }

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

Manager listing of dial plan.

Definition at line 5510 of file pbx.c.

References ast_strlen_zero(), astman_get_header(), astman_send_error(), dialplan_counters::context_existence, EVENT_FLAG_CONFIG, dialplan_counters::extension_existence, manager_event, manager_show_dialplan_helper(), dialplan_counters::total_context, dialplan_counters::total_exten, dialplan_counters::total_items, and dialplan_counters::total_prio.

Referenced by load_pbx().

05511 {
05512    const char *exten, *context;
05513    const char *id = astman_get_header(m, "ActionID");
05514    char idtext[256];
05515    int res;
05516 
05517    /* Variables used for different counters */
05518    struct dialplan_counters counters;
05519 
05520    if (!ast_strlen_zero(id))
05521       snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
05522    else
05523       idtext[0] = '\0';
05524 
05525    memset(&counters, 0, sizeof(counters));
05526 
05527    exten = astman_get_header(m, "Extension");
05528    context = astman_get_header(m, "Context");
05529    
05530    res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
05531 
05532    if (context && !counters.context_existence) {
05533       char errorbuf[BUFSIZ];
05534    
05535       snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
05536       astman_send_error(s, m, errorbuf);
05537       return 0;
05538    }
05539    if (exten && !counters.extension_existence) {
05540       char errorbuf[BUFSIZ];
05541 
05542       if (context)
05543          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
05544       else
05545          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
05546       astman_send_error(s, m, errorbuf);
05547       return 0;
05548    }
05549 
05550    manager_event(EVENT_FLAG_CONFIG, "ShowDialPlanComplete",
05551       "EventList: Complete\r\n"
05552       "ListItems: %d\r\n"
05553       "ListExtensions: %d\r\n"
05554       "ListPriorities: %d\r\n"   
05555       "ListContexts: %d\r\n"  
05556       "%s"
05557       "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
05558 
05559    /* everything ok */
05560    return 0;
05561 }

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 5373 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, dialplan_counters::total_context, dialplan_counters::total_exten, dialplan_counters::total_items, and dialplan_counters::total_prio.

Referenced by manager_show_dialplan().

05377 {
05378    struct ast_context *c;
05379    int res = 0, old_total_exten = dpc->total_exten;
05380 
05381    if (ast_strlen_zero(exten))
05382       exten = NULL;
05383    if (ast_strlen_zero(context))
05384       context = NULL;
05385 
05386    ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
05387 
05388    /* try to lock contexts */
05389    if (ast_rdlock_contexts()) {
05390       astman_send_error(s, m, "Failed to lock contexts");
05391       ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
05392       return -1;
05393    }
05394 
05395    c = NULL;      /* walk all contexts ... */
05396    while ( (c = ast_walk_contexts(c)) ) {
05397       struct ast_exten *e;
05398       struct ast_include *i;
05399       struct ast_ignorepat *ip;
05400 
05401       if (context && strcmp(ast_get_context_name(c), context) != 0)
05402          continue;   /* not the name we want */
05403 
05404       dpc->context_existence = 1;
05405 
05406       ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
05407 
05408       if (ast_rdlock_context(c)) {  /* failed to lock */
05409          ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
05410          continue;
05411       }
05412 
05413       /* XXX note- an empty context is not printed */
05414       e = NULL;      /* walk extensions in context  */
05415       while ( (e = ast_walk_context_extensions(c, e)) ) {
05416          struct ast_exten *p;
05417 
05418          /* looking for extension? is this our extension? */
05419          if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
05420             /* not the one we are looking for, continue */
05421             ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
05422             continue;
05423          }
05424          ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
05425 
05426          dpc->extension_existence = 1;
05427 
05428          /* may we print context info? */ 
05429          dpc->total_context++;
05430          dpc->total_exten++;
05431 
05432          p = NULL;      /* walk next extension peers */
05433          while ( (p = ast_walk_extension_priorities(e, p)) ) {
05434             int prio = ast_get_extension_priority(p);
05435 
05436             dpc->total_prio++;
05437             if (!dpc->total_items++)
05438                manager_dpsendack(s, m);
05439             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05440             astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
05441 
05442             /* XXX maybe make this conditional, if p != e ? */
05443             if (ast_get_extension_label(p))
05444                astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
05445 
05446             if (prio == PRIORITY_HINT) {
05447                astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
05448             } else {
05449                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));
05450             }
05451             astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
05452          }
05453       }
05454 
05455       i = NULL;      /* walk included and write info ... */
05456       while ( (i = ast_walk_context_includes(c, i)) ) {
05457          if (exten) {
05458             /* Check all includes for the requested extension */
05459             manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
05460          } else {
05461             if (!dpc->total_items++)
05462                manager_dpsendack(s, m);
05463             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05464             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));
05465             astman_append(s, "\r\n");
05466             ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
05467          }
05468       }
05469 
05470       ip = NULL;  /* walk ignore patterns and write info ... */
05471       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05472          const char *ipname = ast_get_ignorepat_name(ip);
05473          char ignorepat[AST_MAX_EXTENSION];
05474 
05475          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05476          if (!exten || ast_extension_match(ignorepat, exten)) {
05477             if (!dpc->total_items++)
05478                manager_dpsendack(s, m);
05479             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05480             astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
05481             astman_append(s, "\r\n");
05482          }
05483       }
05484       if (!rinclude) {
05485          struct ast_sw *sw = NULL;
05486          while ( (sw = ast_walk_context_switches(c, sw)) ) {
05487             if (!dpc->total_items++)
05488                manager_dpsendack(s, m);
05489             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05490             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));  
05491             astman_append(s, "\r\n");
05492             ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
05493          }
05494       }
05495 
05496       ast_unlock_context(c);
05497    }
05498    ast_unlock_contexts();
05499 
05500    if (dpc->total_exten == old_total_exten) {
05501       ast_debug(3, "manager_show_dialplan: Found nothing new\n");
05502       /* Nothing new under the sun */
05503       return -1;
05504    } else {
05505       return res;
05506    }
05507 }

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

Definition at line 2057 of file pbx.c.

References ast_extension_match(), and ast_strlen_zero().

Referenced by pbx_find_extension().

02058 {
02059    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
02060       failing to get a number should count as a match, otherwise not */
02061 
02062    if (ast_strlen_zero(callerid))
02063       return ast_strlen_zero(cidpattern) ? 1 : 0;
02064 
02065    return ast_extension_match(cidpattern, callerid);
02066 }

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

References match_char::alt_char, ast_debug, ast_log(), scoreboard::canmatch, match_char::deleted, E_CANMATCH, E_MATCHMORE, ast_exten::exten, scoreboard::exten, match_char::exten, ast_exten::label, LOG_NOTICE, NEW_MATCHER_CHK_MATCH, NEW_MATCHER_RECURSE, match_char::next_char, match_char::specificity, update_scoreboard(), and match_char::x.

Referenced by pbx_find_extension().

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

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

Referenced by pbx_retrieve_variable(), and pbx_substitute_variables_helper_full().

02393 {
02394    int parens = 0;
02395 
02396    *offset = 0;
02397    *length = INT_MAX;
02398    *isfunc = 0;
02399    for (; *var; var++) {
02400       if (*var == '(') {
02401          (*isfunc)++;
02402          parens++;
02403       } else if (*var == ')') {
02404          parens--;
02405       } else if (*var == ':' && parens == 0) {
02406          *var++ = '\0';
02407          sscanf(var, "%30d:%30d", offset, length);
02408          return 1; /* offset:length valid */
02409       }
02410    }
02411    return 0;
02412 }

void pbx_builtin_clear_globals ( void   ) 

Definition at line 8599 of file pbx.c.

References AST_LIST_REMOVE_HEAD, ast_rwlock_unlock(), ast_rwlock_wrlock(), and ast_var_delete().

Referenced by handle_cli_dialplan_reload(), and reload().

08600 {
08601    struct ast_var_t *vardata;
08602 
08603    ast_rwlock_wrlock(&globalslock);
08604    while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
08605       ast_var_delete(vardata);
08606    ast_rwlock_unlock(&globalslock);
08607 }

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 8369 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(), and ast_channel::varshead.

Referenced by __ast_pbx_run(), _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(), ast_park_call_full(), bridge_play_sounds(), builtin_atxfer(), 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(), findparkinglotname(), 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_space_reserve(), pbx_builtin_background(), 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_calling(), try_suggested_sip_codec(), update_bridge_vars(), and wait_for_answer().

08370 {
08371    struct ast_var_t *variables;
08372    const char *ret = NULL;
08373    int i;
08374    struct varshead *places[2] = { NULL, &globals };
08375 
08376    if (!name)
08377       return NULL;
08378 
08379    if (chan) {
08380       ast_channel_lock(chan);
08381       places[0] = &chan->varshead;
08382    }
08383 
08384    for (i = 0; i < 2; i++) {
08385       if (!places[i])
08386          continue;
08387       if (places[i] == &globals)
08388          ast_rwlock_rdlock(&globalslock);
08389       AST_LIST_TRAVERSE(places[i], variables, entries) {
08390          if (!strcmp(name, ast_var_name(variables))) {
08391             ret = ast_var_value(variables);
08392             break;
08393          }
08394       }
08395       if (places[i] == &globals)
08396          ast_rwlock_unlock(&globalslock);
08397       if (ret)
08398          break;
08399    }
08400 
08401    if (chan)
08402       ast_channel_unlock(chan);
08403 
08404    return ret;
08405 }

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

Definition at line 8621 of file pbx.c.

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

08622 {
08623    char *condition, *branch1, *branch2, *branch;
08624    char *stringp;
08625 
08626    if (ast_strlen_zero(data)) {
08627       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
08628       return 0;
08629    }
08630 
08631    stringp = ast_strdupa(data);
08632    condition = strsep(&stringp,"?");
08633    branch1 = strsep(&stringp,":");
08634    branch2 = strsep(&stringp,"");
08635    branch = pbx_checkcondition(condition) ? branch1 : branch2;
08636 
08637    if (ast_strlen_zero(branch)) {
08638       ast_debug(1, "Not taking any branch\n");
08639       return 0;
08640    }
08641 
08642    return pbx_builtin_goto(chan, branch);
08643 }

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

Todo:
XXX should do !ast_strlen_zero(..) of the args ?

Definition at line 8557 of file pbx.c.

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

08558 {
08559    char *name;
08560    char *value;
08561    char *channel;
08562    char tmp[VAR_BUF_SIZE];
08563    static int deprecation_warning = 0;
08564 
08565    if (ast_strlen_zero(data)) {
08566       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
08567       return 0;
08568    }
08569    tmp[0] = 0;
08570    if (!deprecation_warning) {
08571       ast_log(LOG_WARNING, "ImportVar is deprecated.  Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
08572       deprecation_warning = 1;
08573    }
08574 
08575    value = ast_strdupa(data);
08576    name = strsep(&value,"=");
08577    channel = strsep(&value,",");
08578    if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
08579       struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
08580       if (chan2) {
08581          char *s = alloca(strlen(value) + 4);
08582          if (s) {
08583             sprintf(s, "${%s}", value);
08584             pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
08585          }
08586          ast_channel_unlock(chan2);
08587       }
08588       pbx_builtin_setvar_helper(chan, name, tmp);
08589    }
08590 
08591    return(0);
08592 }

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

Definition at line 7960 of file pbx.c.

References __ast_answer(), ast_channel::_state, ast_check_hangup(), AST_PBX_INCOMPLETE, AST_STATE_UP, and ast_strlen_zero().

07961 {
07962    char *options = data;
07963    int answer = 1;
07964 
07965    /* Some channels can receive DTMF in unanswered state; some cannot */
07966    if (!ast_strlen_zero(options) && strchr(options, 'n')) {
07967       answer = 0;
07968    }
07969 
07970    /* If the channel is hungup, stop waiting */
07971    if (ast_check_hangup(chan)) {
07972       return -1;
07973    } else if (chan->_state != AST_STATE_UP && answer) {
07974       __ast_answer(chan, 0, 1);
07975    }
07976 
07977    return AST_PBX_INCOMPLETE;
07978 }

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

Definition at line 8594 of file pbx.c.

08595 {
08596    return 0;
08597 }

void pbx_builtin_pushvar_helper ( struct ast_channel chan,
const char *  name,
const char *  value 
)
Note:
Will lock the channel.

Definition at line 8407 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, LOG_WARNING, and ast_channel::varshead.

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

08408 {
08409    struct ast_var_t *newvariable;
08410    struct varshead *headp;
08411 
08412    if (name[strlen(name)-1] == ')') {
08413       char *function = ast_strdupa(name);
08414 
08415       ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
08416       ast_func_write(chan, function, value);
08417       return;
08418    }
08419 
08420    if (chan) {
08421       ast_channel_lock(chan);
08422       headp = &chan->varshead;
08423    } else {
08424       ast_rwlock_wrlock(&globalslock);
08425       headp = &globals;
08426    }
08427 
08428    if (value) {
08429       if (headp == &globals)
08430          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08431       newvariable = ast_var_assign(name, value);
08432       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08433    }
08434 
08435    if (chan)
08436       ast_channel_unlock(chan);
08437    else
08438       ast_rwlock_unlock(&globalslock);
08439 }

int pbx_builtin_raise_exception ( struct ast_channel chan,
void *  vreason 
)

Definition at line 2595 of file pbx.c.

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

Referenced by __ast_pbx_run().

02596 {
02597    const char *reason = vreason;
02598    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02599    struct pbx_exception *exception = NULL;
02600 
02601    if (!ds) {
02602       ds = ast_datastore_alloc(&exception_store_info, NULL);
02603       if (!ds)
02604          return -1;
02605       exception = ast_calloc(1, sizeof(struct pbx_exception));
02606       if (!exception) {
02607          ast_datastore_free(ds);
02608          return -1;
02609       }
02610       if (ast_string_field_init(exception, 128)) {
02611          ast_free(exception);
02612          ast_datastore_free(ds);
02613          return -1;
02614       }
02615       ds->data = exception;
02616       ast_channel_datastore_add(chan, ds);
02617    } else
02618       exception = ds->data;
02619 
02620    ast_string_field_set(exception, reason, reason);
02621    ast_string_field_set(exception, context, chan->context);
02622    ast_string_field_set(exception, exten, chan->exten);
02623    exception->priority = chan->priority;
02624    set_ext_pri(chan, "e", 0);
02625    return 0;
02626 }

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

Definition at line 8682 of file pbx.c.

References ast_say_character_str().

08683 {
08684    int res = 0;
08685 
08686    if (data)
08687       res = ast_say_character_str(chan, data, "", chan->language);
08688    return res;
08689 }

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

Definition at line 8673 of file pbx.c.

References ast_say_digit_str().

08674 {
08675    int res = 0;
08676 
08677    if (data)
08678       res = ast_say_digit_str(chan, data, "", chan->language);
08679    return res;
08680 }

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

Definition at line 8645 of file pbx.c.

References ast_copy_string(), ast_log(), ast_say_number(), ast_strlen_zero(), LOG_WARNING, and strsep().

08646 {
08647    char tmp[256];
08648    char *number = tmp;
08649    char *options;
08650 
08651    if (ast_strlen_zero(data)) {
08652       ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
08653       return -1;
08654    }
08655    ast_copy_string(tmp, data, sizeof(tmp));
08656    strsep(&number, ",");
08657    options = strsep(&number, ",");
08658    if (options) {
08659       if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
08660          strcasecmp(options, "c") && strcasecmp(options, "n") ) {
08661          ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
08662          return -1;
08663       }
08664    }
08665 
08666    if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
08667       ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
08668    }
08669 
08670    return 0;
08671 }

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

Definition at line 8691 of file pbx.c.

References ast_say_phonetic_str().

08692 {
08693    int res = 0;
08694 
08695    if (data)
08696       res = ast_say_phonetic_str(chan, data, "", chan->language);
08697    return res;
08698 }

int pbx_builtin_serialize_variables ( struct ast_channel chan,
struct ast_str **  buf 
)
Note:
Will lock the channel.

Definition at line 8337 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(), LOG_ERROR, total, var, and ast_channel::varshead.

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

08338 {
08339    struct ast_var_t *variables;
08340    const char *var, *val;
08341    int total = 0;
08342 
08343    if (!chan)
08344       return 0;
08345 
08346    (*buf)->used = 0;
08347    (*buf)->str[0] = '\0';
08348 
08349    ast_channel_lock(chan);
08350 
08351    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
08352       if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
08353          /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
08354          ) {
08355          if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
08356             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
08357             break;
08358          } else
08359             total++;
08360       } else
08361          break;
08362    }
08363 
08364    ast_channel_unlock(chan);
08365 
08366    return total;
08367 }

int pbx_builtin_setvar ( struct ast_channel chan,
void *  data 
)
Note:
Will lock the channel.

Definition at line 8498 of file pbx.c.

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

Referenced by rpt_exec().

08499 {
08500    char *name, *value, *mydata;
08501 
08502    if (ast_compat_app_set) {
08503       return pbx_builtin_setvar_multiple(chan, data);
08504    }
08505 
08506    if (ast_strlen_zero(data)) {
08507       ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
08508       return 0;
08509    }
08510 
08511    mydata = ast_strdupa(data);
08512    name = strsep(&mydata, "=");
08513    value = mydata;
08514    if (strchr(name, ' '))
08515       ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
08516 
08517    pbx_builtin_setvar_helper(chan, name, value);
08518    return(0);
08519 }

void pbx_builtin_setvar_helper ( struct ast_channel chan,
const char *  name,
const char *  value 
)
Note:
Will lock the channel.

Definition at line 8441 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, EVENT_FLAG_DIALPLAN, manager_event, and ast_channel::varshead.

Referenced by __ast_pbx_run(), __oh323_new(), _macro_exec(), _while_exec(), acf_fetch(), acf_odbc_read(), acf_odbc_write(), action_atxfer(), 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_rtp_set_vars(), ast_set_variables(), asyncgoto_exec(), background_detect_exec(), bridge_exec(), bridge_play_sounds(), builtin_atxfer(), 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(), disa_exec(), 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(), manage_parkinglot(), 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_full(), 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(), pri_dchannel(), privacy_exec(), process_ast_dsp(), read_exec(), readexten_exec(), readfile_exec(), record_exec(), return_exec(), rotate_file(), rpt_exec(), rqm_exec(), sendimage_exec(), sendtext_exec(), sendurl_exec(), set(), set_agentbycallerid(), set_queue_result(), sip_addheader(), sip_hangup(), sip_new(), sip_read(), skinny_new(), sla_calc_trunk_timeouts(), sla_station_exec(), sla_trunk_exec(), socket_process(), speech_create(), ss7_start_call(), 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().

08442 {
08443    struct ast_var_t *newvariable;
08444    struct varshead *headp;
08445    const char *nametail = name;
08446 
08447    if (name[strlen(name) - 1] == ')') {
08448       char *function = ast_strdupa(name);
08449 
08450       ast_func_write(chan, function, value);
08451       return;
08452    }
08453 
08454    if (chan) {
08455       ast_channel_lock(chan);
08456       headp = &chan->varshead;
08457    } else {
08458       ast_rwlock_wrlock(&globalslock);
08459       headp = &globals;
08460    }
08461 
08462    /* For comparison purposes, we have to strip leading underscores */
08463    if (*nametail == '_') {
08464       nametail++;
08465       if (*nametail == '_')
08466          nametail++;
08467    }
08468 
08469    AST_LIST_TRAVERSE (headp, newvariable, entries) {
08470       if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
08471          /* there is already such a variable, delete it */
08472          AST_LIST_REMOVE(headp, newvariable, entries);
08473          ast_var_delete(newvariable);
08474          break;
08475       }
08476    }
08477 
08478    if (value) {
08479       if (headp == &globals)
08480          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08481       newvariable = ast_var_assign(name, value);
08482       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08483       manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
08484          "Channel: %s\r\n"
08485          "Variable: %s\r\n"
08486          "Value: %s\r\n"
08487          "Uniqueid: %s\r\n", 
08488          chan ? chan->name : "none", name, value, 
08489          chan ? chan->uniqueid : "none");
08490    }
08491 
08492    if (chan)
08493       ast_channel_unlock(chan);
08494    else
08495       ast_rwlock_unlock(&globalslock);
08496 }

int pbx_builtin_setvar_multiple ( struct ast_channel chan,
void *  vdata 
)

Definition at line 8521 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(), ast_channel::context, ast_channel::exten, LOG_WARNING, pbx_builtin_setvar_helper(), and ast_channel::priority.

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

08522 {
08523    char *data;
08524    int x;
08525    AST_DECLARE_APP_ARGS(args,
08526       AST_APP_ARG(pair)[24];
08527    );
08528    AST_DECLARE_APP_ARGS(pair,
08529       AST_APP_ARG(name);
08530       AST_APP_ARG(value);
08531    );
08532 
08533    if (ast_strlen_zero(vdata)) {
08534       ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
08535       return 0;
08536    }
08537 
08538    data = ast_strdupa(vdata);
08539    AST_STANDARD_APP_ARGS(args, data);
08540 
08541    for (x = 0; x < args.argc; x++) {
08542       AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
08543       if (pair.argc == 2) {
08544          pbx_builtin_setvar_helper(chan, pair.name, pair.value);
08545          if (strchr(pair.name, ' '))
08546             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);
08547       } else if (!chan) {
08548          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
08549       } else {
08550          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, chan->exten, chan->context, chan->priority);
08551       }
08552    }
08553 
08554    return 0;
08555 }

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

08610 {
08611    int res;
08612    if (ast_strlen_zero(condition)) {                /* NULL or empty strings are false */
08613       return 0;
08614    } else if (sscanf(condition, "%30d", &res) == 1) { /* Numbers are evaluated for truth */
08615       return res;
08616    } else {                                         /* Strings are true */
08617       return 1;
08618    }
08619 }

static void pbx_destroy ( struct ast_pbx p  )  [static]

Definition at line 1011 of file pbx.c.

References ast_free.

Referenced by __ast_pbx_run().

01012 {
01013    ast_free(p);
01014 }

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

References __ast_module_user_add(), __ast_module_user_remove(), ast_channel::appl, ast_cdr_setapp(), ast_check_hangup(), ast_log(), ast_opt_dont_warn, ast_strlen_zero(), ast_channel::cdr, ast_channel::data, ast_app::execute, LOG_WARNING, 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(), page_exec(), pbx_builtin_execiftime(), pbx_extension_helper(), realtime_exec(), try_calling(), and tryexec_exec().

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

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 3153 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, pbx_exec(), pbx_find_extension(), pbx_findapp(), pbx_substitute_variables(), ast_channel::priority, ast_exten::priority, S_OR, 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(), and VERBOSITY_ATLEAST.

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

03156 {
03157    struct ast_exten *e;
03158    struct ast_app *app;
03159    int res;
03160    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
03161    char passdata[EXT_DATA_SIZE];
03162 
03163    int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
03164 
03165    ast_rdlock_contexts();
03166    if (found)
03167       *found = 0;
03168 
03169    e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
03170    if (e) {
03171       if (found)
03172          *found = 1;
03173       if (matching_action) {
03174          ast_unlock_contexts();
03175          return -1;  /* success, we found it */
03176       } else if (action == E_FINDLABEL) { /* map the label to a priority */
03177          res = e->priority;
03178          ast_unlock_contexts();
03179          return res; /* the priority we were looking for */
03180       } else { /* spawn */
03181          if (!e->cached_app)
03182             e->cached_app = pbx_findapp(e->app);
03183          app = e->cached_app;
03184          ast_unlock_contexts();
03185          if (!app) {
03186             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
03187             return -1;
03188          }
03189          if (c->context != context)
03190             ast_copy_string(c->context, context, sizeof(c->context));
03191          if (c->exten != exten)
03192             ast_copy_string(c->exten, exten, sizeof(c->exten));
03193          c->priority = priority;
03194          pbx_substitute_variables(passdata, sizeof(passdata), c, e);
03195 #ifdef CHANNEL_TRACE
03196          ast_channel_trace_update(c);
03197 #endif
03198          ast_debug(1, "Launching '%s'\n", app->name);
03199          if (VERBOSITY_ATLEAST(3)) {
03200             char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
03201             ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
03202                exten, context, priority,
03203                term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
03204                term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
03205                term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
03206                "in new stack");
03207          }
03208          manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
03209                "Channel: %s\r\n"
03210                "Context: %s\r\n"
03211                "Extension: %s\r\n"
03212                "Priority: %d\r\n"
03213                "Application: %s\r\n"
03214                "AppData: %s\r\n"
03215                "Uniqueid: %s\r\n",
03216                c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
03217          return pbx_exec(c, app, passdata);  /* 0 on success, -1 on failure */
03218       }
03219    } else if (q.swo) {  /* not found here, but in another switch */
03220       if (found)
03221          *found = 1;
03222       ast_unlock_contexts();
03223       if (matching_action) {
03224          return -1;
03225       } else {
03226          if (!q.swo->exec) {
03227             ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
03228             res = -1;
03229          }
03230          return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
03231       }
03232    } else { /* not found anywhere, see what happened */
03233       ast_unlock_contexts();
03234       /* Using S_OR here because Solaris doesn't like NULL being passed to ast_log */
03235       switch (q.status) {
03236       case STATUS_NO_CONTEXT:
03237          if (!matching_action && !combined_find_spawn)
03238             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
03239          break;
03240       case STATUS_NO_EXTENSION:
03241          if (!matching_action && !combined_find_spawn)
03242             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
03243          break;
03244       case STATUS_NO_PRIORITY:
03245          if (!matching_action && !combined_find_spawn)
03246             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
03247          break;
03248       case STATUS_NO_LABEL:
03249          if (context && !combined_find_spawn)
03250             ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, S_OR(context, ""));
03251          break;
03252       default:
03253          ast_debug(1, "Shouldn't happen!\n");
03254       }
03255 
03256       return (matching_action) ? 0 : -1;
03257    }
03258 }

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

Definition at line 2068 of file pbx.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_copy_string(), ast_hashtab_lookup(), AST_LIST_TRAVERSE, ast_log(), AST_PBX_MAX_STACK, ast_str_thread_get(), ast_strdupa, ast_strlen_zero(), ast_walk_context_extensions(), ast_walk_contexts(), ast_walk_extension_priorities(), ast_switch::canmatch, scoreboard::canmatch_exten, create_match_char_tree(), ast_sw::data, pbx_find_info::data, E_CANMATCH, E_FINDLABEL, E_MATCHMORE, ast_sw::eval, ast_switch::exists, ast_exten::exten, scoreboard::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, 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, strsep(), pbx_find_info::swo, scoreboard::total_length, scoreboard::total_specificity, and trie_find_next_match().

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

02072 {
02073    int x, res;
02074    struct ast_context *tmp = NULL;
02075    struct ast_exten *e = NULL, *eroot = NULL;
02076    struct ast_include *i = NULL;
02077    struct ast_sw *sw = NULL;
02078    struct ast_exten pattern = {NULL, };
02079    struct scoreboard score = {0, };
02080    struct ast_str *tmpdata = NULL;
02081 
02082    pattern.label = label;
02083    pattern.priority = priority;
02084 #ifdef NEED_DEBUG_HERE
02085    ast_log(LOG_NOTICE,"Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int)action);
02086 #endif
02087 
02088    /* Initialize status if appropriate */
02089    if (q->stacklen == 0) {
02090       q->status = STATUS_NO_CONTEXT;
02091       q->swo = NULL;
02092       q->data = NULL;
02093       q->foundcontext = NULL;
02094    } else if (q->stacklen >= AST_PBX_MAX_STACK) {
02095       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
02096       return NULL;
02097    }
02098 
02099    /* Check first to see if we've already been checked */
02100    for (x = 0; x < q->stacklen; x++) {
02101       if (!strcasecmp(q->incstack[x], context))
02102          return NULL;
02103    }
02104 
02105    if (bypass) /* bypass means we only look there */
02106       tmp = bypass;
02107    else {   /* look in contexts */
02108       struct fake_context item;
02109 
02110       ast_copy_string(item.name, context, sizeof(item.name));
02111 
02112       tmp = ast_hashtab_lookup(contexts_table, &item);
02113 #ifdef NOTNOW
02114       tmp = NULL;
02115       while ((tmp = ast_walk_contexts(tmp)) ) {
02116          if (!strcmp(tmp->name, context))
02117             break;
02118       }
02119 #endif
02120       if (!tmp)
02121          return NULL;
02122       
02123    }
02124 
02125    if (q->status < STATUS_NO_EXTENSION)
02126       q->status = STATUS_NO_EXTENSION;
02127    
02128    /* Do a search for matching extension */
02129 
02130    eroot = NULL;
02131    score.total_specificity = 0;
02132    score.exten = 0;
02133    score.total_length = 0;
02134    if (!tmp->pattern_tree && tmp->root_table)
02135    {
02136       create_match_char_tree(tmp);
02137 #ifdef NEED_DEBUG
02138       ast_log(LOG_DEBUG,"Tree Created in context %s:\n", context);
02139       log_match_char_tree(tmp->pattern_tree," ");
02140 #endif
02141    }
02142 #ifdef NEED_DEBUG
02143    ast_log(LOG_NOTICE,"The Trie we are searching in:\n");
02144    log_match_char_tree(tmp->pattern_tree, "::  ");
02145 #endif
02146 
02147    do {
02148       if (!ast_strlen_zero(overrideswitch)) {
02149          char *osw = ast_strdupa(overrideswitch), *name;
02150          struct ast_switch *asw;
02151          ast_switch_f *aswf = NULL;
02152          char *datap;
02153          int eval = 0;
02154 
02155          name = strsep(&osw, "/");
02156          asw = pbx_findswitch(name);
02157 
02158          if (!asw) {
02159             ast_log(LOG_WARNING, "No such switch '%s'\n", name);
02160             break;
02161          }
02162 
02163          if (osw && strchr(osw, '$')) {
02164             eval = 1;
02165          }
02166 
02167          if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02168             ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!");
02169             break;
02170          } else if (eval) {
02171             /* Substitute variables now */
02172             pbx_substitute_variables_helper(chan, osw, tmpdata->str, tmpdata->len);
02173             datap = tmpdata->str;
02174          } else {
02175             datap = osw;
02176          }
02177 
02178          /* equivalent of extension_match_core() at the switch level */
02179          if (action == E_CANMATCH)
02180             aswf = asw->canmatch;
02181          else if (action == E_MATCHMORE)
02182             aswf = asw->matchmore;
02183          else /* action == E_MATCH */
02184             aswf = asw->exists;
02185          if (!aswf) {
02186             res = 0;
02187          } else {
02188             if (chan) {
02189                ast_autoservice_start(chan);
02190             }
02191             res = aswf(chan, context, exten, priority, callerid, datap);
02192             if (chan) {
02193                ast_autoservice_stop(chan);
02194             }
02195          }
02196          if (res) {  /* Got a match */
02197             q->swo = asw;
02198             q->data = datap;
02199             q->foundcontext = context;
02200             /* XXX keep status = STATUS_NO_CONTEXT ? */
02201             return NULL;
02202          }
02203       }
02204    } while (0);
02205 
02206    if (extenpatternmatchnew) {
02207       new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
02208       eroot = score.exten;
02209       
02210       if (score.last_char == '!' && action == E_MATCHMORE) {
02211          /* We match an extension ending in '!'.
02212           * The decision in this case is final and is NULL (no match).
02213           */
02214 #ifdef NEED_DEBUG_HERE
02215          ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
02216 #endif
02217          return NULL;
02218       }
02219       
02220       if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
02221          q->status = STATUS_SUCCESS;
02222 #ifdef NEED_DEBUG_HERE
02223          ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
02224 #endif
02225          return score.canmatch_exten;
02226       }
02227       
02228       if ((action == E_MATCHMORE || action == E_CANMATCH)  && eroot) {
02229          if (score.node) {
02230             struct ast_exten *z = trie_find_next_match(score.node);
02231             if (z) {
02232 #ifdef NEED_DEBUG_HERE
02233                ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
02234 #endif
02235             } else {
02236                if (score.canmatch_exten) {
02237 #ifdef NEED_DEBUG_HERE
02238                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
02239 #endif
02240                   return score.canmatch_exten;
02241                } else {
02242 #ifdef NEED_DEBUG_HERE
02243                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
02244 #endif
02245                }
02246             }
02247             return z;
02248          }
02249 #ifdef NEED_DEBUG_HERE
02250          ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
02251 #endif
02252          return NULL;  /* according to the code, complete matches are null matches in MATCHMORE mode */
02253       }
02254       
02255       if (eroot) {
02256          /* found entry, now look for the right priority */
02257          if (q->status < STATUS_NO_PRIORITY)
02258             q->status = STATUS_NO_PRIORITY;
02259          e = NULL;
02260          if (action == E_FINDLABEL && label ) {
02261             if (q->status < STATUS_NO_LABEL)
02262                q->status = STATUS_NO_LABEL;
02263             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02264          } else {
02265             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02266          }
02267          if (e) { /* found a valid match */
02268             q->status = STATUS_SUCCESS;
02269             q->foundcontext = context;
02270 #ifdef NEED_DEBUG_HERE
02271             ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
02272 #endif
02273             return e;
02274          }
02275       }
02276    } else {   /* the old/current default exten pattern match algorithm */
02277       
02278       /* scan the list trying to match extension and CID */
02279       eroot = NULL;
02280       while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
02281          int match = extension_match_core(eroot->exten, exten, action);
02282          /* 0 on fail, 1 on match, 2 on earlymatch */
02283          
02284          if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
02285             continue;   /* keep trying */
02286          if (match == 2 && action == E_MATCHMORE) {
02287             /* We match an extension ending in '!'.
02288              * The decision in this case is final and is NULL (no match).
02289              */
02290             return NULL;
02291          }
02292          /* found entry, now look for the right priority */
02293          if (q->status < STATUS_NO_PRIORITY)
02294             q->status = STATUS_NO_PRIORITY;
02295          e = NULL;
02296          if (action == E_FINDLABEL && label ) {
02297             if (q->status < STATUS_NO_LABEL)
02298                q->status = STATUS_NO_LABEL;
02299             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02300          } else {
02301             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02302          }
02303 #ifdef NOTNOW
02304          while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
02305             /* Match label or priority */
02306             if (action == E_FINDLABEL) {
02307                if (q->status < STATUS_NO_LABEL)
02308                   q->status = STATUS_NO_LABEL;
02309                if (label && e->label && !strcmp(label, e->label))
02310                   break;   /* found it */
02311             } else if (e->priority == priority) {
02312                break;   /* found it */
02313             } /* else keep searching */
02314          }
02315 #endif
02316          if (e) { /* found a valid match */
02317             q->status = STATUS_SUCCESS;
02318             q->foundcontext = context;
02319             return e;
02320          }
02321       }
02322    }
02323    
02324    
02325    /* Check alternative switches */
02326    AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
02327       struct ast_switch *asw = pbx_findswitch(sw->name);
02328       ast_switch_f *aswf = NULL;
02329       char *datap;
02330 
02331       if (!asw) {
02332          ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
02333          continue;
02334       }
02335       /* Substitute variables now */
02336       
02337       if (sw->eval) {
02338          if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02339             ast_log(LOG_WARNING, "Can't evaluate switch?!");
02340             continue;
02341          }
02342          pbx_substitute_variables_helper(chan, sw->data, tmpdata->str, tmpdata->len);
02343       }
02344 
02345       /* equivalent of extension_match_core() at the switch level */
02346       if (action == E_CANMATCH)
02347          aswf = asw->canmatch;
02348       else if (action == E_MATCHMORE)
02349          aswf = asw->matchmore;
02350       else /* action == E_MATCH */
02351          aswf = asw->exists;
02352       datap = sw->eval ? tmpdata->str : sw->data;
02353       if (!aswf)
02354          res = 0;
02355       else {
02356          if (chan)
02357             ast_autoservice_start(chan);
02358          res = aswf(chan, context, exten, priority, callerid, datap);
02359          if (chan)
02360             ast_autoservice_stop(chan);
02361       }
02362       if (res) {  /* Got a match */
02363          q->swo = asw;
02364          q->data = datap;
02365          q->foundcontext = context;
02366          /* XXX keep status = STATUS_NO_CONTEXT ? */
02367          return NULL;
02368       }
02369    }
02370    q->incstack[q->stacklen++] = tmp->name;   /* Setup the stack */
02371    /* Now try any includes we have in this context */
02372    for (i = tmp->includes; i; i = i->next) {
02373       if (include_valid(i)) {
02374          if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
02375 #ifdef NEED_DEBUG_HERE
02376             ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
02377 #endif
02378             return e;
02379          }
02380          if (q->swo)
02381             return NULL;
02382       }
02383    }
02384    return NULL;
02385 }

struct ast_app* pbx_findapp ( const char *  app  )  [read]

Find application handle in linked list.

Look up an application.

Definition at line 975 of file pbx.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, and AST_RWLIST_UNLOCK.

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(), page_exec(), pbx_builtin_execiftime(), pbx_extension_helper(), realtime_exec(), try_calling(), and tryexec_exec().

00976 {
00977    struct ast_app *tmp;
00978 
00979    AST_RWLIST_RDLOCK(&apps);
00980    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
00981       if (!strcasecmp(tmp->name, app))
00982          break;
00983    }
00984    AST_RWLIST_UNLOCK(&apps);
00985 
00986    return tmp;
00987 }

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

Definition at line 989 of file pbx.c.

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

Referenced by pbx_find_extension().

00990 {
00991    struct ast_switch *asw;
00992 
00993    AST_RWLIST_RDLOCK(&switches);
00994    AST_RWLIST_TRAVERSE(&switches, asw, list) {
00995       if (!strcasecmp(asw->name, sw))
00996          break;
00997    }
00998    AST_RWLIST_UNLOCK(&switches);
00999 
01000    return asw;
01001 }

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

Definition at line 8997 of file pbx.c.

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

Referenced by ast_async_parseable_goto(), and ast_parseable_goto().

08998 {
08999    char *exten, *pri, *context;
09000    char *stringp;
09001    int ipri;
09002    int mode = 0;
09003 
09004    if (ast_strlen_zero(goto_string)) {
09005       ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
09006       return -1;
09007    }
09008    stringp = ast_strdupa(goto_string);
09009    context = strsep(&stringp, ","); /* guaranteed non-null */
09010    exten = strsep(&stringp, ",");
09011    pri = strsep(&stringp, ",");
09012    if (!exten) {  /* Only a priority in this one */
09013       pri = context;
09014       exten = NULL;
09015       context = NULL;
09016    } else if (!pri) {   /* Only an extension and priority in this one */
09017       pri = exten;
09018       exten = context;
09019       context = NULL;
09020    }
09021    if (*pri == '+') {
09022       mode = 1;
09023       pri++;
09024    } else if (*pri == '-') {
09025       mode = -1;
09026       pri++;
09027    }
09028    if (sscanf(pri, "%30d", &ipri) != 1) {
09029       if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
09030          pri, chan->cid.cid_num)) < 1) {
09031          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
09032          return -1;
09033       } else
09034          mode = 0;
09035    }
09036    /* At this point we have a priority and maybe an extension and a context */
09037 
09038    if (mode)
09039       ipri = chan->priority + (ipri * mode);
09040 
09041    if (async)
09042       ast_async_goto(chan, context, exten, ipri);
09043    else
09044       ast_explicit_goto(chan, context, exten, ipri);
09045    
09046    return 0;
09047 
09048 }

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

References ARRAY_LEN, ast_channel_lock, ast_channel_unlock, ast_config_AST_SYSTEM_NAME, ast_copy_string(), ast_eid_default, ast_eid_to_str(), 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, ast_channel::hangupcause, parse_variable_name(), ast_channel::priority, s, substring(), and ast_channel::varshead.

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

02468 {
02469    const char not_found = '\0';
02470    char *tmpvar;
02471    const char *s; /* the result */
02472    int offset, length;
02473    int i, need_substring;
02474    struct varshead *places[2] = { headp, &globals };  /* list of places where we may look */
02475 
02476    if (c) {
02477       ast_channel_lock(c);
02478       places[0] = &c->varshead;
02479    }
02480    /*
02481     * Make a copy of var because parse_variable_name() modifies the string.
02482     * Then if called directly, we might need to run substring() on the result;
02483     * remember this for later in 'need_substring', 'offset' and 'length'
02484     */
02485    tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
02486    need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
02487 
02488    /*
02489     * Look first into predefined variables, then into variable lists.
02490     * Variable 's' points to the result, according to the following rules:
02491     * s == &not_found (set at the beginning) means that we did not find a
02492     * matching variable and need to look into more places.
02493     * If s != &not_found, s is a valid result string as follows:
02494     * s = NULL if the variable does not have a value;
02495     * you typically do this when looking for an unset predefined variable.
02496     * s = workspace if the result has been assembled there;
02497     * typically done when the result is built e.g. with an snprintf(),
02498     * so we don't need to do an additional copy.
02499     * s != workspace in case we have a string, that needs to be copied
02500     * (the ast_copy_string is done once for all at the end).
02501     * Typically done when the result is already available in some string.
02502     */
02503    s = &not_found;   /* default value */
02504    if (c) { /* This group requires a valid channel */
02505       /* Names with common parts are looked up a piece at a time using strncmp. */
02506       if (!strncmp(var, "CALL", 4)) {
02507          if (!strncmp(var + 4, "ING", 3)) {
02508             if (!strcmp(var + 7, "PRES")) {        /* CALLINGPRES */
02509                snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
02510                s = workspace;
02511             } else if (!strcmp(var + 7, "ANI2")) {    /* CALLINGANI2 */
02512                snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
02513                s = workspace;
02514             } else if (!strcmp(var + 7, "TON")) {     /* CALLINGTON */
02515                snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
02516                s = workspace;
02517             } else if (!strcmp(var + 7, "TNS")) {     /* CALLINGTNS */
02518                snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
02519                s = workspace;
02520             }
02521          }
02522       } else if (!strcmp(var, "HINT")) {
02523          s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
02524       } else if (!strcmp(var, "HINTNAME")) {
02525          s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
02526       } else if (!strcmp(var, "EXTEN")) {
02527          s = c->exten;
02528       } else if (!strcmp(var, "CONTEXT")) {
02529          s = c->context;
02530       } else if (!strcmp(var, "PRIORITY")) {
02531          snprintf(workspace, workspacelen, "%d", c->priority);
02532          s = workspace;
02533       } else if (!strcmp(var, "CHANNEL")) {
02534          s = c->name;
02535       } else if (!strcmp(var, "UNIQUEID")) {
02536          s = c->uniqueid;
02537       } else if (!strcmp(var, "HANGUPCAUSE")) {
02538          snprintf(workspace, workspacelen, "%d", c->hangupcause);
02539          s = workspace;
02540       }
02541    }
02542    if (s == &not_found) { /* look for more */
02543       if (!strcmp(var, "EPOCH")) {
02544          snprintf(workspace, workspacelen, "%u",(int)time(NULL));
02545          s = workspace;
02546       } else if (!strcmp(var, "SYSTEMNAME")) {
02547          s = ast_config_AST_SYSTEM_NAME;
02548       } else if (!strcmp(var, "ENTITYID")) {
02549          ast_eid_to_str(workspace, workspacelen, &ast_eid_default);
02550          s = workspace;
02551       }
02552    }
02553    /* if not found, look into chanvars or global vars */
02554    for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
02555       struct ast_var_t *variables;
02556       if (!places[i])
02557          continue;
02558       if (places[i] == &globals)
02559          ast_rwlock_rdlock(&globalslock);
02560       AST_LIST_TRAVERSE(places[i], variables, entries) {
02561          if (!strcasecmp(ast_var_name(variables), var)) {
02562             s = ast_var_value(variables);
02563             break;
02564          }
02565       }
02566       if (places[i] == &globals)
02567          ast_rwlock_unlock(&globalslock);
02568    }
02569    if (s == &not_found || s == NULL)
02570       *ret = NULL;
02571    else {
02572       if (s != workspace)
02573          ast_copy_string(workspace, s, workspacelen);
02574       *ret = workspace;
02575       if (need_substring)
02576          *ret = substring(*ret, offset, length, workspace, workspacelen);
02577    }
02578 
02579    if (c)
02580       ast_channel_unlock(c);
02581 }

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

Referenced by pbx_load_module().

04110 {
04111    int oldval = autofallthrough;
04112    autofallthrough = newval;
04113    return oldval;
04114 }

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

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

04117 {
04118    int oldval = extenpatternmatchnew;
04119    extenpatternmatchnew = newval;
04120    return oldval;
04121 }

void pbx_set_overrideswitch ( const char *  newval  ) 

Set "overrideswitch" field. If set and of nonzero length, all contexts will be tried directly through the named switch prior to any other matching within that context.

Since:
1.6.1

Definition at line 4123 of file pbx.c.

References ast_free, ast_strdup, and ast_strlen_zero().

Referenced by pbx_load_module().

04124 {
04125    if (overrideswitch) {
04126       ast_free(overrideswitch);
04127    }
04128    if (!ast_strlen_zero(newval)) {
04129       overrideswitch = ast_strdup(newval);
04130    } else {
04131       overrideswitch = NULL;
04132    }
04133 }

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

Definition at line 3118 of file pbx.c.

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

Referenced by pbx_extension_helper().

03119 {
03120    const char *tmp;
03121 
03122    /* Nothing more to do */
03123    if (!e->data)
03124       return;
03125 
03126    /* No variables or expressions in e->data, so why scan it? */
03127    if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
03128       ast_copy_string(passdata, e->data, datalen);
03129       return;
03130    }
03131 
03132    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
03133 }

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

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

02917 {
02918    /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
02919    char *cp4;
02920    const char *tmp, *whereweare;
02921    int length, offset, offset2, isfunction;
02922    char *workspace = NULL;
02923    char *ltmp = NULL, *var = NULL;
02924    char *nextvar, *nextexp, *nextthing;
02925    char *vars, *vare;
02926    int pos, brackets, needsub, len;
02927    
02928    *cp2 = 0; /* just in case nothing ends up there */
02929    whereweare=tmp=cp1;
02930    while (!ast_strlen_zero(whereweare) && count) {
02931       /* Assume we're copying the whole remaining string */
02932       pos = strlen(whereweare);
02933       nextvar = NULL;
02934       nextexp = NULL;
02935       nextthing = strchr(whereweare, '$');
02936       if (nextthing) {
02937          switch (nextthing[1]) {
02938          case '{':
02939             nextvar = nextthing;
02940             pos = nextvar - whereweare;
02941             break;
02942          case '[':
02943             nextexp = nextthing;
02944             pos = nextexp - whereweare;
02945             break;
02946          default:
02947             pos = 1;
02948          }
02949       }
02950 
02951       if (pos) {
02952          /* Can't copy more than 'count' bytes */
02953          if (pos > count)
02954             pos = count;
02955 
02956          /* Copy that many bytes */
02957          memcpy(cp2, whereweare, pos);
02958 
02959          count -= pos;
02960          cp2 += pos;
02961          whereweare += pos;
02962          *cp2 = 0;
02963       }
02964 
02965       if (nextvar) {
02966          /* We have a variable.  Find the start and end, and determine
02967             if we are going to have to recursively call ourselves on the
02968             contents */
02969          vars = vare = nextvar + 2;
02970          brackets = 1;
02971          needsub = 0;
02972 
02973          /* Find the end of it */
02974          while (brackets && *vare) {
02975             if ((vare[0] == '$') && (vare[1] == '{')) {
02976                needsub++;
02977             } else if (vare[0] == '{') {
02978                brackets++;
02979             } else if (vare[0] == '}') {
02980                brackets--;
02981             } else if ((vare[0] == '$') && (vare[1] == '['))
02982                needsub++;
02983             vare++;
02984          }
02985          if (brackets)
02986             ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
02987          len = vare - vars - 1;
02988 
02989          /* Skip totally over variable string */
02990          whereweare += (len + 3);
02991 
02992          if (!var)
02993             var = alloca(VAR_BUF_SIZE);
02994 
02995          /* Store variable name (and truncate) */
02996          ast_copy_string(var, vars, len + 1);
02997 
02998          /* Substitute if necessary */
02999          if (needsub) {
03000             if (!ltmp)
03001                ltmp = alloca(VAR_BUF_SIZE);
03002 
03003             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
03004             vars = ltmp;
03005          } else {
03006             vars = var;
03007          }
03008 
03009          if (!workspace)
03010             workspace = alloca(VAR_BUF_SIZE);
03011 
03012          workspace[0] = '\0';
03013 
03014          parse_variable_name(vars, &offset, &offset2, &isfunction);
03015          if (isfunction) {
03016             /* Evaluate function */
03017             if (c || !headp)
03018                cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03019             else {
03020                struct varshead old;
03021                struct ast_channel *bogus = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
03022                if (bogus) {
03023                   memcpy(&old, &bogus->varshead, sizeof(old));
03024                   memcpy(&bogus->varshead, headp, sizeof(bogus->varshead));
03025                   cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03026                   /* Don't deallocate the varshead that was passed in */
03027                   memcpy(&bogus->varshead, &old, sizeof(bogus->varshead));
03028                   ast_channel_free(bogus);
03029                } else
03030                   ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
03031             }
03032             ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
03033          } else {
03034             /* Retrieve variable value */
03035             pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
03036          }
03037          if (cp4) {
03038             cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
03039 
03040             length = strlen(cp4);
03041             if (length > count)
03042                length = count;
03043             memcpy(cp2, cp4, length);
03044             count -= length;
03045             cp2 += length;
03046             *cp2 = 0;
03047          }
03048       } else if (nextexp) {
03049          /* We have an expression.  Find the start and end, and determine
03050             if we are going to have to recursively call ourselves on the
03051             contents */
03052          vars = vare = nextexp + 2;
03053          brackets = 1;
03054          needsub = 0;
03055 
03056          /* Find the end of it */
03057          while (brackets && *vare) {
03058             if ((vare[0] == '$') && (vare[1] == '[')) {
03059                needsub++;
03060                brackets++;
03061                vare++;
03062             } else if (vare[0] == '[') {
03063                brackets++;
03064             } else if (vare[0] == ']') {
03065                brackets--;
03066             } else if ((vare[0] == '$') && (vare[1] == '{')) {
03067                needsub++;
03068                vare++;
03069             }
03070             vare++;
03071          }
03072          if (brackets)
03073             ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
03074          len = vare - vars - 1;
03075 
03076          /* Skip totally over expression */
03077          whereweare += (len + 3);
03078 
03079          if (!var)
03080             var = alloca(VAR_BUF_SIZE);
03081 
03082          /* Store variable name (and truncate) */
03083          ast_copy_string(var, vars, len + 1);
03084 
03085          /* Substitute if necessary */
03086          if (needsub) {
03087             if (!ltmp)
03088                ltmp = alloca(VAR_BUF_SIZE);
03089 
03090             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
03091             vars = ltmp;
03092          } else {
03093             vars = var;
03094          }
03095 
03096          length = ast_expr(vars, cp2, count, c);
03097 
03098          if (length) {
03099             ast_debug(1, "Expression result is '%s'\n", cp2);
03100             count -= length;
03101             cp2 += length;
03102             *cp2 = 0;
03103          }
03104       }
03105    }
03106 }

void pbx_substitute_variables_varshead ( struct varshead *  headp,
const char *  cp1,
char *  cp2,
int  count 
)
static void* pbx_thread ( void *  data  )  [static]

Definition at line 4037 of file pbx.c.

References __ast_pbx_run(), and decrease_call_count().

Referenced by ast_pbx_start().

04038 {
04039    /* Oh joyeous kernel, we're a new thread, with nothing to do but
04040       answer this channel and get it going.
04041    */
04042    /* NOTE:
04043       The launcher of this function _MUST_ increment 'countcalls'
04044       before invoking the function; it will be decremented when the
04045       PBX has finished running on the channel
04046     */
04047    struct ast_channel *c = data;
04048 
04049    __ast_pbx_run(c, NULL);
04050    decrease_call_count();
04051 
04052    pthread_exit(NULL);
04053 
04054    return NULL;
04055 }

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

helper function to print an extension

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

05024 {
05025    int prio = ast_get_extension_priority(e);
05026    if (prio == PRIORITY_HINT) {
05027       snprintf(buf, buflen, "hint: %s",
05028          ast_get_extension_app(e));
05029    } else {
05030       snprintf(buf, buflen, "%d. %s(%s)",
05031          prio, ast_get_extension_app(e),
05032          (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
05033    }
05034 }

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

03678 {
03679    ast_channel_lock(c);
03680    ast_copy_string(c->exten, exten, sizeof(c->exten));
03681    c->priority = pri;
03682    ast_channel_unlock(c);
03683 }

static int show_debug_helper ( int  fd,
const char *  context,
const char *  exten,
struct dialplan_counters dpc,
struct ast_include rinclude,
int  includecount,
const char *  includes[] 
) [static]

Definition at line 5188 of file pbx.c.

References ast_cli(), ast_exists_extension(), ast_get_context_name(), ast_get_context_registrar(), ast_rdlock_context(), ast_rdlock_contexts(), ast_unlock_context(), ast_unlock_contexts(), ast_walk_contexts(), cli_match_char_tree(), dialplan_counters::context_existence, ast_context::pattern_tree, dialplan_counters::total_context, and dialplan_counters::total_exten.

Referenced by handle_debug_dialplan().

05189 {
05190    struct ast_context *c = NULL;
05191    int res = 0, old_total_exten = dpc->total_exten;
05192 
05193    ast_cli(fd,"\n     In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
05194 
05195    ast_cli(fd,"\n           Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
05196    ast_cli(fd,    "                        Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
05197    ast_cli(fd,    "                              <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
05198    ast_cli(fd,    "                              <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
05199    ast_cli(fd,    "                              [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
05200    ast_cli(fd,    "                        In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
05201    ast_cli(fd,    "                        are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
05202    ast_rdlock_contexts();
05203 
05204    /* walk all contexts ... */
05205    while ( (c = ast_walk_contexts(c)) ) {
05206       int context_info_printed = 0;
05207 
05208       if (context && strcmp(ast_get_context_name(c), context))
05209          continue;   /* skip this one, name doesn't match */
05210 
05211       dpc->context_existence = 1;
05212 
05213       if (!c->pattern_tree)
05214          ast_exists_extension(NULL, c->name, "s", 1, ""); /* do this to force the trie to built, if it is not already */
05215 
05216       ast_rdlock_context(c);
05217 
05218       dpc->total_context++;
05219       ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05220          ast_get_context_name(c), ast_get_context_registrar(c));
05221       context_info_printed = 1;
05222       
05223       if (c->pattern_tree)
05224       {
05225          cli_match_char_tree(c->pattern_tree, " ", fd);
05226       } else {
05227          ast_cli(fd,"\n     No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
05228       }
05229 
05230       ast_unlock_context(c);
05231 
05232       /* if we print something in context, make an empty line */
05233       if (context_info_printed)
05234          ast_cli(fd, "\n");
05235    }
05236    ast_unlock_contexts();
05237 
05238    return (dpc->total_exten == old_total_exten) ? -1 : res;
05239 }

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 5037 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, dialplan_counters::context_existence, el, dialplan_counters::extension_existence, LOG_WARNING, ast_exten::matchcid, print_ext(), dialplan_counters::total_context, dialplan_counters::total_exten, and dialplan_counters::total_prio.

Referenced by handle_show_dialplan().

05038 {
05039    struct ast_context *c = NULL;
05040    int res = 0, old_total_exten = dpc->total_exten;
05041 
05042    ast_rdlock_contexts();
05043 
05044    /* walk all contexts ... */
05045    while ( (c = ast_walk_contexts(c)) ) {
05046       struct ast_exten *e;
05047       struct ast_include *i;
05048       struct ast_ignorepat *ip;
05049       char buf[256], buf2[256];
05050       int context_info_printed = 0;
05051 
05052       if (context && strcmp(ast_get_context_name(c), context))
05053          continue;   /* skip this one, name doesn't match */
05054 
05055       dpc->context_existence = 1;
05056 
05057       ast_rdlock_context(c);
05058 
05059       /* are we looking for exten too? if yes, we print context
05060        * only if we find our extension.
05061        * Otherwise print context even if empty ?
05062        * XXX i am not sure how the rinclude is handled.
05063        * I think it ought to go inside.
05064        */
05065       if (!exten) {
05066          dpc->total_context++;
05067          ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05068             ast_get_context_name(c), ast_get_context_registrar(c));
05069          context_info_printed = 1;
05070       }
05071 
05072       /* walk extensions ... */
05073       e = NULL;
05074       while ( (e = ast_walk_context_extensions(c, e)) ) {
05075          struct ast_exten *p;
05076 
05077          if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
05078             continue;   /* skip, extension match failed */
05079 
05080          dpc->extension_existence = 1;
05081 
05082          /* may we print context info? */
05083          if (!context_info_printed) {
05084             dpc->total_context++;
05085             if (rinclude) { /* TODO Print more info about rinclude */
05086                ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
05087                   ast_get_context_name(c), ast_get_context_registrar(c));
05088             } else {
05089                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05090                   ast_get_context_name(c), ast_get_context_registrar(c));
05091             }
05092             context_info_printed = 1;
05093          }
05094          dpc->total_prio++;
05095 
05096          /* write extension name and first peer */
05097          if (e->matchcid)
05098             snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
05099          else
05100             snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
05101 
05102          print_ext(e, buf2, sizeof(buf2));
05103 
05104          ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
05105             ast_get_extension_registrar(e));
05106 
05107          dpc->total_exten++;
05108          /* walk next extension peers */
05109          p = e;   /* skip the first one, we already got it */
05110          while ( (p = ast_walk_extension_priorities(e, p)) ) {
05111             const char *el = ast_get_extension_label(p);
05112             dpc->total_prio++;
05113             if (el)
05114                snprintf(buf, sizeof(buf), "   [%s]", el);
05115             else
05116                buf[0] = '\0';
05117             print_ext(p, buf2, sizeof(buf2));
05118 
05119             ast_cli(fd,"  %-17s %-45s [%s]\n", buf, buf2,
05120                ast_get_extension_registrar(p));
05121          }
05122       }
05123 
05124       /* walk included and write info ... */
05125       i = NULL;
05126       while ( (i = ast_walk_context_includes(c, i)) ) {
05127          snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
05128          if (exten) {
05129             /* Check all includes for the requested extension */
05130             if (includecount >= AST_PBX_MAX_STACK) {
05131                ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
05132             } else {
05133                int dupe = 0;
05134                int x;
05135                for (x = 0; x < includecount; x++) {
05136                   if (!strcasecmp(includes[x], ast_get_include_name(i))) {
05137                      dupe++;
05138                      break;
05139                   }
05140                }
05141                if (!dupe) {
05142                   includes[includecount] = ast_get_include_name(i);
05143                   show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
05144                } else {
05145                   ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
05146                }
05147             }
05148          } else {
05149             ast_cli(fd, "  Include =>        %-45s [%s]\n",
05150                buf, ast_get_include_registrar(i));
05151          }
05152       }
05153 
05154       /* walk ignore patterns and write info ... */
05155       ip = NULL;
05156       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05157          const char *ipname = ast_get_ignorepat_name(ip);
05158          char ignorepat[AST_MAX_EXTENSION];
05159          snprintf(buf, sizeof(buf), "'%s'", ipname);
05160          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05161          if (!exten || ast_extension_match(ignorepat, exten)) {
05162             ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
05163                buf, ast_get_ignorepat_registrar(ip));
05164          }
05165       }
05166       if (!rinclude) {
05167          struct ast_sw *sw = NULL;
05168          while ( (sw = ast_walk_context_switches(c, sw)) ) {
05169             snprintf(buf, sizeof(buf), "'%s/%s'",
05170                ast_get_switch_name(sw),
05171                ast_get_switch_data(sw));
05172             ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
05173                buf, ast_get_switch_registrar(sw));
05174          }
05175       }
05176       
05177       ast_unlock_context(c);
05178 
05179       /* if we print something in context, make an empty line */
05180       if (context_info_printed)
05181          ast_cli(fd, "\n");
05182    }
05183    ast_unlock_contexts();
05184 
05185    return (dpc->total_exten == old_total_exten) ? -1 : res;
05186 }

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

References ast_copy_string().

Referenced by pbx_retrieve_variable(), and pbx_substitute_variables_helper_full().

02426 {
02427    char *ret = workspace;
02428    int lr;  /* length of the input string after the copy */
02429 
02430    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
02431 
02432    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
02433 
02434    /* Quick check if no need to do anything */
02435    if (offset == 0 && length >= lr) /* take the whole string */
02436       return ret;
02437 
02438    if (offset < 0)   {  /* translate negative offset into positive ones */
02439       offset = lr + offset;
02440       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
02441          offset = 0;
02442    }
02443 
02444    /* too large offset result in empty string so we know what to return */
02445    if (offset >= lr)
02446       return ret + lr;  /* the final '\0' */
02447 
02448    ret += offset;    /* move to the start position */
02449    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
02450       ret[length] = '\0';
02451    else if (length < 0) {
02452       if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
02453          ret[lr + length - offset] = '\0';
02454       else
02455          ret[0] = '\0';
02456    }
02457 
02458    return ret;
02459 }

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

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

01184 {
01185    struct match_char *m3;
01186    struct match_char *m4;
01187    struct ast_exten *e3;
01188    
01189    if (node && node->x[0] == '.' && !node->x[1]) /* dot and ! will ALWAYS be next match in a matchmore */
01190       return node->exten;
01191    
01192    if (node && node->x[0] == '!' && !node->x[1])
01193       return node->exten;
01194    
01195    if (!node || !node->next_char)
01196       return NULL;
01197    
01198    m3 = node->next_char;
01199 
01200    if (m3->exten)
01201       return m3->exten;
01202    for(m4=m3->alt_char; m4; m4 = m4->alt_char) {
01203       if (m4->exten)
01204          return m4->exten;
01205    }
01206    for(m4=m3; m4; m4 = m4->alt_char) {
01207       e3 = trie_find_next_match(m3);
01208       if (e3)
01209          return e3;
01210    }
01211    return NULL;
01212 }

static void unreference_cached_app ( struct ast_app app  )  [static]

Definition at line 5833 of file pbx.c.

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

Referenced by ast_unregister_application().

05834 {
05835    struct ast_context *context = NULL;
05836    struct ast_exten *eroot = NULL, *e = NULL;
05837 
05838    ast_rdlock_contexts();
05839    while ((context = ast_walk_contexts(context))) {
05840       while ((eroot = ast_walk_context_extensions(context, eroot))) {
05841          while ((e = ast_walk_extension_priorities(eroot, e))) {
05842             if (e->cached_app == app)
05843                e->cached_app = NULL;
05844          }
05845       }
05846    }
05847    ast_unlock_contexts();
05848 
05849    return;
05850 }

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

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

Referenced by new_find_extension().

01091 {
01092    /* if this extension is marked as deleted, then skip this -- if it never shows
01093       on the scoreboard, it will never be found, nor will halt the traversal. */
01094    if (deleted)
01095       return;
01096    board->total_specificity = spec;
01097    board->total_length = length;
01098    board->exten = exten;
01099    board->last_char = last;
01100    board->node = node;
01101 #ifdef NEED_DEBUG_HERE
01102    ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
01103 #endif
01104 }

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

Definition at line 7864 of file pbx.c.

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

Referenced by pbx_builtin_busy(), and pbx_builtin_congestion().

07865 {
07866    int res;
07867    struct ast_frame *f;
07868    double waitsec;
07869    int waittime;
07870 
07871    if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
07872       waitsec = -1;
07873    if (waitsec > -1) {
07874       waittime = waitsec * 1000.0;
07875       ast_safe_sleep(chan, waittime);
07876    } else do {
07877       res = ast_waitfor(chan, -1);
07878       if (res < 0)
07879          return;
07880       f = ast_read(chan);
07881       if (f)
07882          ast_frfree(f);
07883    } while(f);
07884 }


Variable Documentation

int autofallthrough = 1 [static]

Definition at line 426 of file pbx.c.

struct pbx_builtin builtins[] [static]

Declaration of builtin applications.

Referenced by load_pbx().

struct ast_cli_entry cli_set_chanvar_deprecated = AST_CLI_DEFINE(handle_set_chanvar_deprecated, "Set a channel variable.") [static]

Definition at line 5806 of file pbx.c.

struct ast_cli_entry cli_set_global_deprecated = AST_CLI_DEFINE(handle_set_global_deprecated, "Set global dialplan variable.") [static]

Definition at line 5807 of file pbx.c.

struct ast_cli_entry cli_show_globals_deprecated = AST_CLI_DEFINE(handle_show_globals_deprecated, "Show global dialplan variables.") [static]

Definition at line 5805 of file pbx.c.

int conlock_wrlock_version = 0 [static]

Definition at line 8752 of file pbx.c.

Referenced by ast_wrlock_contexts(), and ast_wrlock_contexts_version().

struct ast_context* contexts [static]

Definition at line 731 of file pbx.c.

struct ast_hashtab* contexts_table = NULL [static]

Definition at line 732 of file pbx.c.

int countcalls [static]

Definition at line 434 of file pbx.c.

char* days[] [static]

Definition at line 6381 of file pbx.c.

Referenced by ast_build_timing().

struct ast_event_sub* device_state_sub [static]

Subscription for device state change events.

Definition at line 431 of file pbx.c.

Definition at line 126 of file pbx.c.

Definition at line 2648 of file pbx.c.

Referenced by load_pbx().

Initial value:
 {
   .type = "EXCEPTION",
   .destroy = exception_store_free,
}

Definition at line 2590 of file pbx.c.

Referenced by acf_exception_read(), and pbx_builtin_raise_exception().

int extenpatternmatchnew = 0 [static]

Definition at line 427 of file pbx.c.

Referenced by ast_extension_state2str().

struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE [static]

Definition at line 424 of file pbx.c.

char mandescr_show_dialplan[] [static]

Definition at line 5563 of file pbx.c.

Referenced by load_pbx().

char* months[] [static]

Definition at line 6393 of file pbx.c.

Referenced by ast_build_timing().

char* overrideswitch = NULL [static]

Definition at line 428 of file pbx.c.

Referenced by handle_cli_dialplan_save().

struct ast_cli_entry pbx_cli[] [static]

Definition at line 5812 of file pbx.c.

Referenced by load_pbx().

int stateid = 1 [static]

Definition at line 740 of file pbx.c.

int totalcalls [static]

Definition at line 435 of file pbx.c.

Referenced by timing_read().


Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1