Wed Mar 3 23:02:37 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)
 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 2035 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_NO_EXTENSION   2

Definition at line 2036 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_NO_LABEL   4

Definition at line 2038 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_NO_PRIORITY   3

Definition at line 2037 of file pbx.c.

Referenced by pbx_extension_helper(), and pbx_find_extension().

#define STATUS_SUCCESS   5

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

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

int __ast_custom_function_register ( struct ast_custom_function acf,
struct ast_module mod 
)

Register a custom function.

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

02796 {
02797    struct ast_custom_function *cur;
02798    char tmps[80];
02799 
02800    if (!acf)
02801       return -1;
02802 
02803    acf->mod = mod;
02804 
02805    AST_RWLIST_WRLOCK(&acf_root);
02806 
02807    AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
02808       if (!strcmp(acf->name, cur->name)) {
02809          ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
02810          AST_RWLIST_UNLOCK(&acf_root);
02811          return -1;
02812       }
02813    }
02814 
02815    /* Store in alphabetical order */
02816    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
02817       if (strcasecmp(acf->name, cur->name) < 0) {
02818          AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
02819          break;
02820       }
02821    }
02822    AST_RWLIST_TRAVERSE_SAFE_END;
02823    if (!cur)
02824       AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
02825 
02826    AST_RWLIST_UNLOCK(&acf_root);
02827 
02828    ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02829 
02830    return 0;
02831 }

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

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

08936 {
08937    int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
08938 
08939    if (!chan)
08940       return -2;
08941 
08942    if (context == NULL)
08943       context = chan->context;
08944    if (exten == NULL)
08945       exten = chan->exten;
08946 
08947    goto_func = (async) ? ast_async_goto : ast_explicit_goto;
08948    if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
08949       return goto_func(chan, context, exten, priority);
08950    else
08951       return -3;
08952 }

static void __ast_internal_context_destroy ( struct ast_context con  )  [static]

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

07654 {
07655    struct ast_include *tmpi;
07656    struct ast_sw *sw;
07657    struct ast_exten *e, *el, *en;
07658    struct ast_ignorepat *ipi;
07659    struct ast_context *tmp = con;
07660    
07661    for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
07662       struct ast_include *tmpil = tmpi;
07663       tmpi = tmpi->next;
07664       ast_free(tmpil);
07665    }
07666    for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
07667       struct ast_ignorepat *ipl = ipi;
07668       ipi = ipi->next;
07669       ast_free(ipl);
07670    }
07671    if (tmp->registrar)
07672       ast_free(tmp->registrar);
07673    
07674    /* destroy the hash tabs */
07675    if (tmp->root_table) {
07676       ast_hashtab_destroy(tmp->root_table, 0);
07677    }
07678    /* and destroy the pattern tree */
07679    if (tmp->pattern_tree)
07680       destroy_pattern_tree(tmp->pattern_tree);
07681    
07682    while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
07683       ast_free(sw);
07684    for (e = tmp->root; e;) {
07685       for (en = e->peer; en;) {
07686          el = en;
07687          en = en->peer;
07688          destroy_exten(el);
07689       }
07690       el = e;
07691       e = e->next;
07692       destroy_exten(el);
07693    }
07694    tmp->root = NULL;
07695    ast_rwlock_destroy(&tmp->lock);
07696    ast_free(tmp);
07697 }

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

References ast_channel::_softhangup, ast_calloc, AST_CAUSE_NORMAL_CLEARING, 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_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, ast_channel::hangupcause, 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().

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

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

Definition at line 1811 of file pbx.c.

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

Referenced by extension_match_core().

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

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

Definition at line 2612 of file pbx.c.

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

02613 {
02614    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02615    struct pbx_exception *exception = NULL;
02616    if (!ds || !ds->data)
02617       return -1;
02618    exception = ds->data;
02619    if (!strcasecmp(data, "REASON"))
02620       ast_copy_string(buf, exception->reason, buflen);
02621    else if (!strcasecmp(data, "CONTEXT"))
02622       ast_copy_string(buf, exception->context, buflen);
02623    else if (!strncasecmp(data, "EXTEN", 5))
02624       ast_copy_string(buf, exception->exten, buflen);
02625    else if (!strcasecmp(data, "PRIORITY"))
02626       snprintf(buf, buflen, "%d", exception->priority);
02627    else
02628       return -1;
02629    return 0;
02630 }

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

References add_pri_lockopt().

Referenced by ast_add_extension2_lockopt().

06868 {
06869    return add_pri_lockopt(con, tmp, el, e, replace, 1);
06870 }

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

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

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

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

04083 {
04084    return countcalls;
04085 }

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

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

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

07054 {
07055    return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
07056 }

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

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

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

References ast_add_extension2_lockopt(), and find_context().

Referenced by ast_merge_contexts_and_delete().

06716 {
06717    int ret = -1;
06718    struct ast_context *c = find_context(context);
06719 
06720    if (c) {
06721       ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
06722          application, data, datad, registrar, 0, 0);
06723    }
06724    
06725    return ret;
06726 }

static int ast_add_hint ( struct ast_exten e  )  [static]

Add hint to hint list, check initial extension state.

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

03547 {
03548    int ret;
03549 
03550    AST_RWLIST_WRLOCK(&hints);
03551    ret = ast_add_hint_nolock(e);
03552    AST_RWLIST_UNLOCK(&hints);
03553    
03554    return ret;
03555 }

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

03518 {
03519    struct ast_hint *hint;
03520 
03521    if (!e)
03522       return -1;
03523 
03524    /* Search if hint exists, do nothing */
03525    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03526       if (hint->exten == e) {
03527          ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03528          return -1;
03529       }
03530    }
03531 
03532    ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03533 
03534    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
03535       return -1;
03536    }
03537    /* Initialize and insert new item at the top */
03538    hint->exten = e;
03539    hint->laststate = ast_extension_state2(e);
03540    AST_RWLIST_INSERT_HEAD(&hints, hint, list);
03541 
03542    return 0;
03543 }

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 6771 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(), and socket_process().

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

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

Definition at line 6824 of file pbx.c.

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

06825 {
06826    struct ast_channel *chan;
06827    int res = -1;
06828 
06829    chan = ast_get_channel_by_name_locked(channame);
06830    if (chan) {
06831       res = ast_async_goto(chan, context, exten, priority);
06832       ast_channel_unlock(chan);
06833    }
06834    return res;
06835 }

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

References __ast_goto_if_exists().

08960 {
08961    return __ast_goto_if_exists(chan, context, exten, priority, 1);
08962 }

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

References pbx_parseable_goto().

Referenced by asyncgoto_exec().

09023 {
09024    return pbx_parseable_goto(chan, goto_string, 1);
09025 }

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

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

06393 {
06394    char info_save[256];
06395    char *info;
06396 
06397    /* Check for empty just in case */
06398    if (ast_strlen_zero(info_in))
06399       return 0;
06400    /* make a copy just in case we were passed a static string */
06401    ast_copy_string(info_save, info_in, sizeof(info_save));
06402    info = info_save;
06403    /* Assume everything except time */
06404    i->monthmask = 0xfff;   /* 12 bits */
06405    i->daymask = 0x7fffffffU; /* 31 bits */
06406    i->dowmask = 0x7f; /* 7 bits */
06407    /* on each call, use strsep() to move info to the next argument */
06408    get_timerange(i, strsep(&info, "|,"));
06409    if (info)
06410       i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
06411    if (info)
06412       i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
06413    if (info)
06414       i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
06415    return 1;
06416 }

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

References E_CANMATCH, and pbx_extension_helper().

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

03645 {
03646    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
03647 }

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

Change hint for an extension.

Definition at line 3558 of file pbx.c.

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

Referenced by add_pri_lockopt().

03559 {
03560    struct ast_hint *hint;
03561    int res = -1;
03562 
03563    AST_RWLIST_WRLOCK(&hints);
03564    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03565       if (hint->exten == oe) {
03566             hint->exten = ne;
03567          res = 0;
03568          break;
03569       }
03570    }
03571    AST_RWLIST_UNLOCK(&hints);
03572 
03573    return res;
03574 }

int ast_check_timing ( const struct ast_timing i  ) 

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

06419 {
06420    struct ast_tm tm;
06421    struct timeval now = ast_tvnow();
06422 
06423    ast_localtime(&now, &tm, NULL);
06424 
06425    /* If it's not the right month, return */
06426    if (!(i->monthmask & (1 << tm.tm_mon)))
06427       return 0;
06428 
06429    /* If it's not that time of the month.... */
06430    /* Warning, tm_mday has range 1..31! */
06431    if (!(i->daymask & (1 << (tm.tm_mday-1))))
06432       return 0;
06433 
06434    /* If it's not the right day of the week */
06435    if (!(i->dowmask & (1 << tm.tm_wday)))
06436       return 0;
06437 
06438    /* Sanity check the hour just to be safe */
06439    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
06440       ast_log(LOG_WARNING, "Insane time...\n");
06441       return 0;
06442    }
06443 
06444    /* Now the tough part, we calculate if it fits
06445       in the right time based on min/hour */
06446    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
06447       return 0;
06448 
06449    /* If we got this far, then we're good */
06450    return 1;
06451 }

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

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

Referenced by handle_cli_dialplan_add_ignorepat().

06645 {
06646    int ret = -1;
06647    struct ast_context *c = find_context_locked(context);
06648 
06649    if (c) {
06650       ret = ast_context_add_ignorepat2(c, value, registrar);
06651       ast_unlock_contexts();
06652    }
06653    return ret;
06654 }

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

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

06657 {
06658    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
06659    int length;
06660    char *pattern;
06661    length = sizeof(struct ast_ignorepat);
06662    length += strlen(value) + 1;
06663    if (!(ignorepat = ast_calloc(1, length)))
06664       return -1;
06665    /* The cast to char * is because we need to write the initial value.
06666     * The field is not supposed to be modified otherwise.  Also, gcc 4.2
06667     * sees the cast as dereferencing a type-punned pointer and warns about
06668     * it.  This is the workaround (we're telling gcc, yes, that's really
06669     * what we wanted to do).
06670     */
06671    pattern = (char *) ignorepat->pattern;
06672    strcpy(pattern, value);
06673    ignorepat->next = NULL;
06674    ignorepat->registrar = registrar;
06675    ast_wrlock_context(con);
06676    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
06677       ignorepatl = ignorepatc;
06678       if (!strcasecmp(ignorepatc->pattern, value)) {
06679          /* Already there */
06680          ast_unlock_context(con);
06681          errno = EEXIST;
06682          return -1;
06683       }
06684    }
06685    if (ignorepatl)
06686       ignorepatl->next = ignorepat;
06687    else
06688       con->ignorepats = ignorepat;
06689    ast_unlock_context(con);
06690    return 0;
06691 
06692 }

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

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

