#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"
#include "asterisk/astobj2.h"
#include "asterisk/cel.h"
#include "asterisk/test.h"
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | ast_dial_features |
struct | ast_park_call_args |
struct | ast_parkinglot |
Structure for parking lots which are put in a container. More... | |
struct | ast_parkinglot::parkinglot_parklist |
struct | feature_group |
struct | feature_group_exten |
struct | feature_groups |
struct | feature_list |
struct | park_app_args |
struct | parkeduser |
Description of one parked call, added to a list while active, then removed. The list belongs to a parkinglot. More... | |
struct | parking_dp_context |
struct | parking_dp_map |
struct | parking_dp_ramp |
struct | parking_dp_ramp_map |
struct | parking_dp_space_map |
struct | parking_dp_spaces |
struct | parkinglot_cfg |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
#define | DEFAULT_ATXFER_DROP_CALL 0 |
#define | DEFAULT_ATXFER_LOOP_DELAY 10000 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
#define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define | DEFAULT_PARK_EXTENSION "700" |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURES_COUNT ARRAY_LEN(builtin_features) |
#define | HFS_FORMAT "%-25s %-7s %-7s\n" |
#define | MAX_DIAL_FEATURE_OPTIONS 30 |
Enumerations | |
enum | { BRIDGE_OPT_PLAYTONE = (1 << 0), OPT_CALLEE_HANGUP = (1 << 1), OPT_CALLER_HANGUP = (1 << 2), OPT_DURATION_LIMIT = (1 << 3), OPT_DURATION_STOP = (1 << 4), OPT_CALLEE_TRANSFER = (1 << 5), OPT_CALLER_TRANSFER = (1 << 6), OPT_CALLEE_MONITOR = (1 << 7), OPT_CALLER_MONITOR = (1 << 8), OPT_CALLEE_PARK = (1 << 9), OPT_CALLER_PARK = (1 << 10), OPT_CALLEE_KILL = (1 << 11) } |
enum | { OPT_ARG_DURATION_LIMIT = 0, OPT_ARG_DURATION_STOP, OPT_ARG_ARRAY_SIZE } |
enum | ast_park_call_options { AST_PARK_OPT_RINGING = (1 << 0), AST_PARK_OPT_RANDOMIZE = (1 << 1), AST_PARK_OPT_SILENCE = (1 << 2) } |
enum | feature_interpret_op { FEATURE_INTERPRET_DETECT, FEATURE_INTERPRET_DO, FEATURE_INTERPRET_CHECK } |
Functions | |
static int | action_bridge (struct mansession *s, const struct message *m) |
Bridge channels together. | |
static void | add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config) |
static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
Announce call parking by ADSI. | |
int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
Bridge a call, optionally allowing redirection. | |
int | ast_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit) |
parse L option and read associated channel variables to set warning, warning frequency, and timelimit | |
int | ast_can_pickup (struct ast_channel *chan) |
Test if a channel can be picked up. | |
void | ast_channel_log (char *title, struct ast_channel *chan) |
int | ast_do_pickup (struct ast_channel *chan, struct ast_channel *target) |
Pickup a call target. | |
int | ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) |
detect a feature before bridging | |
int | ast_features_init (void) |
int | ast_features_reload (void) |
Reload call features from features.conf. | |
ast_call_feature * | ast_find_call_feature (const char *name) |
look for a call feature entry by its sname | |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
int | ast_masq_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
int | ast_park_call (struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout) |
Park a call and read back parked location. | |
int | ast_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout) |
Park a call and read back parked location. | |
int | ast_parking_ext_valid (const char *exten_str, struct ast_channel *chan, const char *context) |
Determine if parking extension exists in a given context. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
const char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_rdlock_call_features (void) |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
void | ast_unlock_call_features (void) |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
static void | ast_unregister_features (void) |
Remove all features in the list. | |
static void | ast_unregister_groups (void) |
Remove all feature groups in the list. | |
static void | atxfer_fail_cleanup (struct ast_channel *transferee, struct ast_channel *transferer, struct ast_party_connected_line *connected_line) |
static void * | bridge_call_thread (void *data) |
bridge the call | |
static void | bridge_call_thread_launch (void *data) |
create thread for the parked call | |
static int | bridge_exec (struct ast_channel *chan, const char *data) |
Bridge channels. | |
static struct parking_dp_context * | build_dialplan_useage_context (struct ast_parkinglot *lot) |
static int | build_dialplan_useage_map (struct parking_dp_map *usage_map, int complain) |
static struct parking_dp_ramp * | build_dialplan_useage_ramp (const char *exten, int exclusive) |
static struct parking_dp_spaces * | build_dialplan_useage_spaces (int start, int stop) |
static struct ast_parkinglot * | build_parkinglot (const char *pl_name, struct ast_variable *var) |
Build parkinglot from configuration and chain it in if it doesn't already exist. | |
static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
Attended transfer. | |
static int | builtin_automixmonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
Monitor a channel by DTMF. | |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
Blind transfer user to another extension. | |
static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
static int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
support routing for one touch call parking | |
static char * | callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len) |
static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
make channels compatible | |
static void | check_goto_on_transfer (struct ast_channel *chan) |
Check goto on transfer. | |
static void | clear_dialed_interfaces (struct ast_channel *chan) |
static struct ast_parkinglot * | copy_parkinglot (const char *name, const struct ast_parkinglot *parkinglot) |
Copy parkinglot and store it with new name. | |
static struct ast_parkinglot * | create_dynamic_parkinglot (const char *name, struct ast_channel *chan) |
static struct ast_parkinglot * | create_parkinglot (const char *name) |
Allocate parking lot structure. | |
static void | destroy_dialplan_usage_context (struct parking_dp_context *doomed) |
static void | destroy_dialplan_usage_map (struct parking_dp_map *doomed) |
static void | destroy_space (const char *context, int space) |
static void | dial_features_destroy (void *data) |
static void * | dial_features_duplicate (void *data) |
static int | dialplan_usage_add_parkinglot (struct parking_dp_map *usage_map, struct ast_parkinglot *lot, int complain) |
static int | dialplan_usage_add_parkinglot_data (struct parking_dp_context *ctx_node, struct ast_parkinglot *lot, int complain) |
static void | do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan) |
Actual bridge. | |
static void * | do_parking_thread (void *ignore) |
Take care of parked calls and unpark them if needed. | |
static int | feature_check (struct ast_channel *chan, struct ast_flags *features, char *code) |
Check if a feature exists. | |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
exec an app by feature | |
static int | feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense) |
Check the dynamic features. | |
static int | feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, feature_interpret_op operation, struct ast_call_feature *feature) |
Helper function for feature_interpret and ast_feature_detect. | |
static struct ast_channel * | feature_request_and_dial (struct ast_channel *caller, const char *caller_name, struct ast_channel *requestor, struct ast_channel *transferee, const char *type, format_t format, void *data, int timeout, int *outstate, const char *language) |
static int | find_channel_by_group (void *obj, void *arg, void *data, int flags) |
static struct ast_call_feature * | find_dynamic_feature (const char *name) |
find a call feature by name | |
static struct feature_group * | find_group (const char *name) |
Find a group by name. | |
static struct ast_parkinglot * | find_parkinglot (const char *name) |
Find parkinglot by name. | |
static const char * | findparkinglotname (struct ast_channel *chan) |
Find parking lot name from channel. | |
static int | finishup (struct ast_channel *chan) |
static struct ast_exten * | get_parking_exten (const char *exten_str, struct ast_channel *chan, const char *context) |
static char * | handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
CLI command to list configured features. | |
static char * | handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
CLI command to list parked calls. | |
static int | load_config (int reload) |
static int | manage_parked_call (struct parkeduser *pu, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms) |
static void | manage_parkinglot (struct ast_parkinglot *curlot, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms) |
Run management on parkinglots, called once per parkinglot. | |
static int | manager_park (struct mansession *s, const struct message *m) |
Create manager event for parked calls. | |
static int | manager_parking_status (struct mansession *s, const struct message *m) |
Dump parking lot status. | |
static int | masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args) |
Park call via masqueraded channel and announce parking spot on peer channel. | |
static enum ast_device_state | metermaidstate (const char *data) |
metermaids callback from devicestate.c | |
static void | notify_metermaids (const char *exten, char *context, enum ast_device_state state) |
Notify metermaids that we've changed an extension. | |
static void | park_add_hints (const char *context, int start, int stop) |
Add parking hints for all defined parking spaces. | |
static int | park_call_exec (struct ast_channel *chan, const char *data) |
Park a call. | |
static int | park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) |
static void | park_space_abort (struct parkeduser *pu) |
static struct parkeduser * | park_space_reserve (struct ast_channel *park_me, struct ast_channel *parker, struct ast_park_call_args *args) |
static int | parked_call_exec (struct ast_channel *chan, const char *data) |
Pickup parked call. | |
static int | parkinglot_activate (struct ast_parkinglot *parkinglot) |
static int | parkinglot_activate_cb (void *obj, void *arg, int flags) |
static struct ast_parkinglot * | parkinglot_addref (struct ast_parkinglot *parkinglot) |
static int | parkinglot_cmp_cb (void *obj, void *arg, int flags) |
static int | parkinglot_config_read (const char *pl_name, struct parkinglot_cfg *cfg, struct ast_variable *var) |
static void | parkinglot_destroy (void *obj) |
Destroy a parking lot. | |
static void | parkinglot_feature_flag_cfg (const char *pl_name, int *param, struct ast_variable *var) |
static int | parkinglot_hash_cb (const void *obj, const int flags) |
static int | parkinglot_is_marked_cb (void *obj, void *arg, int flags) |
static int | parkinglot_markall_cb (void *obj, void *arg, int flags) |
static void | parkinglot_unref (struct ast_parkinglot *parkinglot) |
Unreference parkinglot object. | |
static struct ast_cdr * | pick_unlocked_cdr (struct ast_cdr *cdr) |
return the first unlocked cdr in a possible chain | |
static int | play_message_in_bridged_call (struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile) |
Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages. | |
static int | play_message_on_chan (struct ast_channel *play_to, struct ast_channel *other, const char *msg, const char *audiofile) |
static int | play_message_to_chans (struct ast_channel *left, struct ast_channel *right, int which, const char *msg, const char *audiofile) |
static void | post_manager_event (const char *s, struct parkeduser *pu) |
Output parking event to manager. | |
static void | process_applicationmap_line (struct ast_variable *var) |
static int | process_config (struct ast_config *cfg) |
static const char * | real_ctx (struct ast_channel *transferer, struct ast_channel *transferee) |
Find the context for the transfer. | |
static struct feature_group * | register_group (const char *fgname) |
Add new feature group. | |
static void | register_group_feature (struct feature_group *fg, const char *exten, struct ast_call_feature *feature) |
Add feature to group. | |
static int | remap_feature (const char *name, const char *value) |
static void | remove_dead_context_usage (const char *context, struct parking_dp_context *old_ctx, struct parking_dp_context *new_ctx) |
static void | remove_dead_dialplan_useage (struct parking_dp_map *old_map, struct parking_dp_map *new_map) |
static void | remove_dead_ramp_usage (const char *context, struct parking_dp_ramp_map *old_ramps, struct parking_dp_ramp_map *new_ramps) |
static void | remove_dead_spaces_usage (const char *context, struct parking_dp_space_map *old_spaces, struct parking_dp_space_map *new_spaces, void(*destroy_space)(const char *context, int space)) |
static void | remove_exten_if_exist (const char *context, const char *exten, int priority) |
static void | set_bridge_features_on_config (struct ast_bridge_config *config, const char *features) |
static void | set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri) |
store context, extension and priority | |
static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
static void | set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense) |
set caller and callee according to the direction | |
static void | unmap_features (void) |
static int | usage_context_add_ramp (struct parking_dp_ramp_map *ramp_map, const char *exten, int exclusive, struct ast_parkinglot *lot, int complain) |
static int | usage_context_add_spaces (struct parking_dp_space_map *space_map, int start, int stop, struct ast_parkinglot *lot, int complain) |
static int | xfer_park_call_helper (struct ast_channel *park_me, struct ast_channel *parker, struct ast_exten *park_exten) |
Variables | |
static int | adsipark |
static char * | app_bridge = "Bridge" |
static unsigned int | atxfercallbackretries |
static unsigned int | atxferdropcall |
static unsigned int | atxferloopdelay |
static int | atxfernoanswertimeout |
static struct ast_app_option | bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, } |
static struct ast_call_feature | builtin_features [] |
static struct ast_cli_entry | cli_features [] |
static int | comebacktoorigin = 1 |
static char | courtesytone [256] |
static struct ast_parkinglot * | default_parkinglot |
Default parking lot. | |
static struct ast_datastore_info | dial_features_info |
static int | featuredigittimeout |
static ast_rwlock_t | features_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } |
static ast_mutex_t | features_reload_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
static int | force_reload_load |
static struct ast_app * | mixmonitor_app = NULL |
static int | mixmonitor_ok = 1 |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static struct ast_app_option | park_call_options [128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } |
static const char * | parkcall = "Park" |
static const char * | parkedcall = "ParkedCall" |
static int | parkeddynamic = 0 |
static int | parkedplay = 0 |
static char | parking_con_dial [] = "park-dial" |
Context for parking dialback to parker. | |
static pthread_t | parking_thread |
static struct parkinglot_cfg | parkinglot_cfg_default |
static struct parkinglot_cfg | parkinglot_cfg_default_default |
static struct ao2_container * | parkinglots |
The configured parking lots container. Always at least one - the default parking lot. | |
static struct ast_datastore_info | pickup_active |
static char | pickup_ext [AST_MAX_EXTENSION] |
static char | pickupfailsound [256] |
static char | pickupsound [256] |
static char * | registrar = "features" |
static struct ast_app * | stopmixmonitor_app = NULL |
static int | stopmixmonitor_ok = 1 |
static int | transferdigittimeout |
static char | xferfailsound [256] |
static char | xfersound [256] |
Definition in file features.c.
#define AST_MAX_WATCHERS 256 |
Definition at line 392 of file features.c.
#define DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
#define DEFAULT_ATXFER_DROP_CALL 0 |
#define DEFAULT_ATXFER_LOOP_DELAY 10000 |
#define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define DEFAULT_PARK_EXTENSION "700" |
Definition at line 384 of file features.c.
#define DEFAULT_PARK_TIME 45000 |
ms
Definition at line 383 of file features.c.
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURES_COUNT ARRAY_LEN(builtin_features) |
Definition at line 2828 of file features.c.
Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
#define HFS_FORMAT "%-25s %-7s %-7s\n" |
Referenced by handle_feature_show().
#define MAX_DIAL_FEATURE_OPTIONS 30 |
anonymous enum |
Definition at line 7290 of file features.c.
07290 { 07291 BRIDGE_OPT_PLAYTONE = (1 << 0), 07292 OPT_CALLEE_HANGUP = (1 << 1), 07293 OPT_CALLER_HANGUP = (1 << 2), 07294 OPT_DURATION_LIMIT = (1 << 3), 07295 OPT_DURATION_STOP = (1 << 4), 07296 OPT_CALLEE_TRANSFER = (1 << 5), 07297 OPT_CALLER_TRANSFER = (1 << 6), 07298 OPT_CALLEE_MONITOR = (1 << 7), 07299 OPT_CALLER_MONITOR = (1 << 8), 07300 OPT_CALLEE_PARK = (1 << 9), 07301 OPT_CALLER_PARK = (1 << 10), 07302 OPT_CALLEE_KILL = (1 << 11), 07303 };
anonymous enum |
Definition at line 7305 of file features.c.
07305 { 07306 OPT_ARG_DURATION_LIMIT = 0, 07307 OPT_ARG_DURATION_STOP, 07308 /* note: this entry _MUST_ be the last one in the enum */ 07309 OPT_ARG_ARRAY_SIZE, 07310 };
Options to pass to park_call_full
Definition at line 1035 of file features.c.
01035 { 01036 /*! Provide ringing to the parked caller instead of music on hold */ 01037 AST_PARK_OPT_RINGING = (1 << 0), 01038 /*! Randomly choose a parking spot for the caller instead of choosing 01039 * the first one that is available. */ 01040 AST_PARK_OPT_RANDOMIZE = (1 << 1), 01041 /*! Do not announce the parking number */ 01042 AST_PARK_OPT_SILENCE = (1 << 2), 01043 };
enum feature_interpret_op |
Definition at line 413 of file features.c.
00413 { 00414 FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */ 00415 FEATURE_INTERPRET_DO, /* Used by feature_interpret */ 00416 FEATURE_INTERPRET_CHECK, /* Used by feature_check */ 00417 } feature_interpret_op;
static int action_bridge | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Bridge channels together.
s | ||
m | Make sure valid channels were specified, send errors if any of the channels could not be found/locked, answer channels if needed, create the placeholder channels and grab the other channels make the channels compatible, send error if we fail doing so setup the bridge thread object and start the bridge. |
0 | on success or on incorrect use. | |
1 | on failure to bridge channels. |
Definition at line 6780 of file features.c.
References ast_channel::_state, ast_answer(), ast_calloc, ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_make_compatible(), ast_channel_unref, ast_hangup(), ast_log(), ast_manager_event_multichan, AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), bridge_call_thread_launch(), do_bridge_masquerade(), errno, EVENT_FLAG_CALL, LOG_WARNING, ast_channel::name, playtone(), and xfersound.
Referenced by ast_features_init().
06781 { 06782 const char *channela = astman_get_header(m, "Channel1"); 06783 const char *channelb = astman_get_header(m, "Channel2"); 06784 const char *playtone = astman_get_header(m, "Tone"); 06785 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2]; 06786 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 06787 struct ast_bridge_thread_obj *tobj = NULL; 06788 06789 /* make sure valid channels were specified */ 06790 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 06791 astman_send_error(s, m, "Missing channel parameter in request"); 06792 return 0; 06793 } 06794 06795 /* Start with chana */ 06796 chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); 06797 06798 /* send errors if any of the channels could not be found/locked */ 06799 if (!chana) { 06800 char buf[256]; 06801 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 06802 astman_send_error(s, m, buf); 06803 return 0; 06804 } 06805 06806 /* Answer the channels if needed */ 06807 if (chana->_state != AST_STATE_UP) 06808 ast_answer(chana); 06809 06810 /* create the placeholder channels and grab the other channels */ 06811 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 06812 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) { 06813 astman_send_error(s, m, "Unable to create temporary channel!"); 06814 chana = ast_channel_unref(chana); 06815 return 1; 06816 } 06817 06818 do_bridge_masquerade(chana, tmpchana); 06819 06820 chana = ast_channel_unref(chana); 06821 06822 /* now do chanb */ 06823 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); 06824 /* send errors if any of the channels could not be found/locked */ 06825 if (!chanb) { 06826 char buf[256]; 06827 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 06828 ast_hangup(tmpchana); 06829 astman_send_error(s, m, buf); 06830 return 0; 06831 } 06832 06833 /* Answer the channels if needed */ 06834 if (chanb->_state != AST_STATE_UP) 06835 ast_answer(chanb); 06836 06837 /* create the placeholder channels and grab the other channels */ 06838 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 06839 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) { 06840 astman_send_error(s, m, "Unable to create temporary channels!"); 06841 ast_hangup(tmpchana); 06842 chanb = ast_channel_unref(chanb); 06843 return 1; 06844 } 06845 06846 do_bridge_masquerade(chanb, tmpchanb); 06847 06848 chanb = ast_channel_unref(chanb); 06849 06850 /* make the channels compatible, send error if we fail doing so */ 06851 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 06852 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 06853 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 06854 ast_hangup(tmpchana); 06855 ast_hangup(tmpchanb); 06856 return 1; 06857 } 06858 06859 /* setup the bridge thread object and start the bridge */ 06860 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 06861 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 06862 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 06863 ast_hangup(tmpchana); 06864 ast_hangup(tmpchanb); 06865 return 1; 06866 } 06867 06868 tobj->chan = tmpchana; 06869 tobj->peer = tmpchanb; 06870 tobj->return_to_pbx = 1; 06871 06872 if (ast_true(playtone)) { 06873 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 06874 if (ast_waitstream(tmpchanb, "") < 0) 06875 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 06876 } 06877 } 06878 06879 chans[0] = tmpchana; 06880 chans[1] = tmpchanb; 06881 06882 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans, 06883 "Response: Success\r\n" 06884 "Channel1: %s\r\n" 06885 "Channel2: %s\r\n", tmpchana->name, tmpchanb->name); 06886 06887 bridge_call_thread_launch(tobj); 06888 06889 astman_send_ack(s, m, "Launched bridge thread with success"); 06890 06891 return 0; 06892 }
static void add_features_datastores | ( | struct ast_channel * | caller, | |
struct ast_channel * | callee, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 3740 of file features.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_datastore_alloc, ast_datastore_free(), AST_FLAGS_ALL, ast_log(), config, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, and LOG_WARNING.
Referenced by ast_bridge_call().
03741 { 03742 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 03743 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 03744 03745 ast_channel_lock(caller); 03746 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 03747 ast_channel_unlock(caller); 03748 if (!ds_caller_features) { 03749 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) { 03750 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 03751 return; 03752 } 03753 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 03754 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 03755 ast_datastore_free(ds_caller_features); 03756 return; 03757 } 03758 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 03759 caller_features->is_caller = 1; 03760 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 03761 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 03762 ds_caller_features->data = caller_features; 03763 ast_channel_lock(caller); 03764 ast_channel_datastore_add(caller, ds_caller_features); 03765 ast_channel_unlock(caller); 03766 } else { 03767 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 03768 * flags over from the atxfer to the caller */ 03769 return; 03770 } 03771 03772 ast_channel_lock(callee); 03773 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 03774 ast_channel_unlock(callee); 03775 if (!ds_callee_features) { 03776 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) { 03777 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 03778 return; 03779 } 03780 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 03781 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 03782 ast_datastore_free(ds_callee_features); 03783 return; 03784 } 03785 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 03786 callee_features->is_caller = 0; 03787 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 03788 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 03789 ds_callee_features->data = callee_features; 03790 ast_channel_lock(callee); 03791 ast_channel_datastore_add(callee, ds_callee_features); 03792 ast_channel_unlock(callee); 03793 } 03794 03795 return; 03796 }
static int adsi_announce_park | ( | struct ast_channel * | chan, | |
char * | parkingexten | |||
) | [static] |
Announce call parking by ADSI.
chan | . | |
parkingexten | . Create message to show for ADSI, display message. |
0 | on success. | |
-1 | on failure. |
Definition at line 973 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
00974 { 00975 int res; 00976 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00977 char tmp[256]; 00978 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00979 00980 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00981 message[0] = tmp; 00982 res = ast_adsi_load_session(chan, NULL, 0, 1); 00983 if (res == -1) 00984 return res; 00985 return ast_adsi_print(chan, message, justify, 1); 00986 }
int ast_bridge_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) |
Bridge a call, optionally allowing redirection.
chan | The bridge considers this channel the caller. | |
peer | The bridge considers this channel the callee. | |
config | Configuration for this bridge. |
res | on success. | |
-1 | on failure to bridge. |
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 3826 of file features.c.
References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_cdr::answer, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_bridge(), ast_channel_connected_line_macro(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_lock_both, ast_channel_log(), AST_CHANNEL_NAME, ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_clear_flag, AST_CONTROL_AOC, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, ast_opt_transmit_silence, AST_OPTION_AUDIO_MODE, AST_OPTION_DIGIT_DETECT, AST_OPTION_FAX_DETECT, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_UNBRIDGE, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_write(), ast_channel::caller, ast_channel::cdr, ast_cdr::channel, clear_dialed_interfaces(), config, ast_channel::context, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_party_caller::id, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, ast_party_id::number, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_COR, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_party_number::str, ast_cdr::uniqueid, ast_cdr::userfield, ast_party_number::valid, and ast_channel::visible_indication.
Referenced by app_exec(), bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), and parked_call_exec().
03827 { 03828 /* Copy voice back and forth between the two channels. Give the peer 03829 the ability to transfer calls with '#<extension' syntax. */ 03830 struct ast_frame *f; 03831 struct ast_channel *who; 03832 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03833 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03834 char orig_channame[AST_CHANNEL_NAME]; 03835 char orig_peername[AST_CHANNEL_NAME]; 03836 int res; 03837 int diff; 03838 int hasfeatures=0; 03839 int hadfeatures=0; 03840 int autoloopflag; 03841 int sendingdtmfdigit = 0; 03842 int we_disabled_peer_cdr = 0; 03843 struct ast_option_header *aoh; 03844 struct ast_cdr *bridge_cdr = NULL; 03845 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03846 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03847 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03848 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03849 struct ast_silence_generator *silgen = NULL; 03850 const char *h_context; 03851 03852 if (chan && peer) { 03853 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03854 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03855 } else if (chan) { 03856 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03857 } 03858 03859 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03860 add_features_datastores(chan, peer, config); 03861 03862 /* This is an interesting case. One example is if a ringing channel gets redirected to 03863 * an extension that picks up a parked call. This will make sure that the call taken 03864 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03865 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03866 ast_indicate(peer, AST_CONTROL_RINGING); 03867 } 03868 03869 if (monitor_ok) { 03870 const char *monitor_exec; 03871 struct ast_channel *src = NULL; 03872 if (!monitor_app) { 03873 if (!(monitor_app = pbx_findapp("Monitor"))) 03874 monitor_ok=0; 03875 } 03876 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03877 src = chan; 03878 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03879 src = peer; 03880 if (monitor_app && src) { 03881 char *tmp = ast_strdupa(monitor_exec); 03882 pbx_exec(src, monitor_app, tmp); 03883 } 03884 } 03885 03886 set_config_flags(chan, peer, config); 03887 03888 /* Answer if need be */ 03889 if (chan->_state != AST_STATE_UP) { 03890 if (ast_raw_answer(chan, 1)) { 03891 return -1; 03892 } 03893 } 03894 03895 #ifdef FOR_DEBUG 03896 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 03897 ast_channel_log("Pre-bridge CHAN Channel info", chan); 03898 ast_channel_log("Pre-bridge PEER Channel info", peer); 03899 #endif 03900 /* two channels are being marked as linked here */ 03901 ast_channel_set_linkgroup(chan,peer); 03902 03903 /* copy the userfield from the B-leg to A-leg if applicable */ 03904 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 03905 char tmp[256]; 03906 03907 ast_channel_lock(chan); 03908 if (!ast_strlen_zero(chan->cdr->userfield)) { 03909 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 03910 ast_cdr_appenduserfield(chan, tmp); 03911 } else { 03912 ast_cdr_setuserfield(chan, peer->cdr->userfield); 03913 } 03914 ast_channel_unlock(chan); 03915 /* Don't delete the CDR; just disable it. */ 03916 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03917 we_disabled_peer_cdr = 1; 03918 } 03919 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 03920 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 03921 03922 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 03923 ast_channel_lock_both(chan, peer); 03924 if (chan_cdr) { 03925 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 03926 ast_cdr_update(chan); 03927 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 03928 /* rip any forked CDR's off of the chan_cdr and attach 03929 * them to the bridge_cdr instead */ 03930 bridge_cdr->next = chan_cdr->next; 03931 chan_cdr->next = NULL; 03932 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03933 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03934 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 03935 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03936 } 03937 ast_cdr_setaccount(peer, chan->accountcode); 03938 } else { 03939 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 03940 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 03941 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 03942 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 03943 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 03944 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03945 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03946 ast_cdr_setcid(bridge_cdr, chan); 03947 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 03948 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 03949 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 03950 /* Destination information */ 03951 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 03952 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 03953 if (peer_cdr) { 03954 bridge_cdr->start = peer_cdr->start; 03955 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03956 } else { 03957 ast_cdr_start(bridge_cdr); 03958 } 03959 } 03960 ast_channel_unlock(chan); 03961 ast_channel_unlock(peer); 03962 03963 ast_debug(4,"bridge answer set, chan answer set\n"); 03964 /* peer_cdr->answer will be set when a macro runs on the peer; 03965 in that case, the bridge answer will be delayed while the 03966 macro plays on the peer channel. The peer answered the call 03967 before the macro started playing. To the phone system, 03968 this is billable time for the call, even tho the caller 03969 hears nothing but ringing while the macro does its thing. */ 03970 03971 /* Another case where the peer cdr's time will be set, is when 03972 A self-parks by pickup up phone and dialing 700, then B 03973 picks up A by dialing its parking slot; there may be more 03974 practical paths that get the same result, tho... in which 03975 case you get the previous answer time from the Park... which 03976 is before the bridge's start time, so I added in the 03977 tvcmp check to the if below */ 03978 03979 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 03980 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 03981 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 03982 if (chan_cdr) { 03983 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 03984 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 03985 } 03986 } else { 03987 ast_cdr_answer(bridge_cdr); 03988 if (chan_cdr) { 03989 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 03990 } 03991 } 03992 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 03993 if (chan_cdr) { 03994 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 03995 } 03996 if (peer_cdr) { 03997 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 03998 } 03999 } 04000 /* the DIALED flag may be set if a dialed channel is transfered 04001 * and then bridged to another channel. In order for the 04002 * bridge CDR to be written, the DIALED flag must not be 04003 * present. */ 04004 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04005 } 04006 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04007 04008 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04009 * a call is being bridged, that the humans in charge know what they're doing. If they 04010 * don't, well, what can we do about that? */ 04011 clear_dialed_interfaces(chan); 04012 clear_dialed_interfaces(peer); 04013 04014 for (;;) { 04015 struct ast_channel *other; /* used later */ 04016 04017 res = ast_channel_bridge(chan, peer, config, &f, &who); 04018 04019 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04020 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04021 /* Zombies are present time to leave! */ 04022 res = -1; 04023 if (f) { 04024 ast_frfree(f); 04025 } 04026 goto before_you_go; 04027 } 04028 04029 /* When frame is not set, we are probably involved in a situation 04030 where we've timed out. 04031 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04032 and also for DTMF_END. If we flow into the following 'if' for both, then 04033 our wait times are cut in half, as both will subtract from the 04034 feature_timer. Not good! 04035 */ 04036 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04037 /* Update feature timer for next pass */ 04038 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04039 if (res == AST_BRIDGE_RETRY) { 04040 /* The feature fully timed out but has not been updated. Skip 04041 * the potential round error from the diff calculation and 04042 * explicitly set to expired. */ 04043 config->feature_timer = -1; 04044 } else { 04045 config->feature_timer -= diff; 04046 } 04047 04048 if (hasfeatures) { 04049 if (config->feature_timer <= 0) { 04050 /* Not *really* out of time, just out of time for 04051 digits to come in for features. */ 04052 ast_debug(1, "Timed out for feature!\n"); 04053 if (!ast_strlen_zero(peer_featurecode)) { 04054 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 04055 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04056 } 04057 if (!ast_strlen_zero(chan_featurecode)) { 04058 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 04059 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04060 } 04061 if (f) 04062 ast_frfree(f); 04063 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04064 if (!hasfeatures) { 04065 /* No more digits expected - reset the timer */ 04066 config->feature_timer = 0; 04067 } 04068 hadfeatures = hasfeatures; 04069 /* Continue as we were */ 04070 continue; 04071 } else if (!f) { 04072 /* The bridge returned without a frame and there is a feature in progress. 04073 * However, we don't think the feature has quite yet timed out, so just 04074 * go back into the bridge. */ 04075 continue; 04076 } 04077 } else { 04078 if (config->feature_timer <=0) { 04079 /* We ran out of time */ 04080 config->feature_timer = 0; 04081 who = chan; 04082 if (f) 04083 ast_frfree(f); 04084 f = NULL; 04085 res = 0; 04086 } 04087 } 04088 } 04089 if (res < 0) { 04090 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04091 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 04092 } 04093 goto before_you_go; 04094 } 04095 04096 if (!f || (f->frametype == AST_FRAME_CONTROL && 04097 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04098 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04099 /* 04100 * If the bridge was broken for a hangup that isn't real, 04101 * then don't run the h extension, because the channel isn't 04102 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04103 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04104 */ 04105 ast_channel_lock(chan); 04106 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04107 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 04108 } 04109 ast_channel_unlock(chan); 04110 res = -1; 04111 break; 04112 } 04113 /* many things should be sent to the 'other' channel */ 04114 other = (who == chan) ? peer : chan; 04115 if (f->frametype == AST_FRAME_CONTROL) { 04116 switch (f->subclass.integer) { 04117 case AST_CONTROL_RINGING: 04118 case AST_CONTROL_FLASH: 04119 case -1: 04120 ast_indicate(other, f->subclass.integer); 04121 break; 04122 case AST_CONTROL_CONNECTED_LINE: 04123 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04124 break; 04125 } 04126 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04127 break; 04128 case AST_CONTROL_REDIRECTING: 04129 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04130 break; 04131 } 04132 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04133 break; 04134 case AST_CONTROL_AOC: 04135 case AST_CONTROL_HOLD: 04136 case AST_CONTROL_UNHOLD: 04137 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04138 break; 04139 case AST_CONTROL_OPTION: 04140 aoh = f->data.ptr; 04141 /* Forward option Requests, but only ones we know are safe 04142 * These are ONLY sent by chan_iax2 and I'm not convinced that 04143 * they are useful. I haven't deleted them entirely because I 04144 * just am not sure of the ramifications of removing them. */ 04145 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04146 switch (ntohs(aoh->option)) { 04147 case AST_OPTION_TONE_VERIFY: 04148 case AST_OPTION_TDD: 04149 case AST_OPTION_RELAXDTMF: 04150 case AST_OPTION_AUDIO_MODE: 04151 case AST_OPTION_DIGIT_DETECT: 04152 case AST_OPTION_FAX_DETECT: 04153 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04154 f->datalen - sizeof(struct ast_option_header), 0); 04155 } 04156 } 04157 break; 04158 } 04159 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04160 struct ast_flags *cfg; 04161 char dtmfcode[2] = { f->subclass.integer, }; 04162 size_t featurelen; 04163 04164 if (who == chan) { 04165 featurelen = strlen(chan_featurecode); 04166 cfg = &(config->features_caller); 04167 } else { 04168 featurelen = strlen(peer_featurecode); 04169 cfg = &(config->features_callee); 04170 } 04171 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04172 * DTMF along untouched. If this is not the first digit of a multi-digit code 04173 * then we need to fall through and stream the characters if it matches */ 04174 if (featurelen == 0 04175 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04176 if (option_debug > 3) { 04177 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04178 } 04179 ast_write(other, f); 04180 sendingdtmfdigit = 1; 04181 } else { 04182 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04183 * transmitting something while we hold on to the DTMF waiting for a 04184 * feature. */ 04185 if (!silgen && ast_opt_transmit_silence) { 04186 silgen = ast_channel_start_silence_generator(other); 04187 } 04188 if (option_debug > 3) { 04189 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04190 } 04191 } 04192 } else if (f->frametype == AST_FRAME_DTMF_END) { 04193 char *featurecode; 04194 int sense; 04195 04196 hadfeatures = hasfeatures; 04197 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04198 if (who == chan) { 04199 sense = FEATURE_SENSE_CHAN; 04200 featurecode = chan_featurecode; 04201 } else { 04202 sense = FEATURE_SENSE_PEER; 04203 featurecode = peer_featurecode; 04204 } 04205 04206 if (sendingdtmfdigit == 1) { 04207 /* We let the BEGIN go through happily, so let's not bother with the END, 04208 * since we already know it's not something we bother with */ 04209 ast_write(other, f); 04210 sendingdtmfdigit = 0; 04211 } else { 04212 /*! append the event to featurecode. we rely on the string being zero-filled, and 04213 * not overflowing it. 04214 * \todo XXX how do we guarantee the latter ? 04215 */ 04216 featurecode[strlen(featurecode)] = f->subclass.integer; 04217 /* Get rid of the frame before we start doing "stuff" with the channels */ 04218 ast_frfree(f); 04219 f = NULL; 04220 if (silgen) { 04221 ast_channel_stop_silence_generator(other, silgen); 04222 silgen = NULL; 04223 } 04224 config->feature_timer = 0; 04225 res = feature_interpret(chan, peer, config, featurecode, sense); 04226 switch(res) { 04227 case AST_FEATURE_RETURN_PASSDIGITS: 04228 ast_dtmf_stream(other, who, featurecode, 0, 0); 04229 /* Fall through */ 04230 case AST_FEATURE_RETURN_SUCCESS: 04231 memset(featurecode, 0, sizeof(chan_featurecode)); 04232 break; 04233 } 04234 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04235 res = 0; 04236 } else { 04237 break; 04238 } 04239 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04240 if (hadfeatures && !hasfeatures) { 04241 /* Feature completed or timed out */ 04242 config->feature_timer = 0; 04243 } else if (hasfeatures) { 04244 if (config->timelimit) { 04245 /* No warning next time - we are waiting for feature code */ 04246 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04247 } 04248 config->feature_start_time = ast_tvnow(); 04249 config->feature_timer = featuredigittimeout; 04250 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04251 } 04252 } 04253 } 04254 if (f) 04255 ast_frfree(f); 04256 } 04257 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04258 04259 before_you_go: 04260 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04261 if (silgen) { 04262 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04263 silgen = NULL; 04264 } 04265 04266 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04267 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04268 if (bridge_cdr) { 04269 ast_cdr_discard(bridge_cdr); 04270 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04271 } 04272 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04273 } 04274 04275 if (config->end_bridge_callback) { 04276 config->end_bridge_callback(config->end_bridge_callback_data); 04277 } 04278 04279 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04280 * if it were, then chan belongs to a different thread now, and might have been hung up long 04281 * ago. 04282 */ 04283 if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04284 h_context = NULL; 04285 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04286 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04287 h_context = chan->context; 04288 } else if (!ast_strlen_zero(chan->macrocontext) 04289 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04290 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04291 h_context = chan->macrocontext; 04292 } else { 04293 h_context = NULL; 04294 } 04295 if (h_context) { 04296 struct ast_cdr *swapper = NULL; 04297 char savelastapp[AST_MAX_EXTENSION]; 04298 char savelastdata[AST_MAX_EXTENSION]; 04299 char save_context[AST_MAX_CONTEXT]; 04300 char save_exten[AST_MAX_EXTENSION]; 04301 int save_prio; 04302 int found = 0; /* set if we find at least one match */ 04303 int spawn_error = 0; 04304 04305 /* 04306 * Make sure that the channel is marked as hungup since we are 04307 * going to run the "h" exten on it. 04308 */ 04309 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04310 04311 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04312 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04313 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04314 ast_cdr_end(bridge_cdr); 04315 } 04316 04317 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04318 dialplan code operate on it */ 04319 ast_channel_lock(chan); 04320 if (bridge_cdr) { 04321 swapper = chan->cdr; 04322 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04323 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04324 chan->cdr = bridge_cdr; 04325 } 04326 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04327 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04328 save_prio = chan->priority; 04329 if (h_context != chan->context) { 04330 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04331 } 04332 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04333 chan->priority = 1; 04334 ast_channel_unlock(chan); 04335 04336 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04337 chan->priority, 04338 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04339 &found, 1)) == 0) { 04340 chan->priority++; 04341 } 04342 if (found && spawn_error) { 04343 /* Something bad happened, or a hangup has been requested. */ 04344 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04345 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04346 } 04347 04348 /* swap it back */ 04349 ast_channel_lock(chan); 04350 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04351 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04352 chan->priority = save_prio; 04353 if (bridge_cdr) { 04354 if (chan->cdr == bridge_cdr) { 04355 chan->cdr = swapper; 04356 } else { 04357 bridge_cdr = NULL; 04358 } 04359 } 04360 /* An "h" exten has been run, so indicate that one has been run. */ 04361 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04362 ast_channel_unlock(chan); 04363 04364 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04365 if (bridge_cdr) { 04366 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04367 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04368 } 04369 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04370 } 04371 04372 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04373 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04374 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 04375 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04376 04377 /* we can post the bridge CDR at this point */ 04378 if (bridge_cdr) { 04379 ast_cdr_end(bridge_cdr); 04380 ast_cdr_detach(bridge_cdr); 04381 } 04382 04383 /* do a specialized reset on the beginning channel 04384 CDR's, if they still exist, so as not to mess up 04385 issues in future bridges; 04386 04387 Here are the rules of the game: 04388 1. The chan and peer channel pointers will not change 04389 during the life of the bridge. 04390 2. But, in transfers, the channel names will change. 04391 between the time the bridge is started, and the 04392 time the channel ends. 04393 Usually, when a channel changes names, it will 04394 also change CDR pointers. 04395 3. Usually, only one of the two channels (chan or peer) 04396 will change names. 04397 4. Usually, if a channel changes names during a bridge, 04398 it is because of a transfer. Usually, in these situations, 04399 it is normal to see 2 bridges running simultaneously, and 04400 it is not unusual to see the two channels that change 04401 swapped between bridges. 04402 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04403 to attend to; if the chan or peer changed names, 04404 we have the before and after attached CDR's. 04405 */ 04406 04407 if (new_chan_cdr) { 04408 struct ast_channel *chan_ptr = NULL; 04409 04410 if (strcasecmp(orig_channame, chan->name) != 0) { 04411 /* old channel */ 04412 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04413 ast_channel_lock(chan_ptr); 04414 if (!ast_bridged_channel(chan_ptr)) { 04415 struct ast_cdr *cur; 04416 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04417 if (cur == chan_cdr) { 04418 break; 04419 } 04420 } 04421 if (cur) { 04422 ast_cdr_specialized_reset(chan_cdr, 0); 04423 } 04424 } 04425 ast_channel_unlock(chan_ptr); 04426 chan_ptr = ast_channel_unref(chan_ptr); 04427 } 04428 /* new channel */ 04429 ast_cdr_specialized_reset(new_chan_cdr, 0); 04430 } else { 04431 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04432 } 04433 } 04434 04435 { 04436 struct ast_channel *chan_ptr = NULL; 04437 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04438 if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED)) 04439 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04440 if (strcasecmp(orig_peername, peer->name) != 0) { 04441 /* old channel */ 04442 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04443 ast_channel_lock(chan_ptr); 04444 if (!ast_bridged_channel(chan_ptr)) { 04445 struct ast_cdr *cur; 04446 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04447 if (cur == peer_cdr) { 04448 break; 04449 } 04450 } 04451 if (cur) { 04452 ast_cdr_specialized_reset(peer_cdr, 0); 04453 } 04454 } 04455 ast_channel_unlock(chan_ptr); 04456 chan_ptr = ast_channel_unref(chan_ptr); 04457 } 04458 /* new channel */ 04459 if (new_peer_cdr) { 04460 ast_cdr_specialized_reset(new_peer_cdr, 0); 04461 } 04462 } else { 04463 if (we_disabled_peer_cdr) { 04464 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04465 } 04466 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04467 } 04468 } 04469 04470 return res; 04471 }
int ast_bridge_timelimit | ( | struct ast_channel * | chan, | |
struct ast_bridge_config * | config, | |||
char * | parse, | |||
struct timeval * | calldurationlimit | |||
) |
parse L option and read associated channel variables to set warning, warning frequency, and timelimit
Definition at line 7327 of file features.c.
References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, config, LOG_WARNING, pbx_builtin_getvar_helper(), S_OR, strsep(), and var.
Referenced by bridge_exec(), and dial_exec_full().
07329 { 07330 char *stringp = ast_strdupa(parse); 07331 char *limit_str, *warning_str, *warnfreq_str; 07332 const char *var; 07333 int play_to_caller = 0, play_to_callee = 0; 07334 int delta; 07335 07336 limit_str = strsep(&stringp, ":"); 07337 warning_str = strsep(&stringp, ":"); 07338 warnfreq_str = strsep(&stringp, ":"); 07339 07340 config->timelimit = atol(limit_str); 07341 if (warning_str) 07342 config->play_warning = atol(warning_str); 07343 if (warnfreq_str) 07344 config->warning_freq = atol(warnfreq_str); 07345 07346 if (!config->timelimit) { 07347 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07348 config->timelimit = config->play_warning = config->warning_freq = 0; 07349 config->warning_sound = NULL; 07350 return -1; /* error */ 07351 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07352 int w = config->warning_freq; 07353 07354 /* 07355 * If the first warning is requested _after_ the entire call 07356 * would end, and no warning frequency is requested, then turn 07357 * off the warning. If a warning frequency is requested, reduce 07358 * the 'first warning' time by that frequency until it falls 07359 * within the call's total time limit. 07360 * 07361 * Graphically: 07362 * timelim->| delta |<-playwarning 07363 * 0__________________|_________________| 07364 * | w | | | | 07365 * 07366 * so the number of intervals to cut is 1+(delta-1)/w 07367 */ 07368 if (w == 0) { 07369 config->play_warning = 0; 07370 } else { 07371 config->play_warning -= w * ( 1 + (delta-1)/w ); 07372 if (config->play_warning < 1) 07373 config->play_warning = config->warning_freq = 0; 07374 } 07375 } 07376 07377 ast_channel_lock(chan); 07378 07379 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07380 play_to_caller = var ? ast_true(var) : 1; 07381 07382 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07383 play_to_callee = var ? ast_true(var) : 0; 07384 07385 if (!play_to_caller && !play_to_callee) 07386 play_to_caller = 1; 07387 07388 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07389 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07390 07391 /* The code looking at config wants a NULL, not just "", to decide 07392 * that the message should not be played, so we replace "" with NULL. 07393 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07394 * not found. 07395 */ 07396 07397 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07398 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07399 07400 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07401 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07402 07403 ast_channel_unlock(chan); 07404 07405 /* undo effect of S(x) in case they are both used */ 07406 calldurationlimit->tv_sec = 0; 07407 calldurationlimit->tv_usec = 0; 07408 07409 /* more efficient to do it like S(x) does since no advanced opts */ 07410 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07411 calldurationlimit->tv_sec = config->timelimit / 1000; 07412 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07413 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07414 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07415 config->timelimit = play_to_caller = play_to_callee = 07416 config->play_warning = config->warning_freq = 0; 07417 } else { 07418 ast_verb(4, "Limit Data for this call:\n"); 07419 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07420 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07421 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07422 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07423 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07424 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07425 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07426 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07427 } 07428 if (play_to_caller) 07429 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07430 if (play_to_callee) 07431 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07432 return 0; 07433 }
int ast_can_pickup | ( | struct ast_channel * | chan | ) |
Test if a channel can be picked up.
chan | Channel to test if can be picked up. |
Definition at line 7134 of file features.c.
References ast_channel::_state, ast_channel_datastore_find(), AST_FLAG_ZOMBIE, AST_STATE_DOWN, AST_STATE_RING, AST_STATE_RINGING, ast_test_flag, ast_channel::masq, ast_channel::pbx, and pickup_active.
Referenced by find_by_mark(), find_by_part(), find_channel_by_group(), pickup_by_exten(), and pickup_by_name_cb().
07135 { 07136 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07137 && (chan->_state == AST_STATE_RINGING 07138 || chan->_state == AST_STATE_RING 07139 /* 07140 * Check the down state as well because some SIP devices do not 07141 * give 180 ringing when they can just give 183 session progress 07142 * instead. Issue 14005. (Some ISDN switches as well for that 07143 * matter.) 07144 */ 07145 || chan->_state == AST_STATE_DOWN) 07146 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07147 return 1; 07148 } 07149 return 0; 07150 }
void ast_channel_log | ( | char * | title, | |
struct ast_channel * | chan | |||
) |
Definition at line 3675 of file features.c.
References ast_log(), and LOG_NOTICE.
Referenced by ast_bridge_call().
03676 { 03677 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan); 03678 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n", 03679 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority); 03680 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n", 03681 chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority); 03682 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n", 03683 chan->masq, chan->masqr, 03684 chan->_bridge, chan->uniqueid, chan->linkedid); 03685 if (chan->masqr) 03686 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n", 03687 chan->masqr->name, chan->masqr->cdr); 03688 if (chan->_bridge) 03689 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name); 03690 03691 ast_log(LOG_NOTICE, "===== done ====\n"); 03692 }
int ast_do_pickup | ( | struct ast_channel * | chan, | |
struct ast_channel * | target | |||
) |
Pickup a call target.
chan | channel that initiated pickup. | |
target | channel to be picked up. |
0 | on success. | |
-1 | on failure. |
< A masquerade changes channel names.
< A masquerade changes channel names.
Definition at line 7210 of file features.c.
References ast_answer(), AST_CEL_PICKUP, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_datastore_add(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_masquerade(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_datastore_alloc, ast_datastore_free(), ast_debug, ast_do_masquerade(), AST_FLAG_ANSWERED_ELSEWHERE, ast_log(), ast_manager_event_multichan, ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_queue_control(), ast_set_flag, ast_strdupa, ast_channel::caller, EVENT_FLAG_CALL, LOG_WARNING, ast_channel::name, pickup_active, and ast_party_connected_line::source.
Referenced by ast_pickup_call(), pickup_by_channel(), pickup_by_exten(), pickup_by_group(), pickup_by_mark(), and pickup_by_part().
07211 { 07212 struct ast_party_connected_line connected_caller; 07213 struct ast_channel *chans[2] = { chan, target }; 07214 struct ast_datastore *ds_pickup; 07215 const char *chan_name;/*!< A masquerade changes channel names. */ 07216 const char *target_name;/*!< A masquerade changes channel names. */ 07217 int res = -1; 07218 07219 target_name = ast_strdupa(target->name); 07220 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name); 07221 07222 /* Mark the target to block any call pickup race. */ 07223 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07224 if (!ds_pickup) { 07225 ast_log(LOG_WARNING, 07226 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07227 return -1; 07228 } 07229 ast_channel_datastore_add(target, ds_pickup); 07230 07231 ast_party_connected_line_init(&connected_caller); 07232 ast_party_connected_line_copy(&connected_caller, &target->connected); 07233 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07234 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07235 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07236 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07237 } 07238 ast_party_connected_line_free(&connected_caller); 07239 07240 ast_channel_lock(chan); 07241 chan_name = ast_strdupa(chan->name); 07242 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07243 ast_channel_unlock(chan); 07244 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07245 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07246 ast_party_connected_line_free(&connected_caller); 07247 07248 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07249 07250 if (ast_answer(chan)) { 07251 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07252 goto pickup_failed; 07253 } 07254 07255 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07256 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07257 goto pickup_failed; 07258 } 07259 07260 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07261 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07262 07263 if (ast_channel_masquerade(target, chan)) { 07264 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07265 target_name); 07266 goto pickup_failed; 07267 } 07268 07269 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07270 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07271 "Channel: %s\r\n" 07272 "TargetChannel: %s\r\n", 07273 chan_name, target_name); 07274 07275 /* Do the masquerade manually to make sure that it is completed. */ 07276 ast_do_masquerade(target); 07277 res = 0; 07278 07279 pickup_failed: 07280 ast_channel_lock(target); 07281 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07282 ast_datastore_free(ds_pickup); 07283 } 07284 07285 return res; 07286 }
int ast_feature_detect | ( | struct ast_channel * | chan, | |
struct ast_flags * | features, | |||
const char * | code, | |||
struct ast_call_feature * | feature | |||
) |
detect a feature before bridging
chan | ||
features | an ast_flags ptr | |
code | ptr of input code | |
feature |
ast_call_feature | ptr to be set if found |
Definition at line 3277 of file features.c.
References feature_group_exten::feature, FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03277 { 03278 03279 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03280 }
int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 8076 of file features.c.
References action_bridge(), ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register_xml, ast_pthread_create, ast_register_application2(), AST_TEST_REGISTER, bridge_exec(), cli_features, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), parkcall, parked_call_exec(), parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), and parkinglots.
Referenced by main().
08077 { 08078 int res; 08079 08080 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 08081 if (!parkinglots) { 08082 return -1; 08083 } 08084 08085 res = load_config(0); 08086 if (res) { 08087 return res; 08088 } 08089 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); 08090 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 08091 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); 08092 res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL); 08093 if (!res) 08094 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); 08095 if (!res) { 08096 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status); 08097 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park); 08098 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge); 08099 } 08100 08101 res |= ast_devstate_prov_add("Park", metermaidstate); 08102 #if defined(TEST_FRAMEWORK) 08103 res |= AST_TEST_REGISTER(features_test); 08104 #endif /* defined(TEST_FRAMEWORK) */ 08105 08106 return res; 08107 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6696 of file features.c.
References ast_context_destroy(), ast_context_find(), ast_mutex_lock, ast_mutex_unlock, features_reload_lock, load_config(), parking_con_dial, and registrar.
Referenced by handle_features_reload().
06697 { 06698 struct ast_context *con; 06699 int res; 06700 06701 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06702 06703 /* 06704 * Always destroy the parking_con_dial context to remove buildup 06705 * of recalled extensions in the context. At worst, the parked 06706 * call gets hungup attempting to run an invalid extension when 06707 * we are trying to callback the parker or the preset return 06708 * extension. This is a small window of opportunity on an 06709 * execution chain that is not expected to happen very often. 06710 */ 06711 con = ast_context_find(parking_con_dial); 06712 if (con) { 06713 ast_context_destroy(con, registrar); 06714 } 06715 06716 res = load_config(1); 06717 ast_mutex_unlock(&features_reload_lock); 06718 06719 return res; 06720 }
struct ast_call_feature* ast_find_call_feature | ( | const char * | name | ) |
look for a call feature entry by its sname
name | a string ptr, should match "automon", "blindxfer", "atxfer", etc. |
Definition at line 3011 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
03012 { 03013 int x; 03014 for (x = 0; x < FEATURES_COUNT; x++) { 03015 if (!strcasecmp(name, builtin_features[x].sname)) 03016 return &builtin_features[x]; 03017 } 03018 return NULL; 03019 }
int ast_masq_park_call | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call via a masqueraded channel.
park_me | Channel to be parked. | |
parker | Channel parking the call. | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
0 | on success. | |
-1 | on failure. |
Definition at line 1756 of file features.c.
References args, ast_strdupa, masq_park_call(), and ast_channel::name.
Referenced by handle_soft_key_event_message(), handle_stimulus_message(), parkandannounce_exec(), and rpt_exec().
01757 { 01758 struct ast_park_call_args args = { 01759 .timeout = timeout, 01760 .extout = extout, 01761 }; 01762 01763 if (peer) { 01764 args.orig_chan_name = ast_strdupa(peer->name); 01765 } 01766 return masq_park_call(rchan, peer, &args); 01767 }
int ast_masq_park_call_exten | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
const char * | park_exten, | |||
const char * | park_context, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call via a masqueraded channel.
park_me | Channel to be parked. | |
parker | Channel parking the call. | |
park_exten | Parking lot access extension | |
park_context | Parking lot context | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
0 | on success. | |
-1 | on failure. |
Definition at line 1702 of file features.c.
References args, ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), feature_group_exten::exten, find_parkinglot(), get_parking_exten(), masq_park_call(), ast_channel::name, parkeddynamic, parkinglot_unref(), parse(), and park_app_args::pl_name.
Referenced by __analog_ss_thread(), analog_ss_thread(), and mgcp_ss().
01703 { 01704 int res; 01705 char *parse; 01706 const char *app_data; 01707 struct ast_exten *exten; 01708 struct park_app_args app_args; 01709 struct ast_park_call_args args = { 01710 .timeout = timeout, 01711 .extout = extout, 01712 }; 01713 01714 if (parker) { 01715 args.orig_chan_name = ast_strdupa(parker->name); 01716 } 01717 if (!park_exten || !park_context) { 01718 return masq_park_call(park_me, parker, &args); 01719 } 01720 01721 /* 01722 * Determiine if the specified park extension has an exclusive 01723 * parking lot to use. 01724 */ 01725 if (parker && parker != park_me) { 01726 ast_autoservice_start(park_me); 01727 } 01728 exten = get_parking_exten(park_exten, parker, park_context); 01729 if (exten) { 01730 app_data = ast_get_extension_app_data(exten); 01731 if (!app_data) { 01732 app_data = ""; 01733 } 01734 parse = ast_strdupa(app_data); 01735 AST_STANDARD_APP_ARGS(app_args, parse); 01736 01737 if (!ast_strlen_zero(app_args.pl_name)) { 01738 /* Find the specified exclusive parking lot */ 01739 args.parkinglot = find_parkinglot(app_args.pl_name); 01740 if (!args.parkinglot && parkeddynamic) { 01741 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01742 } 01743 } 01744 } 01745 if (parker && parker != park_me) { 01746 ast_autoservice_stop(park_me); 01747 } 01748 01749 res = masq_park_call(park_me, parker, &args); 01750 if (args.parkinglot) { 01751 parkinglot_unref(args.parkinglot); 01752 } 01753 return res; 01754 }
int ast_park_call | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
int | timeout, | |||
const char * | park_exten, | |||
int * | extout | |||
) |
Park a call and read back parked location.
park_me | Channel to be parked. | |
parker | Channel parking the call. | |
timeout | is a timeout in milliseconds | |
park_exten | Parking lot access extension (Not used) | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
0 | on success. | |
-1 | on failure. |
Definition at line 1605 of file features.c.
References args, and park_call_full().
01606 { 01607 struct ast_park_call_args args = { 01608 .timeout = timeout, 01609 .extout = extout, 01610 }; 01611 01612 return park_call_full(park_me, parker, &args); 01613 }
int ast_park_call_exten | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
const char * | park_exten, | |||
const char * | park_context, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call and read back parked location.
park_me | Channel to be parked. | |
parker | Channel parking the call. | |
park_exten | Parking lot access extension | |
park_context | Parking lot context | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
0 | on success. | |
-1 | on failure. |
Definition at line 1554 of file features.c.
References args, ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), feature_group_exten::exten, find_parkinglot(), get_parking_exten(), park_call_full(), parkeddynamic, parkinglot_unref(), parse(), and park_app_args::pl_name.
Referenced by iax_park_thread(), and sip_park_thread().
01555 { 01556 int res; 01557 char *parse; 01558 const char *app_data; 01559 struct ast_exten *exten; 01560 struct park_app_args app_args; 01561 struct ast_park_call_args args = { 01562 .timeout = timeout, 01563 .extout = extout, 01564 }; 01565 01566 if (!park_exten || !park_context) { 01567 return park_call_full(park_me, parker, &args); 01568 } 01569 01570 /* 01571 * Determiine if the specified park extension has an exclusive 01572 * parking lot to use. 01573 */ 01574 if (parker && parker != park_me) { 01575 ast_autoservice_start(park_me); 01576 } 01577 exten = get_parking_exten(park_exten, parker, park_context); 01578 if (exten) { 01579 app_data = ast_get_extension_app_data(exten); 01580 if (!app_data) { 01581 app_data = ""; 01582 } 01583 parse = ast_strdupa(app_data); 01584 AST_STANDARD_APP_ARGS(app_args, parse); 01585 01586 if (!ast_strlen_zero(app_args.pl_name)) { 01587 /* Find the specified exclusive parking lot */ 01588 args.parkinglot = find_parkinglot(app_args.pl_name); 01589 if (!args.parkinglot && parkeddynamic) { 01590 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01591 } 01592 } 01593 } 01594 if (parker && parker != park_me) { 01595 ast_autoservice_stop(park_me); 01596 } 01597 01598 res = park_call_full(park_me, parker, &args); 01599 if (args.parkinglot) { 01600 parkinglot_unref(args.parkinglot); 01601 } 01602 return res; 01603 }
int ast_parking_ext_valid | ( | const char * | exten_str, | |
struct ast_channel * | chan, | |||
const char * | context | |||
) |
Determine if parking extension exists in a given context.
0 | if extension does not exist | |
1 | if extension does exist |
Definition at line 793 of file features.c.
References get_parking_exten().
Referenced by __analog_ss_thread(), analog_ss_thread(), dp_lookup(), handle_request_refer(), mgcp_ss(), and socket_process().
00794 { 00795 return get_parking_exten(exten_str, chan, context) ? 1 : 0; 00796 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
< Potential pickup target
Definition at line 7176 of file features.c.
References ast_answer(), ast_channel_callback(), ast_channel_unlock, ast_channel_unref, ast_debug, ast_do_pickup(), ast_log(), ast_stream_and_wait(), ast_strlen_zero(), find_channel_by_group(), LOG_NOTICE, LOG_WARNING, ast_channel::name, pbx_builtin_setvar_helper(), pickupfailsound, and pickupsound.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), mgcp_ss(), and sip_pickup_thread().
07177 { 07178 struct ast_channel *target;/*!< Potential pickup target */ 07179 int res = -1; 07180 ast_debug(1, "pickup attempt by %s\n", chan->name); 07181 07182 /* The found channel is already locked. */ 07183 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07184 if (target) { 07185 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name); 07186 07187 res = ast_do_pickup(chan, target); 07188 ast_channel_unlock(target); 07189 if (!res) { 07190 if (!ast_strlen_zero(pickupsound)) { 07191 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07192 } 07193 } else { 07194 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name); 07195 } 07196 target = ast_channel_unref(target); 07197 } 07198 07199 if (res < 0) { 07200 ast_debug(1, "No call pickup possible... for %s\n", chan->name); 07201 if (!ast_strlen_zero(pickupfailsound)) { 07202 ast_answer(chan); 07203 ast_stream_and_wait(chan, pickupfailsound, ""); 07204 } 07205 } 07206 07207 return res; 07208 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 798 of file features.c.
Referenced by __analog_ss_thread(), analog_canmatch_featurecode(), analog_ss_thread(), canmatch_featurecode(), cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), and mgcp_ss().
00799 { 00800 return pickup_ext; 00801 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 3001 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
03002 { 03003 ast_rwlock_rdlock(&features_lock); 03004 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_set
feature | an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call. |
Definition at line 2845 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, feature_group_exten::feature, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
Referenced by process_applicationmap_line().
02846 { 02847 if (!feature) { 02848 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02849 return; 02850 } 02851 02852 AST_RWLIST_WRLOCK(&feature_list); 02853 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 02854 AST_RWLIST_UNLOCK(&feature_list); 02855 02856 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 02857 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 3006 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
03007 { 03008 ast_rwlock_unlock(&features_lock); 03009 }
void ast_unregister_feature | ( | struct ast_call_feature * | feature | ) |
unregister feature from feature_set
feature | the ast_call_feature object which was registered before |
Definition at line 2925 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
02926 { 02927 if (!feature) { 02928 return; 02929 } 02930 02931 AST_RWLIST_WRLOCK(&feature_list); 02932 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 02933 AST_RWLIST_UNLOCK(&feature_list); 02934 02935 ast_free(feature); 02936 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 2939 of file features.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, feature_group_exten::feature, and ast_call_feature::feature_entry.
02940 { 02941 struct ast_call_feature *feature; 02942 02943 AST_RWLIST_WRLOCK(&feature_list); 02944 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 02945 ast_free(feature); 02946 } 02947 AST_RWLIST_UNLOCK(&feature_list); 02948 }
static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 2965 of file features.c.
References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, feature_group_exten::entry, and feature_group::features.
02966 { 02967 struct feature_group *fg; 02968 struct feature_group_exten *fge; 02969 02970 AST_RWLIST_WRLOCK(&feature_groups); 02971 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 02972 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 02973 ast_string_field_free_memory(fge); 02974 ast_free(fge); 02975 } 02976 02977 ast_string_field_free_memory(fg); 02978 ast_free(fg); 02979 } 02980 AST_RWLIST_UNLOCK(&feature_groups); 02981 }
static void atxfer_fail_cleanup | ( | struct ast_channel * | transferee, | |
struct ast_channel * | transferer, | |||
struct ast_party_connected_line * | connected_line | |||
) | [static] |
Definition at line 2388 of file features.c.
References ast_channel_connected_line_macro(), ast_channel_update_connected_line(), ast_party_connected_line_free(), and finishup().
Referenced by builtin_atxfer().
02389 { 02390 finishup(transferee); 02391 02392 /* 02393 * Restore party B connected line info about party A. 02394 * 02395 * Party B was the caller to party C and is the last known mode 02396 * for party B. 02397 */ 02398 if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) { 02399 ast_channel_update_connected_line(transferer, connected_line, NULL); 02400 } 02401 ast_party_connected_line_free(connected_line); 02402 }
static void* bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
data | thread bridge. |
Definition at line 908 of file features.c.
References ast_channel::appl, ast_bridge_call(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, LOG_VERBOSE, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.
Referenced by bridge_call_thread_launch().
00909 { 00910 struct ast_bridge_thread_obj *tobj = data; 00911 int res; 00912 00913 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00914 tobj->chan->data = tobj->peer->name; 00915 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00916 tobj->peer->data = tobj->chan->name; 00917 00918 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00919 00920 if (tobj->return_to_pbx) { 00921 if (!ast_check_hangup(tobj->peer)) { 00922 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 00923 res = ast_pbx_start(tobj->peer); 00924 if (res != AST_PBX_SUCCESS) 00925 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 00926 } else 00927 ast_hangup(tobj->peer); 00928 if (!ast_check_hangup(tobj->chan)) { 00929 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 00930 res = ast_pbx_start(tobj->chan); 00931 if (res != AST_PBX_SUCCESS) 00932 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 00933 } else 00934 ast_hangup(tobj->chan); 00935 } else { 00936 ast_hangup(tobj->chan); 00937 ast_hangup(tobj->peer); 00938 } 00939 00940 ast_free(tobj); 00941 00942 return NULL; 00943 }
static void bridge_call_thread_launch | ( | void * | data | ) | [static] |
create thread for the parked call
data | Create thread and attributes, call bridge_call_thread |
Definition at line 951 of file features.c.
References ast_pthread_create, bridge_call_thread(), and thread.
Referenced by action_bridge(), and builtin_atxfer().
00952 { 00953 pthread_t thread; 00954 pthread_attr_t attr; 00955 struct sched_param sched; 00956 00957 pthread_attr_init(&attr); 00958 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00959 ast_pthread_create(&thread, &attr, bridge_call_thread, data); 00960 pthread_attr_destroy(&attr); 00961 memset(&sched, 0, sizeof(sched)); 00962 pthread_setschedparam(thread, SCHED_RR, &sched); 00963 }
static int bridge_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Bridge channels.
chan | ||
data | channel to bridge with. |
Definition at line 7445 of file features.c.
References ast_channel::_state, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_bridge_timelimit(), ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_make_compatible(), ast_channel_unref, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_free, ast_hangup(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_pbx_start(), AST_PBX_SUCCESS, ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, ast_channel::context, do_bridge_masquerade(), ast_bridge_config::end_sound, EVENT_FLAG_CALL, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_channel::name, OPT_ARG_ARRAY_SIZE, OPT_ARG_DURATION_LIMIT, OPT_CALLEE_HANGUP, OPT_CALLEE_KILL, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DURATION_LIMIT, pbx_builtin_setvar_helper(), ast_channel::priority, ast_bridge_config::start_sound, ast_bridge_config::warning_sound, and xfersound.
Referenced by ast_features_init().
07446 { 07447 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2]; 07448 char *tmp_data = NULL; 07449 struct ast_flags opts = { 0, }; 07450 struct ast_bridge_config bconfig = { { 0, }, }; 07451 char *opt_args[OPT_ARG_ARRAY_SIZE]; 07452 struct timeval calldurationlimit = { 0, }; 07453 07454 AST_DECLARE_APP_ARGS(args, 07455 AST_APP_ARG(dest_chan); 07456 AST_APP_ARG(options); 07457 ); 07458 07459 if (ast_strlen_zero(data)) { 07460 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 07461 return -1; 07462 } 07463 07464 tmp_data = ast_strdupa(data); 07465 AST_STANDARD_APP_ARGS(args, tmp_data); 07466 if (!ast_strlen_zero(args.options)) 07467 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options); 07468 07469 /* avoid bridge with ourselves */ 07470 if (!strcmp(chan->name, args.dest_chan)) { 07471 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 07472 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07473 "Response: Failed\r\n" 07474 "Reason: Unable to bridge channel to itself\r\n" 07475 "Channel1: %s\r\n" 07476 "Channel2: %s\r\n", 07477 chan->name, args.dest_chan); 07478 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 07479 return 0; 07480 } 07481 07482 /* make sure we have a valid end point */ 07483 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan, 07484 strlen(args.dest_chan)))) { 07485 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 07486 "cannot get its lock\n", args.dest_chan); 07487 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07488 "Response: Failed\r\n" 07489 "Reason: Cannot grab end point\r\n" 07490 "Channel1: %s\r\n" 07491 "Channel2: %s\r\n", chan->name, args.dest_chan); 07492 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 07493 return 0; 07494 } 07495 07496 /* answer the channel if needed */ 07497 if (current_dest_chan->_state != AST_STATE_UP) { 07498 ast_answer(current_dest_chan); 07499 } 07500 07501 /* try to allocate a place holder where current_dest_chan will be placed */ 07502 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 07503 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) { 07504 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 07505 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07506 "Response: Failed\r\n" 07507 "Reason: cannot create placeholder\r\n" 07508 "Channel1: %s\r\n" 07509 "Channel2: %s\r\n", chan->name, args.dest_chan); 07510 } 07511 07512 do_bridge_masquerade(current_dest_chan, final_dest_chan); 07513 07514 chans[0] = current_dest_chan; 07515 chans[1] = final_dest_chan; 07516 07517 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 07518 /* try to make compatible, send error if we fail */ 07519 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 07520 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 07521 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07522 "Response: Failed\r\n" 07523 "Reason: Could not make channels compatible for bridge\r\n" 07524 "Channel1: %s\r\n" 07525 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 07526 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 07527 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 07528 current_dest_chan = ast_channel_unref(current_dest_chan); 07529 return 0; 07530 } 07531 07532 /* Report that the bridge will be successfull */ 07533 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07534 "Response: Success\r\n" 07535 "Channel1: %s\r\n" 07536 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 07537 07538 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 07539 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 07540 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 07541 if (ast_waitstream(final_dest_chan, "") < 0) 07542 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 07543 } 07544 } 07545 07546 current_dest_chan = ast_channel_unref(current_dest_chan); 07547 07548 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) { 07549 if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) 07550 goto done; 07551 } 07552 07553 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) 07554 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT); 07555 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) 07556 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT); 07557 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) 07558 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 07559 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) 07560 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 07561 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR)) 07562 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON); 07563 if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 07564 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON); 07565 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) 07566 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL); 07567 if (ast_test_flag(&opts, OPT_CALLER_PARK)) 07568 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL); 07569 07570 ast_bridge_call(chan, final_dest_chan, &bconfig); 07571 07572 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 07573 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 07574 if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) { 07575 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 07576 final_dest_chan->context, final_dest_chan->exten, 07577 final_dest_chan->priority, final_dest_chan->name); 07578 07579 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 07580 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 07581 ast_hangup(final_dest_chan); 07582 } else 07583 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 07584 } else { 07585 ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name); 07586 ast_hangup(final_dest_chan); 07587 } 07588 done: 07589 if (bconfig.warning_sound) { 07590 ast_free((char *)bconfig.warning_sound); 07591 } 07592 if (bconfig.end_sound) { 07593 ast_free((char *)bconfig.end_sound); 07594 } 07595 if (bconfig.start_sound) { 07596 ast_free((char *)bconfig.start_sound); 07597 } 07598 07599 return 0; 07600 }
static struct parking_dp_context* build_dialplan_useage_context | ( | struct ast_parkinglot * | lot | ) | [static] |
Definition at line 6140 of file features.c.
References ast_calloc, ast_parkinglot::cfg, destroy_dialplan_usage_context(), dialplan_usage_add_parkinglot_data(), and parkinglot_cfg::parking_con.
Referenced by dialplan_usage_add_parkinglot().
06141 { 06142 struct parking_dp_context *ctx_node; 06143 06144 ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con)); 06145 if (!ctx_node) { 06146 return NULL; 06147 } 06148 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) { 06149 destroy_dialplan_usage_context(ctx_node); 06150 return NULL; 06151 } 06152 strcpy(ctx_node->context, lot->cfg.parking_con); 06153 return ctx_node; 06154 }
static int build_dialplan_useage_map | ( | struct parking_dp_map * | usage_map, | |
int | complain | |||
) | [static] |
Definition at line 6212 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, dialplan_usage_add_parkinglot(), parkinglots, and status.
Referenced by load_config().
06213 { 06214 int status = 0; 06215 struct ao2_iterator iter; 06216 struct ast_parkinglot *curlot; 06217 06218 /* For all parking lots */ 06219 iter = ao2_iterator_init(parkinglots, 0); 06220 for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) { 06221 /* Add the parking lot to the map. */ 06222 if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) { 06223 ao2_ref(curlot, -1); 06224 status = -1; 06225 break; 06226 } 06227 } 06228 ao2_iterator_destroy(&iter); 06229 06230 return status; 06231 }
static struct parking_dp_ramp* build_dialplan_useage_ramp | ( | const char * | exten, | |
int | exclusive | |||
) | [static] |
Definition at line 5903 of file features.c.
References ast_calloc.
Referenced by usage_context_add_ramp().
05904 { 05905 struct parking_dp_ramp *ramp_node; 05906 05907 ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten)); 05908 if (!ramp_node) { 05909 return NULL; 05910 } 05911 ramp_node->exclusive = exclusive; 05912 strcpy(ramp_node->exten, exten); 05913 return ramp_node; 05914 }
static struct parking_dp_spaces* build_dialplan_useage_spaces | ( | int | start, | |
int | stop | |||
) | [static] |
Definition at line 5984 of file features.c.
References ast_calloc.
Referenced by usage_context_add_spaces().
05985 { 05986 struct parking_dp_spaces *spaces_node; 05987 05988 spaces_node = ast_calloc(1, sizeof(*spaces_node)); 05989 if (!spaces_node) { 05990 return NULL; 05991 } 05992 spaces_node->start = start; 05993 spaces_node->stop = stop; 05994 return spaces_node; 05995 }
static struct ast_parkinglot* build_parkinglot | ( | const char * | pl_name, | |
struct ast_variable * | var | |||
) | [static] |
Build parkinglot from configuration and chain it in if it doesn't already exist.
Definition at line 5507 of file features.c.
References ao2_link, ao2_lock, ao2_unlock, ast_debug, AST_LIST_EMPTY, ast_log(), create_parkinglot(), DEFAULT_PARKINGLOT, find_parkinglot(), force_reload_load, LOG_WARNING, parkinglot, parkinglot_cfg_default, parkinglot_cfg_default_default, parkinglot_config_read(), parkinglot_unref(), parkinglots, and var.
Referenced by load_config(), and process_config().
05508 { 05509 struct ast_parkinglot *parkinglot; 05510 const struct parkinglot_cfg *cfg_defaults; 05511 struct parkinglot_cfg new_cfg; 05512 int cfg_error; 05513 int oldparkinglot = 0; 05514 05515 parkinglot = find_parkinglot(pl_name); 05516 if (parkinglot) { 05517 oldparkinglot = 1; 05518 } else { 05519 parkinglot = create_parkinglot(pl_name); 05520 if (!parkinglot) { 05521 return NULL; 05522 } 05523 } 05524 if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) { 05525 cfg_defaults = &parkinglot_cfg_default_default; 05526 } else { 05527 cfg_defaults = &parkinglot_cfg_default; 05528 } 05529 new_cfg = *cfg_defaults; 05530 05531 ast_debug(1, "Building parking lot %s\n", parkinglot->name); 05532 05533 ao2_lock(parkinglot); 05534 05535 /* Do some config stuff */ 05536 cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var); 05537 if (oldparkinglot) { 05538 if (cfg_error) { 05539 /* Bad configuration read. Keep using the original config. */ 05540 ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n", 05541 parkinglot->name); 05542 cfg_error = 0; 05543 } else if (!AST_LIST_EMPTY(&parkinglot->parkings) 05544 && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) { 05545 /* Try reloading later when parking lot is empty. */ 05546 ast_log(LOG_WARNING, 05547 "Parking lot %s has parked calls. Parking lot changes discarded.\n", 05548 parkinglot->name); 05549 force_reload_load = 1; 05550 } else { 05551 /* Accept the new config */ 05552 parkinglot->cfg = new_cfg; 05553 } 05554 } else { 05555 /* Load the initial parking lot config. */ 05556 parkinglot->cfg = new_cfg; 05557 } 05558 parkinglot->the_mark = 0; 05559 05560 ao2_unlock(parkinglot); 05561 05562 if (cfg_error) { 05563 /* Only new parking lots could have config errors here. */ 05564 ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name); 05565 parkinglot_unref(parkinglot); 05566 return NULL; 05567 } 05568 05569 /* Move it into the list, if it wasn't already there */ 05570 if (!oldparkinglot) { 05571 ao2_link(parkinglots, parkinglot); 05572 } 05573 parkinglot_unref(parkinglot); 05574 05575 return parkinglot; 05576 }
static int builtin_atxfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Attended transfer.
chan | transfered user | |
peer | person transfering call | |
config | ||
code | ||
sense | feature options | |
data | Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel. |
Definition at line 2419 of file features.c.
References ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_calloc, AST_CEL_ATTENDEDTRANSFER, ast_cel_report_event(), ast_channel_alloc, ast_channel_connected_line_macro(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_channel_update_connected_line(), ast_check_hangup(), ast_clear_flag, ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_do_masquerade(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAGS_ALL, ast_hangup(), ast_indicate(), ast_log(), ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), atxfer_fail_cleanup(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, bridge_call_thread_launch(), ast_channel::caller, check_compat(), config, ast_channel::connected, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, feature_request_and_dial(), ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), get_parking_exten(), ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_party_connected_line::source, strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xfer_park_call_helper(), xferfailsound, and xfersound.
02420 { 02421 struct ast_channel *transferer;/* Party B */ 02422 struct ast_channel *transferee;/* Party A */ 02423 struct ast_exten *park_exten; 02424 const char *transferer_real_context; 02425 char xferto[256] = ""; 02426 int res; 02427 int outstate=0; 02428 struct ast_channel *newchan; 02429 struct ast_channel *xferchan; 02430 struct ast_bridge_thread_obj *tobj; 02431 struct ast_bridge_config bconfig; 02432 int l; 02433 struct ast_party_connected_line connected_line; 02434 struct ast_datastore *features_datastore; 02435 struct ast_dial_features *dialfeatures = NULL; 02436 char *transferer_tech; 02437 char *transferer_name; 02438 char *transferer_name_orig; 02439 char *dash; 02440 02441 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 02442 set_peers(&transferer, &transferee, peer, chan, sense); 02443 transferer_real_context = real_ctx(transferer, transferee); 02444 02445 /* Start autoservice on transferee while we talk to the transferer */ 02446 ast_autoservice_start(transferee); 02447 ast_indicate(transferee, AST_CONTROL_HOLD); 02448 02449 /* Transfer */ 02450 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02451 if (res < 0) { 02452 finishup(transferee); 02453 return -1; 02454 } 02455 if (res > 0) { /* If they've typed a digit already, handle it */ 02456 xferto[0] = (char) res; 02457 } 02458 02459 /* this is specific of atxfer */ 02460 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02461 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02462 finishup(transferee); 02463 return -1; 02464 } 02465 l = strlen(xferto); 02466 if (res == 0) { 02467 if (l) { 02468 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02469 xferto, transferer_real_context); 02470 } else { 02471 /* Does anyone care about this case? */ 02472 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n"); 02473 } 02474 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02475 finishup(transferee); 02476 return AST_FEATURE_RETURN_SUCCESS; 02477 } 02478 02479 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02480 if (park_exten) { 02481 /* We are transfering the transferee to a parking lot. */ 02482 return xfer_park_call_helper(transferee, transferer, park_exten); 02483 } 02484 02485 /* Append context to dialed transfer number. */ 02486 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); 02487 02488 /* If we are performing an attended transfer and we have two channels involved then 02489 copy sound file information to play upon attended transfer completion */ 02490 if (transferee) { 02491 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02492 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02493 02494 if (!ast_strlen_zero(chan1_attended_sound)) { 02495 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 02496 } 02497 if (!ast_strlen_zero(chan2_attended_sound)) { 02498 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 02499 } 02500 } 02501 02502 /* Extract redial transferer information from the channel name. */ 02503 transferer_name_orig = ast_strdupa(transferer->name); 02504 transferer_name = ast_strdupa(transferer_name_orig); 02505 transferer_tech = strsep(&transferer_name, "/"); 02506 dash = strrchr(transferer_name, '-'); 02507 if (dash) { 02508 /* Trim off channel name sequence/serial number. */ 02509 *dash = '\0'; 02510 } 02511 02512 /* Stop autoservice so we can monitor all parties involved in the transfer. */ 02513 if (ast_autoservice_stop(transferee) < 0) { 02514 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02515 return -1; 02516 } 02517 02518 /* Save connected line info for party B about party A in case transfer fails. */ 02519 ast_party_connected_line_init(&connected_line); 02520 ast_channel_lock(transferer); 02521 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02522 ast_channel_unlock(transferer); 02523 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02524 02525 /* Dial party C */ 02526 newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer, 02527 transferee, "Local", ast_best_codec(transferer->nativeformats), xferto, 02528 atxfernoanswertimeout, &outstate, transferer->language); 02529 ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate); 02530 02531 if (!ast_check_hangup(transferer)) { 02532 int hangup_dont = 0; 02533 02534 /* Transferer (party B) is up */ 02535 ast_debug(1, "Actually doing an attended transfer.\n"); 02536 02537 /* Start autoservice on transferee while the transferer deals with party C. */ 02538 ast_autoservice_start(transferee); 02539 02540 ast_indicate(transferer, -1); 02541 if (!newchan) { 02542 /* any reason besides user requested cancel and busy triggers the failed sound */ 02543 switch (outstate) { 02544 case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */ 02545 case AST_CONTROL_BUSY: 02546 case AST_CONTROL_CONGESTION: 02547 if (ast_stream_and_wait(transferer, xfersound, "")) { 02548 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02549 } 02550 break; 02551 default: 02552 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02553 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02554 } 02555 break; 02556 } 02557 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02558 return AST_FEATURE_RETURN_SUCCESS; 02559 } 02560 02561 if (check_compat(transferer, newchan)) { 02562 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02563 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02564 } 02565 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02566 return AST_FEATURE_RETURN_SUCCESS; 02567 } 02568 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 02569 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 02570 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 02571 02572 /* ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we don't 02573 want that to happen here because we're also in another bridge already 02574 */ 02575 if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) { 02576 hangup_dont = 1; 02577 } 02578 /* Let party B and party C talk as long as they want. */ 02579 ast_bridge_call(transferer, newchan, &bconfig); 02580 if (hangup_dont) { 02581 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 02582 } 02583 02584 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 02585 ast_hangup(newchan); 02586 if (ast_stream_and_wait(transferer, xfersound, "")) { 02587 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02588 } 02589 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02590 return AST_FEATURE_RETURN_SUCCESS; 02591 } 02592 02593 /* Transferer (party B) is confirmed hung up at this point. */ 02594 if (check_compat(transferee, newchan)) { 02595 finishup(transferee); 02596 ast_party_connected_line_free(&connected_line); 02597 return -1; 02598 } 02599 02600 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02601 if ((ast_autoservice_stop(transferee) < 0) 02602 || (ast_waitfordigit(transferee, 100) < 0) 02603 || (ast_waitfordigit(newchan, 100) < 0) 02604 || ast_check_hangup(transferee) 02605 || ast_check_hangup(newchan)) { 02606 ast_hangup(newchan); 02607 ast_party_connected_line_free(&connected_line); 02608 return -1; 02609 } 02610 } else if (!ast_check_hangup(transferee)) { 02611 /* Transferer (party B) has hung up at this point. Doing blonde transfer. */ 02612 ast_debug(1, "Actually doing a blonde transfer.\n"); 02613 02614 if (!newchan && !atxferdropcall) { 02615 /* Party C is not available, try to call party B back. */ 02616 unsigned int tries = 0; 02617 02618 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 02619 ast_log(LOG_WARNING, 02620 "Transferer channel name: '%s' cannot be used for callback.\n", 02621 transferer_name_orig); 02622 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02623 ast_party_connected_line_free(&connected_line); 02624 return -1; 02625 } 02626 02627 tries = 0; 02628 for (;;) { 02629 /* Try to get party B back. */ 02630 ast_debug(1, "We're trying to callback %s/%s\n", 02631 transferer_tech, transferer_name); 02632 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02633 transferee, transferee, transferer_tech, 02634 ast_best_codec(transferee->nativeformats), transferer_name, 02635 atxfernoanswertimeout, &outstate, transferer->language); 02636 ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n", 02637 !!newchan, outstate); 02638 if (newchan || ast_check_hangup(transferee)) { 02639 break; 02640 } 02641 02642 ++tries; 02643 if (atxfercallbackretries <= tries) { 02644 /* No more callback tries remaining. */ 02645 break; 02646 } 02647 02648 if (atxferloopdelay) { 02649 /* Transfer failed, sleeping */ 02650 ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n", 02651 atxferloopdelay); 02652 ast_safe_sleep(transferee, atxferloopdelay); 02653 if (ast_check_hangup(transferee)) { 02654 ast_party_connected_line_free(&connected_line); 02655 return -1; 02656 } 02657 } 02658 02659 /* Retry dialing party C. */ 02660 ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto); 02661 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02662 transferer, transferee, "Local", 02663 ast_best_codec(transferee->nativeformats), xferto, 02664 atxfernoanswertimeout, &outstate, transferer->language); 02665 ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n", 02666 !!newchan, outstate); 02667 if (newchan || ast_check_hangup(transferee)) { 02668 break; 02669 } 02670 } 02671 } 02672 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02673 if (!newchan) { 02674 /* No party C or could not callback party B. */ 02675 ast_party_connected_line_free(&connected_line); 02676 return -1; 02677 } 02678 02679 /* newchan is up, we should prepare transferee and bridge them */ 02680 if (ast_check_hangup(newchan)) { 02681 ast_hangup(newchan); 02682 ast_party_connected_line_free(&connected_line); 02683 return -1; 02684 } 02685 if (check_compat(transferee, newchan)) { 02686 ast_party_connected_line_free(&connected_line); 02687 return -1; 02688 } 02689 } else { 02690 /* 02691 * Both the transferer and transferee have hungup. If newchan 02692 * is up, hang it up as it has no one to talk to. 02693 */ 02694 ast_debug(1, "Everyone is hungup.\n"); 02695 if (newchan) { 02696 ast_hangup(newchan); 02697 } 02698 ast_party_connected_line_free(&connected_line); 02699 return -1; 02700 } 02701 02702 /* Initiate the channel transfer of party A to party C (or recalled party B). */ 02703 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan); 02704 02705 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name); 02706 if (!xferchan) { 02707 ast_hangup(newchan); 02708 ast_party_connected_line_free(&connected_line); 02709 return -1; 02710 } 02711 02712 /* Give party A a momentary ringback tone during transfer. */ 02713 xferchan->visible_indication = AST_CONTROL_RINGING; 02714 02715 /* Make formats okay */ 02716 xferchan->readformat = transferee->readformat; 02717 xferchan->writeformat = transferee->writeformat; 02718 02719 ast_channel_masquerade(xferchan, transferee); 02720 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 02721 xferchan->_state = AST_STATE_UP; 02722 ast_clear_flag(xferchan, AST_FLAGS_ALL); 02723 02724 /* Do the masquerade manually to make sure that is is completed. */ 02725 ast_do_masquerade(xferchan); 02726 02727 newchan->_state = AST_STATE_UP; 02728 ast_clear_flag(newchan, AST_FLAGS_ALL); 02729 tobj = ast_calloc(1, sizeof(*tobj)); 02730 if (!tobj) { 02731 ast_hangup(xferchan); 02732 ast_hangup(newchan); 02733 ast_party_connected_line_free(&connected_line); 02734 return -1; 02735 } 02736 02737 ast_channel_lock(newchan); 02738 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 02739 dialfeatures = features_datastore->data; 02740 } 02741 ast_channel_unlock(newchan); 02742 02743 if (dialfeatures) { 02744 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 02745 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 02746 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 02747 dialfeatures = NULL; 02748 } 02749 02750 ast_channel_lock(xferchan); 02751 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 02752 dialfeatures = features_datastore->data; 02753 } 02754 ast_channel_unlock(xferchan); 02755 02756 if (dialfeatures) { 02757 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 02758 } 02759 02760 tobj->chan = newchan; 02761 tobj->peer = xferchan; 02762 tobj->bconfig = *config; 02763 02764 if (tobj->bconfig.end_bridge_callback_data_fixup) { 02765 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 02766 } 02767 02768 /* 02769 * xferchan is transferee, and newchan is the transfer target 02770 * So...in a transfer, who is the caller and who is the callee? 02771 * 02772 * When the call is originally made, it is clear who is caller and callee. 02773 * When a transfer occurs, it is my humble opinion that the transferee becomes 02774 * the caller, and the transfer target is the callee. 02775 * 02776 * The problem is that these macros were set with the intention of the original 02777 * caller and callee taking those roles. A transfer can totally mess things up, 02778 * to be technical. What sucks even more is that you can't effectively change 02779 * the macros in the dialplan during the call from the transferer to the transfer 02780 * target because the transferee is stuck with whatever role he originally had. 02781 * 02782 * I think the answer here is just to make sure that it is well documented that 02783 * during a transfer, the transferee is the "caller" and the transfer target 02784 * is the "callee." 02785 * 02786 * This means that if party B calls party A, and party B transfers party A to 02787 * party C, then A has switched roles for the call. Now party A will have the 02788 * caller macro called on his channel instead of the callee macro. 02789 * 02790 * Luckily, the method by which the party B to party C bridge is 02791 * launched above ensures that the transferee is the "chan" on 02792 * the bridge and the transfer target is the "peer," so my idea 02793 * for the roles post-transfer does not require extensive code 02794 * changes. 02795 */ 02796 02797 /* Transfer party C connected line to party A */ 02798 ast_channel_lock(transferer); 02799 /* 02800 * Due to a limitation regarding when callerID is set on a Local channel, 02801 * we use the transferer's connected line information here. 02802 */ 02803 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02804 ast_channel_unlock(transferer); 02805 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02806 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { 02807 ast_channel_update_connected_line(xferchan, &connected_line, NULL); 02808 } 02809 02810 /* Transfer party A connected line to party C */ 02811 ast_channel_lock(xferchan); 02812 ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller); 02813 ast_channel_unlock(xferchan); 02814 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02815 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { 02816 ast_channel_update_connected_line(newchan, &connected_line, NULL); 02817 } 02818 02819 if (ast_stream_and_wait(newchan, xfersound, "")) 02820 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02821 bridge_call_thread_launch(tobj); 02822 02823 ast_party_connected_line_free(&connected_line); 02824 return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */ 02825 }
static int builtin_automixmonitor | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 2092 of file features.c.
References args, AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_unlock, AST_FEATURE_RETURN_SUCCESS, AST_FRAME_DTMF_END, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, ast_channel::name, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_COR, S_OR, set_peers(), stopmixmonitor_app, stopmixmonitor_ok, ast_party_number::str, and ast_party_number::valid.
02093 { 02094 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02095 int x = 0; 02096 size_t len; 02097 struct ast_channel *caller_chan, *callee_chan; 02098 const char *mixmonitor_spy_type = "MixMonitor"; 02099 int count = 0; 02100 02101 if (!mixmonitor_ok) { 02102 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02103 return -1; 02104 } 02105 02106 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 02107 mixmonitor_ok = 0; 02108 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02109 return -1; 02110 } 02111 02112 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02113 02114 if (!ast_strlen_zero(courtesytone)) { 02115 if (ast_autoservice_start(callee_chan)) 02116 return -1; 02117 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END); 02118 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 02119 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02120 ast_autoservice_stop(callee_chan); 02121 return -1; 02122 } 02123 if (ast_autoservice_stop(callee_chan)) 02124 return -1; 02125 } 02126 02127 ast_channel_lock(callee_chan); 02128 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02129 ast_channel_unlock(callee_chan); 02130 02131 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 02132 if (count > 0) { 02133 02134 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 02135 02136 /* Make sure they are running */ 02137 ast_channel_lock(callee_chan); 02138 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02139 ast_channel_unlock(callee_chan); 02140 if (count > 0) { 02141 if (!stopmixmonitor_ok) { 02142 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02143 return -1; 02144 } 02145 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 02146 stopmixmonitor_ok = 0; 02147 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02148 return -1; 02149 } else { 02150 pbx_exec(callee_chan, stopmixmonitor_app, ""); 02151 return AST_FEATURE_RETURN_SUCCESS; 02152 } 02153 } 02154 02155 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 02156 } 02157 02158 if (caller_chan && callee_chan) { 02159 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 02160 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 02161 02162 if (!touch_format) 02163 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 02164 02165 if (!touch_monitor) 02166 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 02167 02168 if (touch_monitor) { 02169 len = strlen(touch_monitor) + 50; 02170 args = alloca(len); 02171 touch_filename = alloca(len); 02172 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 02173 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 02174 } else { 02175 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 02176 caller_chan->caller.id.number.str, caller_chan->name)); 02177 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 02178 callee_chan->caller.id.number.str, callee_chan->name)); 02179 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02180 args = alloca(len); 02181 touch_filename = alloca(len); 02182 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 02183 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 02184 } 02185 02186 for( x = 0; x < strlen(args); x++) { 02187 if (args[x] == '/') 02188 args[x] = '-'; 02189 } 02190 02191 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 02192 02193 pbx_exec(callee_chan, mixmonitor_app, args); 02194 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02195 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02196 return AST_FEATURE_RETURN_SUCCESS; 02197 02198 } 02199 02200 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 02201 return -1; 02202 02203 }
static int builtin_automonitor | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Monitor a channel by DTMF.
chan | channel requesting monitor | |
peer | channel to be monitored | |
config | ||
code | ||
sense | feature options | |
data | Check monitor app enabled, setup channels, both caller/callee chans not null get TOUCH_MONITOR variable for filename if exists, exec monitor app. |
AST_FEATURE_RETURN_SUCCESS | on success. | |
-1 | on error. |
Definition at line 1997 of file features.c.
References args, AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, LOG_NOTICE, ast_channel::monitor, monitor_app, monitor_ok, ast_channel::name, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_COR, S_OR, set_peers(), ast_channel_monitor::stop, ast_party_number::str, and ast_party_number::valid.
01998 { 01999 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02000 int x = 0; 02001 size_t len; 02002 struct ast_channel *caller_chan, *callee_chan; 02003 const char *automon_message_start = NULL; 02004 const char *automon_message_stop = NULL; 02005 02006 if (!monitor_ok) { 02007 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02008 return -1; 02009 } 02010 02011 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 02012 monitor_ok = 0; 02013 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02014 return -1; 02015 } 02016 02017 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02018 if (caller_chan) { /* Find extra messages */ 02019 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 02020 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 02021 } 02022 02023 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 02024 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 02025 return -1; 02026 } 02027 } 02028 02029 if (callee_chan->monitor) { 02030 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 02031 if (!ast_strlen_zero(automon_message_stop)) { 02032 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 02033 } 02034 callee_chan->monitor->stop(callee_chan, 1); 02035 return AST_FEATURE_RETURN_SUCCESS; 02036 } 02037 02038 if (caller_chan && callee_chan) { 02039 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 02040 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 02041 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 02042 02043 if (!touch_format) 02044 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 02045 02046 if (!touch_monitor) 02047 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 02048 02049 if (!touch_monitor_prefix) 02050 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 02051 02052 if (touch_monitor) { 02053 len = strlen(touch_monitor) + 50; 02054 args = alloca(len); 02055 touch_filename = alloca(len); 02056 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 02057 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02058 } else { 02059 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 02060 caller_chan->caller.id.number.str, caller_chan->name)); 02061 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 02062 callee_chan->caller.id.number.str, callee_chan->name)); 02063 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02064 args = alloca(len); 02065 touch_filename = alloca(len); 02066 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 02067 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02068 } 02069 02070 for(x = 0; x < strlen(args); x++) { 02071 if (args[x] == '/') 02072 args[x] = '-'; 02073 } 02074 02075 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 02076 02077 pbx_exec(callee_chan, monitor_app, args); 02078 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02079 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02080 02081 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 02082 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 02083 } 02084 02085 return AST_FEATURE_RETURN_SUCCESS; 02086 } 02087 02088 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 02089 return -1; 02090 }
static int builtin_blindtransfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Blind transfer user to another extension.
chan | channel to be transfered | |
peer | channel initiated blind transfer | |
config | ||
code | ||
data | ||
sense | feature options |
AST_FEATURE_RETURN_SUCCESS. | ||
-1 | on failure. |
Definition at line 2248 of file features.c.
References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CEL_BLINDTRANSFER, ast_cel_report_event(), ast_channel_lock, ast_channel_unlock, AST_CONTROL_HOLD, ast_debug, AST_DIGIT_ANY, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, AST_FLAG_BRIDGE_HANGUP_DONT, ast_indicate(), ast_log(), ast_set_flag, ast_stream_and_wait(), ast_verb, ast_channel::cdr, ast_cdr::channel, check_goto_on_transfer(), ast_cdr::dstchannel, finishup(), get_parking_exten(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, ast_channel::name, ast_channel::pbx, pbx_builtin_setvar_helper(), ast_exten::peer, real_ctx(), set_c_e_p(), set_peers(), transferdigittimeout, and xfer_park_call_helper().
02249 { 02250 struct ast_channel *transferer; 02251 struct ast_channel *transferee; 02252 struct ast_exten *park_exten; 02253 const char *transferer_real_context; 02254 char xferto[256] = ""; 02255 int res; 02256 02257 ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 02258 set_peers(&transferer, &transferee, peer, chan, sense); 02259 transferer_real_context = real_ctx(transferer, transferee); 02260 02261 /* Start autoservice on transferee while we talk to the transferer */ 02262 ast_autoservice_start(transferee); 02263 ast_indicate(transferee, AST_CONTROL_HOLD); 02264 02265 /* Transfer */ 02266 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02267 if (res < 0) { 02268 finishup(transferee); 02269 return -1; /* error ? */ 02270 } 02271 if (res > 0) { /* If they've typed a digit already, handle it */ 02272 xferto[0] = (char) res; 02273 } 02274 02275 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02276 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02277 finishup(transferee); 02278 return -1; 02279 } 02280 if (res == 0) { 02281 if (xferto[0]) { 02282 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02283 xferto, transferer_real_context); 02284 } else { 02285 /* Does anyone care about this case? */ 02286 ast_log(LOG_WARNING, "No digits dialed.\n"); 02287 } 02288 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02289 finishup(transferee); 02290 return AST_FEATURE_RETURN_SUCCESS; 02291 } 02292 02293 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02294 if (park_exten) { 02295 /* We are transfering the transferee to a parking lot. */ 02296 return xfer_park_call_helper(transferee, transferer, park_exten); 02297 } 02298 02299 /* Do blind transfer. */ 02300 ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n", 02301 transferee->name, xferto, transferer_real_context); 02302 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee); 02303 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 02304 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 02305 finishup(transferee); 02306 ast_channel_lock(transferer); 02307 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 02308 transferer->cdr = ast_cdr_alloc(); 02309 if (transferer->cdr) { 02310 ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */ 02311 ast_cdr_start(transferer->cdr); 02312 } 02313 } 02314 ast_channel_unlock(transferer); 02315 if (transferer->cdr) { 02316 struct ast_cdr *swap = transferer->cdr; 02317 02318 ast_debug(1, 02319 "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 02320 transferer->name, transferee->name, transferer->cdr->lastapp, 02321 transferer->cdr->lastdata, transferer->cdr->channel, 02322 transferer->cdr->dstchannel); 02323 ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 02324 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, 02325 transferee->cdr->dstchannel); 02326 ast_debug(1, "transferer_real_context=%s; xferto=%s\n", 02327 transferer_real_context, xferto); 02328 /* swap cdrs-- it will save us some time & work */ 02329 transferer->cdr = transferee->cdr; 02330 transferee->cdr = swap; 02331 } 02332 if (!transferee->pbx) { 02333 /* Doh! Use our handy async_goto functions */ 02334 ast_debug(1, "About to ast_async_goto %s.\n", transferee->name); 02335 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) { 02336 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 02337 } 02338 02339 /* The transferee is masqueraded and the original bridged channels can be hungup. */ 02340 res = -1; 02341 } else { 02342 /* Set the transferee's new extension, since it exists, using transferer context */ 02343 ast_debug(1, "About to explicit goto %s, it has a PBX.\n", transferee->name); 02344 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 02345 set_c_e_p(transferee, transferer_real_context, xferto, 0); 02346 02347 /* 02348 * Break the bridge. The transferee needs to resume executing 02349 * dialplan at the xferto location. 02350 */ 02351 res = AST_FEATURE_RETURN_SUCCESSBREAK; 02352 } 02353 check_goto_on_transfer(transferer); 02354 return res; 02355 }
static int builtin_disconnect | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 2205 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
02206 { 02207 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 02208 return AST_FEATURE_RETURN_HANGUP; 02209 }
static int builtin_parkcall | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
support routing for one touch call parking
chan | channel parking call | |
peer | channel to be parked | |
config | unsed | |
code | unused | |
sense | feature options | |
data | unused |
-1 | on successful park. | |
-1 | on chan hangup. | |
AST_FEATURE_RETURN_SUCCESS | on error to keep the bridge connected. |
Definition at line 1875 of file features.c.
References ast_channel::_state, args, ast_answer(), AST_FEATURE_RETURN_SUCCESS, ast_safe_sleep(), AST_STATE_UP, masq_park_call(), and set_peers().
01876 { 01877 struct ast_channel *parker; 01878 struct ast_channel *parkee; 01879 struct ast_park_call_args args = { 0, }; 01880 01881 /* 01882 * We used to set chan's exten and priority to "s" and 1 here, 01883 * but this generates (in some cases) an invalid extension, and 01884 * if "s" exists, could errantly cause execution of extensions 01885 * you don't expect. It makes more sense to let nature take its 01886 * course when chan finishes, and let the pbx do its thing and 01887 * hang up when the park is over. 01888 */ 01889 01890 /* Answer if call is not up */ 01891 if (chan->_state != AST_STATE_UP) { 01892 /* 01893 * XXX Why are we doing this? Both of the channels should be up 01894 * since you cannot do DTMF features unless you are bridged. 01895 */ 01896 if (ast_answer(chan)) { 01897 return -1; 01898 } 01899 01900 /* Sleep to allow VoIP streams to settle down */ 01901 if (ast_safe_sleep(chan, 1000)) { 01902 return -1; 01903 } 01904 } 01905 01906 /* one direction used to call park_call.... */ 01907 set_peers(&parker, &parkee, peer, chan, sense); 01908 return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1; 01909 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 4496 of file features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, and ast_test_flag.
Referenced by manage_parked_call().
04497 { 04498 int i = 0; 04499 enum { 04500 OPT_CALLEE_REDIRECT = 't', 04501 OPT_CALLER_REDIRECT = 'T', 04502 OPT_CALLEE_AUTOMON = 'w', 04503 OPT_CALLER_AUTOMON = 'W', 04504 OPT_CALLEE_DISCONNECT = 'h', 04505 OPT_CALLER_DISCONNECT = 'H', 04506 OPT_CALLEE_PARKCALL = 'k', 04507 OPT_CALLER_PARKCALL = 'K', 04508 }; 04509 04510 memset(options, 0, len); 04511 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 04512 options[i++] = OPT_CALLER_REDIRECT; 04513 } 04514 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 04515 options[i++] = OPT_CALLER_AUTOMON; 04516 } 04517 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 04518 options[i++] = OPT_CALLER_DISCONNECT; 04519 } 04520 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 04521 options[i++] = OPT_CALLER_PARKCALL; 04522 } 04523 04524 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 04525 options[i++] = OPT_CALLEE_REDIRECT; 04526 } 04527 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 04528 options[i++] = OPT_CALLEE_AUTOMON; 04529 } 04530 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 04531 options[i++] = OPT_CALLEE_DISCONNECT; 04532 } 04533 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 04534 options[i++] = OPT_CALLEE_PARKCALL; 04535 } 04536 04537 return options; 04538 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
make channels compatible
c | ||
newchan |
0 | on success. | |
-1 | on failure. |
Definition at line 2364 of file features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by builtin_atxfer().
02365 { 02366 if (ast_channel_make_compatible(c, newchan) < 0) { 02367 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 02368 c->name, newchan->name); 02369 ast_hangup(newchan); 02370 return -1; 02371 } 02372 return 0; 02373 }
static void check_goto_on_transfer | ( | struct ast_channel * | chan | ) | [static] |
Check goto on transfer.
chan | Check if channel has 'GOTO_ON_BLINDXFR' set, if not exit. When found make sure the types are compatible. Check if channel is valid if so start the new channel else hangup the call. |
Definition at line 845 of file features.c.
References ast_channel::_state, ast_channel_alloc, ast_channel_clear_softhangup(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_clear_flag, ast_debug, ast_do_masquerade(), AST_FLAGS_ALL, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), AST_SOFTHANGUP_ALL, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_channel::linkedid, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.
Referenced by builtin_blindtransfer().
00846 { 00847 struct ast_channel *xferchan; 00848 const char *val; 00849 char *goto_on_transfer; 00850 char *x; 00851 00852 ast_channel_lock(chan); 00853 val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00854 if (ast_strlen_zero(val)) { 00855 ast_channel_unlock(chan); 00856 return; 00857 } 00858 goto_on_transfer = ast_strdupa(val); 00859 ast_channel_unlock(chan); 00860 00861 ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, chan->name); 00862 00863 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, 00864 "%s", chan->name); 00865 if (!xferchan) { 00866 return; 00867 } 00868 00869 /* Make formats okay */ 00870 xferchan->readformat = chan->readformat; 00871 xferchan->writeformat = chan->writeformat; 00872 00873 if (ast_channel_masquerade(xferchan, chan)) { 00874 /* Failed to setup masquerade. */ 00875 ast_hangup(xferchan); 00876 return; 00877 } 00878 00879 for (x = goto_on_transfer; *x; ++x) { 00880 if (*x == '^') { 00881 *x = ','; 00882 } 00883 } 00884 ast_parseable_goto(xferchan, goto_on_transfer); 00885 xferchan->_state = AST_STATE_UP; 00886 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00887 ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL); 00888 00889 if (ast_do_masquerade(xferchan) || ast_pbx_start(xferchan)) { 00890 /* Failed to do masquerade or could not start PBX. */ 00891 ast_hangup(xferchan); 00892 } 00893 }
static void clear_dialed_interfaces | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 3798 of file features.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_free(), ast_log(), dialed_interface_info, LOG_DEBUG, ast_channel::name, and option_debug.
Referenced by ast_bridge_call().
03799 { 03800 struct ast_datastore *di_datastore; 03801 03802 ast_channel_lock(chan); 03803 if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) { 03804 if (option_debug) { 03805 ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name); 03806 } 03807 if (!ast_channel_datastore_remove(chan, di_datastore)) { 03808 ast_datastore_free(di_datastore); 03809 } 03810 } 03811 ast_channel_unlock(chan); 03812 }
static struct ast_parkinglot * copy_parkinglot | ( | const char * | name, | |
const struct ast_parkinglot * | parkinglot | |||
) | [static] |
Copy parkinglot and store it with new name.
Definition at line 4859 of file features.c.
References ao2_ref, ast_debug, ast_parkinglot::cfg, create_parkinglot(), find_parkinglot(), and parkinglot.
Referenced by create_dynamic_parkinglot().
04860 { 04861 struct ast_parkinglot *copylot; 04862 04863 if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */ 04864 ao2_ref(copylot, -1); 04865 return NULL; 04866 } 04867 04868 copylot = create_parkinglot(name); 04869 if (!copylot) { 04870 return NULL; 04871 } 04872 04873 ast_debug(1, "Building parking lot %s\n", name); 04874 04875 /* Copy the source parking lot configuration. */ 04876 copylot->cfg = parkinglot->cfg; 04877 04878 return copylot; 04879 }
static struct ast_parkinglot* create_dynamic_parkinglot | ( | const char * | name, | |
struct ast_channel * | chan | |||
) | [static] |
Definition at line 1075 of file features.c.
References ao2_link, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, ast_log(), ast_strdupa, ast_strlen_zero(), ast_parkinglot::cfg, copy_parkinglot(), default_parkinglot, find_parkinglot(), parkinglot_cfg::is_invalid, LOG_ERROR, LOG_WARNING, ast_parkinglot::name, parkinglot_cfg::parkext, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglot, parkinglot_activate(), parkinglot_addref(), parkinglot_unref(), parkinglots, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_masq_park_call_exten(), ast_park_call_exten(), park_call_exec(), park_space_reserve(), and xfer_park_call_helper().
01076 { 01077 const char *dyn_context; 01078 const char *dyn_exten; 01079 const char *dyn_range; 01080 const char *template_name; 01081 struct ast_parkinglot *template_parkinglot = NULL; 01082 struct ast_parkinglot *parkinglot; 01083 int dyn_start; 01084 int dyn_end; 01085 01086 ast_channel_lock(chan); 01087 template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), "")); 01088 dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), "")); 01089 dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), "")); 01090 dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), "")); 01091 ast_channel_unlock(chan); 01092 01093 if (!ast_strlen_zero(template_name)) { 01094 template_parkinglot = find_parkinglot(template_name); 01095 if (!template_parkinglot) { 01096 ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n", 01097 template_name); 01098 } else if (template_parkinglot->cfg.is_invalid) { 01099 ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n", 01100 template_name); 01101 parkinglot_unref(template_parkinglot); 01102 template_parkinglot = NULL; 01103 } 01104 } 01105 if (!template_parkinglot) { 01106 template_parkinglot = parkinglot_addref(default_parkinglot); 01107 ast_debug(1, "Using default parking lot for template\n"); 01108 } 01109 01110 parkinglot = copy_parkinglot(name, template_parkinglot); 01111 if (!parkinglot) { 01112 ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n"); 01113 } else { 01114 /* Configure the dynamic parking lot. */ 01115 if (!ast_strlen_zero(dyn_context)) { 01116 ast_copy_string(parkinglot->cfg.parking_con, dyn_context, 01117 sizeof(parkinglot->cfg.parking_con)); 01118 } 01119 if (!ast_strlen_zero(dyn_exten)) { 01120 ast_copy_string(parkinglot->cfg.parkext, dyn_exten, 01121 sizeof(parkinglot->cfg.parkext)); 01122 } 01123 if (!ast_strlen_zero(dyn_range)) { 01124 if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) { 01125 ast_log(LOG_WARNING, 01126 "Format for parking positions is a-b, where a and b are numbers\n"); 01127 } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) { 01128 ast_log(LOG_WARNING, 01129 "Format for parking positions is a-b, where a <= b\n"); 01130 } else { 01131 parkinglot->cfg.parking_start = dyn_start; 01132 parkinglot->cfg.parking_stop = dyn_end; 01133 } 01134 } 01135 01136 /* 01137 * Sanity check for dynamic parking lot configuration. 01138 * 01139 * XXX It may be desirable to instead check if the dynamic 01140 * parking lot overlaps any existing lots like what is done for 01141 * a reload. 01142 */ 01143 if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) { 01144 if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext) 01145 && parkinglot->cfg.parkext_exclusive) { 01146 ast_log(LOG_WARNING, 01147 "Parking lot '%s' conflicts with template parking lot '%s'!\n" 01148 "Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n", 01149 parkinglot->name, template_parkinglot->name); 01150 } 01151 if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start 01152 && parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop) 01153 || (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop 01154 && parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop) 01155 || (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start 01156 && template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) { 01157 ast_log(LOG_WARNING, 01158 "Parking lot '%s' parking spaces overlap template parking lot '%s'!\n" 01159 "Change PARKINGDYNPOS.\n", 01160 parkinglot->name, template_parkinglot->name); 01161 } 01162 } 01163 01164 parkinglot_activate(parkinglot); 01165 ao2_link(parkinglots, parkinglot); 01166 } 01167 parkinglot_unref(template_parkinglot); 01168 01169 return parkinglot; 01170 }
static struct ast_parkinglot * create_parkinglot | ( | const char * | name | ) | [static] |
Allocate parking lot structure.
Definition at line 5283 of file features.c.
References ao2_alloc, ast_copy_string(), AST_LIST_HEAD_INIT, ast_strlen_zero(), and parkinglot_destroy().
Referenced by build_parkinglot(), and copy_parkinglot().
05284 { 05285 struct ast_parkinglot *newlot; 05286 05287 if (ast_strlen_zero(name)) { /* No name specified */ 05288 return NULL; 05289 } 05290 05291 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 05292 if (!newlot) 05293 return NULL; 05294 05295 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 05296 newlot->cfg.is_invalid = 1;/* No config is set yet. */ 05297 AST_LIST_HEAD_INIT(&newlot->parkings); 05298 05299 return newlot; 05300 }
static void destroy_dialplan_usage_context | ( | struct parking_dp_context * | doomed | ) | [static] |
Definition at line 5859 of file features.c.
References parking_dp_context::access_extens, ast_free, AST_LIST_REMOVE_HEAD, parking_dp_context::hints, parking_dp_spaces::node, and parking_dp_context::spaces.
Referenced by build_dialplan_useage_context(), and destroy_dialplan_usage_map().
05860 { 05861 struct parking_dp_ramp *ramp; 05862 struct parking_dp_spaces *spaces; 05863 05864 while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) { 05865 ast_free(ramp); 05866 } 05867 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) { 05868 ast_free(spaces); 05869 } 05870 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) { 05871 ast_free(spaces); 05872 } 05873 ast_free(doomed); 05874 }
static void destroy_dialplan_usage_map | ( | struct parking_dp_map * | doomed | ) | [static] |
Definition at line 5884 of file features.c.
References AST_LIST_REMOVE_HEAD, destroy_dialplan_usage_context(), and parking_dp_context::node.
Referenced by load_config().
05885 { 05886 struct parking_dp_context *item; 05887 05888 while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) { 05889 destroy_dialplan_usage_context(item); 05890 } 05891 }
static void destroy_space | ( | const char * | context, | |
int | space | |||
) | [static] |
Definition at line 6314 of file features.c.
References AST_MAX_EXTENSION, PRIORITY_HINT, and remove_exten_if_exist().
Referenced by remove_dead_spaces_usage().
06315 { 06316 char exten[AST_MAX_EXTENSION]; 06317 06318 /* Destroy priorities of the parking space that we registered. */ 06319 snprintf(exten, sizeof(exten), "%d", space); 06320 remove_exten_if_exist(context, exten, PRIORITY_HINT); 06321 remove_exten_if_exist(context, exten, 1); 06322 }
static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 739 of file features.c.
References ast_free.
00740 { 00741 struct ast_dial_features *df = data; 00742 if (df) { 00743 ast_free(df); 00744 } 00745 }
static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 726 of file features.c.
References ast_calloc.
00727 { 00728 struct ast_dial_features *df = data, *df_copy; 00729 00730 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00731 return NULL; 00732 } 00733 00734 memcpy(df_copy, df, sizeof(*df)); 00735 00736 return df_copy; 00737 }
static int dialplan_usage_add_parkinglot | ( | struct parking_dp_map * | usage_map, | |
struct ast_parkinglot * | lot, | |||
int | complain | |||
) | [static] |
Definition at line 6167 of file features.c.
References AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, build_dialplan_useage_context(), ast_parkinglot::cfg, parking_dp_context::context, dialplan_usage_add_parkinglot_data(), parking_dp_context::node, and parkinglot_cfg::parking_con.
Referenced by build_dialplan_useage_map().
06168 { 06169 struct parking_dp_context *cur_ctx; 06170 struct parking_dp_context *new_ctx; 06171 int cmp; 06172 06173 AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) { 06174 cmp = strcmp(lot->cfg.parking_con, cur_ctx->context); 06175 if (cmp > 0) { 06176 /* The parking lot context goes after this node. */ 06177 continue; 06178 } 06179 if (cmp == 0) { 06180 /* This is the node we will add parking lot spaces to the map. */ 06181 return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain); 06182 } 06183 /* The new parking lot context goes before this node. */ 06184 new_ctx = build_dialplan_useage_context(lot); 06185 if (!new_ctx) { 06186 return -1; 06187 } 06188 AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node); 06189 return 0; 06190 } 06191 AST_LIST_TRAVERSE_SAFE_END; 06192 06193 /* New parking lot context goes on the end. */ 06194 new_ctx = build_dialplan_useage_context(lot); 06195 if (!new_ctx) { 06196 return -1; 06197 } 06198 AST_LIST_INSERT_TAIL(usage_map, new_ctx, node); 06199 return 0; 06200 }
static int dialplan_usage_add_parkinglot_data | ( | struct parking_dp_context * | ctx_node, | |
struct ast_parkinglot * | lot, | |||
int | complain | |||
) | [static] |
Definition at line 6113 of file features.c.
References parking_dp_context::access_extens, ast_parkinglot::cfg, parking_dp_context::hints, parkinglot_cfg::parkaddhints, parkinglot_cfg::parkext, parkinglot_cfg::parkext_exclusive, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parking_dp_context::spaces, usage_context_add_ramp(), and usage_context_add_spaces().
Referenced by build_dialplan_useage_context(), and dialplan_usage_add_parkinglot().
06114 { 06115 if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext, 06116 lot->cfg.parkext_exclusive, lot, complain)) { 06117 return -1; 06118 } 06119 if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start, 06120 lot->cfg.parking_stop, lot, complain)) { 06121 return -1; 06122 } 06123 if (lot->cfg.parkaddhints 06124 && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start, 06125 lot->cfg.parking_stop, lot, 0)) { 06126 return -1; 06127 } 06128 return 0; 06129 }
static void do_bridge_masquerade | ( | struct ast_channel * | chan, | |
struct ast_channel * | tmpchan | |||
) | [static] |
Actual bridge.
chan | ||
tmpchan | Stop hold music, lock both channels, masq channels, after bridge return channel to next priority. |
Definition at line 6747 of file features.c.
References ast_channel::_state, ast_channel_lock_both, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_explicit_goto(), ast_moh_stop(), ast_setstate(), ast_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
Referenced by action_bridge(), and bridge_exec().
06748 { 06749 ast_moh_stop(chan); 06750 ast_channel_lock_both(chan, tmpchan); 06751 ast_setstate(tmpchan, chan->_state); 06752 tmpchan->readformat = chan->readformat; 06753 tmpchan->writeformat = chan->writeformat; 06754 ast_channel_unlock(chan); 06755 ast_channel_unlock(tmpchan); 06756 06757 ast_channel_masquerade(tmpchan, chan); 06758 06759 /* must be done without any channel locks held */ 06760 ast_do_masquerade(tmpchan); 06761 06762 /* when returning from bridge, the channel will continue at the next priority */ 06763 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 06764 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
ignore | unused var. |
Definition at line 4809 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_free, ast_poll, manage_parkinglot(), and parkinglots.
Referenced by ast_features_init().
04810 { 04811 struct pollfd *pfds = NULL, *new_pfds = NULL; 04812 int nfds = 0, new_nfds = 0; 04813 04814 for (;;) { 04815 struct ao2_iterator iter; 04816 struct ast_parkinglot *curlot; 04817 int ms = -1; /* poll2 timeout, uninitialized */ 04818 04819 iter = ao2_iterator_init(parkinglots, 0); 04820 while ((curlot = ao2_iterator_next(&iter))) { 04821 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms); 04822 ao2_ref(curlot, -1); 04823 } 04824 ao2_iterator_destroy(&iter); 04825 04826 /* Recycle */ 04827 ast_free(pfds); 04828 pfds = new_pfds; 04829 nfds = new_nfds; 04830 new_pfds = NULL; 04831 new_nfds = 0; 04832 04833 /* Wait for something to happen */ 04834 ast_poll(pfds, nfds, ms); 04835 pthread_testcancel(); 04836 } 04837 /* If this WERE reached, we'd need to free(pfds) */ 04838 return NULL; /* Never reached */ 04839 }
static int feature_check | ( | struct ast_channel * | chan, | |
struct ast_flags * | features, | |||
char * | code | |||
) | [static] |
Check if a feature exists.
Definition at line 3283 of file features.c.
References ast_channel_lock, ast_channel_unlock, ast_strdupa, FEATURE_INTERPRET_CHECK, feature_interpret_helper(), pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
03283 { 03284 char *chan_dynamic_features; 03285 ast_channel_lock(chan); 03286 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03287 ast_channel_unlock(chan); 03288 03289 return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL); 03290 }
static int feature_exec_app | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
exec an app by feature
chan,peer,config,code,sense,data | Find a feature, determine which channel activated |
AST_FEATURE_RETURN_NO_HANGUP_PEER | ||
-1 | error. | |
-2 | when an application cannot be found. |
Definition at line 3030 of file features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, AST_FRAME_DTMF_END, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, feature_group_exten::feature, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_channel::name, pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), and ast_call_feature::sname.
Referenced by process_applicationmap_line().
03031 { 03032 struct ast_app *app; 03033 struct ast_call_feature *feature = data; 03034 struct ast_channel *work, *idle; 03035 int res; 03036 03037 if (!feature) { /* shouldn't ever happen! */ 03038 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 03039 return -1; 03040 } 03041 03042 if (sense == FEATURE_SENSE_CHAN) { 03043 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 03044 return AST_FEATURE_RETURN_KEEPTRYING; 03045 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03046 work = chan; 03047 idle = peer; 03048 } else { 03049 work = peer; 03050 idle = chan; 03051 } 03052 } else { 03053 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 03054 return AST_FEATURE_RETURN_KEEPTRYING; 03055 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03056 work = peer; 03057 idle = chan; 03058 } else { 03059 work = chan; 03060 idle = peer; 03061 } 03062 } 03063 03064 if (!(app = pbx_findapp(feature->app))) { 03065 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 03066 return -2; 03067 } 03068 03069 ast_autoservice_start(idle); 03070 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END); 03071 03072 if(work && idle) { 03073 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name); 03074 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name); 03075 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname); 03076 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname); 03077 } 03078 03079 if (!ast_strlen_zero(feature->moh_class)) 03080 ast_moh_start(idle, feature->moh_class, NULL); 03081 03082 res = pbx_exec(work, app, feature->app_args); 03083 03084 if (!ast_strlen_zero(feature->moh_class)) 03085 ast_moh_stop(idle); 03086 03087 ast_autoservice_stop(idle); 03088 03089 if (res) { 03090 return AST_FEATURE_RETURN_SUCCESSBREAK; 03091 } 03092 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 03093 }
static int feature_interpret | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense | |||
) | [static] |
Check the dynamic features.
chan,peer,config,code,sense |
res | on success. | |
-1 | on failure. |
Definition at line 3248 of file features.c.
References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, config, feature_group_exten::feature, FEATURE_INTERPRET_DO, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
03248 { 03249 03250 char dynamic_features_buf[128]; 03251 const char *peer_dynamic_features, *chan_dynamic_features; 03252 struct ast_flags features; 03253 struct ast_call_feature feature; 03254 if (sense == FEATURE_SENSE_CHAN) { 03255 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 03256 } 03257 else { 03258 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 03259 } 03260 03261 ast_channel_lock(peer); 03262 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 03263 ast_channel_unlock(peer); 03264 03265 ast_channel_lock(chan); 03266 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03267 ast_channel_unlock(chan); 03268 03269 snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,"")); 03270 03271 ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf); 03272 03273 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature); 03274 }
static int feature_interpret_helper | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
char * | dynamic_features_buf, | |||
struct ast_flags * | features, | |||
feature_interpret_op | operation, | |||
struct ast_call_feature * | feature | |||
) | [static] |
Helper function for feature_interpret and ast_feature_detect.
chan,peer,config,code,sense,dynamic_features_buf,features,operation,feature | Lock features list, browse for code, unlock list If a feature is found and the operation variable is set, that feature's operation is executed. The first feature found is copied to the feature parameter. |
res | on success. | |
-1 | on failure. |
Definition at line 3133 of file features.c.
References ast_debug, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_STOREDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_strlen_zero(), ast_test_flag, ast_verb, builtin_features, config, feature_group_exten::entry, ast_call_feature::exten, feature_group_exten::exten, feature_group_exten::feature, FEATURE_INTERPRET_CHECK, FEATURE_INTERPRET_DO, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), find_group(), ast_call_feature::fname, ast_call_feature::operation, ast_call_feature::sname, and strsep().
Referenced by ast_feature_detect(), feature_check(), and feature_interpret().
03136 { 03137 int x; 03138 struct feature_group *fg = NULL; 03139 struct feature_group_exten *fge; 03140 struct ast_call_feature *tmpfeature; 03141 char *tmp, *tok; 03142 int res = AST_FEATURE_RETURN_PASSDIGITS; 03143 int feature_detected = 0; 03144 03145 if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) { 03146 return -1; /* can not run feature operation */ 03147 } 03148 03149 ast_rwlock_rdlock(&features_lock); 03150 for (x = 0; x < FEATURES_COUNT; x++) { 03151 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 03152 !ast_strlen_zero(builtin_features[x].exten)) { 03153 /* Feature is up for consideration */ 03154 if (!strcmp(builtin_features[x].exten, code)) { 03155 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 03156 if (operation == FEATURE_INTERPRET_CHECK) { 03157 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03158 } else if (operation == FEATURE_INTERPRET_DO) { 03159 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 03160 } 03161 if (feature) { 03162 memcpy(feature, &builtin_features[x], sizeof(feature)); 03163 } 03164 feature_detected = 1; 03165 break; 03166 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 03167 if (res == AST_FEATURE_RETURN_PASSDIGITS) { 03168 res = AST_FEATURE_RETURN_STOREDIGITS; 03169 } 03170 } 03171 } 03172 } 03173 ast_rwlock_unlock(&features_lock); 03174 03175 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 03176 return res; 03177 } 03178 03179 tmp = dynamic_features_buf; 03180 03181 while ((tok = strsep(&tmp, "#"))) { 03182 AST_RWLIST_RDLOCK(&feature_groups); 03183 03184 fg = find_group(tok); 03185 03186 if (fg) { 03187 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03188 if (!strcmp(fge->exten, code)) { 03189 if (operation) { 03190 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 03191 } 03192 memcpy(feature, fge->feature, sizeof(feature)); 03193 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03194 AST_RWLIST_UNLOCK(&feature_groups); 03195 break; 03196 } 03197 res = AST_FEATURE_RETURN_PASSDIGITS; 03198 } else if (!strncmp(fge->exten, code, strlen(code))) { 03199 res = AST_FEATURE_RETURN_STOREDIGITS; 03200 } 03201 } 03202 if (fge) { 03203 break; 03204 } 03205 } 03206 03207 AST_RWLIST_UNLOCK(&feature_groups); 03208 03209 AST_RWLIST_RDLOCK(&feature_list); 03210 03211 if (!(tmpfeature = find_dynamic_feature(tok))) { 03212 AST_RWLIST_UNLOCK(&feature_list); 03213 continue; 03214 } 03215 03216 /* Feature is up for consideration */ 03217 if (!strcmp(tmpfeature->exten, code)) { 03218 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 03219 if (operation == FEATURE_INTERPRET_CHECK) { 03220 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03221 } else if (operation == FEATURE_INTERPRET_DO) { 03222 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 03223 } 03224 if (feature) { 03225 memcpy(feature, tmpfeature, sizeof(feature)); 03226 } 03227 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03228 AST_RWLIST_UNLOCK(&feature_list); 03229 break; 03230 } 03231 res = AST_FEATURE_RETURN_PASSDIGITS; 03232 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 03233 res = AST_FEATURE_RETURN_STOREDIGITS; 03234 03235 AST_RWLIST_UNLOCK(&feature_list); 03236 } 03237 03238 return res; 03239 }
static struct ast_channel * feature_request_and_dial | ( | struct ast_channel * | caller, | |
const char * | caller_name, | |||
struct ast_channel * | requestor, | |||
struct ast_channel * | transferee, | |||
const char * | type, | |||
format_t | format, | |||
void * | data, | |||
int | timeout, | |||
int * | outstate, | |||
const char * | language | |||
) | [static] |
Definition at line 3387 of file features.c.
References ast_channel::_state, ast_autoservice_start(), ast_autoservice_stop(), ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_connected_line_macro(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_redirecting_macro(), ast_channel_set_connected_line(), ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), ast_connected_line_parse_data(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_INCOMPLETE, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_frisolate(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_is_deferrable_frame(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_party_connected_line_free(), ast_party_connected_line_set_init(), ast_poll_channel_add(), ast_poll_channel_del(), ast_queue_frame_head(), ast_read(), ast_request(), ast_rwlock_rdlock, ast_rwlock_unlock, AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), builtin_features, ast_channel::call_forward, ast_channel::caller, cause, connected, ast_channel::connected, ast_channel::exten, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_channel::hangupcause, LOG_NOTICE, ast_channel::name, and pbx_builtin_setvar_helper().
Referenced by builtin_atxfer().
03391 { 03392 int state = 0; 03393 int cause = 0; 03394 int to; 03395 int caller_hungup; 03396 int transferee_hungup; 03397 struct ast_channel *chan; 03398 struct ast_channel *monitor_chans[3]; 03399 struct ast_channel *active_channel; 03400 int res; 03401 int ready = 0; 03402 struct timeval started; 03403 int x, len = 0; 03404 char *disconnect_code = NULL, *dialed_code = NULL; 03405 struct ast_frame *f; 03406 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; 03407 03408 caller_hungup = ast_check_hangup(caller); 03409 03410 if (!(chan = ast_request(type, format, requestor, data, &cause))) { 03411 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 03412 switch (cause) { 03413 case AST_CAUSE_BUSY: 03414 state = AST_CONTROL_BUSY; 03415 break; 03416 case AST_CAUSE_CONGESTION: 03417 state = AST_CONTROL_CONGESTION; 03418 break; 03419 default: 03420 state = 0; 03421 break; 03422 } 03423 goto done; 03424 } 03425 03426 ast_string_field_set(chan, language, language); 03427 ast_channel_inherit_variables(caller, chan); 03428 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name); 03429 03430 ast_channel_lock(chan); 03431 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller); 03432 ast_channel_unlock(chan); 03433 03434 if (ast_call(chan, data, timeout)) { 03435 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 03436 switch (chan->hangupcause) { 03437 case AST_CAUSE_BUSY: 03438 state = AST_CONTROL_BUSY; 03439 break; 03440 case AST_CAUSE_CONGESTION: 03441 state = AST_CONTROL_CONGESTION; 03442 break; 03443 default: 03444 state = 0; 03445 break; 03446 } 03447 goto done; 03448 } 03449 03450 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 03451 ast_rwlock_rdlock(&features_lock); 03452 for (x = 0; x < FEATURES_COUNT; x++) { 03453 if (strcasecmp(builtin_features[x].sname, "disconnect")) 03454 continue; 03455 03456 disconnect_code = builtin_features[x].exten; 03457 len = strlen(disconnect_code) + 1; 03458 dialed_code = alloca(len); 03459 memset(dialed_code, 0, len); 03460 break; 03461 } 03462 ast_rwlock_unlock(&features_lock); 03463 x = 0; 03464 started = ast_tvnow(); 03465 to = timeout; 03466 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); 03467 03468 ast_poll_channel_add(caller, chan); 03469 03470 transferee_hungup = 0; 03471 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) { 03472 int num_chans = 0; 03473 03474 monitor_chans[num_chans++] = transferee; 03475 monitor_chans[num_chans++] = chan; 03476 if (!caller_hungup) { 03477 if (ast_check_hangup(caller)) { 03478 caller_hungup = 1; 03479 03480 #if defined(ATXFER_NULL_TECH) 03481 /* Change caller's name to ensure that it will remain unique. */ 03482 set_new_chan_name(caller); 03483 03484 /* 03485 * Get rid of caller's physical technology so it is free for 03486 * other calls. 03487 */ 03488 set_kill_chan_tech(caller); 03489 #endif /* defined(ATXFER_NULL_TECH) */ 03490 } else { 03491 /* caller is not hungup so monitor it. */ 03492 monitor_chans[num_chans++] = caller; 03493 } 03494 } 03495 03496 /* see if the timeout has been violated */ 03497 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 03498 state = AST_CONTROL_UNHOLD; 03499 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name); 03500 break; /*doh! timeout*/ 03501 } 03502 03503 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to); 03504 if (!active_channel) 03505 continue; 03506 03507 f = NULL; 03508 if (transferee == active_channel) { 03509 struct ast_frame *dup_f; 03510 03511 f = ast_read(transferee); 03512 if (f == NULL) { /*doh! where'd he go?*/ 03513 transferee_hungup = 1; 03514 state = 0; 03515 break; 03516 } 03517 if (ast_is_deferrable_frame(f)) { 03518 dup_f = ast_frisolate(f); 03519 if (dup_f) { 03520 if (dup_f == f) { 03521 f = NULL; 03522 } 03523 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); 03524 } 03525 } 03526 } else if (chan == active_channel) { 03527 if (!ast_strlen_zero(chan->call_forward)) { 03528 state = 0; 03529 ast_autoservice_start(transferee); 03530 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state); 03531 ast_autoservice_stop(transferee); 03532 if (!chan) { 03533 break; 03534 } 03535 continue; 03536 } 03537 f = ast_read(chan); 03538 if (f == NULL) { /*doh! where'd he go?*/ 03539 switch (chan->hangupcause) { 03540 case AST_CAUSE_BUSY: 03541 state = AST_CONTROL_BUSY; 03542 break; 03543 case AST_CAUSE_CONGESTION: 03544 state = AST_CONTROL_CONGESTION; 03545 break; 03546 default: 03547 state = 0; 03548 break; 03549 } 03550 break; 03551 } 03552 03553 if (f->frametype == AST_FRAME_CONTROL) { 03554 if (f->subclass.integer == AST_CONTROL_RINGING) { 03555 ast_verb(3, "%s is ringing\n", chan->name); 03556 ast_indicate(caller, AST_CONTROL_RINGING); 03557 } else if (f->subclass.integer == AST_CONTROL_BUSY) { 03558 state = f->subclass.integer; 03559 ast_verb(3, "%s is busy\n", chan->name); 03560 ast_indicate(caller, AST_CONTROL_BUSY); 03561 ast_frfree(f); 03562 break; 03563 } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) { 03564 ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", chan->name, chan->exten); 03565 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) { 03566 state = f->subclass.integer; 03567 ast_verb(3, "%s is congested\n", chan->name); 03568 ast_indicate(caller, AST_CONTROL_CONGESTION); 03569 ast_frfree(f); 03570 break; 03571 } else if (f->subclass.integer == AST_CONTROL_ANSWER) { 03572 /* This is what we are hoping for */ 03573 state = f->subclass.integer; 03574 ast_frfree(f); 03575 ready=1; 03576 break; 03577 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) { 03578 if (caller_hungup) { 03579 struct ast_party_connected_line connected; 03580 03581 /* Just save it for the transfer. */ 03582 ast_party_connected_line_set_init(&connected, &caller->connected); 03583 res = ast_connected_line_parse_data(f->data.ptr, f->datalen, 03584 &connected); 03585 if (!res) { 03586 ast_channel_set_connected_line(caller, &connected, NULL); 03587 } 03588 ast_party_connected_line_free(&connected); 03589 } else { 03590 ast_autoservice_start(transferee); 03591 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { 03592 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, 03593 f->data.ptr, f->datalen); 03594 } 03595 ast_autoservice_stop(transferee); 03596 } 03597 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) { 03598 if (!caller_hungup) { 03599 ast_autoservice_start(transferee); 03600 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { 03601 ast_indicate_data(caller, AST_CONTROL_REDIRECTING, 03602 f->data.ptr, f->datalen); 03603 } 03604 ast_autoservice_stop(transferee); 03605 } 03606 } else if (f->subclass.integer != -1 03607 && f->subclass.integer != AST_CONTROL_PROGRESS 03608 && f->subclass.integer != AST_CONTROL_PROCEEDING) { 03609 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer); 03610 } 03611 /* else who cares */ 03612 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03613 ast_write(caller, f); 03614 } 03615 } else if (caller == active_channel) { 03616 f = ast_read(caller); 03617 if (f) { 03618 if (f->frametype == AST_FRAME_DTMF) { 03619 dialed_code[x++] = f->subclass.integer; 03620 dialed_code[x] = '\0'; 03621 if (strlen(dialed_code) == len) { 03622 x = 0; 03623 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 03624 x = 0; 03625 dialed_code[x] = '\0'; 03626 } 03627 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 03628 /* Caller Canceled the call */ 03629 state = AST_CONTROL_UNHOLD; 03630 ast_frfree(f); 03631 break; 03632 } 03633 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03634 ast_write(chan, f); 03635 } 03636 } 03637 } 03638 if (f) 03639 ast_frfree(f); 03640 } /* end while */ 03641 03642 ast_poll_channel_del(caller, chan); 03643 03644 /* 03645 * We need to free all the deferred frames, but we only need to 03646 * queue the deferred frames if no hangup was received. 03647 */ 03648 ast_channel_lock(transferee); 03649 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee)); 03650 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { 03651 if (!transferee_hungup) { 03652 ast_queue_frame_head(transferee, f); 03653 } 03654 ast_frfree(f); 03655 } 03656 ast_channel_unlock(transferee); 03657 03658 done: 03659 ast_indicate(caller, -1); 03660 if (chan && (ready || chan->_state == AST_STATE_UP)) { 03661 state = AST_CONTROL_ANSWER; 03662 } else if (chan) { 03663 ast_hangup(chan); 03664 chan = NULL; 03665 } 03666 03667 if (outstate) 03668 *outstate = state; 03669 03670 return chan; 03671 }
static int find_channel_by_group | ( | void * | obj, | |
void * | arg, | |||
void * | data, | |||
int | flags | |||
) | [static] |
Definition at line 7152 of file features.c.
References ast_can_pickup(), ast_channel_lock, ast_channel_unlock, ast_channel::callgroup, CMP_MATCH, CMP_STOP, and ast_channel::pickupgroup.
07153 { 07154 struct ast_channel *target = obj;/*!< Potential pickup target */ 07155 struct ast_channel *chan = data;/*!< Channel wanting to pickup call */ 07156 07157 ast_channel_lock(target); 07158 if (chan != target && (chan->pickupgroup & target->callgroup) 07159 && ast_can_pickup(target)) { 07160 /* Return with the channel still locked on purpose */ 07161 return CMP_MATCH | CMP_STOP; 07162 } 07163 ast_channel_unlock(target); 07164 07165 return 0; 07166 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a call feature by name
Definition at line 2951 of file features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by feature_interpret_helper(), process_applicationmap_line(), and set_config_flags().
02952 { 02953 struct ast_call_feature *tmp; 02954 02955 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 02956 if (!strcasecmp(tmp->sname, name)) { 02957 break; 02958 } 02959 } 02960 02961 return tmp; 02962 }
static struct feature_group* find_group | ( | const char * | name | ) | [static] |
Find a group by name.
name | feature name |
feature | group on success. | |
NULL | on failure. |
Definition at line 2989 of file features.c.
References AST_LIST_TRAVERSE, feature_group_exten::entry, and feature_group::gname.
Referenced by feature_interpret_helper().
02990 { 02991 struct feature_group *fg = NULL; 02992 02993 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 02994 if (!strcasecmp(fg->gname, name)) 02995 break; 02996 } 02997 02998 return fg; 02999 }
static struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) | [static] |
Find parkinglot by name.
Definition at line 4842 of file features.c.
References ao2_find, ast_debug, ast_strlen_zero(), parkinglot, and parkinglots.
Referenced by ast_masq_park_call_exten(), ast_park_call_exten(), build_parkinglot(), copy_parkinglot(), create_dynamic_parkinglot(), manager_park(), park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().
04843 { 04844 struct ast_parkinglot *parkinglot; 04845 04846 if (ast_strlen_zero(name)) { 04847 return NULL; 04848 } 04849 04850 parkinglot = ao2_find(parkinglots, (void *) name, 0); 04851 if (parkinglot) { 04852 ast_debug(1, "Found Parking lot: %s\n", parkinglot->name); 04853 } 04854 04855 return parkinglot; 04856 }
static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 992 of file features.c.
References ast_strlen_zero(), name, ast_channel::parkinglot, and pbx_builtin_getvar_helper().
Referenced by park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().
00993 { 00994 const char *name; 00995 00996 /* The channel variable overrides everything */ 00997 name = pbx_builtin_getvar_helper(chan, "PARKINGLOT"); 00998 if (!name && !ast_strlen_zero(chan->parkinglot)) { 00999 /* Use the channel's parking lot. */ 01000 name = chan->parkinglot; 01001 } 01002 return name; 01003 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1769 of file features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by atxfer_fail_cleanup(), builtin_atxfer(), builtin_blindtransfer(), and xfer_park_call_helper().
01770 { 01771 ast_indicate(chan, AST_CONTROL_UNHOLD); 01772 01773 return ast_autoservice_stop(chan); 01774 }
static struct ast_exten* get_parking_exten | ( | const char * | exten_str, | |
struct ast_channel * | chan, | |||
const char * | context | |||
) | [static] |
Definition at line 773 of file features.c.
References ast_get_extension_app(), E_MATCH, feature_group_exten::exten, parkcall, pbx_find_extension(), and pbx_find_info::stacklen.
Referenced by ast_masq_park_call_exten(), ast_park_call_exten(), ast_parking_ext_valid(), builtin_atxfer(), and builtin_blindtransfer().
00774 { 00775 struct ast_exten *exten; 00776 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 00777 const char *app_at_exten; 00778 00779 exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, 00780 E_MATCH); 00781 if (!exten) { 00782 return NULL; 00783 } 00784 00785 app_at_exten = ast_get_extension_app(exten); 00786 if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) { 00787 return NULL; 00788 } 00789 00790 return exten; 00791 }
static char* handle_feature_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
CLI command to list configured features.
e | ||
cmd | ||
a |
CLI_SUCCESS | on success. | |
NULL | when tab completion is used. |
Definition at line 6616 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), AST_CLI_YESNO, AST_LIST_TRAVERSE, ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, builtin_features, ast_parkinglot::cfg, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, ast_parkinglot::disabled, feature_group_exten::entry, feature_group_exten::exten, ast_call_feature::exten, ast_cli_args::fd, feature_group_exten::feature, feature_group::features, FEATURES_COUNT, features_lock, ast_call_feature::fname, feature_group::gname, HFS_FORMAT, parkinglot_cfg::mohclass, ast_parkinglot::name, parkinglot_cfg::parkext, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglots, parkinglot_cfg::parkingtime, ast_call_feature::sname, and ast_cli_entry::usage.
06617 { 06618 int i; 06619 struct ast_call_feature *feature; 06620 struct ao2_iterator iter; 06621 struct ast_parkinglot *curlot; 06622 #define HFS_FORMAT "%-25s %-7s %-7s\n" 06623 06624 switch (cmd) { 06625 06626 case CLI_INIT: 06627 e->command = "features show"; 06628 e->usage = 06629 "Usage: features show\n" 06630 " Lists configured features\n"; 06631 return NULL; 06632 case CLI_GENERATE: 06633 return NULL; 06634 } 06635 06636 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 06637 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06638 06639 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 06640 06641 ast_rwlock_rdlock(&features_lock); 06642 for (i = 0; i < FEATURES_COUNT; i++) 06643 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 06644 ast_rwlock_unlock(&features_lock); 06645 06646 ast_cli(a->fd, "\n"); 06647 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 06648 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06649 if (AST_RWLIST_EMPTY(&feature_list)) { 06650 ast_cli(a->fd, "(none)\n"); 06651 } else { 06652 AST_RWLIST_RDLOCK(&feature_list); 06653 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 06654 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 06655 } 06656 AST_RWLIST_UNLOCK(&feature_list); 06657 } 06658 06659 ast_cli(a->fd, "\nFeature Groups:\n"); 06660 ast_cli(a->fd, "---------------\n"); 06661 if (AST_RWLIST_EMPTY(&feature_groups)) { 06662 ast_cli(a->fd, "(none)\n"); 06663 } else { 06664 struct feature_group *fg; 06665 struct feature_group_exten *fge; 06666 06667 AST_RWLIST_RDLOCK(&feature_groups); 06668 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 06669 ast_cli(a->fd, "===> Group: %s\n", fg->gname); 06670 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 06671 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten); 06672 } 06673 } 06674 AST_RWLIST_UNLOCK(&feature_groups); 06675 } 06676 06677 iter = ao2_iterator_init(parkinglots, 0); 06678 while ((curlot = ao2_iterator_next(&iter))) { 06679 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 06680 ast_cli(a->fd, "------------\n"); 06681 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->cfg.parkext); 06682 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->cfg.parking_con); 06683 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", 06684 curlot->cfg.parking_start, curlot->cfg.parking_stop); 06685 ast_cli(a->fd,"%-22s: %d ms\n", "Parkingtime", curlot->cfg.parkingtime); 06686 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->cfg.mohclass); 06687 ast_cli(a->fd,"%-22s: %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled)); 06688 ast_cli(a->fd,"\n"); 06689 ao2_ref(curlot, -1); 06690 } 06691 ao2_iterator_destroy(&iter); 06692 06693 return CLI_SUCCESS; 06694 }
static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6722 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
06723 { 06724 switch (cmd) { 06725 case CLI_INIT: 06726 e->command = "features reload"; 06727 e->usage = 06728 "Usage: features reload\n" 06729 " Reloads configured call features from features.conf\n"; 06730 return NULL; 06731 case CLI_GENERATE: 06732 return NULL; 06733 } 06734 ast_features_reload(); 06735 06736 return CLI_SUCCESS; 06737 }
static char* handle_parkedcalls | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
CLI command to list parked calls.
e | ||
cmd | ||
a | Check right usage, lock parking lot, display parked calls, unlock parking lot list. |
CLI_SUCCESS | on success. | |
CLI_SHOWUSAGE | on incorrect number of arguments. | |
NULL | when tab completion is used. |
Definition at line 6905 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_entry::args, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, parkeduser::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, parkeduser::context, default_parkinglot, ESS, parkeduser::exten, ast_cli_args::fd, ast_channel::name, ast_parkinglot::name, parkeduser::parkingexten, parkinglots, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.
06906 { 06907 struct parkeduser *cur; 06908 int numparked = 0; 06909 struct ao2_iterator iter; 06910 struct ast_parkinglot *curlot; 06911 06912 switch (cmd) { 06913 case CLI_INIT: 06914 e->command = "parkedcalls show"; 06915 e->usage = 06916 "Usage: parkedcalls show\n" 06917 " List currently parked calls\n"; 06918 return NULL; 06919 case CLI_GENERATE: 06920 return NULL; 06921 } 06922 06923 if (a->argc > e->args) 06924 return CLI_SHOWUSAGE; 06925 06926 ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel", 06927 "Context", "Extension", "Pri", "Timeout"); 06928 06929 iter = ao2_iterator_init(parkinglots, 0); 06930 while ((curlot = ao2_iterator_next(&iter))) { 06931 int lotparked = 0; 06932 06933 /* subtract ref for iterator and for configured parking lot */ 06934 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, 06935 ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot)); 06936 06937 AST_LIST_LOCK(&curlot->parkings); 06938 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 06939 ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n", 06940 cur->parkingexten, cur->chan->name, cur->context, cur->exten, 06941 cur->priority, 06942 (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL))); 06943 ++lotparked; 06944 } 06945 AST_LIST_UNLOCK(&curlot->parkings); 06946 if (lotparked) { 06947 numparked += lotparked; 06948 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, 06949 ESS(lotparked), curlot->name); 06950 } 06951 06952 ao2_ref(curlot, -1); 06953 } 06954 ao2_iterator_destroy(&iter); 06955 06956 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 06957 06958 return CLI_SUCCESS; 06959 }
static int load_config | ( | int | reload | ) | [static] |
Definition at line 6533 of file features.c.
References ao2_t_callback, ast_config_destroy(), ast_config_load2(), ast_debug, AST_LIST_HEAD_NOLOCK_INIT_VALUE, ast_log(), build_dialplan_useage_map(), build_parkinglot(), CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_PARKINGLOT, default_parkinglot, destroy_dialplan_usage_map(), force_reload_load, LOG_ERROR, LOG_WARNING, OBJ_NODATA, OBJ_UNLINK, parkinglot_activate_cb(), parkinglot_addref(), parkinglot_is_marked_cb(), parkinglot_markall_cb(), parkinglots, process_config(), and remove_dead_dialplan_useage().
06534 { 06535 struct ast_flags config_flags = { 06536 reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06537 struct ast_config *cfg; 06538 struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06539 struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06540 06541 /* We are reloading now and have already determined if we will force the reload. */ 06542 force_reload_load = 0; 06543 06544 if (!default_parkinglot) { 06545 /* Must create the default default parking lot */ 06546 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 06547 if (!default_parkinglot) { 06548 ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n"); 06549 return -1; 06550 } 06551 ast_debug(1, "Configuration of default default parking lot done.\n"); 06552 parkinglot_addref(default_parkinglot); 06553 } 06554 06555 cfg = ast_config_load2("features.conf", "features", config_flags); 06556 if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06557 /* No sense in asking for reload trouble if nothing changed. */ 06558 ast_debug(1, "features.conf did not change.\n"); 06559 return 0; 06560 } 06561 if (cfg == CONFIG_STATUS_FILEMISSING 06562 || cfg == CONFIG_STATUS_FILEINVALID) { 06563 ast_log(LOG_WARNING, "Could not load features.conf\n"); 06564 return 0; 06565 } 06566 06567 /* Save current parking lot dialplan needs. */ 06568 if (build_dialplan_useage_map(&old_usage_map, 0)) { 06569 destroy_dialplan_usage_map(&old_usage_map); 06570 06571 /* Allow reloading later to see if conditions have improved. */ 06572 force_reload_load = 1; 06573 return -1; 06574 } 06575 06576 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, 06577 "callback to mark all parking lots"); 06578 process_config(cfg); 06579 ast_config_destroy(cfg); 06580 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, 06581 "callback to remove marked parking lots"); 06582 06583 /* Save updated parking lot dialplan needs. */ 06584 if (build_dialplan_useage_map(&new_usage_map, 1)) { 06585 /* 06586 * Yuck, if this failure caused any parking lot dialplan items 06587 * to be lost, they will likely remain lost until Asterisk is 06588 * restarted. 06589 */ 06590 destroy_dialplan_usage_map(&old_usage_map); 06591 destroy_dialplan_usage_map(&new_usage_map); 06592 return -1; 06593 } 06594 06595 /* Remove no longer needed parking lot dialplan usage. */ 06596 remove_dead_dialplan_useage(&old_usage_map, &new_usage_map); 06597 06598 destroy_dialplan_usage_map(&old_usage_map); 06599 destroy_dialplan_usage_map(&new_usage_map); 06600 06601 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL, 06602 "callback to activate all parking lots"); 06603 06604 return 0; 06605 }
static int manage_parked_call | ( | struct parkeduser * | pu, | |
const struct pollfd * | pfds, | |||
int | nfds, | |||
struct pollfd ** | new_pfds, | |||
int * | new_nfds, | |||
int * | ms | |||
) | [static] |
Definition at line 4548 of file features.c.
References ast_add_extension(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_debug, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, ast_pbx_start(), ast_read(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, callback_dialoptions(), ast_parkinglot::cfg, parkeduser::chan, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, ast_channel::generatordata, parkeduser::hold_method, LOG_ERROR, LOG_NOTICE, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, parkinglot_cfg::mohclass, ast_parkinglot::name, ast_channel::name, parkeduser::options_specified, parking_con_dial, parkeduser::parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), and parkeduser::start.
Referenced by manage_parkinglot().
04549 { 04550 struct ast_channel *chan = pu->chan; /* shorthand */ 04551 int tms; /* timeout for this item */ 04552 int x; /* fd index in channel */ 04553 int parking_complete = 0; 04554 04555 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 04556 if (tms > pu->parkingtime) { 04557 /* 04558 * Call has been parked too long. 04559 * Stop entertaining the caller. 04560 */ 04561 switch (pu->hold_method) { 04562 case AST_CONTROL_HOLD: 04563 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 04564 break; 04565 case AST_CONTROL_RINGING: 04566 ast_indicate(pu->chan, -1); 04567 break; 04568 default: 04569 break; 04570 } 04571 pu->hold_method = 0; 04572 04573 /* Get chan, exten from derived kludge */ 04574 if (pu->peername[0]) { 04575 char *peername; 04576 char *dash; 04577 char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 04578 int i; 04579 04580 peername = ast_strdupa(pu->peername); 04581 dash = strrchr(peername, '-'); 04582 if (dash) { 04583 *dash = '\0'; 04584 } 04585 04586 peername_flat = ast_strdupa(peername); 04587 for (i = 0; peername_flat[i]; i++) { 04588 if (peername_flat[i] == '/') { 04589 peername_flat[i] = '_'; 04590 } 04591 } 04592 04593 if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) { 04594 ast_log(LOG_ERROR, 04595 "Parking dial context '%s' does not exist and unable to create\n", 04596 parking_con_dial); 04597 } else { 04598 char returnexten[AST_MAX_EXTENSION]; 04599 struct ast_datastore *features_datastore; 04600 struct ast_dial_features *dialfeatures; 04601 04602 if (!strncmp(peername, "Parked/", 7)) { 04603 peername += 7; 04604 } 04605 04606 ast_channel_lock(chan); 04607 features_datastore = ast_channel_datastore_find(chan, &dial_features_info, 04608 NULL); 04609 if (features_datastore && (dialfeatures = features_datastore->data)) { 04610 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 04611 04612 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, 04613 callback_dialoptions(&(dialfeatures->features_callee), 04614 &(dialfeatures->features_caller), buf, sizeof(buf))); 04615 } else { /* Existing default */ 04616 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", 04617 chan->name); 04618 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername); 04619 } 04620 ast_channel_unlock(chan); 04621 04622 if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL, 04623 "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) { 04624 ast_log(LOG_ERROR, 04625 "Could not create parking return dial exten: %s@%s\n", 04626 peername_flat, parking_con_dial); 04627 } 04628 } 04629 if (pu->options_specified) { 04630 /* 04631 * Park() was called with overriding return arguments, respect 04632 * those arguments. 04633 */ 04634 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04635 } else if (comebacktoorigin) { 04636 set_c_e_p(chan, parking_con_dial, peername_flat, 1); 04637 } else { 04638 char parkingslot[AST_MAX_EXTENSION]; 04639 04640 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 04641 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 04642 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 04643 } 04644 } else { 04645 /* 04646 * They've been waiting too long, send them back to where they 04647 * came. Theoretically they should have their original 04648 * extensions and such, but we copy to be on the safe side. 04649 */ 04650 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04651 } 04652 post_manager_event("ParkedCallTimeOut", pu); 04653 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL); 04654 04655 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", 04656 pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, 04657 pu->chan->exten, pu->chan->priority); 04658 04659 /* Start up the PBX, or hang them up */ 04660 if (ast_pbx_start(chan)) { 04661 ast_log(LOG_WARNING, 04662 "Unable to restart the PBX for user on '%s', hanging them up...\n", 04663 pu->chan->name); 04664 ast_hangup(chan); 04665 } 04666 04667 /* And take them out of the parking lot */ 04668 parking_complete = 1; 04669 } else { /* still within parking time, process descriptors */ 04670 for (x = 0; x < AST_MAX_FDS; x++) { 04671 struct ast_frame *f; 04672 int y; 04673 04674 if (chan->fds[x] == -1) { 04675 continue; /* nothing on this descriptor */ 04676 } 04677 04678 for (y = 0; y < nfds; y++) { 04679 if (pfds[y].fd == chan->fds[x]) { 04680 /* Found poll record! */ 04681 break; 04682 } 04683 } 04684 if (y == nfds) { 04685 /* Not found */ 04686 continue; 04687 } 04688 04689 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) { 04690 /* Next x */ 04691 continue; 04692 } 04693 04694 if (pfds[y].revents & POLLPRI) { 04695 ast_set_flag(chan, AST_FLAG_EXCEPTION); 04696 } else { 04697 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 04698 } 04699 chan->fdno = x; 04700 04701 /* See if they need servicing */ 04702 f = ast_read(pu->chan); 04703 /* Hangup? */ 04704 if (!f || (f->frametype == AST_FRAME_CONTROL 04705 && f->subclass.integer == AST_CONTROL_HANGUP)) { 04706 if (f) { 04707 ast_frfree(f); 04708 } 04709 post_manager_event("ParkedCallGiveUp", pu); 04710 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", 04711 NULL); 04712 04713 /* There's a problem, hang them up */ 04714 ast_verb(2, "%s got tired of being parked\n", chan->name); 04715 ast_hangup(chan); 04716 04717 /* And take them out of the parking lot */ 04718 parking_complete = 1; 04719 break; 04720 } else { 04721 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 04722 ast_frfree(f); 04723 if (pu->hold_method == AST_CONTROL_HOLD 04724 && pu->moh_trys < 3 04725 && !chan->generatordata) { 04726 ast_debug(1, 04727 "MOH on parked call stopped by outside source. Restarting on channel %s.\n", 04728 chan->name); 04729 ast_indicate_data(chan, AST_CONTROL_HOLD, 04730 S_OR(pu->parkinglot->cfg.mohclass, NULL), 04731 (!ast_strlen_zero(pu->parkinglot->cfg.mohclass) 04732 ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0)); 04733 pu->moh_trys++; 04734 } 04735 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 04736 } 04737 } /* End for */ 04738 if (x >= AST_MAX_FDS) { 04739 std: for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */ 04740 if (chan->fds[x] > -1) { 04741 void *tmp = ast_realloc(*new_pfds, 04742 (*new_nfds + 1) * sizeof(struct pollfd)); 04743 04744 if (!tmp) { 04745 continue; 04746 } 04747 *new_pfds = tmp; 04748 (*new_pfds)[*new_nfds].fd = chan->fds[x]; 04749 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI; 04750 (*new_pfds)[*new_nfds].revents = 0; 04751 (*new_nfds)++; 04752 } 04753 } 04754 /* Keep track of our shortest wait */ 04755 if (tms < *ms || *ms < 0) { 04756 *ms = tms; 04757 } 04758 } 04759 } 04760 04761 return parking_complete; 04762 }
static void manage_parkinglot | ( | struct ast_parkinglot * | curlot, | |
const struct pollfd * | pfds, | |||
int | nfds, | |||
struct pollfd ** | new_pfds, | |||
int * | new_nfds, | |||
int * | ms | |||
) | [static] |
Run management on parkinglots, called once per parkinglot.
Definition at line 4765 of file features.c.
References ast_context_find(), ast_context_remove_extension2(), AST_DEVICE_NOT_INUSE, ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_parkinglot::cfg, LOG_WARNING, manage_parked_call(), ast_parkinglot::name, notify_metermaids(), parkeduser::notquiteyet, parkinglot_cfg::parking_con, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_unref(), and ast_parkinglot::parkings.
Referenced by do_parking_thread().
04766 { 04767 struct parkeduser *pu; 04768 struct ast_context *con; 04769 04770 /* Lock parkings list */ 04771 AST_LIST_LOCK(&curlot->parkings); 04772 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 04773 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 04774 continue; 04775 } 04776 if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) { 04777 /* Parking is complete for this call so remove it from the parking lot. */ 04778 con = ast_context_find(pu->parkinglot->cfg.parking_con); 04779 if (con) { 04780 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 04781 ast_log(LOG_WARNING, 04782 "Whoa, failed to remove the parking extension %s@%s!\n", 04783 pu->parkingexten, pu->parkinglot->cfg.parking_con); 04784 } 04785 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, 04786 AST_DEVICE_NOT_INUSE); 04787 } else { 04788 ast_log(LOG_WARNING, 04789 "Whoa, parking lot '%s' context '%s' does not exist.\n", 04790 pu->parkinglot->name, pu->parkinglot->cfg.parking_con); 04791 } 04792 AST_LIST_REMOVE_CURRENT(list); 04793 parkinglot_unref(pu->parkinglot); 04794 ast_free(pu); 04795 } 04796 } 04797 AST_LIST_TRAVERSE_SAFE_END; 04798 AST_LIST_UNLOCK(&curlot->parkings); 04799 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Create manager event for parked calls.
s | ||
m | Get channels involved in park, create event. |
Definition at line 7041 of file features.c.
References args, ast_channel_get_by_name(), ast_channel_unref, AST_PARK_OPT_SILENCE, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), find_parkinglot(), masq_park_call(), and parkinglot_unref().
Referenced by ast_features_init().
07042 { 07043 const char *channel = astman_get_header(m, "Channel"); 07044 const char *channel2 = astman_get_header(m, "Channel2"); 07045 const char *timeout = astman_get_header(m, "Timeout"); 07046 const char *parkinglotname = astman_get_header(m, "Parkinglot"); 07047 char buf[BUFSIZ]; 07048 int res = 0; 07049 struct ast_channel *ch1, *ch2; 07050 struct ast_park_call_args args = { 07051 /* 07052 * Don't say anything to ch2 since AMI is a third party parking 07053 * a call and we will likely crash if we do. 07054 * 07055 * XXX When the AMI action was originally implemented, the 07056 * parking space was announced to ch2. Unfortunately, grabbing 07057 * the ch2 lock and holding it while the announcement is played 07058 * was not really a good thing to do to begin with since it 07059 * could hold up the system. Also holding the lock is no longer 07060 * possible with a masquerade. 07061 * 07062 * Restoring the announcement to ch2 is not easily doable for 07063 * the following reasons: 07064 * 07065 * 1) The AMI manager is not the thread processing ch2. 07066 * 07067 * 2) ch2 could be the same as ch1, bridged to ch1, or some 07068 * random uninvolved channel. 07069 */ 07070 .flags = AST_PARK_OPT_SILENCE, 07071 }; 07072 07073 if (ast_strlen_zero(channel)) { 07074 astman_send_error(s, m, "Channel not specified"); 07075 return 0; 07076 } 07077 07078 if (ast_strlen_zero(channel2)) { 07079 astman_send_error(s, m, "Channel2 not specified"); 07080 return 0; 07081 } 07082 07083 if (!ast_strlen_zero(timeout)) { 07084 if (sscanf(timeout, "%30d", &args.timeout) != 1) { 07085 astman_send_error(s, m, "Invalid timeout value."); 07086 return 0; 07087 } 07088 } 07089 07090 if (!(ch1 = ast_channel_get_by_name(channel))) { 07091 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 07092 astman_send_error(s, m, buf); 07093 return 0; 07094 } 07095 07096 if (!(ch2 = ast_channel_get_by_name(channel2))) { 07097 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 07098 astman_send_error(s, m, buf); 07099 ast_channel_unref(ch1); 07100 return 0; 07101 } 07102 07103 if (!ast_strlen_zero(parkinglotname)) { 07104 args.parkinglot = find_parkinglot(parkinglotname); 07105 } 07106 07107 res = masq_park_call(ch1, ch2, &args); 07108 if (!res) { 07109 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 07110 astman_send_ack(s, m, "Park successful"); 07111 } else { 07112 astman_send_error(s, m, "Park failure"); 07113 } 07114 07115 if (args.parkinglot) { 07116 parkinglot_unref(args.parkinglot); 07117 } 07118 ch1 = ast_channel_unref(ch1); 07119 ch2 = ast_channel_unref(ch2); 07120 07121 return 0; 07122 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump parking lot status.
s | ||
m | Lock parking lot, iterate list and append parked calls status, unlock parking lot. |
Definition at line 6975 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::caller, parkeduser::chan, ast_channel::connected, ast_party_connected_line::id, ast_party_caller::id, ast_party_id::name, ast_channel::name, ast_parkinglot::name, ast_party_id::number, parkinglots, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, S_COR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.
Referenced by ast_features_init().
06976 { 06977 struct parkeduser *cur; 06978 const char *id = astman_get_header(m, "ActionID"); 06979 char idText[256] = ""; 06980 struct ao2_iterator iter; 06981 struct ast_parkinglot *curlot; 06982 int numparked = 0; 06983 06984 if (!ast_strlen_zero(id)) 06985 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 06986 06987 astman_send_ack(s, m, "Parked calls will follow"); 06988 06989 iter = ao2_iterator_init(parkinglots, 0); 06990 while ((curlot = ao2_iterator_next(&iter))) { 06991 AST_LIST_LOCK(&curlot->parkings); 06992 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 06993 astman_append(s, "Event: ParkedCall\r\n" 06994 "Parkinglot: %s\r\n" 06995 "Exten: %d\r\n" 06996 "Channel: %s\r\n" 06997 "From: %s\r\n" 06998 "Timeout: %ld\r\n" 06999 "CallerIDNum: %s\r\n" 07000 "CallerIDName: %s\r\n" 07001 "ConnectedLineNum: %s\r\n" 07002 "ConnectedLineName: %s\r\n" 07003 "%s" 07004 "\r\n", 07005 curlot->name, 07006 cur->parkingnum, cur->chan->name, cur->peername, 07007 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 07008 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""), /* XXX in other places it is <unknown> */ 07009 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""), 07010 S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""), /* XXX in other places it is <unknown> */ 07011 S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""), 07012 idText); 07013 ++numparked; 07014 } 07015 AST_LIST_UNLOCK(&curlot->parkings); 07016 ao2_ref(curlot, -1); 07017 } 07018 ao2_iterator_destroy(&iter); 07019 07020 astman_append(s, 07021 "Event: ParkedCallsComplete\r\n" 07022 "Total: %d\r\n" 07023 "%s" 07024 "\r\n", 07025 numparked, idText); 07026 07027 return RESULT_SUCCESS; 07028 }
static int masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Park call via masqueraded channel and announce parking spot on peer channel.
rchan | the real channel to be parked | |
peer | the channel to have the parking read to. | |
args | Additional parking options when parking a call. |
0 | on success. | |
-1 | on failure. |
Definition at line 1625 of file features.c.
References ast_channel::accountcode, ast_channel::amaflags, args, ast_channel_alloc, ast_channel_masquerade(), ast_copy_string(), ast_do_masquerade(), ast_hangup(), ast_log(), AST_PARK_OPT_SILENCE, AST_STATE_DOWN, ast_stream_and_wait(), ast_test_flag, ast_channel::context, ast_channel::exten, ast_channel::linkedid, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, ast_channel::name, park_call_full(), park_space_abort(), park_space_reserve(), play_message_on_chan(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.
Referenced by ast_masq_park_call(), ast_masq_park_call_exten(), builtin_parkcall(), manager_park(), park_call_exec(), and xfer_park_call_helper().
01626 { 01627 struct ast_channel *chan; 01628 01629 /* Make a new, channel that we'll use to masquerade in the real one */ 01630 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, 01631 rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s", rchan->name); 01632 if (!chan) { 01633 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 01634 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01635 if (peer == rchan) { 01636 /* Only have one channel to worry about. */ 01637 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01638 } else if (peer) { 01639 /* Have two different channels to worry about. */ 01640 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01641 } 01642 } 01643 return -1; 01644 } 01645 01646 args->pu = park_space_reserve(rchan, peer, args); 01647 if (!args->pu) { 01648 ast_hangup(chan); 01649 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01650 if (peer == rchan) { 01651 /* Only have one channel to worry about. */ 01652 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01653 } else if (peer) { 01654 /* Have two different channels to worry about. */ 01655 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01656 } 01657 } 01658 return -1; 01659 } 01660 01661 /* Make formats okay */ 01662 chan->readformat = rchan->readformat; 01663 chan->writeformat = rchan->writeformat; 01664 01665 if (ast_channel_masquerade(chan, rchan)) { 01666 park_space_abort(args->pu); 01667 args->pu = NULL; 01668 ast_hangup(chan); 01669 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01670 if (peer == rchan) { 01671 /* Only have one channel to worry about. */ 01672 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01673 } else if (peer) { 01674 /* Have two different channels to worry about. */ 01675 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01676 } 01677 } 01678 return -1; 01679 } 01680 01681 /* Setup the extensions and such */ 01682 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 01683 01684 /* Setup the macro extension and such */ 01685 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext)); 01686 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten)); 01687 chan->macropriority = rchan->macropriority; 01688 01689 /* Manually do the masquerade to make sure it is complete. */ 01690 ast_do_masquerade(chan); 01691 01692 if (peer == rchan) { 01693 peer = chan; 01694 } 01695 01696 /* parking space reserved, return code check unnecessary */ 01697 park_call_full(chan, peer, args); 01698 01699 return 0; 01700 }
static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 1015 of file features.c.
References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_strdupa, and strsep().
Referenced by ast_features_init().
01016 { 01017 char *context; 01018 char *exten; 01019 01020 context = ast_strdupa(data); 01021 01022 exten = strsep(&context, "@"); 01023 if (!context) 01024 return AST_DEVICE_INVALID; 01025 01026 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 01027 01028 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 01029 return AST_DEVICE_NOT_INUSE; 01030 01031 return AST_DEVICE_INUSE; 01032 }
static void notify_metermaids | ( | const char * | exten, | |
char * | context, | |||
enum ast_device_state | state | |||
) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 1006 of file features.c.
References ast_debug, ast_devstate2str(), and ast_devstate_changed().
Referenced by manage_parkinglot(), park_call_full(), parked_call_exec(), and parkinglot_activate().
01007 { 01008 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 01009 exten, context, ast_devstate2str(state)); 01010 01011 ast_devstate_changed(state, "park:%s@%s", exten, context); 01012 }
static void park_add_hints | ( | const char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Add parking hints for all defined parking spaces.
context | Dialplan context to add the hints. | |
start | Starting space in parkinglot. | |
stop | Ending space in parkinglot. |
Definition at line 5308 of file features.c.
References ast_add_extension(), AST_MAX_EXTENSION, PRIORITY_HINT, and registrar.
Referenced by parkinglot_activate().
05309 { 05310 int numext; 05311 char device[AST_MAX_EXTENSION]; 05312 char exten[10]; 05313 05314 for (numext = start; numext <= stop; numext++) { 05315 snprintf(exten, sizeof(exten), "%d", numext); 05316 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 05317 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 05318 } 05319 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Park a call.
Definition at line 4888 of file features.c.
References ast_channel::_state, args, ast_answer(), ast_app_parse_options(), ast_copy_string(), ast_log(), AST_MAX_EXTENSION, AST_PARK_OPT_SILENCE, ast_safe_sleep(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, create_dynamic_parkinglot(), default_parkinglot, ast_channel::exten, find_parkinglot(), findparkinglotname(), ast_flags::flags, LOG_WARNING, masq_park_call(), ast_channel::name, park_app_args::options, orig_exten(), park_call_options, parkeddynamic, parkinglot_addref(), parkinglot_unref(), parse(), park_app_args::pl_name, ast_channel::priority, park_app_args::return_con, park_app_args::return_ext, park_app_args::return_pri, and park_app_args::timeout.
Referenced by ast_features_init().
04889 { 04890 /* Cache the original channel name in case we get masqueraded in the middle 04891 * of a park--it is still theoretically possible for a transfer to happen before 04892 * we get here, but it is _really_ unlikely */ 04893 char *orig_chan_name = ast_strdupa(chan->name); 04894 struct ast_park_call_args args = { 04895 .orig_chan_name = orig_chan_name, 04896 }; 04897 struct ast_flags flags = { 0 }; 04898 char orig_exten[AST_MAX_EXTENSION]; 04899 int orig_priority; 04900 int res; 04901 const char *pl_name; 04902 char *parse; 04903 struct park_app_args app_args; 04904 04905 /* Answer if call is not up */ 04906 if (chan->_state != AST_STATE_UP) { 04907 if (ast_answer(chan)) { 04908 return -1; 04909 } 04910 04911 /* Sleep to allow VoIP streams to settle down */ 04912 if (ast_safe_sleep(chan, 1000)) { 04913 return -1; 04914 } 04915 } 04916 04917 /* Process the dialplan application options. */ 04918 parse = ast_strdupa(data); 04919 AST_STANDARD_APP_ARGS(app_args, parse); 04920 04921 if (!ast_strlen_zero(app_args.timeout)) { 04922 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) { 04923 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 04924 args.timeout = 0; 04925 } 04926 } 04927 if (!ast_strlen_zero(app_args.return_con)) { 04928 args.return_con = app_args.return_con; 04929 } 04930 if (!ast_strlen_zero(app_args.return_ext)) { 04931 args.return_ext = app_args.return_ext; 04932 } 04933 if (!ast_strlen_zero(app_args.return_pri)) { 04934 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) { 04935 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 04936 args.return_pri = 0; 04937 } 04938 } 04939 04940 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 04941 args.flags = flags.flags; 04942 04943 /* 04944 * Setup the exten/priority to be s/1 since we don't know where 04945 * this call should return. 04946 */ 04947 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 04948 orig_priority = chan->priority; 04949 strcpy(chan->exten, "s"); 04950 chan->priority = 1; 04951 04952 /* Park the call */ 04953 if (!ast_strlen_zero(app_args.pl_name)) { 04954 pl_name = app_args.pl_name; 04955 } else { 04956 pl_name = findparkinglotname(chan); 04957 } 04958 if (ast_strlen_zero(pl_name)) { 04959 /* Parking lot is not specified, so use the default parking lot. */ 04960 args.parkinglot = parkinglot_addref(default_parkinglot); 04961 } else { 04962 args.parkinglot = find_parkinglot(pl_name); 04963 if (!args.parkinglot && parkeddynamic) { 04964 args.parkinglot = create_dynamic_parkinglot(pl_name, chan); 04965 } 04966 } 04967 if (args.parkinglot) { 04968 res = masq_park_call(chan, chan, &args); 04969 parkinglot_unref(args.parkinglot); 04970 } else { 04971 /* Parking failed because the parking lot does not exist. */ 04972 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { 04973 ast_stream_and_wait(chan, "pbx-parkingfailed", ""); 04974 } 04975 res = -1; 04976 } 04977 if (res) { 04978 /* Park failed, try to continue in the dialplan. */ 04979 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 04980 chan->priority = orig_priority; 04981 res = 0; 04982 } else { 04983 /* Park succeeded. */ 04984 res = -1; 04985 } 04986 04987 return res; 04988 }
static int park_call_full | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 1380 of file features.c.
References adsi_announce_park(), adsipark, ast_channel::appl, args, ast_add_extension(), ast_adsi_available(), ast_adsi_unload_session(), ast_bridged_channel(), AST_CEL_PARK_START, ast_cel_report_event(), ast_channel_get_by_name(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_unlock, ast_channel_unref, ast_clear_flag, AST_CONTROL_HOLD, AST_CONTROL_RINGING, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), ast_manager_event, AST_MAX_CONTEXT, AST_MAX_EXTENSION, AST_PARK_OPT_RINGING, AST_PARK_OPT_SILENCE, ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, ast_channel::caller, ast_parkinglot::cfg, parkeduser::chan, ast_channel::connected, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, parkeduser::hold_method, ast_party_connected_line::id, ast_party_caller::id, ast_channel::language, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, parkinglot_cfg::mohclass, ast_party_id::name, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkeduser::options_specified, park_space_reserve(), parkinglot_cfg::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, parkinglot_cfg::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, registrar, S_COR, S_OR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_channel::tech, ast_channel_tech::type, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.
Referenced by ast_park_call(), ast_park_call_exten(), and masq_park_call().
01381 { 01382 struct parkeduser *pu = args->pu; 01383 const char *event_from; 01384 char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT]; 01385 01386 if (pu == NULL) { 01387 args->pu = pu = park_space_reserve(chan, peer, args); 01388 if (pu == NULL) { 01389 return -1; 01390 } 01391 } 01392 01393 chan->appl = "Parked Call"; 01394 chan->data = NULL; 01395 01396 pu->chan = chan; 01397 01398 /* Put the parked channel on hold if we have two different channels */ 01399 if (chan != peer) { 01400 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 01401 pu->hold_method = AST_CONTROL_RINGING; 01402 ast_indicate(pu->chan, AST_CONTROL_RINGING); 01403 } else { 01404 pu->hold_method = AST_CONTROL_HOLD; 01405 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01406 S_OR(pu->parkinglot->cfg.mohclass, NULL), 01407 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0); 01408 } 01409 } 01410 01411 pu->start = ast_tvnow(); 01412 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->cfg.parkingtime; 01413 if (args->extout) 01414 *(args->extout) = pu->parkingnum; 01415 01416 if (peer) { 01417 /* 01418 * This is so ugly that it hurts, but implementing 01419 * get_base_channel() on local channels could have ugly side 01420 * effects. We could have 01421 * transferer<->local,1<->local,2<->parking and we need the 01422 * callback name to be that of transferer. Since local,1/2 have 01423 * the same name we can be tricky and just grab the bridged 01424 * channel from the other side of the local. 01425 */ 01426 if (!strcasecmp(peer->tech->type, "Local")) { 01427 struct ast_channel *tmpchan, *base_peer; 01428 char other_side[AST_CHANNEL_NAME]; 01429 char *c; 01430 01431 ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side)); 01432 if ((c = strrchr(other_side, ';'))) { 01433 *++c = '1'; 01434 } 01435 if ((tmpchan = ast_channel_get_by_name(other_side))) { 01436 ast_channel_lock(tmpchan); 01437 if ((base_peer = ast_bridged_channel(tmpchan))) { 01438 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 01439 } 01440 ast_channel_unlock(tmpchan); 01441 tmpchan = ast_channel_unref(tmpchan); 01442 } 01443 } else { 01444 ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername)); 01445 } 01446 } 01447 01448 /* 01449 * Remember what had been dialed, so that if the parking 01450 * expires, we try to come back to the same place 01451 */ 01452 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri); 01453 01454 /* 01455 * If extension has options specified, they override all other 01456 * possibilities such as the returntoorigin flag and transferred 01457 * context. Information on extension options is lost here, so 01458 * we set a flag 01459 */ 01460 ast_copy_string(pu->context, 01461 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 01462 sizeof(pu->context)); 01463 ast_copy_string(pu->exten, 01464 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 01465 sizeof(pu->exten)); 01466 pu->priority = args->return_pri ? args->return_pri : 01467 (chan->macropriority ? chan->macropriority : chan->priority); 01468 01469 /* 01470 * If parking a channel directly, don't quite yet get parking 01471 * running on it. All parking lot entries are put into the 01472 * parking lot with notquiteyet on. 01473 */ 01474 if (peer != chan) { 01475 pu->notquiteyet = 0; 01476 } 01477 01478 /* Wake up the (presumably select()ing) thread */ 01479 pthread_kill(parking_thread, SIGURG); 01480 ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", 01481 pu->chan->name, pu->parkingnum, pu->parkinglot->name, 01482 pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000)); 01483 01484 ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer); 01485 01486 if (peer) { 01487 event_from = peer->name; 01488 } else { 01489 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 01490 } 01491 01492 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "ParkedCall", 01493 "Exten: %s\r\n" 01494 "Channel: %s\r\n" 01495 "Parkinglot: %s\r\n" 01496 "From: %s\r\n" 01497 "Timeout: %ld\r\n" 01498 "CallerIDNum: %s\r\n" 01499 "CallerIDName: %s\r\n" 01500 "ConnectedLineNum: %s\r\n" 01501 "ConnectedLineName: %s\r\n" 01502 "Uniqueid: %s\r\n", 01503 pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "", 01504 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 01505 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 01506 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 01507 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 01508 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 01509 pu->chan->uniqueid 01510 ); 01511 01512 if (peer && adsipark && ast_adsi_available(peer)) { 01513 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 01514 ast_adsi_unload_session(peer); 01515 } 01516 01517 snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten, 01518 pu->parkinglot->name); 01519 if (ast_add_extension(pu->parkinglot->cfg.parking_con, 1, pu->parkingexten, 1, 01520 NULL, NULL, parkedcall, ast_strdup(app_data), ast_free_ptr, registrar)) { 01521 ast_log(LOG_ERROR, "Could not create parked call exten: %s@%s\n", 01522 pu->parkingexten, pu->parkinglot->cfg.parking_con); 01523 } else { 01524 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE); 01525 } 01526 01527 AST_LIST_UNLOCK(&pu->parkinglot->parkings); 01528 01529 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 01530 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) 01531 && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) { 01532 /* 01533 * If a channel is masqueraded into peer while playing back the 01534 * parking space number do not continue playing it back. This 01535 * is the case if an attended transfer occurs. 01536 */ 01537 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01538 /* Tell the peer channel the number of the parking space */ 01539 ast_say_digits(peer, pu->parkingnum, "", peer->language); 01540 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01541 } 01542 if (peer == chan) { /* pu->notquiteyet = 1 */ 01543 /* Wake up parking thread if we're really done */ 01544 pu->hold_method = AST_CONTROL_HOLD; 01545 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01546 S_OR(pu->parkinglot->cfg.mohclass, NULL), 01547 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0); 01548 pu->notquiteyet = 0; 01549 pthread_kill(parking_thread, SIGURG); 01550 } 01551 return 0; 01552 }
static void park_space_abort | ( | struct parkeduser * | pu | ) | [static] |
Definition at line 1182 of file features.c.
References ast_free, AST_LIST_REMOVE, AST_LIST_UNLOCK, parkeduser::parkinglot, parkinglot, and parkinglot_unref().
Referenced by masq_park_call().
01183 { 01184 struct ast_parkinglot *parkinglot; 01185 01186 parkinglot = pu->parkinglot; 01187 01188 /* Put back the parking space just allocated. */ 01189 --parkinglot->next_parking_space; 01190 01191 AST_LIST_REMOVE(&parkinglot->parkings, pu, list); 01192 01193 AST_LIST_UNLOCK(&parkinglot->parkings); 01194 parkinglot_unref(parkinglot); 01195 ast_free(pu); 01196 }
static struct parkeduser* park_space_reserve | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 1209 of file features.c.
References args, ast_calloc, ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_parkinglot::cfg, create_dynamic_parkinglot(), default_parkinglot, find_parkinglot(), findparkinglotname(), LOG_WARNING, ast_channel::name, parkeddynamic, parkinglot_cfg::parking_start, parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, pbx_builtin_getvar_helper(), and S_OR.
Referenced by masq_park_call(), and park_call_full().
01210 { 01211 struct parkeduser *pu; 01212 int i; 01213 int parking_space = -1; 01214 const char *parkinglotname; 01215 const char *parkingexten; 01216 struct parkeduser *cur; 01217 struct ast_parkinglot *parkinglot = NULL; 01218 01219 if (args->parkinglot) { 01220 parkinglot = parkinglot_addref(args->parkinglot); 01221 parkinglotname = parkinglot->name; 01222 } else { 01223 if (parker) { 01224 parkinglotname = findparkinglotname(parker); 01225 } else { /* parker was NULL, check park_me (ParkAndAnnounce / res_agi) */ 01226 parkinglotname = findparkinglotname(park_me); 01227 } 01228 if (!ast_strlen_zero(parkinglotname)) { 01229 parkinglot = find_parkinglot(parkinglotname); 01230 } else { 01231 /* Parking lot is not specified, so use the default parking lot. */ 01232 ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n"); 01233 parkinglot = parkinglot_addref(default_parkinglot); 01234 } 01235 } 01236 01237 /* Dynamically create parkinglot */ 01238 if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) { 01239 parkinglot = create_dynamic_parkinglot(parkinglotname, park_me); 01240 } 01241 01242 if (!parkinglot) { 01243 ast_log(LOG_WARNING, "Parking lot not available to park %s.\n", park_me->name); 01244 return NULL; 01245 } 01246 01247 ast_debug(1, "Parking lot: %s\n", parkinglot->name); 01248 if (parkinglot->disabled || parkinglot->cfg.is_invalid) { 01249 ast_log(LOG_WARNING, "Parking lot %s is not in a useable state.\n", 01250 parkinglot->name); 01251 parkinglot_unref(parkinglot); 01252 return NULL; 01253 } 01254 01255 /* Allocate memory for parking data */ 01256 if (!(pu = ast_calloc(1, sizeof(*pu)))) { 01257 parkinglot_unref(parkinglot); 01258 return NULL; 01259 } 01260 01261 /* Lock parking list */ 01262 AST_LIST_LOCK(&parkinglot->parkings); 01263 01264 /* Check for channel variable PARKINGEXTEN */ 01265 parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(park_me, "PARKINGEXTEN"), "")); 01266 if (!ast_strlen_zero(parkingexten)) { 01267 /*! 01268 * \note The API forces us to specify a numeric parking slot, even 01269 * though the architecture would tend to support non-numeric extensions 01270 * (as are possible with SIP, for example). Hence, we enforce that 01271 * limitation here. If extout was not numeric, we could permit 01272 * arbitrary non-numeric extensions. 01273 */ 01274 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space <= 0) { 01275 ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", 01276 parkingexten); 01277 AST_LIST_UNLOCK(&parkinglot->parkings); 01278 parkinglot_unref(parkinglot); 01279 ast_free(pu); 01280 return NULL; 01281 } 01282 01283 if (parking_space < parkinglot->cfg.parking_start 01284 || parkinglot->cfg.parking_stop < parking_space) { 01285 /* 01286 * Cannot allow park because parking lots are not setup for 01287 * spaces outside of the lot. (Things like dialplan hints don't 01288 * exist for outside lot space.) 01289 */ 01290 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is not in %s (%d-%d).\n", 01291 parking_space, parkinglot->name, parkinglot->cfg.parking_start, 01292 parkinglot->cfg.parking_stop); 01293 AST_LIST_UNLOCK(&parkinglot->parkings); 01294 parkinglot_unref(parkinglot); 01295 ast_free(pu); 01296 return NULL; 01297 } 01298 01299 /* Check if requested parking space is in use. */ 01300 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 01301 if (cur->parkingnum == parking_space) { 01302 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is already in use in %s\n", 01303 parking_space, parkinglot->name); 01304 AST_LIST_UNLOCK(&parkinglot->parkings); 01305 parkinglot_unref(parkinglot); 01306 ast_free(pu); 01307 return NULL; 01308 } 01309 } 01310 } else { 01311 /* PARKINGEXTEN is empty, so find a usable extension in the lot to park the call */ 01312 int start; /* The first slot we look in the parkinglot. It can be randomized. */ 01313 int start_checked = 0; /* flag raised once the first slot is checked */ 01314 01315 /* If using randomize mode, set start to random position on parking range */ 01316 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) { 01317 start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1); 01318 start += parkinglot->cfg.parking_start; 01319 } else if (parkinglot->cfg.parkfindnext 01320 && parkinglot->cfg.parking_start <= parkinglot->next_parking_space 01321 && parkinglot->next_parking_space <= parkinglot->cfg.parking_stop) { 01322 /* Start looking with the next parking space in the lot. */ 01323 start = parkinglot->next_parking_space; 01324 } else { 01325 /* Otherwise, just set it to the start position. */ 01326 start = parkinglot->cfg.parking_start; 01327 } 01328 01329 /* free parking extension linear search: O(n^2) */ 01330 for (i = start; ; i++) { 01331 /* If we are past the end, wrap around to the first parking slot*/ 01332 if (i == parkinglot->cfg.parking_stop + 1) { 01333 i = parkinglot->cfg.parking_start; 01334 } 01335 01336 if (i == start) { 01337 /* At this point, if start_checked, we've exhausted all the possible slots. */ 01338 if (start_checked) { 01339 break; 01340 } else { 01341 start_checked = 1; 01342 } 01343 } 01344 01345 /* Search the list of parked calls already in use for i. If we find it, it's in use. */ 01346 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 01347 if (cur->parkingnum == i) { 01348 break; 01349 } 01350 } 01351 if (!cur) { 01352 /* We found a parking space. */ 01353 parking_space = i; 01354 break; 01355 } 01356 } 01357 if (parking_space == -1) { 01358 /* We did not find a parking space. Lot is full. */ 01359 ast_log(LOG_WARNING, "No more parking spaces in %s\n", parkinglot->name); 01360 AST_LIST_UNLOCK(&parkinglot->parkings); 01361 parkinglot_unref(parkinglot); 01362 ast_free(pu); 01363 return NULL; 01364 } 01365 } 01366 01367 /* Prepare for next parking space search. */ 01368 parkinglot->next_parking_space = parking_space + 1; 01369 01370 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 01371 pu->notquiteyet = 1; 01372 pu->parkingnum = parking_space; 01373 pu->parkinglot = parkinglot; 01374 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list); 01375 01376 return pu; 01377 }
static int parked_call_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Pickup parked call.
< Parking lot space to retrieve if present.
< Parking lot name to use if present.
< Place to put any remaining args string.
Definition at line 4991 of file features.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_bridge_call(), ast_cdr_setdestchan(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_flags, AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_free, ast_hangup(), ast_indicate(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_manager_event, ast_party_connected_line_free(), ast_party_connected_line_init(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, ast_channel::caller, ast_channel::cdr, parkeduser::chan, config, connected, ast_channel::connected, courtesytone, ast_datastore::data, default_parkinglot, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_caller, find_parkinglot(), findparkinglotname(), parkeduser::hold_method, ast_party_connected_line::id, ast_party_caller::id, LOG_WARNING, ast_party_id::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkedplay, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, parse(), ast_channel::pbx, pbx_builtin_setvar_helper(), play_message_to_chans(), S_COR, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.
Referenced by ast_features_init().
04992 { 04993 int res = 0; 04994 struct ast_channel *peer = NULL; 04995 struct parkeduser *pu; 04996 struct ast_context *con; 04997 char *parse; 04998 const char *pl_name; 04999 int park = 0; 05000 struct ast_bridge_config config; 05001 struct ast_parkinglot *parkinglot; 05002 AST_DECLARE_APP_ARGS(app_args, 05003 AST_APP_ARG(pl_space); /*!< Parking lot space to retrieve if present. */ 05004 AST_APP_ARG(pl_name); /*!< Parking lot name to use if present. */ 05005 AST_APP_ARG(dummy); /*!< Place to put any remaining args string. */ 05006 ); 05007 05008 parse = ast_strdupa(data); 05009 AST_STANDARD_APP_ARGS(app_args, parse); 05010 05011 if (!ast_strlen_zero(app_args.pl_space)) { 05012 if (sscanf(app_args.pl_space, "%30u", &park) != 1) { 05013 ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n", 05014 app_args.pl_space); 05015 park = -1; 05016 } 05017 } 05018 05019 if (!ast_strlen_zero(app_args.pl_name)) { 05020 pl_name = app_args.pl_name; 05021 } else { 05022 pl_name = findparkinglotname(chan); 05023 } 05024 if (ast_strlen_zero(pl_name)) { 05025 /* Parking lot is not specified, so use the default parking lot. */ 05026 parkinglot = parkinglot_addref(default_parkinglot); 05027 } else { 05028 parkinglot = find_parkinglot(pl_name); 05029 if (!parkinglot) { 05030 /* It helps to answer the channel if not already up. :) */ 05031 if (chan->_state != AST_STATE_UP) { 05032 ast_answer(chan); 05033 } 05034 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05035 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", 05036 "pbx-invalidpark", chan->name); 05037 } 05038 ast_log(LOG_WARNING, 05039 "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n", 05040 chan->name, pl_name); 05041 return -1; 05042 } 05043 } 05044 05045 AST_LIST_LOCK(&parkinglot->parkings); 05046 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 05047 if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park) 05048 && !pu->notquiteyet && !pu->chan->pbx) { 05049 /* The parking space has a call and can be picked up now. */ 05050 AST_LIST_REMOVE_CURRENT(list); 05051 break; 05052 } 05053 } 05054 AST_LIST_TRAVERSE_SAFE_END; 05055 if (pu) { 05056 /* Found a parked call to pickup. */ 05057 peer = pu->chan; 05058 con = ast_context_find(parkinglot->cfg.parking_con); 05059 if (con) { 05060 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 05061 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 05062 } else { 05063 notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE); 05064 } 05065 } else { 05066 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 05067 } 05068 05069 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan); 05070 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall", 05071 "Exten: %s\r\n" 05072 "Channel: %s\r\n" 05073 "From: %s\r\n" 05074 "CallerIDNum: %s\r\n" 05075 "CallerIDName: %s\r\n" 05076 "ConnectedLineNum: %s\r\n" 05077 "ConnectedLineName: %s\r\n", 05078 pu->parkingexten, pu->chan->name, chan->name, 05079 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 05080 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 05081 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 05082 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>") 05083 ); 05084 05085 /* Stop entertaining the caller. */ 05086 switch (pu->hold_method) { 05087 case AST_CONTROL_HOLD: 05088 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 05089 break; 05090 case AST_CONTROL_RINGING: 05091 ast_indicate(pu->chan, -1); 05092 break; 05093 default: 05094 break; 05095 } 05096 pu->hold_method = 0; 05097 05098 parkinglot_unref(pu->parkinglot); 05099 ast_free(pu); 05100 } 05101 AST_LIST_UNLOCK(&parkinglot->parkings); 05102 05103 if (peer) { 05104 /* Update connected line between retrieving call and parked call. */ 05105 struct ast_party_connected_line connected; 05106 05107 ast_party_connected_line_init(&connected); 05108 05109 /* Send our caller-id to peer. */ 05110 ast_channel_lock(chan); 05111 ast_connected_line_copy_from_caller(&connected, &chan->caller); 05112 ast_channel_unlock(chan); 05113 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05114 if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) { 05115 ast_channel_update_connected_line(peer, &connected, NULL); 05116 } 05117 05118 /* 05119 * Get caller-id from peer. 05120 * 05121 * Update the retrieving call before it is answered if possible 05122 * for best results. Some phones do not support updating the 05123 * connected line information after connection. 05124 */ 05125 ast_channel_lock(peer); 05126 ast_connected_line_copy_from_caller(&connected, &peer->caller); 05127 ast_channel_unlock(peer); 05128 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05129 if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) { 05130 ast_channel_update_connected_line(chan, &connected, NULL); 05131 } 05132 05133 ast_party_connected_line_free(&connected); 05134 } 05135 05136 /* JK02: it helps to answer the channel if not already up */ 05137 if (chan->_state != AST_STATE_UP) { 05138 ast_answer(chan); 05139 } 05140 05141 if (peer) { 05142 struct ast_datastore *features_datastore; 05143 struct ast_dial_features *dialfeatures = NULL; 05144 05145 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 05146 if (!ast_strlen_zero(courtesytone)) { 05147 static const char msg[] = "courtesy tone"; 05148 05149 switch (parkedplay) { 05150 case 0:/* Courtesy tone to pickup chan */ 05151 res = play_message_to_chans(chan, peer, -1, msg, courtesytone); 05152 break; 05153 case 1:/* Courtesy tone to parked chan */ 05154 res = play_message_to_chans(chan, peer, 1, msg, courtesytone); 05155 break; 05156 case 2:/* Courtesy tone to both chans */ 05157 res = play_message_to_chans(chan, peer, 0, msg, courtesytone); 05158 break; 05159 default: 05160 res = 0; 05161 break; 05162 } 05163 if (res) { 05164 ast_hangup(peer); 05165 parkinglot_unref(parkinglot); 05166 return -1; 05167 } 05168 } 05169 05170 res = ast_channel_make_compatible(chan, peer); 05171 if (res < 0) { 05172 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 05173 ast_hangup(peer); 05174 parkinglot_unref(parkinglot); 05175 return -1; 05176 } 05177 /* This runs sorta backwards, since we give the incoming channel control, as if it 05178 were the person called. */ 05179 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park); 05180 05181 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 05182 ast_cdr_setdestchan(chan->cdr, peer->name); 05183 memset(&config, 0, sizeof(struct ast_bridge_config)); 05184 05185 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 05186 ast_channel_lock(peer); 05187 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 05188 dialfeatures = features_datastore->data; 05189 } 05190 05191 /* 05192 * When the datastores for both caller and callee are created, 05193 * both the callee and caller channels use the features_caller 05194 * flag variable to represent themselves. With that said, the 05195 * config.features_callee flags should be copied from the 05196 * datastore's caller feature flags regardless if peer was a 05197 * callee or caller. 05198 */ 05199 if (dialfeatures) { 05200 ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 05201 } 05202 ast_channel_unlock(peer); 05203 05204 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05205 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 05206 } 05207 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05208 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 05209 } 05210 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05211 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 05212 } 05213 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05214 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 05215 } 05216 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05217 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 05218 } 05219 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05220 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 05221 } 05222 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05223 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 05224 } 05225 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05226 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 05227 } 05228 05229 res = ast_bridge_call(chan, peer, &config); 05230 05231 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 05232 ast_cdr_setdestchan(chan->cdr, peer->name); 05233 05234 /* Simulate the PBX hanging up */ 05235 ast_hangup(peer); 05236 } else { 05237 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05238 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", 05239 chan->name); 05240 } 05241 ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n", 05242 chan->name, park); 05243 } 05244 05245 parkinglot_unref(parkinglot); 05246 return -1; 05247 }
static int parkinglot_activate | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 5458 of file features.c.
References ast_add_extension(), ast_context_find_or_create(), AST_DEVICE_INUSE, ast_free_ptr, ast_log(), AST_MAX_CONTEXT, ast_strdup, LOG_ERROR, notify_metermaids(), park_add_hints(), parkcall, parkinglot, and registrar.
Referenced by create_dynamic_parkinglot(), and parkinglot_activate_cb().
05459 { 05460 int disabled = 0; 05461 char app_data[5 + AST_MAX_CONTEXT]; 05462 05463 /* Create Park option list. Must match with struct park_app_args options. */ 05464 if (parkinglot->cfg.parkext_exclusive) { 05465 /* Specify the parking lot this parking extension parks calls. */ 05466 snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name); 05467 } else { 05468 /* The dialplan must specify which parking lot to use. */ 05469 app_data[0] = '\0'; 05470 } 05471 05472 /* Create context */ 05473 if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) { 05474 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", 05475 parkinglot->cfg.parking_con); 05476 disabled = 1; 05477 05478 /* Add a parking extension into the context */ 05479 } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext, 05480 1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) { 05481 ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n", 05482 parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con); 05483 disabled = 1; 05484 } else { 05485 /* Add parking hints */ 05486 if (parkinglot->cfg.parkaddhints) { 05487 park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start, 05488 parkinglot->cfg.parking_stop); 05489 } 05490 05491 /* 05492 * XXX Not sure why we should need to notify the metermaids for 05493 * this exten. It was originally done for the default parking 05494 * lot entry exten only but should be done for all entry extens 05495 * if we do it for one. 05496 */ 05497 /* Notify metermaids about parking lot entry exten state. */ 05498 notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con, 05499 AST_DEVICE_INUSE); 05500 } 05501 05502 parkinglot->disabled = disabled; 05503 return disabled ? -1 : 0; 05504 }
static int parkinglot_activate_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6505 of file features.c.
References ast_debug, ast_log(), force_reload_load, LOG_WARNING, parkinglot, and parkinglot_activate().
Referenced by load_config().
06506 { 06507 struct ast_parkinglot *parkinglot = obj; 06508 06509 if (parkinglot->the_mark) { 06510 /* 06511 * Don't activate a parking lot that still bears the_mark since 06512 * it is effectively deleted. 06513 */ 06514 return 0; 06515 } 06516 06517 if (parkinglot_activate(parkinglot)) { 06518 /* 06519 * The parking lot failed to activate. Allow reloading later to 06520 * see if that fixes it. 06521 */ 06522 force_reload_load = 1; 06523 ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name); 06524 } else { 06525 ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n", 06526 parkinglot->name, parkinglot->cfg.parking_start, 06527 parkinglot->cfg.parking_stop); 06528 } 06529 06530 return 0; 06531 }
static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 5259 of file features.c.
References ao2_ref, ast_debug, and parkinglot.
Referenced by create_dynamic_parkinglot(), load_config(), park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().
05260 { 05261 int refcount; 05262 05263 refcount = ao2_ref(parkinglot, +1); 05264 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1); 05265 return parkinglot; 05266 }
static int parkinglot_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 818 of file features.c.
References CMP_MATCH, CMP_STOP, ast_parkinglot::name, and parkinglot.
Referenced by ast_features_init().
00819 { 00820 struct ast_parkinglot *parkinglot = obj; 00821 struct ast_parkinglot *parkinglot2 = arg; 00822 00823 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0; 00824 }
static int parkinglot_config_read | ( | const char * | pl_name, | |
struct parkinglot_cfg * | cfg, | |||
struct ast_variable * | var | |||
) | [static] |
Definition at line 5370 of file features.c.
References ast_copy_string(), ast_log(), ast_strlen_zero(), ast_true(), parkinglot_cfg::is_invalid, LOG_WARNING, parkinglot_cfg::mohclass, parkinglot_cfg::parkaddhints, parkinglot_cfg::parkedcallhangup, parkinglot_cfg::parkedcallrecording, parkinglot_cfg::parkedcallreparking, parkinglot_cfg::parkedcalltransfers, parkinglot_cfg::parkext, parkinglot_cfg::parkext_exclusive, parkinglot_cfg::parkfindnext, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglot_feature_flag_cfg(), parkinglot_cfg::parkingtime, and var.
Referenced by build_parkinglot().
05371 { 05372 int error = 0; 05373 05374 while (var) { 05375 if (!strcasecmp(var->name, "context")) { 05376 ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con)); 05377 } else if (!strcasecmp(var->name, "parkext")) { 05378 ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext)); 05379 } else if (!strcasecmp(var->name, "parkext_exclusive")) { 05380 cfg->parkext_exclusive = ast_true(var->value); 05381 } else if (!strcasecmp(var->name, "parkinghints")) { 05382 cfg->parkaddhints = ast_true(var->value); 05383 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 05384 ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass)); 05385 } else if (!strcasecmp(var->name, "parkingtime")) { 05386 int parkingtime = 0; 05387 05388 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) { 05389 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 05390 error = -1; 05391 } else { 05392 cfg->parkingtime = parkingtime * 1000; 05393 } 05394 } else if (!strcasecmp(var->name, "parkpos")) { 05395 int start = 0; 05396 int end = 0; 05397 05398 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 05399 ast_log(LOG_WARNING, 05400 "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n", 05401 var->lineno, var->file); 05402 error = -1; 05403 } else if (end < start || start <= 0 || end <= 0) { 05404 ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n", 05405 var->lineno, var->file); 05406 error = -1; 05407 } else { 05408 cfg->parking_start = start; 05409 cfg->parking_stop = end; 05410 } 05411 } else if (!strcasecmp(var->name, "findslot")) { 05412 cfg->parkfindnext = (!strcasecmp(var->value, "next")); 05413 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 05414 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var); 05415 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 05416 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var); 05417 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 05418 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var); 05419 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 05420 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var); 05421 } 05422 var = var->next; 05423 } 05424 05425 /* Check for configuration errors */ 05426 if (ast_strlen_zero(cfg->parking_con)) { 05427 ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name); 05428 error = -1; 05429 } 05430 if (ast_strlen_zero(cfg->parkext)) { 05431 ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name); 05432 error = -1; 05433 } 05434 if (!cfg->parking_start) { 05435 ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name); 05436 error = -1; 05437 } 05438 if (error) { 05439 cfg->is_invalid = 1; 05440 } 05441 05442 return error; 05443 }
static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 5269 of file features.c.
References ast_assert, AST_LIST_EMPTY, AST_LIST_HEAD_DESTROY, and ast_parkinglot::parkings.
Referenced by create_parkinglot().
05270 { 05271 struct ast_parkinglot *doomed = obj; 05272 05273 /* 05274 * No need to destroy parked calls here because any parked call 05275 * holds a parking lot reference. Therefore the parkings list 05276 * must be empty. 05277 */ 05278 ast_assert(AST_LIST_EMPTY(&doomed->parkings)); 05279 AST_LIST_HEAD_DESTROY(&doomed->parkings); 05280 }
static void parkinglot_feature_flag_cfg | ( | const char * | pl_name, | |
int * | param, | |||
struct ast_variable * | var | |||
) | [static] |
Definition at line 5347 of file features.c.
References ast_debug, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, and var.
Referenced by parkinglot_config_read().
05348 { 05349 ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value); 05350 if (!strcasecmp(var->value, "both")) { 05351 *param = AST_FEATURE_FLAG_BYBOTH; 05352 } else if (!strcasecmp(var->value, "caller")) { 05353 *param = AST_FEATURE_FLAG_BYCALLER; 05354 } else if (!strcasecmp(var->value, "callee")) { 05355 *param = AST_FEATURE_FLAG_BYCALLEE; 05356 } 05357 }
static int parkinglot_hash_cb | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 811 of file features.c.
References ast_str_case_hash(), and parkinglot.
Referenced by ast_features_init().
00812 { 00813 const struct ast_parkinglot *parkinglot = obj; 00814 00815 return ast_str_case_hash(parkinglot->name); 00816 }
static int parkinglot_is_marked_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6485 of file features.c.
References AST_LIST_EMPTY, ast_log(), CMP_MATCH, force_reload_load, LOG_WARNING, and parkinglot.
Referenced by load_config().
06486 { 06487 struct ast_parkinglot *parkinglot = obj; 06488 06489 if (parkinglot->the_mark) { 06490 if (AST_LIST_EMPTY(&parkinglot->parkings)) { 06491 /* This parking lot can actually be deleted. */ 06492 return CMP_MATCH; 06493 } 06494 /* Try reloading later when parking lot is empty. */ 06495 ast_log(LOG_WARNING, 06496 "Parking lot %s has parked calls. Could not remove.\n", 06497 parkinglot->name); 06498 parkinglot->disabled = 1; 06499 force_reload_load = 1; 06500 } 06501 06502 return 0; 06503 }
static int parkinglot_markall_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6477 of file features.c.
References parkinglot.
Referenced by load_config().
06478 { 06479 struct ast_parkinglot *parkinglot = obj; 06480 06481 parkinglot->the_mark = 1; 06482 return 0; 06483 }
static void parkinglot_unref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Unreference parkinglot object.
Definition at line 5252 of file features.c.
References ao2_ref, ast_debug, and parkinglot.
Referenced by ast_masq_park_call_exten(), ast_park_call_exten(), build_parkinglot(), create_dynamic_parkinglot(), manage_parkinglot(), manager_park(), park_call_exec(), park_space_abort(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().
05253 { 05254 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, 05255 ao2_ref(parkinglot, 0) - 1); 05256 ao2_ref(parkinglot, -1); 05257 }
return the first unlocked cdr in a possible chain
Definition at line 3697 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
03698 { 03699 struct ast_cdr *cdr_orig = cdr; 03700 while (cdr) { 03701 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 03702 return cdr; 03703 cdr = cdr->next; 03704 } 03705 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 03706 }
static int play_message_in_bridged_call | ( | struct ast_channel * | caller_chan, | |
struct ast_channel * | callee_chan, | |||
const char * | audiofile | |||
) | [static] |
Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages.
Definition at line 1977 of file features.c.
References play_message_to_chans().
Referenced by builtin_automonitor().
01978 { 01979 return play_message_to_chans(caller_chan, callee_chan, 0, "automon message", 01980 audiofile); 01981 }
static int play_message_on_chan | ( | struct ast_channel * | play_to, | |
struct ast_channel * | other, | |||
const char * | msg, | |||
const char * | audiofile | |||
) | [static] |
Definition at line 1923 of file features.c.
References ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_log(), ast_stream_and_wait(), and LOG_WARNING.
Referenced by masq_park_call(), and play_message_to_chans().
01924 { 01925 /* Put other channel in autoservice. */ 01926 if (ast_autoservice_start(other)) { 01927 return -1; 01928 } 01929 ast_autoservice_ignore(other, AST_FRAME_DTMF_BEGIN); 01930 ast_autoservice_ignore(other, AST_FRAME_DTMF_END); 01931 if (ast_stream_and_wait(play_to, audiofile, "")) { 01932 ast_log(LOG_WARNING, "Failed to play %s '%s'!\n", msg, audiofile); 01933 ast_autoservice_stop(other); 01934 return -1; 01935 } 01936 if (ast_autoservice_stop(other)) { 01937 return -1; 01938 } 01939 return 0; 01940 }
static int play_message_to_chans | ( | struct ast_channel * | left, | |
struct ast_channel * | right, | |||
int | which, | |||
const char * | msg, | |||
const char * | audiofile | |||
) | [static] |
Definition at line 1958 of file features.c.
References play_message_on_chan().
Referenced by parked_call_exec(), and play_message_in_bridged_call().
01959 { 01960 /* First play the file to the left channel if requested. */ 01961 if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) { 01962 return -1; 01963 } 01964 01965 /* Then play the file to the right channel if requested. */ 01966 if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) { 01967 return -1; 01968 } 01969 01970 return 0; 01971 }
static void post_manager_event | ( | const char * | s, | |
struct parkeduser * | pu | |||
) | [static] |
Output parking event to manager.
Definition at line 4474 of file features.c.
References ast_channel::caller, parkeduser::chan, ast_channel::connected, EVENT_FLAG_CALL, ast_party_connected_line::id, ast_party_caller::id, manager_event, ast_party_id::name, ast_parkinglot::name, ast_channel::name, ast_party_id::number, parkeduser::parkingexten, parkeduser::parkinglot, S_COR, ast_party_name::str, ast_party_number::str, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.
Referenced by manage_parked_call().
04475 { 04476 manager_event(EVENT_FLAG_CALL, s, 04477 "Exten: %s\r\n" 04478 "Channel: %s\r\n" 04479 "Parkinglot: %s\r\n" 04480 "CallerIDNum: %s\r\n" 04481 "CallerIDName: %s\r\n" 04482 "ConnectedLineNum: %s\r\n" 04483 "ConnectedLineName: %s\r\n" 04484 "UniqueID: %s\r\n", 04485 pu->parkingexten, 04486 pu->chan->name, 04487 pu->parkinglot->name, 04488 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 04489 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 04490 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 04491 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 04492 pu->chan->uniqueid 04493 ); 04494 }
static void process_applicationmap_line | ( | struct ast_variable * | var | ) | [static] |
Definition at line 5586 of file features.c.
References app, ast_call_feature::app_args, args, AST_APP_ARG, ast_calloc, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FEATURE_FLAG_ONPEER, AST_FEATURE_FLAG_ONSELF, ast_log(), ast_register_feature(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_verb, feature_group_exten::feature, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_MOH_LEN, FEATURE_SNAME_LEN, find_dynamic_feature(), LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, strsep(), and var.
05587 { 05588 char *tmp_val = ast_strdupa(var->value); 05589 char *activateon; 05590 struct ast_call_feature *feature; 05591 AST_DECLARE_APP_ARGS(args, 05592 AST_APP_ARG(exten); 05593 AST_APP_ARG(activatedby); 05594 AST_APP_ARG(app); 05595 AST_APP_ARG(app_args); 05596 AST_APP_ARG(moh_class); 05597 ); 05598 05599 AST_STANDARD_APP_ARGS(args, tmp_val); 05600 if (strchr(args.app, '(')) { 05601 /* New syntax */ 05602 args.moh_class = args.app_args; 05603 args.app_args = strchr(args.app, '('); 05604 *args.app_args++ = '\0'; 05605 if (args.app_args[strlen(args.app_args) - 1] == ')') { 05606 args.app_args[strlen(args.app_args) - 1] = '\0'; 05607 } 05608 } 05609 05610 activateon = strsep(&args.activatedby, "/"); 05611 05612 /*! \todo XXX var_name or app_args ? */ 05613 if (ast_strlen_zero(args.app) 05614 || ast_strlen_zero(args.exten) 05615 || ast_strlen_zero(activateon) 05616 || ast_strlen_zero(var->name)) { 05617 ast_log(LOG_NOTICE, 05618 "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 05619 args.app, args.exten, activateon, var->name); 05620 return; 05621 } 05622 05623 AST_RWLIST_RDLOCK(&feature_list); 05624 if (find_dynamic_feature(var->name)) { 05625 AST_RWLIST_UNLOCK(&feature_list); 05626 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", 05627 var->name); 05628 return; 05629 } 05630 AST_RWLIST_UNLOCK(&feature_list); 05631 05632 if (!(feature = ast_calloc(1, sizeof(*feature)))) { 05633 return; 05634 } 05635 05636 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 05637 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN); 05638 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN); 05639 05640 if (args.app_args) { 05641 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN); 05642 } 05643 05644 if (args.moh_class) { 05645 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN); 05646 } 05647 05648 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten)); 05649 feature->operation = feature_exec_app; 05650 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 05651 05652 /* Allow caller and callee to be specified for backwards compatability */ 05653 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) { 05654 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 05655 } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) { 05656 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 05657 } else { 05658 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 05659 " must be 'self', or 'peer'\n", var->name); 05660 return; 05661 } 05662 05663 if (ast_strlen_zero(args.activatedby)) { 05664 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05665 } else if (!strcasecmp(args.activatedby, "caller")) { 05666 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 05667 } else if (!strcasecmp(args.activatedby, "callee")) { 05668 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 05669 } else if (!strcasecmp(args.activatedby, "both")) { 05670 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05671 } else { 05672 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 05673 " must be 'caller', or 'callee', or 'both'\n", var->name); 05674 return; 05675 } 05676 05677 ast_register_feature(feature); 05678 05679 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", 05680 var->name, args.app, args.app_args, args.exten); 05681 }
static int process_config | ( | struct ast_config * | cfg | ) | [static] |
Definition at line 5683 of file features.c.
References adsipark, ast_true(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARKINGLOT, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, parkeddynamic, parkedplay, pickupfailsound, pickupsound, transferdigittimeout, var, xferfailsound, and xfersound.
Referenced by load_config().
05684 { 05685 int i; 05686 struct ast_variable *var = NULL; 05687 struct feature_group *fg = NULL; 05688 char *ctg; 05689 static const char * const categories[] = { 05690 /* Categories in features.conf that are not 05691 * to be parsed as group categories 05692 */ 05693 "general", 05694 "featuremap", 05695 "applicationmap" 05696 }; 05697 05698 /* Set general features global defaults. */ 05699 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05700 05701 /* Set global call pickup defaults. */ 05702 strcpy(pickup_ext, "*8"); 05703 pickupsound[0] = '\0'; 05704 pickupfailsound[0] = '\0'; 05705 05706 /* Set global call transfer defaults. */ 05707 strcpy(xfersound, "beep"); 05708 strcpy(xferfailsound, "beeperr"); 05709 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05710 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05711 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05712 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 05713 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05714 05715 /* Set global call parking defaults. */ 05716 comebacktoorigin = 1; 05717 courtesytone[0] = '\0'; 05718 parkedplay = 0; 05719 adsipark = 0; 05720 parkeddynamic = 0; 05721 05722 var = ast_variable_browse(cfg, "general"); 05723 build_parkinglot(DEFAULT_PARKINGLOT, var); 05724 for (; var; var = var->next) { 05725 if (!strcasecmp(var->name, "parkeddynamic")) { 05726 parkeddynamic = ast_true(var->value); 05727 } else if (!strcasecmp(var->name, "adsipark")) { 05728 adsipark = ast_true(var->value); 05729 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 05730 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 05731 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 05732 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05733 } else { 05734 transferdigittimeout = transferdigittimeout * 1000; 05735 } 05736 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 05737 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 05738 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 05739 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05740 } 05741 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 05742 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 05743 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 05744 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05745 } else { 05746 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 05747 } 05748 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 05749 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 05750 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 05751 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05752 } else { 05753 atxferloopdelay *= 1000; 05754 } 05755 } else if (!strcasecmp(var->name, "atxferdropcall")) { 05756 atxferdropcall = ast_true(var->value); 05757 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 05758 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) { 05759 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 05760 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05761 } 05762 } else if (!strcasecmp(var->name, "courtesytone")) { 05763 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 05764 } else if (!strcasecmp(var->name, "parkedplay")) { 05765 if (!strcasecmp(var->value, "both")) { 05766 parkedplay = 2; 05767 } else if (!strcasecmp(var->value, "parked")) { 05768 parkedplay = 1; 05769 } else { 05770 parkedplay = 0; 05771 } 05772 } else if (!strcasecmp(var->name, "xfersound")) { 05773 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 05774 } else if (!strcasecmp(var->name, "xferfailsound")) { 05775 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 05776 } else if (!strcasecmp(var->name, "pickupexten")) { 05777 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 05778 } else if (!strcasecmp(var->name, "pickupsound")) { 05779 ast_copy_string(pickupsound, var->value, sizeof(pickupsound)); 05780 } else if (!strcasecmp(var->name, "pickupfailsound")) { 05781 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound)); 05782 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 05783 comebacktoorigin = ast_true(var->value); 05784 } 05785 } 05786 05787 unmap_features(); 05788 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 05789 if (remap_feature(var->name, var->value)) { 05790 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 05791 } 05792 } 05793 05794 /* Map a key combination to an application */ 05795 ast_unregister_features(); 05796 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 05797 process_applicationmap_line(var); 05798 } 05799 05800 ast_unregister_groups(); 05801 AST_RWLIST_WRLOCK(&feature_groups); 05802 05803 ctg = NULL; 05804 while ((ctg = ast_category_browse(cfg, ctg))) { 05805 /* Is this a parkinglot definition ? */ 05806 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 05807 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 05808 if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) { 05809 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 05810 } else { 05811 ast_debug(1, "Configured parking context %s\n", ctg); 05812 } 05813 continue; 05814 } 05815 05816 /* No, check if it's a group */ 05817 for (i = 0; i < ARRAY_LEN(categories); i++) { 05818 if (!strcasecmp(categories[i], ctg)) { 05819 break; 05820 } 05821 } 05822 if (i < ARRAY_LEN(categories)) { 05823 continue; 05824 } 05825 05826 if (!(fg = register_group(ctg))) { 05827 continue; 05828 } 05829 05830 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 05831 struct ast_call_feature *feature; 05832 05833 AST_RWLIST_RDLOCK(&feature_list); 05834 if (!(feature = find_dynamic_feature(var->name)) && 05835 !(feature = ast_find_call_feature(var->name))) { 05836 AST_RWLIST_UNLOCK(&feature_list); 05837 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 05838 continue; 05839 } 05840 AST_RWLIST_UNLOCK(&feature_list); 05841 05842 register_group_feature(fg, var->value, feature); 05843 } 05844 } 05845 05846 AST_RWLIST_UNLOCK(&feature_groups); 05847 05848 return 0; 05849 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
transferer | ||
transferee | Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext. |
Definition at line 2219 of file features.c.
References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, and pbx_builtin_getvar_helper().
Referenced by builtin_atxfer(), and builtin_blindtransfer().
02220 { 02221 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 02222 if (ast_strlen_zero(s)) { 02223 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 02224 } 02225 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 02226 s = transferer->macrocontext; 02227 } 02228 if (ast_strlen_zero(s)) { 02229 s = transferer->context; 02230 } 02231 return s; 02232 }
static struct feature_group* register_group | ( | const char * | fgname | ) | [static] |
Add new feature group.
fgname | feature group name. |
Definition at line 2866 of file features.c.
References ast_calloc_with_stringfields, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_set, ast_verb, feature_group_exten::entry, feature_group::gname, and LOG_NOTICE.
02867 { 02868 struct feature_group *fg; 02869 02870 if (!fgname) { 02871 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 02872 return NULL; 02873 } 02874 02875 if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) { 02876 return NULL; 02877 } 02878 02879 ast_string_field_set(fg, gname, fgname); 02880 02881 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 02882 02883 ast_verb(2, "Registered group '%s'\n", fg->gname); 02884 02885 return fg; 02886 }
static void register_group_feature | ( | struct feature_group * | fg, | |
const char * | exten, | |||
struct ast_call_feature * | feature | |||
) | [static] |
Add feature to group.
fg | feature group | |
exten | ||
feature | feature to add. |
Definition at line 2897 of file features.c.
References ast_calloc_with_stringfields, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_set, ast_verb, feature_group_exten::entry, feature_group_exten::exten, ast_call_feature::exten, feature_group_exten::feature, feature_group::features, feature_group::gname, LOG_NOTICE, S_OR, and ast_call_feature::sname.
02898 { 02899 struct feature_group_exten *fge; 02900 02901 if (!fg) { 02902 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 02903 return; 02904 } 02905 02906 if (!feature) { 02907 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 02908 return; 02909 } 02910 02911 if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) { 02912 return; 02913 } 02914 02915 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 02916 02917 fge->feature = feature; 02918 02919 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 02920 02921 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 02922 feature->sname, fg->gname, fge->exten); 02923 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 3105 of file features.c.
References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, FEATURES_COUNT, and features_lock.
03106 { 03107 int x, res = -1; 03108 03109 ast_rwlock_wrlock(&features_lock); 03110 for (x = 0; x < FEATURES_COUNT; x++) { 03111 if (strcasecmp(builtin_features[x].sname, name)) 03112 continue; 03113 03114 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 03115 res = 0; 03116 break; 03117 } 03118 ast_rwlock_unlock(&features_lock); 03119 03120 return res; 03121 }
static void remove_dead_context_usage | ( | const char * | context, | |
struct parking_dp_context * | old_ctx, | |||
struct parking_dp_context * | new_ctx | |||
) | [static] |
Definition at line 6410 of file features.c.
References parking_dp_context::access_extens, parking_dp_context::hints, remove_dead_ramp_usage(), remove_dead_spaces_usage(), and parking_dp_context::spaces.
Referenced by remove_dead_dialplan_useage().
06411 { 06412 remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens); 06413 remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space); 06414 #if 0 06415 /* I don't think we should destroy hints if the parking space still exists. */ 06416 remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint); 06417 #endif 06418 }
static void remove_dead_dialplan_useage | ( | struct parking_dp_map * | old_map, | |
struct parking_dp_map * | new_map | |||
) | [static] |
Definition at line 6433 of file features.c.
References ast_context_destroy(), ast_context_find(), AST_LIST_FIRST, AST_LIST_NEXT, parking_dp_context::context, registrar, and remove_dead_context_usage().
Referenced by load_config().
06434 { 06435 struct parking_dp_context *old_ctx; 06436 struct parking_dp_context *new_ctx; 06437 struct ast_context *con; 06438 int cmp; 06439 06440 old_ctx = AST_LIST_FIRST(old_map); 06441 new_ctx = AST_LIST_FIRST(new_map); 06442 06443 while (new_ctx) { 06444 if (!old_ctx) { 06445 /* No old contexts left, so no dead stuff can remain. */ 06446 return; 06447 } 06448 cmp = strcmp(old_ctx->context, new_ctx->context); 06449 if (cmp < 0) { 06450 /* New map does not have old map context. */ 06451 con = ast_context_find(old_ctx->context); 06452 if (con) { 06453 ast_context_destroy(con, registrar); 06454 } 06455 old_ctx = AST_LIST_NEXT(old_ctx, node); 06456 continue; 06457 } 06458 if (cmp == 0) { 06459 /* Old and new map have this context. */ 06460 remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx); 06461 old_ctx = AST_LIST_NEXT(old_ctx, node); 06462 } else { 06463 /* Old map does not have new map context. */ 06464 } 06465 new_ctx = AST_LIST_NEXT(new_ctx, node); 06466 } 06467 06468 /* Any old contexts left must be dead. */ 06469 for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) { 06470 con = ast_context_find(old_ctx->context); 06471 if (con) { 06472 ast_context_destroy(con, registrar); 06473 } 06474 } 06475 }
static void remove_dead_ramp_usage | ( | const char * | context, | |
struct parking_dp_ramp_map * | old_ramps, | |||
struct parking_dp_ramp_map * | new_ramps | |||
) | [static] |
Definition at line 6269 of file features.c.
References AST_LIST_FIRST, AST_LIST_NEXT, parking_dp_ramp::exten, parking_dp_ramp::node, and remove_exten_if_exist().
Referenced by remove_dead_context_usage().
06270 { 06271 struct parking_dp_ramp *old_ramp; 06272 struct parking_dp_ramp *new_ramp; 06273 int cmp; 06274 06275 old_ramp = AST_LIST_FIRST(old_ramps); 06276 new_ramp = AST_LIST_FIRST(new_ramps); 06277 06278 while (new_ramp) { 06279 if (!old_ramp) { 06280 /* No old ramps left, so no dead ramps can remain. */ 06281 return; 06282 } 06283 cmp = strcmp(old_ramp->exten, new_ramp->exten); 06284 if (cmp < 0) { 06285 /* New map does not have old ramp. */ 06286 remove_exten_if_exist(context, old_ramp->exten, 1); 06287 old_ramp = AST_LIST_NEXT(old_ramp, node); 06288 continue; 06289 } 06290 if (cmp == 0) { 06291 /* Old and new map have this ramp. */ 06292 old_ramp = AST_LIST_NEXT(old_ramp, node); 06293 } else { 06294 /* Old map does not have new ramp. */ 06295 } 06296 new_ramp = AST_LIST_NEXT(new_ramp, node); 06297 } 06298 06299 /* Any old ramps left must be dead. */ 06300 for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) { 06301 remove_exten_if_exist(context, old_ramp->exten, 1); 06302 } 06303 }
static void remove_dead_spaces_usage | ( | const char * | context, | |
struct parking_dp_space_map * | old_spaces, | |||
struct parking_dp_space_map * | new_spaces, | |||
void(*)(const char *context, int space) | destroy_space | |||
) | [static] |
Definition at line 6339 of file features.c.
References AST_LIST_FIRST, AST_LIST_NEXT, destroy_space(), parking_dp_spaces::node, parking_dp_spaces::start, and parking_dp_spaces::stop.
Referenced by remove_dead_context_usage().
06342 { 06343 struct parking_dp_spaces *old_range; 06344 struct parking_dp_spaces *new_range; 06345 int space;/*!< Current position in the current old range. */ 06346 int stop; 06347 06348 old_range = AST_LIST_FIRST(old_spaces); 06349 new_range = AST_LIST_FIRST(new_spaces); 06350 space = -1; 06351 06352 while (old_range) { 06353 if (space < old_range->start) { 06354 space = old_range->start; 06355 } 06356 if (new_range) { 06357 if (space < new_range->start) { 06358 /* Current position in old range starts before new range. */ 06359 if (old_range->stop < new_range->start) { 06360 /* Old range ends before new range. */ 06361 stop = old_range->stop; 06362 old_range = AST_LIST_NEXT(old_range, node); 06363 } else { 06364 /* Tail of old range overlaps new range. */ 06365 stop = new_range->start - 1; 06366 } 06367 } else if (/* new_range->start <= space && */ space <= new_range->stop) { 06368 /* Current position in old range overlaps new range. */ 06369 if (old_range->stop <= new_range->stop) { 06370 /* Old range ends at or before new range. */ 06371 old_range = AST_LIST_NEXT(old_range, node); 06372 } else { 06373 /* Old range extends beyond end of new range. */ 06374 space = new_range->stop + 1; 06375 new_range = AST_LIST_NEXT(new_range, node); 06376 } 06377 continue; 06378 } else /* if (new_range->stop < space) */ { 06379 /* Current position in old range starts after new range. */ 06380 new_range = AST_LIST_NEXT(new_range, node); 06381 continue; 06382 } 06383 } else { 06384 /* No more new ranges. All remaining old spaces are dead. */ 06385 stop = old_range->stop; 06386 old_range = AST_LIST_NEXT(old_range, node); 06387 } 06388 06389 /* Destroy dead parking spaces. */ 06390 for (; space <= stop; ++space) { 06391 destroy_space(context, space); 06392 } 06393 } 06394 }
static void remove_exten_if_exist | ( | const char * | context, | |
const char * | exten, | |||
int | priority | |||
) | [static] |
Definition at line 6243 of file features.c.
References ast_context_remove_extension(), ast_debug, E_MATCH, pbx_find_extension(), registrar, and pbx_find_info::stacklen.
Referenced by destroy_space(), and remove_dead_ramp_usage().
06244 { 06245 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 06246 06247 if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL, 06248 E_MATCH)) { 06249 ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n", 06250 context, exten, priority); 06251 ast_context_remove_extension(context, exten, priority, registrar); 06252 } 06253 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 3708 of file features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), config, feature_group_exten::feature, and LOG_WARNING.
Referenced by ast_bridge_call().
03709 { 03710 const char *feature; 03711 03712 if (ast_strlen_zero(features)) { 03713 return; 03714 } 03715 03716 for (feature = features; *feature; feature++) { 03717 switch (*feature) { 03718 case 'T' : 03719 case 't' : 03720 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 03721 break; 03722 case 'K' : 03723 case 'k' : 03724 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 03725 break; 03726 case 'H' : 03727 case 'h' : 03728 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 03729 break; 03730 case 'W' : 03731 case 'w' : 03732 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 03733 break; 03734 default : 03735 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 03736 } 03737 } 03738 }
static void set_c_e_p | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | ext, | |||
int | pri | |||
) | [static] |
store context, extension and priority
chan,context,ext,pri |
Definition at line 830 of file features.c.
References ast_copy_string(), ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by builtin_blindtransfer(), manage_parked_call(), and masq_park_call().
00831 { 00832 ast_copy_string(chan->context, context, sizeof(chan->context)); 00833 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00834 chan->priority = pri; 00835 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 3292 of file features.c.
References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, config, feature_group_exten::entry, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().
Referenced by ast_bridge_call().
03293 { 03294 int x; 03295 03296 ast_clear_flag(config, AST_FLAGS_ALL); 03297 03298 ast_rwlock_rdlock(&features_lock); 03299 for (x = 0; x < FEATURES_COUNT; x++) { 03300 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 03301 continue; 03302 03303 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 03304 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03305 03306 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 03307 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03308 } 03309 ast_rwlock_unlock(&features_lock); 03310 03311 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 03312 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 03313 03314 if (dynamic_features) { 03315 char *tmp = ast_strdupa(dynamic_features); 03316 char *tok; 03317 struct ast_call_feature *feature; 03318 03319 /* while we have a feature */ 03320 while ((tok = strsep(&tmp, "#"))) { 03321 struct feature_group *fg; 03322 03323 AST_RWLIST_RDLOCK(&feature_groups); 03324 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 03325 struct feature_group_exten *fge; 03326 03327 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03328 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) { 03329 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03330 } 03331 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) { 03332 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03333 } 03334 } 03335 } 03336 AST_RWLIST_UNLOCK(&feature_groups); 03337 03338 AST_RWLIST_RDLOCK(&feature_list); 03339 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 03340 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) { 03341 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03342 } 03343 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) { 03344 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03345 } 03346 } 03347 AST_RWLIST_UNLOCK(&feature_list); 03348 } 03349 } 03350 } 03351 }
static void set_peers | ( | struct ast_channel ** | caller, | |
struct ast_channel ** | callee, | |||
struct ast_channel * | peer, | |||
struct ast_channel * | chan, | |||
int | sense | |||
) | [static] |
set caller and callee according to the direction
caller,callee,peer,chan,sense | Detect who triggered feature and set callee/caller variables accordingly |
Definition at line 1850 of file features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
01852 { 01853 if (sense == FEATURE_SENSE_PEER) { 01854 *caller = peer; 01855 *callee = chan; 01856 } else { 01857 *callee = peer; 01858 *caller = chan; 01859 } 01860 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 3095 of file features.c.
References ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, FEATURES_COUNT, and features_lock.
03096 { 03097 int x; 03098 03099 ast_rwlock_wrlock(&features_lock); 03100 for (x = 0; x < FEATURES_COUNT; x++) 03101 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 03102 ast_rwlock_unlock(&features_lock); 03103 }
static int usage_context_add_ramp | ( | struct parking_dp_ramp_map * | ramp_map, | |
const char * | exten, | |||
int | exclusive, | |||
struct ast_parkinglot * | lot, | |||
int | complain | |||
) | [static] |
Definition at line 5929 of file features.c.
References AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), build_dialplan_useage_ramp(), ast_parkinglot::cfg, parking_dp_ramp::exclusive, parking_dp_ramp::exten, LOG_WARNING, ast_parkinglot::name, parking_dp_ramp::node, and parkinglot_cfg::parking_con.
Referenced by dialplan_usage_add_parkinglot_data().
05930 { 05931 struct parking_dp_ramp *cur_ramp; 05932 struct parking_dp_ramp *new_ramp; 05933 int cmp; 05934 05935 /* Make sure that exclusive is only 0 or 1 */ 05936 if (exclusive) { 05937 exclusive = 1; 05938 } 05939 05940 AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) { 05941 cmp = strcmp(exten, cur_ramp->exten); 05942 if (cmp > 0) { 05943 /* The parking lot ramp goes after this node. */ 05944 continue; 05945 } 05946 if (cmp == 0) { 05947 /* The ramp is already in the map. */ 05948 if (complain && (cur_ramp->exclusive || exclusive)) { 05949 ast_log(LOG_WARNING, 05950 "Parking lot '%s' parkext %s@%s used by another parking lot.\n", 05951 lot->name, exten, lot->cfg.parking_con); 05952 } 05953 return 0; 05954 } 05955 /* The new parking lot ramp goes before this node. */ 05956 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 05957 if (!new_ramp) { 05958 return -1; 05959 } 05960 AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node); 05961 return 0; 05962 } 05963 AST_LIST_TRAVERSE_SAFE_END; 05964 05965 /* New parking lot access ramp goes on the end. */ 05966 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 05967 if (!new_ramp) { 05968 return -1; 05969 } 05970 AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node); 05971 return 0; 05972 }
static int usage_context_add_spaces | ( | struct parking_dp_space_map * | space_map, | |
int | start, | |||
int | stop, | |||
struct ast_parkinglot * | lot, | |||
int | complain | |||
) | [static] |
Definition at line 6010 of file features.c.
References ast_free, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), build_dialplan_useage_spaces(), ast_parkinglot::cfg, LOG_WARNING, ast_parkinglot::name, parking_dp_spaces::node, parkinglot_cfg::parking_con, parking_dp_spaces::start, and parking_dp_spaces::stop.
Referenced by dialplan_usage_add_parkinglot_data().
06011 { 06012 struct parking_dp_spaces *cur_node; 06013 struct parking_dp_spaces *expand_node; 06014 struct parking_dp_spaces *new_node; 06015 06016 expand_node = NULL; 06017 AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) { 06018 /* NOTE: stop + 1 to combine immediately adjacent nodes into one. */ 06019 if (expand_node) { 06020 /* The previous node is expanding to possibly eat following nodes. */ 06021 if (expand_node->stop + 1 < cur_node->start) { 06022 /* Current node is completely after expanding node. */ 06023 return 0; 06024 } 06025 06026 if (complain 06027 && ((cur_node->start <= start && start <= cur_node->stop) 06028 || (cur_node->start <= stop && stop <= cur_node->stop) 06029 || (start < cur_node->start && cur_node->stop < stop))) { 06030 /* Only complain once per range add. */ 06031 complain = 0; 06032 ast_log(LOG_WARNING, 06033 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06034 lot->name, start, stop, lot->cfg.parking_con); 06035 } 06036 06037 /* Current node is eaten by the expanding node. */ 06038 if (expand_node->stop < cur_node->stop) { 06039 expand_node->stop = cur_node->stop; 06040 } 06041 AST_LIST_REMOVE_CURRENT(node); 06042 ast_free(cur_node); 06043 continue; 06044 } 06045 06046 if (cur_node->stop + 1 < start) { 06047 /* New range is completely after current node. */ 06048 continue; 06049 } 06050 if (stop + 1 < cur_node->start) { 06051 /* New range is completely before current node. */ 06052 new_node = build_dialplan_useage_spaces(start, stop); 06053 if (!new_node) { 06054 return -1; 06055 } 06056 AST_LIST_INSERT_BEFORE_CURRENT(new_node, node); 06057 return 0; 06058 } 06059 06060 if (complain 06061 && ((cur_node->start <= start && start <= cur_node->stop) 06062 || (cur_node->start <= stop && stop <= cur_node->stop) 06063 || (start < cur_node->start && cur_node->stop < stop))) { 06064 /* Only complain once per range add. */ 06065 complain = 0; 06066 ast_log(LOG_WARNING, 06067 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06068 lot->name, start, stop, lot->cfg.parking_con); 06069 } 06070 06071 /* Current node range overlaps or is immediately adjacent to new range. */ 06072 if (start < cur_node->start) { 06073 /* Expand the current node in the front. */ 06074 cur_node->start = start; 06075 } 06076 if (stop <= cur_node->stop) { 06077 /* Current node is not expanding in the rear. */ 06078 return 0; 06079 } 06080 cur_node->stop = stop; 06081 expand_node = cur_node; 06082 } 06083 AST_LIST_TRAVERSE_SAFE_END; 06084 06085 if (expand_node) { 06086 /* 06087 * The previous node expanded and either ate all following nodes 06088 * or it was the last node. 06089 */ 06090 return 0; 06091 } 06092 06093 /* New range goes on the end. */ 06094 new_node = build_dialplan_useage_spaces(start, stop); 06095 if (!new_node) { 06096 return -1; 06097 } 06098 AST_LIST_INSERT_TAIL(space_map, new_node, node); 06099 return 0; 06100 }
static int xfer_park_call_helper | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
struct ast_exten * | park_exten | |||
) | [static] |
Definition at line 1790 of file features.c.
References args, AST_FEATURE_RETURN_SUCCESS, ast_get_extension_app_data(), AST_PARK_OPT_SILENCE, AST_STANDARD_APP_ARGS, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, create_dynamic_parkinglot(), default_parkinglot, find_parkinglot(), findparkinglotname(), finishup(), masq_park_call(), parkeddynamic, parkinglot_addref(), parkinglot_unref(), parse(), and park_app_args::pl_name.
Referenced by builtin_atxfer(), and builtin_blindtransfer().
01791 { 01792 char *parse; 01793 const char *app_data; 01794 const char *pl_name; 01795 struct ast_park_call_args args = { 0, }; 01796 struct park_app_args app_args; 01797 int res; 01798 01799 app_data = ast_get_extension_app_data(park_exten); 01800 if (!app_data) { 01801 app_data = ""; 01802 } 01803 parse = ast_strdupa(app_data); 01804 AST_STANDARD_APP_ARGS(app_args, parse); 01805 01806 /* Find the parking lot */ 01807 if (!ast_strlen_zero(app_args.pl_name)) { 01808 pl_name = app_args.pl_name; 01809 } else { 01810 pl_name = findparkinglotname(parker); 01811 } 01812 if (ast_strlen_zero(pl_name)) { 01813 /* Parking lot is not specified, so use the default parking lot. */ 01814 args.parkinglot = parkinglot_addref(default_parkinglot); 01815 } else { 01816 args.parkinglot = find_parkinglot(pl_name); 01817 if (!args.parkinglot && parkeddynamic) { 01818 args.parkinglot = create_dynamic_parkinglot(pl_name, park_me); 01819 } 01820 } 01821 01822 if (args.parkinglot) { 01823 /* Park the call */ 01824 res = finishup(park_me); 01825 if (res) { 01826 /* park_me hungup on us. */ 01827 parkinglot_unref(args.parkinglot); 01828 return -1; 01829 } 01830 res = masq_park_call(park_me, parker, &args); 01831 parkinglot_unref(args.parkinglot); 01832 } else { 01833 /* Parking failed because parking lot does not exist. */ 01834 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { 01835 ast_stream_and_wait(parker, "pbx-parkingfailed", ""); 01836 } 01837 finishup(park_me); 01838 res = -1; 01839 } 01840 01841 return res ? AST_FEATURE_RETURN_SUCCESS : -1; 01842 }
int adsipark [static] |
char* app_bridge = "Bridge" [static] |
Definition at line 7288 of file features.c.
unsigned int atxfercallbackretries [static] |
unsigned int atxferdropcall [static] |
unsigned int atxferloopdelay [static] |
int atxfernoanswertimeout [static] |
struct ast_app_option bridge_exec_options[128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, } [static] |
struct ast_call_feature builtin_features[] [static] |
Definition at line 2832 of file features.c.
Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
struct ast_cli_entry cli_features[] [static] |
Initial value:
{ { .handler = handle_feature_show , .summary = "Lists configured features" ,__VA_ARGS__ }, { .handler = handle_features_reload , .summary = "Reloads configured features" ,__VA_ARGS__ }, { .handler = handle_parkedcalls , .summary = "List currently parked calls" ,__VA_ARGS__ }, }
Definition at line 6961 of file features.c.
Referenced by ast_features_init().
int comebacktoorigin = 1 [static] |
Definition at line 612 of file features.c.
Referenced by manage_parked_call(), and process_config().
char courtesytone[256] [static] |
Courtesy tone used to pickup parked calls and on-touch-record
Definition at line 589 of file features.c.
Referenced by builtin_automixmonitor(), builtin_automonitor(), parked_call_exec(), and process_config().
struct ast_parkinglot* default_parkinglot [static] |
Default parking lot.
Will not be NULL while running.
Definition at line 582 of file features.c.
struct ast_datastore_info dial_features_info [static] |
Initial value:
{ .type = "dial-features", .destroy = dial_features_destroy, .duplicate = dial_features_duplicate, }
Definition at line 747 of file features.c.
Referenced by add_features_datastores(), builtin_atxfer(), manage_parked_call(), and parked_call_exec().
int featuredigittimeout [static] |
Definition at line 611 of file features.c.
ast_rwlock_t features_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } [static] |
Definition at line 2830 of file features.c.
Referenced by ast_rdlock_call_features(), ast_unlock_call_features(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
ast_mutex_t features_reload_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
Ensure that features.conf reloads on one thread at a time.
Definition at line 606 of file features.c.
Referenced by ast_features_reload().
int force_reload_load [static] |
Force a config reload to reload regardless of config file timestamp.
Definition at line 585 of file features.c.
Referenced by build_parkinglot(), load_config(), parkinglot_activate_cb(), and parkinglot_is_marked_cb().
struct ast_app* mixmonitor_app = NULL [static] |
int mixmonitor_ok = 1 [static] |
struct ast_app* monitor_app = NULL [static] |
Definition at line 635 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 636 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
struct ast_app_option park_call_options[128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } [static] |
const char* parkcall = "Park" [static] |
Definition at line 633 of file features.c.
Referenced by ast_features_init(), get_parking_exten(), and parkinglot_activate().
const char* parkedcall = "ParkedCall" [static] |
Definition at line 419 of file features.c.
int parkeddynamic = 0 [static] |
Enable creation of parkinglots dynamically
Definition at line 588 of file features.c.
Referenced by ast_masq_park_call_exten(), ast_park_call_exten(), park_call_exec(), park_space_reserve(), process_config(), and xfer_park_call_helper().
int parkedplay = 0 [static] |
Who to play courtesytone to when someone picks up a parked call.
Definition at line 587 of file features.c.
Referenced by parked_call_exec(), and process_config().
char parking_con_dial[] = "park-dial" [static] |
Context for parking dialback to parker.
Definition at line 603 of file features.c.
Referenced by ast_features_reload(), and manage_parked_call().
pthread_t parking_thread [static] |
struct parkinglot_cfg parkinglot_cfg_default [static] |
Initial value:
{ .parkext = DEFAULT_PARK_EXTENSION, .parkingtime = DEFAULT_PARK_TIME, }
Definition at line 5332 of file features.c.
Referenced by build_parkinglot().
struct parkinglot_cfg parkinglot_cfg_default_default [static] |
Default configuration for default parking lot.
Definition at line 5322 of file features.c.
Referenced by build_parkinglot().
struct ao2_container* parkinglots [static] |
The configured parking lots container. Always at least one - the default parking lot.
Definition at line 575 of file features.c.
Referenced by ast_features_init(), build_dialplan_useage_map(), build_parkinglot(), create_dynamic_parkinglot(), do_parking_thread(), find_parkinglot(), handle_feature_show(), handle_parkedcalls(), load_config(), and manager_parking_status().
struct ast_datastore_info pickup_active [static] |
Initial value:
{
.type = "pickup-active",
}
Definition at line 7130 of file features.c.
Referenced by ast_can_pickup(), and ast_do_pickup().
char pickup_ext[AST_MAX_EXTENSION] [static] |
Call pickup extension
Definition at line 421 of file features.c.
Referenced by analog_canmatch_featurecode(), and canmatch_featurecode().
char pickupfailsound[256] [static] |
Pickup failure sound
Definition at line 593 of file features.c.
Referenced by ast_pickup_call(), and process_config().
char pickupsound[256] [static] |
Pickup sound
Definition at line 592 of file features.c.
Referenced by ast_pickup_call(), and process_config().
char* registrar = "features" [static] |
Registrar for operations
Definition at line 619 of file features.c.
Referenced by ast_features_reload(), manage_parked_call(), park_add_hints(), park_call_full(), parkinglot_activate(), remove_dead_dialplan_useage(), and remove_exten_if_exist().
struct ast_app* stopmixmonitor_app = NULL [static] |
int stopmixmonitor_ok = 1 [static] |
int transferdigittimeout [static] |
Definition at line 610 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and process_config().
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 591 of file features.c.
Referenced by builtin_atxfer(), and process_config().
char xfersound[256] [static] |
Call transfer sound
Definition at line 590 of file features.c.
Referenced by action_bridge(), bridge_exec(), builtin_atxfer(), local_attended_transfer(), and process_config().