Referenced by handle_cli_dialplan_add_include().

06199 {
06200    int ret = -1;
06201    struct ast_context *c = find_context_locked(context);
06202 
06203    if (c) {
06204       ret = ast_context_add_include2(c, include, registrar);
06205       ast_unlock_contexts();
06206    }
06207    return ret;
06208 }

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

06462 {
06463    struct ast_include *new_include;
06464    char *c;
06465    struct ast_include *i, *il = NULL; /* include, include_last */
06466    int length;
06467    char *p;
06468 
06469    length = sizeof(struct ast_include);
06470    length += 2 * (strlen(value) + 1);
06471 
06472    /* allocate new include structure ... */
06473    if (!(new_include = ast_calloc(1, length)))
06474       return -1;
06475    /* Fill in this structure. Use 'p' for assignments, as the fields
06476     * in the structure are 'const char *'
06477     */
06478    p = new_include->stuff;
06479    new_include->name = p;
06480    strcpy(p, value);
06481    p += strlen(value) + 1;
06482    new_include->rname = p;
06483    strcpy(p, value);
06484    /* Strip off timing info, and process if it is there */
06485    if ( (c = strchr(p, ',')) ) {
06486       *c++ = '\0';
06487            new_include->hastime = ast_build_timing(&(new_include->timing), c);
06488    }
06489    new_include->next      = NULL;
06490    new_include->registrar = registrar;
06491 
06492    ast_wrlock_context(con);
06493 
06494    /* ... go to last include and check if context is already included too... */
06495    for (i = con->includes; i; i = i->next) {
06496       if (!strcasecmp(i->name, new_include->name)) {
06497          ast_free(new_include);
06498          ast_unlock_context(con);
06499          errno = EEXIST;
06500          return -1;
06501       }
06502       il = i;
06503    }
06504 
06505    /* ... include new context into context list, unlock, return */
06506    if (il)
06507       il->next = new_include;
06508    else
06509       con->includes = new_include;
06510    ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
06511 
06512    ast_unlock_context(con);
06513 
06514    return 0;
06515 }

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

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

06523 {
06524    int ret = -1;
06525    struct ast_context *c = find_context_locked(context);
06526 
06527    if (c) { /* found, add switch to this context */
06528       ret = ast_context_add_switch2(c, sw, data, eval, registrar);
06529       ast_unlock_contexts();
06530    }
06531    return ret;
06532 }

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

06543 {
06544    struct ast_sw *new_sw;
06545    struct ast_sw *i;
06546    int length;
06547    char *p;
06548 
06549    length = sizeof(struct ast_sw);
06550    length += strlen(value) + 1;
06551    if (data)
06552       length += strlen(data);
06553    length++;
06554 
06555    /* allocate new sw structure ... */
06556    if (!(new_sw = ast_calloc(1, length)))
06557       return -1;
06558    /* ... fill in this structure ... */
06559    p = new_sw->stuff;
06560    new_sw->name = p;
06561    strcpy(new_sw->name, value);
06562    p += strlen(value) + 1;
06563    new_sw->data = p;
06564    if (data) {
06565       strcpy(new_sw->data, data);
06566       p += strlen(data) + 1;
06567    } else {
06568       strcpy(new_sw->data, "");
06569       p++;
06570    }
06571    new_sw->eval     = eval;
06572    new_sw->registrar = registrar;
06573 
06574    /* ... try to lock this context ... */
06575    ast_wrlock_context(con);
06576 
06577    /* ... go to last sw and check if context is already swd too... */
06578    AST_LIST_TRAVERSE(&con->alts, i, list) {
06579       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
06580          ast_free(new_sw);
06581          ast_unlock_context(con);
06582          errno = EEXIST;
06583          return -1;
06584       }
06585    }
06586 
06587    /* ... sw new context into context list, unlock, return */
06588    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
06589 
06590    ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
06591 
06592    ast_unlock_context(con);
06593 
06594    return 0;
06595 }

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

02016 {
02017    struct ast_context *tmp = NULL;
02018    struct fake_context item;
02019 
02020    ast_copy_string(item.name, name, sizeof(item.name));
02021 
02022    ast_rdlock_contexts();
02023    if( contexts_table ) {
02024       tmp = ast_hashtab_lookup(contexts_table,&item);
02025    } else {
02026       while ( (tmp = ast_walk_contexts(tmp)) ) {
02027          if (!name || !strcasecmp(name, tmp->name))
02028             break;
02029       }
02030    }
02031    ast_unlock_contexts();
02032    return tmp;
02033 }

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

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

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

04470 {
04471    struct ast_context *c = NULL;
04472    int ret = -1;
04473    struct fake_context item;
04474 
04475    ast_rdlock_contexts();
04476 
04477    ast_copy_string(item.name, context, sizeof(item.name));
04478 
04479    c = ast_hashtab_lookup(contexts_table,&item);
04480    if (c)
04481       ret = 0;
04482 
04483 
04484 #ifdef NOTNOW
04485 
04486    while ((c = ast_walk_contexts(c))) {
04487       if (!strcmp(ast_get_context_name(c), context)) {
04488          ret = 0;
04489          break;
04490       }
04491    }
04492 
04493 #endif
04494    ast_unlock_contexts();
04495 
04496    /* if we found context, lock macrolock */
04497    if (ret == 0) 
04498       ret = ast_mutex_lock(&c->macrolock);
04499 
04500    return ret;
04501 }

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

References ast_context_remove_extension_callerid().

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

04277 {
04278    return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
04279 }

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

References ast_context_remove_extension_callerid2().

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

04304 {
04305    return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked);
04306 }

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

04282 {
04283    int ret = -1; /* default error return */
04284    struct ast_context *c = find_context_locked(context);
04285 
04286    if (c) { /* ... remove extension ... */
04287       ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcallerid, registrar, 1);
04288       ast_unlock_contexts();
04289    }
04290    return ret;
04291 }

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

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

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

Definition at line 6601 of file pbx.c.

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

Referenced by handle_cli_dialplan_remove_ignorepat().

06602 {
06603    int ret = -1;
06604    struct ast_context *c = find_context_locked(context);
06605 
06606    if (c) {
06607       ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
06608       ast_unlock_contexts();
06609    }
06610    return ret;
06611 }

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

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

06614 {
06615    struct ast_ignorepat *ip, *ipl = NULL;
06616 
06617    ast_wrlock_context(con);
06618 
06619    for (ip = con->ignorepats; ip; ip = ip->next) {
06620       if (!strcmp(ip->pattern, ignorepat) &&
06621          (!registrar || (registrar == ip->registrar))) {
06622          if (ipl) {
06623             ipl->next = ip->next;
06624             ast_free(ip);
06625          } else {
06626             con->ignorepats = ip->next;
06627             ast_free(ip);
06628          }
06629          ast_unlock_context(con);
06630          return 0;
06631       }
06632       ipl = ip;
06633    }
06634 
06635    ast_unlock_context(con);
06636    errno = EINVAL;
06637    return -1;
06638 }

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

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

Referenced by handle_cli_dialplan_remove_include().

04169 {
04170    int ret = -1;
04171    struct ast_context *c = find_context_locked(context);
04172 
04173    if (c) {
04174       /* found, remove include from this context ... */
04175       ret = ast_context_remove_include2(c, include, registrar);
04176       ast_unlock_contexts();
04177    }
04178    return ret;
04179 }

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

04191 {
04192    struct ast_include *i, *pi = NULL;
04193    int ret = -1;
04194 
04195    ast_wrlock_context(con);
04196 
04197    /* find our include */
04198    for (i = con->includes; i; pi = i, i = i->next) {
04199       if (!strcmp(i->name, include) &&
04200             (!registrar || !strcmp(i->registrar, registrar))) {
04201          /* remove from list */
04202          ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
04203          if (pi)
04204             pi->next = i->next;
04205          else
04206             con->includes = i->next;
04207          /* free include and return */
04208          ast_free(i);
04209          ret = 0;
04210          break;
04211       }
04212    }
04213 
04214    ast_unlock_context(con);
04215 
04216    return ret;
04217 }

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

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

04225 {
04226    int ret = -1; /* default error return */
04227    struct ast_context *c = find_context_locked(context);
04228 
04229    if (c) {
04230       /* remove switch from this context ... */
04231       ret = ast_context_remove_switch2(c, sw, data, registrar);
04232       ast_unlock_contexts();
04233    }
04234    return ret;
04235 }

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

04246 {
04247    struct ast_sw *i;
04248    int ret = -1;
04249 
04250    ast_wrlock_context(con);
04251 
04252    /* walk switches */
04253    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
04254       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
04255          (!registrar || !strcmp(i->registrar, registrar))) {
04256          /* found, remove from list */
04257          ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
04258          AST_LIST_REMOVE_CURRENT(list);
04259          ast_free(i); /* free switch and return */
04260          ret = 0;
04261          break;
04262       }
04263    }
04264    AST_LIST_TRAVERSE_SAFE_END;
04265 
04266    ast_unlock_context(con);
04267 
04268    return ret;
04269 }

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

04509 {
04510    struct ast_context *c = NULL;
04511    int ret = -1;
04512    struct fake_context item;
04513 
04514    ast_rdlock_contexts();
04515 
04516    ast_copy_string(item.name, context, sizeof(item.name));
04517 
04518    c = ast_hashtab_lookup(contexts_table,&item);
04519    if (c)
04520       ret = 0;
04521 #ifdef NOTNOW
04522 
04523    while ((c = ast_walk_contexts(c))) {
04524       if (!strcmp(ast_get_context_name(c), context)) {
04525          ret = 0;
04526          break;
04527       }
04528    }
04529 
04530 #endif
04531    ast_unlock_contexts();
04532 
04533    /* if we found context, unlock macrolock */
04534    if (ret == 0) 
04535       ret = ast_mutex_unlock(&c->macrolock);
04536 
04537    return ret;
04538 }

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

08917 {
08918    struct ast_include *inc = NULL;
08919    int res = 0;
08920 
08921    while ( (inc = ast_walk_context_includes(con, inc)) ) {
08922       if (ast_context_find(inc->rname))
08923          continue;
08924 
08925       res = -1;
08926       ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
08927          ast_get_context_name(con), inc->rname);
08928       break;
08929    }
08930 
08931    return res;
08932 }

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

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

02767 {
02768    struct ast_custom_function *acf = NULL;
02769 
02770    AST_RWLIST_RDLOCK(&acf_root);
02771    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02772       if (!strcmp(name, acf->name))
02773          break;
02774    }
02775    AST_RWLIST_UNLOCK(&acf_root);
02776 
02777    return acf;
02778 }

int ast_custom_function_unregister ( struct ast_custom_function acf  ) 

Unregister a custom function.

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

02781 {
02782    struct ast_custom_function *cur;
02783 
02784    if (!acf)
02785       return -1;
02786 
02787    AST_RWLIST_WRLOCK(&acf_root);
02788    if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist)))
02789       ast_verb(2, "Unregistered custom function %s\n", cur->name);
02790    AST_RWLIST_UNLOCK(&acf_root);
02791 
02792    return cur ? 0 : -1;
02793 }

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

03260 {
03261    switch (devstate) {
03262    case AST_DEVICE_ONHOLD:
03263       return AST_EXTENSION_ONHOLD;
03264    case AST_DEVICE_BUSY:
03265       return AST_EXTENSION_BUSY;
03266    case AST_DEVICE_UNAVAILABLE:
03267    case AST_DEVICE_UNKNOWN:
03268    case AST_DEVICE_INVALID:
03269       return AST_EXTENSION_UNAVAILABLE;
03270    case AST_DEVICE_RINGINUSE:
03271       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
03272    case AST_DEVICE_RINGING:
03273       return AST_EXTENSION_RINGING;
03274    case AST_DEVICE_INUSE:
03275       return AST_EXTENSION_INUSE;
03276    case AST_DEVICE_NOT_INUSE:
03277       return AST_EXTENSION_NOT_INUSE;
03278    case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
03279       break;
03280    }
03281 
03282    return AST_EXTENSION_NOT_INUSE;
03283 }

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 3629 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(), skinny_ss(), socket_process(), ss7_linkset(), ss_thread(), and waitstream_core().

03630 {
03631    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
03632 }

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

06749 {
06750    if (!chan)
06751       return -1;
06752 
06753    ast_channel_lock(chan);
06754 
06755    if (!ast_strlen_zero(context))
06756       ast_copy_string(chan->context, context, sizeof(chan->context));
06757    if (!ast_strlen_zero(exten))
06758       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06759    if (priority > -1) {
06760       chan->priority = priority;
06761       /* see flag description in channel.h for explanation */
06762       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
06763          chan->priority--;
06764    }
06765 
06766    ast_channel_unlock(chan);
06767 
06768    return 0;
06769 }

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

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

01993 {
01994    if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
01995       ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
01996    return extension_match_core(pattern, data, needmore);
01997 }

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

References ext_cmp().

Referenced by lua_extension_cmp().

01795 {
01796    return ext_cmp(a, b);
01797 }

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

01988 {
01989    return extension_match_core(pattern, data, E_MATCH);
01990 }

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

References ast_extension_state2(), and ast_hint_extension().

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

03322 {
03323    struct ast_exten *e;
03324 
03325    e = ast_hint_extension(c, context, exten);   /* Do we have a hint for this extension ? */
03326    if (!e)
03327       return -1;           /* No hint, return -1 */
03328 
03329    return ast_extension_state2(e);        /* Check all devices in the hint */
03330 }

static int ast_extension_state2 ( struct ast_exten e  )  [static]

Check state of extension by using hints.

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

03287 {
03288    char hint[AST_MAX_EXTENSION] = "";
03289    char *cur, *rest;
03290    struct ast_devstate_aggregate agg;
03291 
03292    if (!e)
03293       return -1;
03294 
03295    ast_devstate_aggregate_init(&agg);
03296 
03297    ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
03298 
03299    rest = hint;   /* One or more devices separated with a & character */
03300 
03301    while ( (cur = strsep(&rest, "&")) ) {
03302       ast_devstate_aggregate_add(&agg, ast_device_state(cur));
03303    }
03304 
03305    return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
03306 }

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

03310 {
03311    int i;
03312 
03313    for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
03314       if (extension_states[i].extension_state == extension_state)
03315          return extension_states[i].text;
03316    }
03317    return "Unknown";
03318 }

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

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

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

03473 {
03474    struct ast_state_cb *p_cur = NULL;
03475    int ret = -1;
03476 
03477    if (!id && !callback)
03478       return -1;
03479 
03480    AST_RWLIST_WRLOCK(&hints);
03481 
03482    if (!id) {  /* id == 0 is a callback without extension */
03483       AST_LIST_TRAVERSE_SAFE_BEGIN(&statecbs, p_cur, entry) {
03484          if (p_cur->callback == callback) {
03485             AST_LIST_REMOVE_CURRENT(entry);
03486             break;
03487          }
03488       }
03489       AST_LIST_TRAVERSE_SAFE_END;
03490    } else { /* callback with extension, find the callback based on ID */
03491       struct ast_hint *hint;
03492       AST_RWLIST_TRAVERSE(&hints, hint, list) {
03493          AST_LIST_TRAVERSE_SAFE_BEGIN(&hint->callbacks, p_cur, entry) {
03494             if (p_cur->id == id) {
03495                AST_LIST_REMOVE_CURRENT(entry);
03496                break;
03497             }
03498          }
03499          AST_LIST_TRAVERSE_SAFE_END;
03500 
03501          if (p_cur)
03502             break;
03503       }
03504    }
03505 
03506    if (p_cur) {
03507       ast_free(p_cur);
03508    }
03509 
03510    AST_RWLIST_UNLOCK(&hints);
03511 
03512    return ret;
03513 }

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

03635 {
03636    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03637 }

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

References E_FINDLABEL, and pbx_extension_helper().

Referenced by pbx_load_config().

03640 {
03641    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03642 }

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

02854 {
02855    char *copy = ast_strdupa(function);
02856    char *args = func_args(copy);
02857    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02858 
02859    if (acfptr == NULL)
02860       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02861    else if (!acfptr->read)
02862       ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
02863    else {
02864       int res;
02865       struct ast_module_user *u = NULL;
02866       if (acfptr->mod)
02867          u = __ast_module_user_add(acfptr->mod, chan);
02868       res = acfptr->read(chan, copy, args, workspace, len);
02869       if (acfptr->mod && u)
02870          __ast_module_user_remove(acfptr->mod, u);
02871       return res;
02872    }
02873    return -1;
02874 }

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

02877 {
02878    char *copy = ast_strdupa(function);
02879    char *args = func_args(copy);
02880    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02881 
02882    if (acfptr == NULL)
02883       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02884    else if (!acfptr->write)
02885       ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
02886    else {
02887       int res;
02888       struct ast_module_user *u = NULL;
02889       if (acfptr->mod)
02890          u = __ast_module_user_add(acfptr->mod, chan);
02891       res = acfptr->write(chan, copy, args, value);
02892       if (acfptr->mod && u)
02893          __ast_module_user_remove(acfptr->mod, u);
02894       return res;
02895    }
02896 
02897    return -1;
02898 }

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

Definition at line 8806 of file pbx.c.

References ast_context::registrar.

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

08807 {
08808    return c ? c->registrar : NULL;
08809 }

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

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

08842 {
08843    return e ? e->data : NULL;
08844 }

const char* ast_get_extension_cidmatch ( struct ast_exten e  ) 

Definition at line 8831 of file pbx.c.

References ast_exten::cidmatch.

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

08832 {
08833    return e ? e->cidmatch : NULL;
08834 }

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

Definition at line 8773 of file pbx.c.

References ast_exten::parent.

Referenced by handle_show_hint(), and handle_show_hints().

08774 {
08775    return exten ? exten->parent : NULL;
08776 }

const char* ast_get_extension_label ( struct ast_exten exten  ) 

Definition at line 8783 of file pbx.c.

References ast_exten::label.

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

08784 {
08785    return exten ? exten->label : NULL;
08786 }

int ast_get_extension_matchcid ( struct ast_exten e  ) 

Definition at line 8826 of file pbx.c.

References ast_exten::matchcid.

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

08827 {
08828    return e ? e->matchcid : 0;
08829 }

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

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

08799 {
08800    return exten ? exten->priority : -1;
08801 }

const char* ast_get_extension_registrar ( struct ast_exten e  ) 

Definition at line 8811 of file pbx.c.

References ast_exten::registrar.

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

08812 {
08813    return e ? e->registrar : NULL;
08814 }

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

03613 {
03614    struct ast_exten *e = ast_hint_extension(c, context, exten);
03615 
03616    if (e) {
03617       if (hint)
03618          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
03619       if (name) {
03620          const char *tmp = ast_get_extension_app_data(e);
03621          if (tmp)
03622             ast_copy_string(name, tmp, namesize);
03623       }
03624       return -1;
03625    }
03626    return 0;
03627 }

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

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

08822 {
08823    return ip ? ip->registrar : NULL;
08824 }

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

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

08817 {
08818    return i ? i->registrar : NULL;
08819 }

const char* ast_get_switch_data ( struct ast_sw sw  ) 

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

08852 {
08853    return sw ? sw->data : NULL;
08854 }

int ast_get_switch_eval ( struct ast_sw sw  ) 

Definition at line 8856 of file pbx.c.

References ast_sw::eval.

Referenced by context_merge_incls_swits_igps_other_registrars().

08857 {
08858    return sw->eval;
08859 }

const char* ast_get_switch_name ( struct ast_sw sw  ) 

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

08847 {
08848    return sw ? sw->name : NULL;
08849 }

const char* ast_get_switch_registrar ( struct ast_sw sw  ) 

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

08862 {
08863    return sw ? sw->registrar : NULL;
08864 }

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

08955 {
08956    return __ast_goto_if_exists(chan, context, exten, priority, 0);
08957 }

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

03251 {
03252    struct ast_exten *e;
03253    ast_rdlock_contexts();
03254    e = ast_hint_extension_nolock(c, context, exten);
03255    ast_unlock_contexts();
03256    return e;
03257 }

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

03245 {
03246    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
03247    return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
03248 }

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

06695 {
06696    struct ast_context *con = ast_context_find(context);
06697    if (con) {
06698       struct ast_ignorepat *pat;
06699       for (pat = con->ignorepats; pat; pat = pat->next) {
06700          if (ast_extension_match(pat->pattern, pattern))
06701             return 1;
06702       }
06703    }
06704 
06705    return 0;
06706 }

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

03650 {
03651    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
03652 }

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 6054 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_context::registrar, and pbx_find_info::stacklen.

Referenced by lua_reload_extensions(), and pbx_load_module().

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

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

09018 {
09019    return pbx_parseable_goto(chan, goto_string, 0);
09020 }

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

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

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

07339 {
07340    /* allocate a channel */
07341    struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");
07342 
07343    if (!chan)
07344       return -1;  /* failure */
07345 
07346    if (!chan->cdr) {
07347       /* allocation of the cdr failed */
07348       ast_channel_free(chan);   /* free the channel */
07349       return -1;                /* return failure */
07350    }
07351 
07352    /* allocation of the cdr was successful */
07353    ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
07354    ast_cdr_start(chan->cdr);       /* record the start and stop time */
07355    ast_cdr_end(chan->cdr);
07356    ast_cdr_failed(chan->cdr);      /* set the status to failed */
07357    ast_cdr_detach(chan->cdr);      /* post and free the record */
07358    chan->cdr = NULL;
07359    ast_channel_free(chan);         /* free the channel */
07360 
07361    return 0;  /* success */
07362 }

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

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

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

04078 {
04079    return ast_pbx_run_args(c, NULL);
04080 }

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

run the application and free the descriptor once done

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

07516 {
07517    struct app_tmp *tmp = data;
07518    struct ast_app *app;
07519    app = pbx_findapp(tmp->app);
07520    if (app) {
07521       ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
07522       pbx_exec(tmp->chan, app, tmp->data);
07523    } else
07524       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
07525    ast_hangup(tmp->chan);
07526    ast_free(tmp);
07527    return NULL;
07528 }

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

04063 {
04064    enum ast_pbx_result res = AST_PBX_SUCCESS;
04065 
04066    if (increase_call_count(c)) {
04067       return AST_PBX_CALL_LIMIT;
04068    }
04069 
04070    res = __ast_pbx_run(c, args);
04071 
04072    decrease_call_count();
04073 
04074    return res;
04075 }

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

04041 {
04042    pthread_t t;
04043 
04044    if (!c) {
04045       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
04046       return AST_PBX_FAILED;
04047    }
04048 
04049    if (increase_call_count(c))
04050       return AST_PBX_CALL_LIMIT;
04051 
04052    /* Start a new thread, and get something handling this channel. */
04053    if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
04054       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
04055       decrease_call_count();
04056       return AST_PBX_FAILED;
04057    }
04058 
04059    return AST_PBX_SUCCESS;
04060 }

int ast_processed_calls ( void   ) 

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

Definition at line 4087 of file pbx.c.

Referenced by handle_chanlist(), and handle_showcalls().

04088 {
04089    return totalcalls;
04090 }

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

08756 {
08757    return ast_rwlock_rdlock(&con->lock);
08758 }

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

04542 {
04543    struct ast_app *tmp, *cur = NULL;
04544    char tmps[80];
04545    int length, res;
04546 
04547    AST_RWLIST_WRLOCK(&apps);
04548    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
04549       if (!(res = strcasecmp(app, tmp->name))) {
04550          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
04551          AST_RWLIST_UNLOCK(&apps);
04552          return -1;
04553       } else if (res < 0)
04554          break;
04555    }
04556 
04557    length = sizeof(*tmp) + strlen(app) + 1;
04558 
04559    if (!(tmp = ast_calloc(1, length))) {
04560       AST_RWLIST_UNLOCK(&apps);
04561       return -1;
04562    }
04563 
04564    strcpy(tmp->name, app);
04565    tmp->execute = execute;
04566    tmp->synopsis = synopsis;
04567    tmp->description = description;
04568    tmp->module = mod;
04569 
04570    /* Store in alphabetical order */
04571    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
04572       if (strcasecmp(tmp->name, cur->name) < 0) {
04573          AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
04574          break;
04575       }
04576    }
04577    AST_RWLIST_TRAVERSE_SAFE_END;
04578    if (!cur)
04579       AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
04580 
04581    ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
04582 
04583    AST_RWLIST_UNLOCK(&apps);
04584 
04585    return 0;
04586 }

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

04593 {
04594    struct ast_switch *tmp;
04595 
04596    AST_RWLIST_WRLOCK(&switches);
04597    AST_RWLIST_TRAVERSE(&switches, tmp, list) {
04598       if (!strcasecmp(tmp->name, sw->name)) {
04599          AST_RWLIST_UNLOCK(&switches);
04600          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
04601          return -1;
04602       }
04603    }
04604    AST_RWLIST_INSERT_TAIL(&switches, sw, list);
04605    AST_RWLIST_UNLOCK(&switches);
04606 
04607    return 0;
04608 }

static int ast_remove_hint ( struct ast_exten e  )  [static]

Remove hint from extension.

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

03578 {
03579    /* Cleanup the Notifys if hint is removed */
03580    struct ast_hint *hint;
03581    struct ast_state_cb *cblist;
03582    int res = -1;
03583 
03584    if (!e)
03585       return -1;
03586 
03587    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
03588       if (hint->exten != e)
03589          continue;
03590 
03591       while ((cblist = AST_LIST_REMOVE_HEAD(&hint->callbacks, entry))) {
03592          /* Notify with -1 and remove all callbacks */
03593          cblist->callback(hint->exten->parent->name, hint->exten->exten, 
03594             AST_EXTENSION_DEACTIVATED, cblist->data);
03595          ast_free(cblist);
03596       }
03597 
03598       AST_RWLIST_REMOVE_CURRENT(list);
03599       ast_free(hint);
03600 
03601          res = 0;
03602 
03603       break;
03604    }
03605    AST_RWLIST_TRAVERSE_SAFE_END;
03606 
03607    return res;
03608 }

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

03655 {
03656    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
03657 }

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

05836 {
05837    struct ast_app *tmp;
05838 
05839    AST_RWLIST_WRLOCK(&apps);
05840    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
05841       if (!strcasecmp(app, tmp->name)) {
05842          unreference_cached_app(tmp);
05843          AST_RWLIST_REMOVE_CURRENT(list);
05844          ast_verb(2, "Unregistered application '%s'\n", tmp->name);
05845          ast_free(tmp);
05846          break;
05847       }
05848    }
05849    AST_RWLIST_TRAVERSE_SAFE_END;
05850    AST_RWLIST_UNLOCK(&apps);
05851 
05852    return tmp ? 0 : -1;
05853 }

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

References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by __unload_module(), and unload_module().

04611 {
04612    AST_RWLIST_WRLOCK(&switches);
04613    AST_RWLIST_REMOVE(&switches, sw, list);
04614    AST_RWLIST_UNLOCK(&switches);
04615 }

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

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

08876 {
08877    if (!exten)
08878       return con ? con->root : NULL;
08879    else
08880       return exten->next;
08881 }

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

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

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

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

08885 {
08886    if (!sw)
08887       return con ? AST_LIST_FIRST(&con->alts) : NULL;
08888    else
08889       return AST_LIST_NEXT(sw, list);
08890 }

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

08751 {
08752    return ast_rwlock_wrlock(&con->lock);
08753 }

int ast_wrlock_contexts ( void   ) 

Write locks the context list.

Return values:
0 on success
-1 on error

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

08730 {
08731    int res = ast_rwlock_wrlock(&conlock);
08732    if (!res)
08733       ast_atomic_fetchadd_int(&conlock_wrlock_version, 1);
08734    return res;
08735 }

int ast_wrlock_contexts_version ( void   ) 

Definition at line 8721 of file pbx.c.

References conlock_wrlock_version.

Referenced by ast_merge_contexts_and_delete().

08722 {
08723    return conlock_wrlock_version;
08724 }

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

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

07278 {
07279    struct async_stat *as = data;
07280    struct ast_channel *chan = as->chan;
07281    int timeout = as->timeout;
07282    int res;
07283    struct ast_frame *f;
07284    struct ast_app *app;
07285 
07286    while (timeout && (chan->_state != AST_STATE_UP)) {
07287       res = ast_waitfor(chan, timeout);
07288       if (res < 1)
07289          break;
07290       if (timeout > -1)
07291          timeout = res;
07292       f = ast_read(chan);
07293       if (!f)
07294          break;
07295       if (f->frametype == AST_FRAME_CONTROL) {
07296          if ((f->subclass == AST_CONTROL_BUSY)  ||
07297              (f->subclass == AST_CONTROL_CONGESTION) ) {
07298             ast_frfree(f);
07299             break;
07300          }
07301       }
07302       ast_frfree(f);
07303    }
07304    if (chan->_state == AST_STATE_UP) {
07305       if (!ast_strlen_zero(as->app)) {
07306          app = pbx_findapp(as->app);
07307          if (app) {
07308             ast_verb(3, "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
07309             pbx_exec(chan, app, as->appdata);
07310          } else
07311             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
07312       } else {
07313          if (!ast_strlen_zero(as->context))
07314             ast_copy_string(chan->context, as->context, sizeof(chan->context));
07315          if (!ast_strlen_zero(as->exten))
07316             ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
07317          if (as->priority > 0)
07318             chan->priority = as->priority;
07319          /* Run the PBX */
07320          if (ast_pbx_run(chan)) {
07321             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
07322          } else {
07323             /* PBX will have taken care of this */
07324             chan = NULL;
07325          }
07326       }
07327    }
07328    ast_free(as);
07329    if (chan)
07330       ast_hangup(chan);
07331    return NULL;
07332 }

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

03674 {
03675    int digit;
03676 
03677    buf[pos] = '\0';  /* make sure it is properly terminated */
03678    while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
03679       /* As long as we're willing to wait, and as long as it's not defined,
03680          keep reading digits until we can't possibly get a right answer anymore.  */
03681       digit = ast_waitfordigit(c, waittime);
03682       if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03683          c->_softhangup = 0;
03684       } else {
03685          if (!digit) /* No entry */
03686             break;
03687          if (digit < 0) /* Error, maybe a  hangup */
03688             return -1;
03689          if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
03690             buf[pos++] = digit;
03691             buf[pos] = '\0';
03692          }
03693          waittime = c->pbx->dtimeoutms;
03694       }
03695    }
03696    return 0;
03697 }

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

04771 {
04772    struct ast_hint *hint;
04773    char *ret = NULL;
04774    int which = 0;
04775    int wordlen;
04776 
04777    if (pos != 3)
04778       return NULL;
04779    
04780    wordlen = strlen(word);
04781 
04782    AST_RWLIST_RDLOCK(&hints);
04783    /* walk through all hints */
04784    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04785       if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
04786          ret = ast_strdup(ast_get_extension_name(hint->exten));
04787          break;
04788       }
04789    }
04790    AST_RWLIST_UNLOCK(&hints);
04791 
04792    return ret;
04793 }

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

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

04968 {
04969    struct ast_context *c = NULL;
04970    char *ret = NULL;
04971    int which = 0;
04972    int wordlen;
04973 
04974    /* we are do completion of [exten@]context on second position only */
04975    if (pos != 2)
04976       return NULL;
04977 
04978    ast_rdlock_contexts();
04979 
04980    wordlen = strlen(word);
04981 
04982    /* walk through all contexts and return the n-th match */
04983    while ( (c = ast_walk_contexts(c)) ) {
04984       if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
04985          ret = ast_strdup(ast_get_context_name(c));
04986          break;
04987       }
04988    }
04989 
04990    ast_unlock_contexts();
04991 
04992    return ret;
04993 }

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

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

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

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

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

05938 {
05939    struct ast_include *i;
05940    struct ast_ignorepat *ip;
05941    struct ast_sw *sw;
05942    
05943    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);
05944    /* copy in the includes, switches, and ignorepats */
05945    /* walk through includes */
05946    for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
05947       if (strcmp(ast_get_include_registrar(i), registrar) == 0)
05948          continue; /* not mine */
05949       ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
05950    }
05951    
05952    /* walk through switches */
05953    for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
05954       if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
05955          continue; /* not mine */
05956       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));
05957    }
05958    
05959    /* walk thru ignorepats ... */
05960    for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
05961       if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
05962          continue; /* not mine */
05963       ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
05964    }
05965 }

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

References ast_mutex_lock(), and ast_mutex_unlock().

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

03999 {
04000    ast_mutex_lock(&maxcalllock);
04001    if (countcalls > 0)
04002       countcalls--;
04003    ast_mutex_unlock(&maxcalllock);
04004 }

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

08668 {
08669    const char *device;
08670    struct statechange *sc;
08671 
08672    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
08673    if (ast_strlen_zero(device)) {
08674       ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
08675       return;
08676    }
08677 
08678    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device) + 1)))
08679       return;
08680    strcpy(sc->dev, device);
08681    if (ast_taskprocessor_push(device_state_tps, handle_statechange, sc) < 0) {
08682       ast_free(sc);
08683    }
08684 }

static void exception_store_free ( void *  data  )  [static]

Definition at line 2567 of file pbx.c.

References ast_free, and ast_string_field_free_memory.

02568 {
02569    struct pbx_exception *exception = data;
02570    ast_string_field_free_memory(exception);
02571    ast_free(exception);
02572 }

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

the full routine to compare extensions in rules.

Definition at line 1768 of file pbx.c.

References ext_cmp1().

Referenced by ast_add_extension2_lockopt(), and ast_extension_cmp().

01769 {
01770    /* make sure non-patterns come first.
01771     * If a is not a pattern, it either comes first or
01772     * we use strcmp to compare the strings.
01773     */
01774    int ret = 0;
01775 
01776    if (a[0] != '_')
01777       return (b[0] == '_') ? -1 : strcmp(a, b);
01778 
01779    /* Now we know a is a pattern; if b is not, a comes first */
01780    if (b[0] != '_')
01781       return 1;
01782 #if 0 /* old mode for ext matching */
01783    return strcmp(a, b);
01784 #endif
01785    /* ok we need full pattern sorting routine */
01786    while (!ret && a && b)
01787       ret = ext_cmp1(&a) - ext_cmp1(&b);
01788    if (ret == 0)
01789       return 0;
01790    else
01791       return (ret > 0) ? 1 : -1;
01792 }

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

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

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

Definition at line 1697 of file pbx.c.

References ast_log(), and LOG_WARNING.

Referenced by ext_cmp().

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

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

copy a string skipping whitespace

Definition at line 6838 of file pbx.c.

Referenced by ast_add_extension2_lockopt().

06839 {
06840    int count = 0;
06841 
06842    while (*src && (count < len - 1)) {
06843       switch (*src) {
06844       case ' ':
06845          /* otherwise exten => [a-b],1,... doesn't work */
06846          /*    case '-': */
06847          /* Ignore */
06848          break;
06849       default:
06850          *dst = *src;
06851          dst++;
06852       }
06853       src++;
06854       count++;
06855    }
06856    *dst = '\0';
06857 
06858    return count;
06859 }

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

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

01976 {
01977    int i;
01978    static int prof_id = -2;   /* marker for 'unallocated' id */
01979    if (prof_id == -2)
01980       prof_id = ast_add_profile("ext_match", 0);
01981    ast_mark(prof_id, 1);
01982    i = _extension_match_core(pattern, data, mode);
01983    ast_mark(prof_id, 0);
01984    return i;
01985 }

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

References ast_copy_string(), and ast_hashtab_lookup().

Referenced by ast_add_extension_nolock().

04123 {
04124    struct ast_context *c = NULL;
04125    struct fake_context item;
04126 
04127    ast_copy_string(item.name, context, sizeof(item.name));
04128 
04129    c = ast_hashtab_lookup(contexts_table,&item);
04130 
04131    return c;
04132 }

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

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    ast_rdlock_contexts();
04147    c = ast_hashtab_lookup(contexts_table,&item);
04148 
04149 #ifdef NOTNOW
04150 
04151    while ( (c = ast_walk_contexts(c)) ) {
04152       if (!strcmp(ast_get_context_name(c), context))
04153          return c;
04154    }
04155 #endif
04156    if (!c)
04157       ast_unlock_contexts();
04158 
04159    return c;
04160 }

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

References ast_log(), and LOG_WARNING.

Referenced by ast_func_read(), and ast_func_write().

02837 {
02838    char *args = strchr(function, '(');
02839 
02840    if (!args)
02841       ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
02842    else {
02843       char *p;
02844       *args++ = '\0';
02845       if ((p = strrchr(args, ')')) )
02846          *p = '\0';
02847       else
02848          ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
02849    }
02850    return args;
02851 }

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

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

Referenced by ast_build_timing().

06233 {
06234    int s, e; /* start and ending position */
06235    unsigned int mask = 0;
06236 
06237    /* Check for whole range */
06238    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
06239       s = 0;
06240       e = max - 1;
06241    } else {
06242       /* Get start and ending position */
06243       char *c = strchr(src, '-');
06244       if (c)
06245          *c++ = '\0';
06246       /* Find the start */
06247       s = lookup_name(src, names, max);
06248       if (!s) {
06249          ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
06250          return 0;
06251       }
06252       s--;
06253       if (c) { /* find end of range */
06254          e = lookup_name(c, names, max);
06255          if (!e) {
06256             ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
06257             return 0;
06258          }
06259          e--;
06260       } else
06261          e = s;
06262    }
06263    /* Fill the mask. Remember that ranges are cyclic */
06264    mask = 1 << e; /* initialize with last element */
06265    while (s != e) {
06266       if (s >= max) {
06267          s = 0;
06268          mask |= (1 << s);
06269       } else {
06270          mask |= (1 << s);
06271          s++;
06272       }
06273    }
06274    return mask;
06275 }

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

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

Referenced by ast_build_timing().

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

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

Send ack once.

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

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

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

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

05686 {
05687    struct ast_channel *chan;
05688    const char *chan_name, *var_name, *var_value;
05689 
05690    switch (cmd) {
05691    case CLI_INIT:
05692       e->command = "dialplan set chanvar";
05693       e->usage = 
05694          "Usage: dialplan set chanvar <channel> <varname> <value>\n"
05695          "       Set channel variable <varname> to <value>\n";
05696       return NULL;
05697    case CLI_GENERATE:
05698       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05699    }
05700 
05701    if (a->argc != e->args + 3)
05702       return CLI_SHOWUSAGE;
05703 
05704    chan_name = a->argv[e->args];
05705    var_name = a->argv[e->args + 1];
05706    var_value = a->argv[e->args + 2];
05707 
05708    if (!(chan = ast_get_channel_by_name_locked(chan_name))) {
05709       ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
05710       return CLI_FAILURE;
05711    }
05712 
05713    pbx_builtin_setvar_helper(chan, var_name, var_value);
05714    ast_channel_unlock(chan);
05715    ast_cli(a->fd, "\n    -- Channel variable '%s' set to '%s' for '%s'\n",  var_name, var_value, chan_name);
05716 
05717    return CLI_SUCCESS;
05718 }

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

Definition at line 5720 of file pbx.c.

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

05721 {
05722    char *res = handle_set_chanvar(e, cmd, a);
05723    if (cmd == CLI_INIT)
05724       e->command = "core set chanvar";
05725    return res;
05726 }

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

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

05729 {
05730    int oldval = 0;
05731    
05732    switch (cmd) {
05733    case CLI_INIT:
05734       e->command = "dialplan set extenpatternmatchnew true";
05735       e->usage = 
05736          "Usage: dialplan set extenpatternmatchnew true|false\n"
05737          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05738       return NULL;
05739    case CLI_GENERATE:
05740       return NULL;   
05741    }
05742 
05743    if (a->argc != 4)
05744       return CLI_SHOWUSAGE;
05745 
05746    oldval =  pbx_set_extenpatternmatchnew(1);
05747    
05748    if (oldval)
05749       ast_cli(a->fd, "\n    -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
05750    else
05751       ast_cli(a->fd, "\n    -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
05752 
05753    return CLI_SUCCESS;
05754 }

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

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

05656 {
05657    switch (cmd) {
05658    case CLI_INIT:
05659       e->command = "dialplan set global";
05660       e->usage = 
05661          "Usage: dialplan set global <name> <value>\n"
05662          "       Set global dialplan variable <name> to <value>\n";
05663       return NULL;
05664    case CLI_GENERATE:
05665       return NULL;   
05666    }
05667 
05668    if (a->argc != e->args + 2)
05669       return CLI_SHOWUSAGE;
05670 
05671    pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
05672    ast_cli(a->fd, "\n    -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
05673 
05674    return CLI_SUCCESS;
05675 }

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

Definition at line 5677 of file pbx.c.

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

05678 {
05679    char *res = handle_set_global(e, cmd, a);
05680    if (cmd == CLI_INIT)
05681       e->command = "core set global";
05682    return res;
05683 }

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

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

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

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

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

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

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

05624 {
05625    struct ast_channel *chan = NULL;
05626    struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX large because we might have lots of channel vars */
05627 
05628    switch (cmd) {
05629    case CLI_INIT:
05630       e->command = "dialplan show chanvar";
05631       e->usage = 
05632          "Usage: dialplan show chanvar <channel>\n"
05633          "       List current channel variables and their values\n";
05634       return NULL;
05635    case CLI_GENERATE:
05636       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05637    }
05638 
05639    if (a->argc != e->args + 1)
05640       return CLI_SHOWUSAGE;
05641 
05642    if (!(chan = ast_get_channel_by_name_locked(a->argv[e->args]))) {
05643       ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
05644       return CLI_FAILURE;
05645    }
05646 
05647    pbx_builtin_serialize_variables(chan, &vars);
05648    if (vars->str) {
05649       ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], vars->str);
05650    }
05651    ast_channel_unlock(chan);
05652    return CLI_SUCCESS;
05653 }

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

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

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

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

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

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

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

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

02647 {
02648    struct ast_custom_function *acf;
02649    int count_acf = 0;
02650    int like = 0;
02651 
02652    switch (cmd) {
02653    case CLI_INIT:
02654       e->command = "core show functions [like]";
02655       e->usage = 
02656          "Usage: core show functions [like <text>]\n"
02657          "       List builtin functions, optionally only those matching a given string\n";
02658       return NULL;
02659    case CLI_GENERATE:
02660       return NULL;
02661    }
02662 
02663    if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
02664       like = 1;
02665    } else if (a->argc != 3) {
02666       return CLI_SHOWUSAGE;
02667    }
02668 
02669    ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
02670 
02671    AST_RWLIST_RDLOCK(&acf_root);
02672    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02673       if (!like || strstr(acf->name, a->argv[4])) {
02674          count_acf++;
02675          ast_cli(a->fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
02676       }
02677    }
02678    AST_RWLIST_UNLOCK(&acf_root);
02679 
02680    ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
02681 
02682    return CLI_SUCCESS;
02683 }

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

05557 {
05558    int i = 0;
05559    struct ast_var_t *newvariable;
05560 
05561    switch (cmd) {
05562    case CLI_INIT:
05563       e->command = "dialplan show globals";
05564       e->usage = 
05565          "Usage: dialplan show globals\n"
05566          "       List current global dialplan variables and their values\n";
05567       return NULL;
05568    case CLI_GENERATE:
05569       return NULL;
05570    }
05571 
05572    ast_rwlock_rdlock(&globalslock);
05573    AST_LIST_TRAVERSE (&globals, newvariable, entries) {
05574       i++;
05575       ast_cli(a->fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
05576    }
05577    ast_rwlock_unlock(&globalslock);
05578    ast_cli(a->fd, "\n    -- %d variable(s)\n", i);
05579 
05580    return CLI_SUCCESS;
05581 }

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

Definition at line 5583 of file pbx.c.

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

05584 {
05585 
05586    char *res = handle_show_globals(e, cmd, a);
05587    if (cmd == CLI_INIT)
05588       e->command = "core show globals";
05589    return res;
05590 }

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

04797 {
04798    struct ast_hint *hint;
04799    int watchers;
04800    int num = 0, extenlen;
04801    struct ast_state_cb *watcher;
04802 
04803    switch (cmd) {
04804    case CLI_INIT:
04805       e->command = "core show hint";
04806       e->usage =
04807          "Usage: core show hint <exten>\n"
04808          "       List registered hint\n";
04809       return NULL;
04810    case CLI_GENERATE:
04811       return complete_core_show_hint(a->line, a->word, a->pos, a->n);
04812    }
04813 
04814    if (a->argc < 4)
04815       return CLI_SHOWUSAGE;
04816 
04817    AST_RWLIST_RDLOCK(&hints);
04818    if (AST_RWLIST_EMPTY(&hints)) {
04819       ast_cli(a->fd, "There are no registered dialplan hints\n");
04820       AST_RWLIST_UNLOCK(&hints);
04821       return CLI_SUCCESS;
04822    }
04823    extenlen = strlen(a->argv[3]);
04824    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04825       if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
04826          watchers = 0;
04827          AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04828             watchers++;
04829          }
04830          ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04831             ast_get_extension_name(hint->exten),
04832             ast_get_context_name(ast_get_extension_context(hint->exten)),
04833             ast_get_extension_app(hint->exten),
04834             ast_extension_state2str(hint->laststate), watchers);
04835          num++;
04836       }
04837    }
04838    AST_RWLIST_UNLOCK(&hints);
04839    if (!num)
04840       ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
04841    else
04842       ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
04843    return CLI_SUCCESS;
04844 }

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

04726 {
04727    struct ast_hint *hint;
04728    int num = 0;
04729    int watchers;
04730    struct ast_state_cb *watcher;
04731 
04732    switch (cmd) {
04733    case CLI_INIT:
04734       e->command = "core show hints";
04735       e->usage = 
04736          "Usage: core show hints\n"
04737          "       List registered hints\n";
04738       return NULL;
04739    case CLI_GENERATE:
04740       return NULL;   
04741    }
04742 
04743    AST_RWLIST_RDLOCK(&hints);
04744    if (AST_RWLIST_EMPTY(&hints)) {
04745       ast_cli(a->fd, "There are no registered dialplan hints\n");
04746       AST_RWLIST_UNLOCK(&hints);
04747       return CLI_SUCCESS;
04748    }
04749    /* ... we have hints ... */
04750    ast_cli(a->fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
04751    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04752       watchers = 0;
04753       AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04754          watchers++;
04755       }
04756       ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04757          ast_get_extension_name(hint->exten),
04758          ast_get_context_name(ast_get_extension_context(hint->exten)),
04759          ast_get_extension_app(hint->exten),
04760          ast_extension_state2str(hint->laststate), watchers);
04761       num++;
04762    }
04763    ast_cli(a->fd, "----------------\n");
04764    ast_cli(a->fd, "- %d hints registered\n", num);
04765    AST_RWLIST_UNLOCK(&hints);
04766    return CLI_SUCCESS;
04767 }

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

04849 {
04850    struct ast_switch *sw;
04851 
04852    switch (cmd) {
04853    case CLI_INIT:
04854       e->command = "core show switches";
04855       e->usage = 
04856          "Usage: core show switches\n"
04857          "       List registered switches\n";
04858       return NULL;
04859    case CLI_GENERATE:
04860       return NULL;   
04861    }
04862 
04863    AST_RWLIST_RDLOCK(&switches);
04864 
04865    if (AST_RWLIST_EMPTY(&switches)) {
04866       AST_RWLIST_UNLOCK(&switches);
04867       ast_cli(a->fd, "There are no registered alternative switches\n");
04868       return CLI_SUCCESS;
04869    }
04870 
04871    ast_cli(a->fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
04872    AST_RWLIST_TRAVERSE(&switches, sw, list)
04873       ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
04874 
04875    AST_RWLIST_UNLOCK(&switches);
04876 
04877    return CLI_SUCCESS;
04878 }

static int handle_statechange ( void *  datap  )  [static]

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

03333 {
03334    struct ast_hint *hint;
03335    struct statechange *sc = datap;
03336 
03337    ast_rdlock_contexts();
03338    AST_RWLIST_RDLOCK(&hints);
03339 
03340    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03341       struct ast_state_cb *cblist;
03342       char buf[AST_MAX_EXTENSION];
03343       char *parse = buf;
03344       char *cur;
03345       int state;
03346 
03347       ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
03348       while ( (cur = strsep(&parse, "&")) ) {
03349          if (!strcasecmp(cur, sc->dev))
03350             break;
03351       }
03352       if (!cur)
03353          continue;
03354 
03355       /* Get device state for this hint */
03356       state = ast_extension_state2(hint->exten);
03357 
03358       if ((state == -1) || (state == hint->laststate))
03359          continue;
03360 
03361       /* Device state changed since last check - notify the watchers */
03362 
03363       /* For general callbacks */
03364       AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
03365          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03366       }
03367 
03368       /* For extension callbacks */
03369       AST_LIST_TRAVERSE(&hint->callbacks, cblist, entry) {
03370          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03371       }
03372 
03373       hint->laststate = state;   /* record we saw the change */
03374    }
03375    AST_RWLIST_UNLOCK(&hints);
03376    ast_unlock_contexts();
03377    ast_free(sc);
03378    return 0;
03379 }

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

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

05757 {
05758    int oldval = 0;
05759    
05760    switch (cmd) {
05761    case CLI_INIT:
05762       e->command = "dialplan set extenpatternmatchnew false";
05763       e->usage = 
05764          "Usage: dialplan set extenpatternmatchnew true|false\n"
05765          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05766       return NULL;
05767    case CLI_GENERATE:
05768       return NULL;   
05769    }
05770 
05771    if (a->argc != 4)
05772       return CLI_SHOWUSAGE;
05773 
05774    oldval =  pbx_set_extenpatternmatchnew(0);
05775    
05776    if (!oldval)
05777       ast_cli(a->fd, "\n    -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
05778    else
05779       ast_cli(a->fd, "\n    -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
05780 
05781    return CLI_SUCCESS;
05782 }

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

03952 {
03953    int failed = 0;
03954    double curloadavg;
03955 #if defined(HAVE_SYSINFO)
03956    long curfreemem;
03957    struct sysinfo sys_info;
03958 #endif
03959 
03960    ast_mutex_lock(&maxcalllock);
03961    if (option_maxcalls) {
03962       if (countcalls >= option_maxcalls) {
03963          ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
03964          failed = -1;
03965       }
03966    }
03967    if (option_maxload) {
03968       getloadavg(&curloadavg, 1);
03969       if (curloadavg >= option_maxload) {
03970          ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
03971          failed = -1;
03972       }
03973    }
03974 #if defined(HAVE_SYSINFO)
03975    if (option_minmemfree) {
03976       if (!sysinfo(&sys_info)) {
03977          /* make sure that the free system memory is above the configured low watermark
03978           * convert the amount of freeram from mem_units to MB */
03979          curfreemem = sys_info.freeram / sys_info.mem_unit; 
03980          curfreemem /= 1024*1024; 
03981          if (curfreemem < option_minmemfree) {
03982             ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
03983             failed = -1;
03984          }
03985       }
03986    }
03987 #endif
03988       
03989    if (!failed) {
03990       countcalls++;
03991       totalcalls++;
03992    }
03993    ast_mutex_unlock(&maxcalllock);
03994 
03995    return failed;
03996 }

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

08687 {
08688    int x;
08689 
08690    /* Initialize the PBX */
08691    ast_verb(1, "Asterisk PBX Core Initializing\n");
08692    if (!(device_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
08693       ast_log(LOG_WARNING, "failed to create pbx-core taskprocessor\n");
08694    }
08695 
08696    ast_verb(1, "Registering builtin applications:\n");
08697    ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
08698    __ast_custom_function_register(&exception_function, NULL);
08699 
08700    /* Register builtin applications */
08701    for (x = 0; x < sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
08702       ast_verb(1, "[%s]\n", builtins[x].name);
08703       if (ast_register_application2(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description, NULL)) {
08704          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
08705          return -1;
08706       }
08707    }
08708    
08709    /* Register manager application */
08710    ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
08711 
08712    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL,
08713          AST_EVENT_IE_END))) {
08714       return -1;
08715    }
08716 
08717    return 0;
08718 }

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

Referenced by get_range().

06215 {
06216    int i;
06217 
06218    if (names) {
06219       for (i = 0; names[i]; i++) {
06220          if (!strcasecmp(s, names[i]))
06221             return i+1;
06222       }
06223    } else if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
06224       return i;
06225    }
06226    return 0; /* error return */
06227 }

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

Send ack once.

Definition at line 5347 of file pbx.c.

References astman_send_listack().

Referenced by manager_show_dialplan_helper().

05348 {
05349    astman_send_listack(s, m, "DialPlan list will follow", "start");
05350 }

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

Manager listing of dial plan.

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

05494 {
05495    const char *exten, *context;
05496    const char *id = astman_get_header(m, "ActionID");
05497    char idtext[256];
05498    int res;
05499 
05500    /* Variables used for different counters */
05501    struct dialplan_counters counters;
05502 
05503    if (!ast_strlen_zero(id))
05504       snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
05505    else
05506       idtext[0] = '\0';
05507 
05508    memset(&counters, 0, sizeof(counters));
05509 
05510    exten = astman_get_header(m, "Extension");
05511    context = astman_get_header(m, "Context");
05512    
05513    res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
05514 
05515    if (context && !counters.context_existence) {
05516       char errorbuf[BUFSIZ];
05517    
05518       snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
05519       astman_send_error(s, m, errorbuf);
05520       return 0;
05521    }
05522    if (exten && !counters.extension_existence) {
05523       char errorbuf[BUFSIZ];
05524 
05525       if (context)
05526          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
05527       else
05528          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
05529       astman_send_error(s, m, errorbuf);
05530       return 0;
05531    }
05532 
05533    manager_event(EVENT_FLAG_CONFIG, "ShowDialPlanComplete",
05534       "EventList: Complete\r\n"
05535       "ListItems: %d\r\n"
05536       "ListExtensions: %d\r\n"
05537       "ListPriorities: %d\r\n"   
05538       "ListContexts: %d\r\n"  
05539       "%s"
05540       "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
05541 
05542    /* everything ok */
05543    return 0;
05544 }

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

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

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

Definition at line 2041 of file pbx.c.

References ast_extension_match(), and ast_strlen_zero().

Referenced by pbx_find_extension().

02042 {
02043    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
02044       failing to get a number should count as a match, otherwise not */
02045 
02046    if (ast_strlen_zero(callerid))
02047       return ast_strlen_zero(cidpattern) ? 1 : 0;
02048 
02049    return ast_extension_match(cidpattern, callerid);
02050 }

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

Referenced by pbx_retrieve_variable(), and pbx_substitute_variables_helper_full().

02377 {
02378    int parens = 0;
02379 
02380    *offset = 0;
02381    *length = INT_MAX;
02382    *isfunc = 0;
02383    for (; *var; var++) {
02384       if (*var == '(') {
02385          (*isfunc)++;
02386          parens++;
02387       } else if (*var == ')') {
02388          parens--;
02389       } else if (*var == ':' && parens == 0) {
02390          *var++ = '\0';
02391          sscanf(var, "%30d:%30d", offset, length);
02392          return 1; /* offset:length valid */
02393       }
02394    }
02395    return 0;
02396 }

void pbx_builtin_clear_globals ( void   ) 

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

08567 {
08568    struct ast_var_t *vardata;
08569 
08570    ast_rwlock_wrlock(&globalslock);
08571    while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
08572       ast_var_delete(vardata);
08573    ast_rwlock_unlock(&globalslock);
08574 }

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

08337 {
08338    struct ast_var_t *variables;
08339    const char *ret = NULL;
08340    int i;
08341    struct varshead *places[2] = { NULL, &globals };
08342 
08343    if (!name)
08344       return NULL;
08345 
08346    if (chan) {
08347       ast_channel_lock(chan);
08348       places[0] = &chan->varshead;
08349    }
08350 
08351    for (i = 0; i < 2; i++) {
08352       if (!places[i])
08353          continue;
08354       if (places[i] == &globals)
08355          ast_rwlock_rdlock(&globalslock);
08356       AST_LIST_TRAVERSE(places[i], variables, entries) {
08357          if (!strcmp(name, ast_var_name(variables))) {
08358             ret = ast_var_value(variables);
08359             break;
08360          }
08361       }
08362       if (places[i] == &globals)
08363          ast_rwlock_unlock(&globalslock);
08364       if (ret)
08365          break;
08366    }
08367 
08368    if (chan)
08369       ast_channel_unlock(chan);
08370 
08371    return ret;
08372 }

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

Definition at line 8588 of file pbx.c.

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

08589 {
08590    char *condition, *branch1, *branch2, *branch;
08591    char *stringp;
08592 
08593    if (ast_strlen_zero(data)) {
08594       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
08595       return 0;
08596    }
08597 
08598    stringp = ast_strdupa(data);
08599    condition = strsep(&stringp,"?");
08600    branch1 = strsep(&stringp,":");
08601    branch2 = strsep(&stringp,"");
08602    branch = pbx_checkcondition(condition) ? branch1 : branch2;
08603 
08604    if (ast_strlen_zero(branch)) {
08605       ast_debug(1, "Not taking any branch\n");
08606       return 0;
08607    }
08608 
08609    return pbx_builtin_goto(chan, branch);
08610 }

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

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

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

08525 {
08526    char *name;
08527    char *value;
08528    char *channel;
08529    char tmp[VAR_BUF_SIZE];
08530    static int deprecation_warning = 0;
08531 
08532    if (ast_strlen_zero(data)) {
08533       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
08534       return 0;
08535    }
08536    tmp[0] = 0;
08537    if (!deprecation_warning) {
08538       ast_log(LOG_WARNING, "ImportVar is deprecated.  Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
08539       deprecation_warning = 1;
08540    }
08541 
08542    value = ast_strdupa(data);
08543    name = strsep(&value,"=");
08544    channel = strsep(&value,",");
08545    if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
08546       struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
08547       if (chan2) {
08548          char *s = alloca(strlen(value) + 4);
08549          if (s) {
08550             sprintf(s, "${%s}", value);
08551             pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
08552          }
08553          ast_channel_unlock(chan2);
08554       }
08555       pbx_builtin_setvar_helper(chan, name, tmp);
08556    }
08557 
08558    return(0);
08559 }

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

Definition at line 7942 of file pbx.c.

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

07943 {
07944    char *options = data;
07945    int answer = 1;
07946 
07947    /* Some channels can receive DTMF in unanswered state; some cannot */
07948    if (!ast_strlen_zero(options) && strchr(options, 'n')) {
07949       answer = 0;
07950    }
07951 
07952    /* If the channel is hungup, stop waiting */
07953    if (ast_check_hangup(chan)) {
07954       return -1;
07955    } else if (chan->_state != AST_STATE_UP && answer) {
07956       __ast_answer(chan, 0, 1);
07957    }
07958 
07959    return AST_PBX_INCOMPLETE;
07960 }

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

Definition at line 8561 of file pbx.c.

08562 {
08563    return 0;
08564 }

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

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

08375 {
08376    struct ast_var_t *newvariable;
08377    struct varshead *headp;
08378 
08379    if (name[strlen(name)-1] == ')') {
08380       char *function = ast_strdupa(name);
08381 
08382       ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
08383       ast_func_write(chan, function, value);
08384       return;
08385    }
08386 
08387    if (chan) {
08388       ast_channel_lock(chan);
08389       headp = &chan->varshead;
08390    } else {
08391       ast_rwlock_wrlock(&globalslock);
08392       headp = &globals;
08393    }
08394 
08395    if (value) {
08396       if (headp == &globals)
08397          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08398       newvariable = ast_var_assign(name, value);
08399       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08400    }
08401 
08402    if (chan)
08403       ast_channel_unlock(chan);
08404    else
08405       ast_rwlock_unlock(&globalslock);
08406 }

int pbx_builtin_raise_exception ( struct ast_channel chan,
void *  vreason 
)

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

02580 {
02581    const char *reason = vreason;
02582    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02583    struct pbx_exception *exception = NULL;
02584 
02585    if (!ds) {
02586       ds = ast_datastore_alloc(&exception_store_info, NULL);
02587       if (!ds)
02588          return -1;
02589       exception = ast_calloc(1, sizeof(struct pbx_exception));
02590       if (!exception) {
02591          ast_datastore_free(ds);
02592          return -1;
02593       }
02594       if (ast_string_field_init(exception, 128)) {
02595          ast_free(exception);
02596          ast_datastore_free(ds);
02597          return -1;
02598       }
02599       ds->data = exception;
02600       ast_channel_datastore_add(chan, ds);
02601    } else
02602       exception = ds->data;
02603 
02604    ast_string_field_set(exception, reason, reason);
02605    ast_string_field_set(exception, context, chan->context);
02606    ast_string_field_set(exception, exten, chan->exten);
02607    exception->priority = chan->priority;
02608    set_ext_pri(chan, "e", 0);
02609    return 0;
02610 }

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

Definition at line 8649 of file pbx.c.

References ast_say_character_str().

08650 {
08651    int res = 0;
08652 
08653    if (data)
08654       res = ast_say_character_str(chan, data, "", chan->language);
08655    return res;
08656 }

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

Definition at line 8640 of file pbx.c.

References ast_say_digit_str().

08641 {
08642    int res = 0;
08643 
08644    if (data)
08645       res = ast_say_digit_str(chan, data, "", chan->language);
08646    return res;
08647 }

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

Definition at line 8612 of file pbx.c.

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

08613 {
08614    char tmp[256];
08615    char *number = tmp;
08616    char *options;
08617 
08618    if (ast_strlen_zero(data)) {
08619       ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
08620       return -1;
08621    }
08622    ast_copy_string(tmp, data, sizeof(tmp));
08623    strsep(&number, ",");
08624    options = strsep(&number, ",");
08625    if (options) {
08626       if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
08627          strcasecmp(options, "c") && strcasecmp(options, "n") ) {
08628          ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
08629          return -1;
08630       }
08631    }
08632 
08633    if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
08634       ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
08635    }
08636 
08637    return 0;
08638 }

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

Definition at line 8658 of file pbx.c.

References ast_say_phonetic_str().

08659 {
08660    int res = 0;
08661 
08662    if (data)
08663       res = ast_say_phonetic_str(chan, data, "", chan->language);
08664    return res;
08665 }

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

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

08305 {
08306    struct ast_var_t *variables;
08307    const char *var, *val;
08308    int total = 0;
08309 
08310    if (!chan)
08311       return 0;
08312 
08313    (*buf)->used = 0;
08314    (*buf)->str[0] = '\0';
08315 
08316    ast_channel_lock(chan);
08317 
08318    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
08319       if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
08320          /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
08321          ) {
08322          if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
08323             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
08324             break;
08325          } else
08326             total++;
08327       } else
08328          break;
08329    }
08330 
08331    ast_channel_unlock(chan);
08332 
08333    return total;
08334 }

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

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

08466 {
08467    char *name, *value, *mydata;
08468 
08469    if (ast_compat_app_set) {
08470       return pbx_builtin_setvar_multiple(chan, data);
08471    }
08472 
08473    if (ast_strlen_zero(data)) {
08474       ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
08475       return 0;
08476    }
08477 
08478    mydata = ast_strdupa(data);
08479    name = strsep(&mydata, "=");
08480    value = mydata;
08481    if (strchr(name, ' '))
08482       ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
08483 
08484    pbx_builtin_setvar_helper(chan, name, value);
08485    return(0);
08486 }

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

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

08409 {
08410    struct ast_var_t *newvariable;
08411    struct varshead *headp;
08412    const char *nametail = name;
08413 
08414    if (name[strlen(name) - 1] == ')') {
08415       char *function = ast_strdupa(name);
08416 
08417       ast_func_write(chan, function, value);
08418       return;
08419    }
08420 
08421    if (chan) {
08422       ast_channel_lock(chan);
08423       headp = &chan->varshead;
08424    } else {
08425       ast_rwlock_wrlock(&globalslock);
08426       headp = &globals;
08427    }
08428 
08429    /* For comparison purposes, we have to strip leading underscores */
08430    if (*nametail == '_') {
08431       nametail++;
08432       if (*nametail == '_')
08433          nametail++;
08434    }
08435 
08436    AST_LIST_TRAVERSE (headp, newvariable, entries) {
08437       if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
08438          /* there is already such a variable, delete it */
08439          AST_LIST_REMOVE(headp, newvariable, entries);
08440          ast_var_delete(newvariable);
08441          break;
08442       }
08443    }
08444 
08445    if (value) {
08446       if (headp == &globals)
08447          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08448       newvariable = ast_var_assign(name, value);
08449       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08450       manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
08451          "Channel: %s\r\n"
08452          "Variable: %s\r\n"
08453          "Value: %s\r\n"
08454          "Uniqueid: %s\r\n", 
08455          chan ? chan->name : "none", name, value, 
08456          chan ? chan->uniqueid : "none");
08457    }
08458 
08459    if (chan)
08460       ast_channel_unlock(chan);
08461    else
08462       ast_rwlock_unlock(&globalslock);
08463 }

int pbx_builtin_setvar_multiple ( struct ast_channel chan,
void *  vdata 
)

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

08489 {
08490    char *data;
08491    int x;
08492    AST_DECLARE_APP_ARGS(args,
08493       AST_APP_ARG(pair)[24];
08494    );
08495    AST_DECLARE_APP_ARGS(pair,
08496       AST_APP_ARG(name);
08497       AST_APP_ARG(value);
08498    );
08499 
08500    if (ast_strlen_zero(vdata)) {
08501       ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
08502       return 0;
08503    }
08504 
08505    data = ast_strdupa(vdata);
08506    AST_STANDARD_APP_ARGS(args, data);
08507 
08508    for (x = 0; x < args.argc; x++) {
08509       AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
08510       if (pair.argc == 2) {
08511          pbx_builtin_setvar_helper(chan, pair.name, pair.value);
08512          if (strchr(pair.name, ' '))
08513             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);
08514       } else if (!chan) {
08515          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
08516       } else {
08517          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, chan->exten, chan->context, chan->priority);
08518       }
08519    }
08520 
08521    return 0;
08522 }

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

08577 {
08578    int res;
08579    if (ast_strlen_zero(condition)) {                /* NULL or empty strings are false */
08580       return 0;
08581    } else if (sscanf(condition, "%30d", &res) == 1) { /* Numbers are evaluated for truth */
08582       return res;
08583    } else {                                         /* Strings are true */
08584       return 1;
08585    }
08586 }

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_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, ',')) {
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 3137 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, 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().

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

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

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

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

08965 {
08966    char *exten, *pri, *context;
08967    char *stringp;
08968    int ipri;
08969    int mode = 0;
08970 
08971    if (ast_strlen_zero(goto_string)) {
08972       ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
08973       return -1;
08974    }
08975    stringp = ast_strdupa(goto_string);
08976    context = strsep(&stringp, ","); /* guaranteed non-null */
08977    exten = strsep(&stringp, ",");
08978    pri = strsep(&stringp, ",");
08979    if (!exten) {  /* Only a priority in this one */
08980       pri = context;
08981       exten = NULL;
08982       context = NULL;
08983    } else if (!pri) {   /* Only an extension and priority in this one */
08984       pri = exten;
08985       exten = context;
08986       context = NULL;
08987    }
08988    if (*pri == '+') {
08989       mode = 1;
08990       pri++;
08991    } else if (*pri == '-') {
08992       mode = -1;
08993       pri++;
08994    }
08995    if (sscanf(pri, "%30d", &ipri) != 1) {
08996       if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
08997          pri, chan->cid.cid_num)) < 1) {
08998          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
08999          return -1;
09000       } else
09001          mode = 0;
09002    }
09003    /* At this point we have a priority and maybe an extension and a context */
09004 
09005    if (mode)
09006       ipri = chan->priority + (ipri * mode);
09007 
09008    if (async)
09009       ast_async_goto(chan, context, exten, ipri);
09010    else
09011       ast_explicit_goto(chan, context, exten, ipri);
09012    
09013    return 0;
09014 
09015 }

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

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

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

Referenced by pbx_load_module().

04093 {
04094    int oldval = autofallthrough;
04095    autofallthrough = newval;
04096    return oldval;
04097 }

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

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

04100 {
04101    int oldval = extenpatternmatchnew;
04102    extenpatternmatchnew = newval;
04103    return oldval;
04104 }

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

References ast_free, ast_strdup, and ast_strlen_zero().

Referenced by pbx_load_module().

04107 {
04108    if (overrideswitch) {
04109       ast_free(overrideswitch);
04110    }
04111    if (!ast_strlen_zero(newval)) {
04112       overrideswitch = ast_strdup(newval);
04113    } else {
04114       overrideswitch = NULL;
04115    }
04116 }

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

Definition at line 3102 of file pbx.c.

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

Referenced by pbx_extension_helper().

03103 {
03104    const char *tmp;
03105 
03106    /* Nothing more to do */
03107    if (!e->data)
03108       return;
03109 
03110    /* No variables or expressions in e->data, so why scan it? */
03111    if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
03112       ast_copy_string(passdata, e->data, datalen);
03113       return;
03114    }
03115 
03116    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
03117 }

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

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

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

References __ast_pbx_run(), and decrease_call_count().

Referenced by ast_pbx_start().

04021 {
04022    /* Oh joyeous kernel, we're a new thread, with nothing to do but
04023       answer this channel and get it going.
04024    */
04025    /* NOTE:
04026       The launcher of this function _MUST_ increment 'countcalls'
04027       before invoking the function; it will be decremented when the
04028       PBX has finished running on the channel
04029     */
04030    struct ast_channel *c = data;
04031 
04032    __ast_pbx_run(c, NULL);
04033    decrease_call_count();
04034 
04035    pthread_exit(NULL);
04036 
04037    return NULL;
04038 }

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

helper function to print an extension

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

05007 {
05008    int prio = ast_get_extension_priority(e);
05009    if (prio == PRIORITY_HINT) {
05010       snprintf(buf, buflen, "hint: %s",
05011          ast_get_extension_app(e));
05012    } else {
05013       snprintf(buf, buflen, "%d. %s(%s)",
05014          prio, ast_get_extension_app(e),
05015          (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
05016    }
05017 }

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

03661 {
03662    ast_channel_lock(c);
03663    ast_copy_string(c->exten, exten, sizeof(c->exten));
03664    c->priority = pri;
03665    ast_channel_unlock(c);
03666 }

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

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

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

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

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

References ast_copy_string().

Referenced by pbx_retrieve_variable(), and pbx_substitute_variables_helper_full().

02410 {
02411    char *ret = workspace;
02412    int lr;  /* length of the input string after the copy */
02413 
02414    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
02415 
02416    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
02417 
02418    /* Quick check if no need to do anything */
02419    if (offset == 0 && length >= lr) /* take the whole string */
02420       return ret;
02421 
02422    if (offset < 0)   {  /* translate negative offset into positive ones */
02423       offset = lr + offset;
02424       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
02425          offset = 0;
02426    }
02427 
02428    /* too large offset result in empty string so we know what to return */
02429    if (offset >= lr)
02430       return ret + lr;  /* the final '\0' */
02431 
02432    ret += offset;    /* move to the start position */
02433    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
02434       ret[length] = '\0';
02435    else if (length < 0) {
02436       if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
02437          ret[lr + length - offset] = '\0';
02438       else
02439          ret[0] = '\0';
02440    }
02441 
02442    return ret;
02443 }

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

05817 {
05818    struct ast_context *context = NULL;
05819    struct ast_exten *eroot = NULL, *e = NULL;
05820 
05821    ast_rdlock_contexts();
05822    while ((context = ast_walk_contexts(context))) {
05823       while ((eroot = ast_walk_context_extensions(context, eroot))) {
05824          while ((e = ast_walk_extension_priorities(eroot, e))) {
05825             if (e->cached_app == app)
05826                e->cached_app = NULL;
05827          }
05828       }
05829    }
05830    ast_unlock_contexts();
05831 
05832    return;
05833 }

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

07847 {
07848    int res;
07849    struct ast_frame *f;
07850    double waitsec;
07851    int waittime;
07852 
07853    if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
07854       waitsec = -1;
07855    if (waitsec > -1) {
07856       waittime = waitsec * 1000.0;
07857       ast_safe_sleep(chan, waittime);
07858    } else do {
07859       res = ast_waitfor(chan, -1);
07860       if (res < 0)
07861          return;
07862       f = ast_read(chan);
07863       if (f)
07864          ast_frfree(f);
07865    } while(f);
07866 }


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 5789 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 5790 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 5788 of file pbx.c.

int conlock_wrlock_version = 0 [static]

Definition at line 8719 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 6363 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 2632 of file pbx.c.

Referenced by load_pbx().

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

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

Referenced by load_pbx().

char* months[] [static]

Definition at line 6375 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 5795 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 3 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1