#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 int | add_features_datastore (struct ast_channel *chan, const struct ast_flags *my_features, const struct ast_flags *peer_features) |
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 (struct ast_bridge_thread_obj *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 int | 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 int | set_chan_app_data (struct ast_channel *chan, const char *src_app_data) |
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_datastore_info | channel_app_data_datastore |
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 2950 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 7407 of file features.c.
07407 { 07408 BRIDGE_OPT_PLAYTONE = (1 << 0), 07409 OPT_CALLEE_HANGUP = (1 << 1), 07410 OPT_CALLER_HANGUP = (1 << 2), 07411 OPT_DURATION_LIMIT = (1 << 3), 07412 OPT_DURATION_STOP = (1 << 4), 07413 OPT_CALLEE_TRANSFER = (1 << 5), 07414 OPT_CALLER_TRANSFER = (1 << 6), 07415 OPT_CALLEE_MONITOR = (1 << 7), 07416 OPT_CALLER_MONITOR = (1 << 8), 07417 OPT_CALLEE_PARK = (1 << 9), 07418 OPT_CALLER_PARK = (1 << 10), 07419 OPT_CALLEE_KILL = (1 << 11), 07420 };
anonymous enum |
Definition at line 7422 of file features.c.
07422 { 07423 OPT_ARG_DURATION_LIMIT = 0, 07424 OPT_ARG_DURATION_STOP, 07425 /* note: this entry _MUST_ be the last one in the enum */ 07426 OPT_ARG_ARRAY_SIZE, 07427 };
Options to pass to park_call_full
Definition at line 1121 of file features.c.
01121 { 01122 /*! Provide ringing to the parked caller instead of music on hold */ 01123 AST_PARK_OPT_RINGING = (1 << 0), 01124 /*! Randomly choose a parking spot for the caller instead of choosing 01125 * the first one that is available. */ 01126 AST_PARK_OPT_RANDOMIZE = (1 << 1), 01127 /*! Do not announce the parking number */ 01128 AST_PARK_OPT_SILENCE = (1 << 2), 01129 };
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 |
Definition at line 6887 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().
06888 { 06889 const char *channela = astman_get_header(m, "Channel1"); 06890 const char *channelb = astman_get_header(m, "Channel2"); 06891 const char *playtone = astman_get_header(m, "Tone"); 06892 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2]; 06893 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 06894 struct ast_bridge_thread_obj *tobj = NULL; 06895 char buf[256]; 06896 06897 /* make sure valid channels were specified */ 06898 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 06899 astman_send_error(s, m, "Missing channel parameter in request"); 06900 return 0; 06901 } 06902 06903 /* Start with chana */ 06904 chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); 06905 if (!chana) { 06906 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 06907 astman_send_error(s, m, buf); 06908 return 0; 06909 } 06910 06911 /* Answer the channels if needed */ 06912 if (chana->_state != AST_STATE_UP) 06913 ast_answer(chana); 06914 06915 /* create the placeholder channels and grab the other channels */ 06916 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 06917 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) { 06918 astman_send_error(s, m, "Unable to create temporary channel!"); 06919 chana = ast_channel_unref(chana); 06920 return 0; 06921 } 06922 06923 if (do_bridge_masquerade(chana, tmpchana)) { 06924 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela); 06925 astman_send_error(s, m, buf); 06926 ast_hangup(tmpchana); 06927 chana = ast_channel_unref(chana); 06928 return 0; 06929 } 06930 06931 chana = ast_channel_unref(chana); 06932 06933 /* now do chanb */ 06934 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); 06935 if (!chanb) { 06936 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 06937 astman_send_error(s, m, buf); 06938 ast_hangup(tmpchana); 06939 return 0; 06940 } 06941 06942 /* Answer the channels if needed */ 06943 if (chanb->_state != AST_STATE_UP) 06944 ast_answer(chanb); 06945 06946 /* create the placeholder channels and grab the other channels */ 06947 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 06948 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) { 06949 astman_send_error(s, m, "Unable to create temporary channels!"); 06950 ast_hangup(tmpchana); 06951 chanb = ast_channel_unref(chanb); 06952 return 0; 06953 } 06954 06955 if (do_bridge_masquerade(chanb, tmpchanb)) { 06956 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb); 06957 astman_send_error(s, m, buf); 06958 ast_hangup(tmpchana); 06959 ast_hangup(tmpchanb); 06960 chanb = ast_channel_unref(chanb); 06961 return 0; 06962 } 06963 06964 chanb = ast_channel_unref(chanb); 06965 06966 /* make the channels compatible, send error if we fail doing so */ 06967 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 06968 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 06969 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 06970 ast_hangup(tmpchana); 06971 ast_hangup(tmpchanb); 06972 return 0; 06973 } 06974 06975 /* setup the bridge thread object and start the bridge */ 06976 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 06977 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 06978 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 06979 ast_hangup(tmpchana); 06980 ast_hangup(tmpchanb); 06981 return 0; 06982 } 06983 06984 tobj->chan = tmpchana; 06985 tobj->peer = tmpchanb; 06986 tobj->return_to_pbx = 1; 06987 06988 if (ast_true(playtone)) { 06989 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 06990 if (ast_waitstream(tmpchanb, "") < 0) 06991 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 06992 } 06993 } 06994 06995 chans[0] = tmpchana; 06996 chans[1] = tmpchanb; 06997 06998 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans, 06999 "Response: Success\r\n" 07000 "Channel1: %s\r\n" 07001 "Channel2: %s\r\n", tmpchana->name, tmpchanb->name); 07002 07003 bridge_call_thread_launch(tobj); 07004 07005 astman_send_ack(s, m, "Launched bridge thread with success"); 07006 07007 return 0; 07008 }
static int add_features_datastore | ( | struct ast_channel * | chan, | |
const struct ast_flags * | my_features, | |||
const struct ast_flags * | peer_features | |||
) | [static] |
Definition at line 764 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(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, LOG_WARNING, ast_dial_features::my_features, and ast_dial_features::peer_features.
Referenced by add_features_datastores(), and builtin_atxfer().
00765 { 00766 struct ast_datastore *datastore; 00767 struct ast_dial_features *dialfeatures; 00768 00769 ast_channel_lock(chan); 00770 datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL); 00771 ast_channel_unlock(chan); 00772 if (datastore) { 00773 /* Already exists. */ 00774 return 1; 00775 } 00776 00777 /* Create a new datastore with specified feature flags. */ 00778 datastore = ast_datastore_alloc(&dial_features_info, NULL); 00779 if (!datastore) { 00780 ast_log(LOG_WARNING, "Unable to create channel features datastore.\n"); 00781 return 0; 00782 } 00783 dialfeatures = ast_calloc(1, sizeof(*dialfeatures)); 00784 if (!dialfeatures) { 00785 ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n"); 00786 ast_datastore_free(datastore); 00787 return 0; 00788 } 00789 ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL); 00790 ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL); 00791 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 00792 datastore->data = dialfeatures; 00793 ast_channel_lock(chan); 00794 ast_channel_datastore_add(chan, datastore); 00795 ast_channel_unlock(chan); 00796 return 0; 00797 }
static void add_features_datastores | ( | struct ast_channel * | caller, | |
struct ast_channel * | callee, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 3864 of file features.c.
References add_features_datastore(), and config.
Referenced by ast_bridge_call().
03865 { 03866 if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) { 03867 /* 03868 * If we don't return here, then when we do a builtin_atxfer we 03869 * will copy the disconnect flags over from the atxfer to the 03870 * callee (Party C). 03871 */ 03872 return; 03873 } 03874 03875 add_features_datastore(callee, &config->features_callee, &config->features_caller); 03876 }
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 1059 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
01060 { 01061 int res; 01062 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 01063 char tmp[256]; 01064 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 01065 01066 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 01067 message[0] = tmp; 01068 res = ast_adsi_load_session(chan, NULL, 0, 1); 01069 if (res == -1) 01070 return res; 01071 return ast_adsi_print(chan, message, justify, 1); 01072 }
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 3906 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_copy_vars(), 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().
03907 { 03908 /* Copy voice back and forth between the two channels. Give the peer 03909 the ability to transfer calls with '#<extension' syntax. */ 03910 struct ast_frame *f; 03911 struct ast_channel *who; 03912 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03913 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03914 char orig_channame[AST_CHANNEL_NAME]; 03915 char orig_peername[AST_CHANNEL_NAME]; 03916 int res; 03917 int diff; 03918 int hasfeatures=0; 03919 int hadfeatures=0; 03920 int autoloopflag; 03921 int sendingdtmfdigit = 0; 03922 int we_disabled_peer_cdr = 0; 03923 struct ast_option_header *aoh; 03924 struct ast_cdr *bridge_cdr = NULL; 03925 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03926 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03927 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03928 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03929 struct ast_silence_generator *silgen = NULL; 03930 const char *h_context; 03931 03932 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03933 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03934 03935 /* Clear any BLINDTRANSFER since the transfer has completed. */ 03936 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03937 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL); 03938 03939 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03940 add_features_datastores(chan, peer, config); 03941 03942 /* This is an interesting case. One example is if a ringing channel gets redirected to 03943 * an extension that picks up a parked call. This will make sure that the call taken 03944 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03945 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03946 ast_indicate(peer, AST_CONTROL_RINGING); 03947 } 03948 03949 if (monitor_ok) { 03950 const char *monitor_exec; 03951 struct ast_channel *src = NULL; 03952 if (!monitor_app) { 03953 if (!(monitor_app = pbx_findapp("Monitor"))) 03954 monitor_ok=0; 03955 } 03956 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03957 src = chan; 03958 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03959 src = peer; 03960 if (monitor_app && src) { 03961 char *tmp = ast_strdupa(monitor_exec); 03962 pbx_exec(src, monitor_app, tmp); 03963 } 03964 } 03965 03966 set_config_flags(chan, peer, config); 03967 03968 /* Answer if need be */ 03969 if (chan->_state != AST_STATE_UP) { 03970 if (ast_raw_answer(chan, 1)) { 03971 return -1; 03972 } 03973 } 03974 03975 #ifdef FOR_DEBUG 03976 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 03977 ast_channel_log("Pre-bridge CHAN Channel info", chan); 03978 ast_channel_log("Pre-bridge PEER Channel info", peer); 03979 #endif 03980 /* two channels are being marked as linked here */ 03981 ast_channel_set_linkgroup(chan,peer); 03982 03983 /* copy the userfield from the B-leg to A-leg if applicable */ 03984 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 03985 char tmp[256]; 03986 03987 ast_channel_lock(chan); 03988 if (!ast_strlen_zero(chan->cdr->userfield)) { 03989 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 03990 ast_cdr_appenduserfield(chan, tmp); 03991 } else { 03992 ast_cdr_setuserfield(chan, peer->cdr->userfield); 03993 } 03994 ast_channel_unlock(chan); 03995 /* Don't delete the CDR; just disable it. */ 03996 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03997 we_disabled_peer_cdr = 1; 03998 } 03999 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 04000 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 04001 04002 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 04003 ast_channel_lock_both(chan, peer); 04004 if (chan_cdr) { 04005 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 04006 ast_cdr_update(chan); 04007 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 04008 /* rip any forked CDR's off of the chan_cdr and attach 04009 * them to the bridge_cdr instead */ 04010 bridge_cdr->next = chan_cdr->next; 04011 chan_cdr->next = NULL; 04012 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04013 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04014 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 04015 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04016 } 04017 ast_cdr_setaccount(peer, chan->accountcode); 04018 } else { 04019 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 04020 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 04021 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 04022 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 04023 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 04024 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04025 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04026 ast_cdr_setcid(bridge_cdr, chan); 04027 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 04028 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 04029 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 04030 /* Destination information */ 04031 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 04032 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 04033 if (peer_cdr) { 04034 bridge_cdr->start = peer_cdr->start; 04035 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04036 } else { 04037 ast_cdr_start(bridge_cdr); 04038 } 04039 } 04040 ast_channel_unlock(chan); 04041 ast_channel_unlock(peer); 04042 04043 ast_debug(4,"bridge answer set, chan answer set\n"); 04044 /* peer_cdr->answer will be set when a macro runs on the peer; 04045 in that case, the bridge answer will be delayed while the 04046 macro plays on the peer channel. The peer answered the call 04047 before the macro started playing. To the phone system, 04048 this is billable time for the call, even tho the caller 04049 hears nothing but ringing while the macro does its thing. */ 04050 04051 /* Another case where the peer cdr's time will be set, is when 04052 A self-parks by pickup up phone and dialing 700, then B 04053 picks up A by dialing its parking slot; there may be more 04054 practical paths that get the same result, tho... in which 04055 case you get the previous answer time from the Park... which 04056 is before the bridge's start time, so I added in the 04057 tvcmp check to the if below */ 04058 04059 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 04060 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 04061 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 04062 if (chan_cdr) { 04063 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 04064 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 04065 } 04066 } else { 04067 ast_cdr_answer(bridge_cdr); 04068 if (chan_cdr) { 04069 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 04070 } 04071 } 04072 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 04073 if (chan_cdr) { 04074 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 04075 } 04076 if (peer_cdr) { 04077 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 04078 } 04079 } 04080 /* the DIALED flag may be set if a dialed channel is transfered 04081 * and then bridged to another channel. In order for the 04082 * bridge CDR to be written, the DIALED flag must not be 04083 * present. */ 04084 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04085 } 04086 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04087 04088 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04089 * a call is being bridged, that the humans in charge know what they're doing. If they 04090 * don't, well, what can we do about that? */ 04091 clear_dialed_interfaces(chan); 04092 clear_dialed_interfaces(peer); 04093 04094 for (;;) { 04095 struct ast_channel *other; /* used later */ 04096 04097 res = ast_channel_bridge(chan, peer, config, &f, &who); 04098 04099 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04100 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04101 /* Zombies are present time to leave! */ 04102 res = -1; 04103 if (f) { 04104 ast_frfree(f); 04105 } 04106 goto before_you_go; 04107 } 04108 04109 /* When frame is not set, we are probably involved in a situation 04110 where we've timed out. 04111 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04112 and also for DTMF_END. If we flow into the following 'if' for both, then 04113 our wait times are cut in half, as both will subtract from the 04114 feature_timer. Not good! 04115 */ 04116 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04117 /* Update feature timer for next pass */ 04118 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04119 if (res == AST_BRIDGE_RETRY) { 04120 /* The feature fully timed out but has not been updated. Skip 04121 * the potential round error from the diff calculation and 04122 * explicitly set to expired. */ 04123 config->feature_timer = -1; 04124 } else { 04125 config->feature_timer -= diff; 04126 } 04127 04128 if (hasfeatures) { 04129 if (config->feature_timer <= 0) { 04130 /* Not *really* out of time, just out of time for 04131 digits to come in for features. */ 04132 ast_debug(1, "Timed out for feature!\n"); 04133 if (!ast_strlen_zero(peer_featurecode)) { 04134 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 04135 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04136 } 04137 if (!ast_strlen_zero(chan_featurecode)) { 04138 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 04139 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04140 } 04141 if (f) 04142 ast_frfree(f); 04143 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04144 if (!hasfeatures) { 04145 /* No more digits expected - reset the timer */ 04146 config->feature_timer = 0; 04147 } 04148 hadfeatures = hasfeatures; 04149 /* Continue as we were */ 04150 continue; 04151 } else if (!f) { 04152 /* The bridge returned without a frame and there is a feature in progress. 04153 * However, we don't think the feature has quite yet timed out, so just 04154 * go back into the bridge. */ 04155 continue; 04156 } 04157 } else { 04158 if (config->feature_timer <=0) { 04159 /* We ran out of time */ 04160 config->feature_timer = 0; 04161 who = chan; 04162 if (f) 04163 ast_frfree(f); 04164 f = NULL; 04165 res = 0; 04166 } 04167 } 04168 } 04169 if (res < 0) { 04170 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04171 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 04172 } 04173 goto before_you_go; 04174 } 04175 04176 if (!f || (f->frametype == AST_FRAME_CONTROL && 04177 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04178 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04179 /* 04180 * If the bridge was broken for a hangup that isn't real, 04181 * then don't run the h extension, because the channel isn't 04182 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04183 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04184 */ 04185 ast_channel_lock(chan); 04186 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04187 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 04188 } 04189 ast_channel_unlock(chan); 04190 res = -1; 04191 break; 04192 } 04193 /* many things should be sent to the 'other' channel */ 04194 other = (who == chan) ? peer : chan; 04195 if (f->frametype == AST_FRAME_CONTROL) { 04196 switch (f->subclass.integer) { 04197 case AST_CONTROL_RINGING: 04198 case AST_CONTROL_FLASH: 04199 case -1: 04200 ast_indicate(other, f->subclass.integer); 04201 break; 04202 case AST_CONTROL_CONNECTED_LINE: 04203 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04204 break; 04205 } 04206 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04207 break; 04208 case AST_CONTROL_REDIRECTING: 04209 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04210 break; 04211 } 04212 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04213 break; 04214 case AST_CONTROL_AOC: 04215 case AST_CONTROL_HOLD: 04216 case AST_CONTROL_UNHOLD: 04217 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04218 break; 04219 case AST_CONTROL_OPTION: 04220 aoh = f->data.ptr; 04221 /* Forward option Requests, but only ones we know are safe 04222 * These are ONLY sent by chan_iax2 and I'm not convinced that 04223 * they are useful. I haven't deleted them entirely because I 04224 * just am not sure of the ramifications of removing them. */ 04225 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04226 switch (ntohs(aoh->option)) { 04227 case AST_OPTION_TONE_VERIFY: 04228 case AST_OPTION_TDD: 04229 case AST_OPTION_RELAXDTMF: 04230 case AST_OPTION_AUDIO_MODE: 04231 case AST_OPTION_DIGIT_DETECT: 04232 case AST_OPTION_FAX_DETECT: 04233 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04234 f->datalen - sizeof(struct ast_option_header), 0); 04235 } 04236 } 04237 break; 04238 } 04239 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04240 struct ast_flags *cfg; 04241 char dtmfcode[2] = { f->subclass.integer, }; 04242 size_t featurelen; 04243 04244 if (who == chan) { 04245 featurelen = strlen(chan_featurecode); 04246 cfg = &(config->features_caller); 04247 } else { 04248 featurelen = strlen(peer_featurecode); 04249 cfg = &(config->features_callee); 04250 } 04251 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04252 * DTMF along untouched. If this is not the first digit of a multi-digit code 04253 * then we need to fall through and stream the characters if it matches */ 04254 if (featurelen == 0 04255 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04256 if (option_debug > 3) { 04257 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04258 } 04259 ast_write(other, f); 04260 sendingdtmfdigit = 1; 04261 } else { 04262 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04263 * transmitting something while we hold on to the DTMF waiting for a 04264 * feature. */ 04265 if (!silgen && ast_opt_transmit_silence) { 04266 silgen = ast_channel_start_silence_generator(other); 04267 } 04268 if (option_debug > 3) { 04269 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04270 } 04271 } 04272 } else if (f->frametype == AST_FRAME_DTMF_END) { 04273 char *featurecode; 04274 int sense; 04275 04276 hadfeatures = hasfeatures; 04277 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04278 if (who == chan) { 04279 sense = FEATURE_SENSE_CHAN; 04280 featurecode = chan_featurecode; 04281 } else { 04282 sense = FEATURE_SENSE_PEER; 04283 featurecode = peer_featurecode; 04284 } 04285 04286 if (sendingdtmfdigit == 1) { 04287 /* We let the BEGIN go through happily, so let's not bother with the END, 04288 * since we already know it's not something we bother with */ 04289 ast_write(other, f); 04290 sendingdtmfdigit = 0; 04291 } else { 04292 /*! append the event to featurecode. we rely on the string being zero-filled, and 04293 * not overflowing it. 04294 * \todo XXX how do we guarantee the latter ? 04295 */ 04296 featurecode[strlen(featurecode)] = f->subclass.integer; 04297 /* Get rid of the frame before we start doing "stuff" with the channels */ 04298 ast_frfree(f); 04299 f = NULL; 04300 if (silgen) { 04301 ast_channel_stop_silence_generator(other, silgen); 04302 silgen = NULL; 04303 } 04304 config->feature_timer = 0; 04305 res = feature_interpret(chan, peer, config, featurecode, sense); 04306 switch(res) { 04307 case AST_FEATURE_RETURN_PASSDIGITS: 04308 ast_dtmf_stream(other, who, featurecode, 0, 0); 04309 /* Fall through */ 04310 case AST_FEATURE_RETURN_SUCCESS: 04311 memset(featurecode, 0, sizeof(chan_featurecode)); 04312 break; 04313 } 04314 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04315 res = 0; 04316 } else { 04317 break; 04318 } 04319 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04320 if (hadfeatures && !hasfeatures) { 04321 /* Feature completed or timed out */ 04322 config->feature_timer = 0; 04323 } else if (hasfeatures) { 04324 if (config->timelimit) { 04325 /* No warning next time - we are waiting for feature code */ 04326 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04327 } 04328 config->feature_start_time = ast_tvnow(); 04329 config->feature_timer = featuredigittimeout; 04330 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04331 } 04332 } 04333 } 04334 if (f) 04335 ast_frfree(f); 04336 } 04337 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04338 04339 before_you_go: 04340 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04341 if (silgen) { 04342 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04343 silgen = NULL; 04344 } 04345 04346 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04347 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04348 if (bridge_cdr) { 04349 ast_cdr_discard(bridge_cdr); 04350 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04351 } 04352 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04353 } 04354 04355 if (config->end_bridge_callback) { 04356 config->end_bridge_callback(config->end_bridge_callback_data); 04357 } 04358 04359 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04360 * if it were, then chan belongs to a different thread now, and might have been hung up long 04361 * ago. 04362 */ 04363 if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04364 h_context = NULL; 04365 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04366 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04367 h_context = chan->context; 04368 } else if (!ast_strlen_zero(chan->macrocontext) 04369 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04370 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04371 h_context = chan->macrocontext; 04372 } else { 04373 h_context = NULL; 04374 } 04375 if (h_context) { 04376 struct ast_cdr *swapper = NULL; 04377 char savelastapp[AST_MAX_EXTENSION]; 04378 char savelastdata[AST_MAX_EXTENSION]; 04379 char save_context[AST_MAX_CONTEXT]; 04380 char save_exten[AST_MAX_EXTENSION]; 04381 int save_prio; 04382 int found = 0; /* set if we find at least one match */ 04383 int spawn_error = 0; 04384 04385 /* 04386 * Make sure that the channel is marked as hungup since we are 04387 * going to run the "h" exten on it. 04388 */ 04389 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04390 04391 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04392 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04393 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04394 ast_cdr_end(bridge_cdr); 04395 } 04396 04397 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04398 dialplan code operate on it */ 04399 ast_channel_lock(chan); 04400 if (bridge_cdr) { 04401 swapper = chan->cdr; 04402 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04403 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04404 chan->cdr = bridge_cdr; 04405 } 04406 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04407 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04408 save_prio = chan->priority; 04409 if (h_context != chan->context) { 04410 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04411 } 04412 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04413 chan->priority = 1; 04414 ast_channel_unlock(chan); 04415 04416 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04417 chan->priority, 04418 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04419 &found, 1)) == 0) { 04420 chan->priority++; 04421 } 04422 if (found && spawn_error) { 04423 /* Something bad happened, or a hangup has been requested. */ 04424 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04425 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04426 } 04427 04428 /* swap it back */ 04429 ast_channel_lock(chan); 04430 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04431 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04432 chan->priority = save_prio; 04433 if (bridge_cdr) { 04434 if (chan->cdr == bridge_cdr) { 04435 chan->cdr = swapper; 04436 } else { 04437 bridge_cdr = NULL; 04438 } 04439 } 04440 /* An "h" exten has been run, so indicate that one has been run. */ 04441 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04442 ast_channel_unlock(chan); 04443 04444 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04445 if (bridge_cdr) { 04446 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04447 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04448 } 04449 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04450 } 04451 04452 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04453 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04454 /* If the channel CDR has been modified during the call, record the changes in the bridge cdr, 04455 * BUT, if we've gone through the h extension block above, the CDR got swapped so don't overwrite 04456 * what was done in the h extension. What a mess. This is why you never touch CDR code. */ 04457 if (new_chan_cdr && bridge_cdr && !h_context) { 04458 ast_cdr_copy_vars(bridge_cdr, new_chan_cdr); 04459 ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield)); 04460 bridge_cdr->amaflags = new_chan_cdr->amaflags; 04461 ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode)); 04462 if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 04463 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04464 } 04465 } 04466 04467 /* we can post the bridge CDR at this point */ 04468 if (bridge_cdr) { 04469 ast_cdr_end(bridge_cdr); 04470 ast_cdr_detach(bridge_cdr); 04471 } 04472 04473 /* do a specialized reset on the beginning channel 04474 CDR's, if they still exist, so as not to mess up 04475 issues in future bridges; 04476 04477 Here are the rules of the game: 04478 1. The chan and peer channel pointers will not change 04479 during the life of the bridge. 04480 2. But, in transfers, the channel names will change. 04481 between the time the bridge is started, and the 04482 time the channel ends. 04483 Usually, when a channel changes names, it will 04484 also change CDR pointers. 04485 3. Usually, only one of the two channels (chan or peer) 04486 will change names. 04487 4. Usually, if a channel changes names during a bridge, 04488 it is because of a transfer. Usually, in these situations, 04489 it is normal to see 2 bridges running simultaneously, and 04490 it is not unusual to see the two channels that change 04491 swapped between bridges. 04492 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04493 to attend to; if the chan or peer changed names, 04494 we have the before and after attached CDR's. 04495 */ 04496 04497 if (new_chan_cdr) { 04498 struct ast_channel *chan_ptr = NULL; 04499 04500 if (strcasecmp(orig_channame, chan->name) != 0) { 04501 /* old channel */ 04502 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04503 ast_channel_lock(chan_ptr); 04504 if (!ast_bridged_channel(chan_ptr)) { 04505 struct ast_cdr *cur; 04506 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04507 if (cur == chan_cdr) { 04508 break; 04509 } 04510 } 04511 if (cur) { 04512 ast_cdr_specialized_reset(chan_cdr, 0); 04513 } 04514 } 04515 ast_channel_unlock(chan_ptr); 04516 chan_ptr = ast_channel_unref(chan_ptr); 04517 } 04518 /* new channel */ 04519 ast_cdr_specialized_reset(new_chan_cdr, 0); 04520 } else { 04521 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04522 } 04523 } 04524 04525 { 04526 struct ast_channel *chan_ptr = NULL; 04527 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04528 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)) 04529 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04530 if (strcasecmp(orig_peername, peer->name) != 0) { 04531 /* old channel */ 04532 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04533 ast_channel_lock(chan_ptr); 04534 if (!ast_bridged_channel(chan_ptr)) { 04535 struct ast_cdr *cur; 04536 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04537 if (cur == peer_cdr) { 04538 break; 04539 } 04540 } 04541 if (cur) { 04542 ast_cdr_specialized_reset(peer_cdr, 0); 04543 } 04544 } 04545 ast_channel_unlock(chan_ptr); 04546 chan_ptr = ast_channel_unref(chan_ptr); 04547 } 04548 /* new channel */ 04549 if (new_peer_cdr) { 04550 ast_cdr_specialized_reset(new_peer_cdr, 0); 04551 } 04552 } else { 04553 if (we_disabled_peer_cdr) { 04554 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04555 } 04556 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04557 } 04558 } 04559 04560 return res; 04561 }
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 7444 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().
07446 { 07447 char *stringp = ast_strdupa(parse); 07448 char *limit_str, *warning_str, *warnfreq_str; 07449 const char *var; 07450 int play_to_caller = 0, play_to_callee = 0; 07451 int delta; 07452 07453 limit_str = strsep(&stringp, ":"); 07454 warning_str = strsep(&stringp, ":"); 07455 warnfreq_str = strsep(&stringp, ":"); 07456 07457 config->timelimit = atol(limit_str); 07458 if (warning_str) 07459 config->play_warning = atol(warning_str); 07460 if (warnfreq_str) 07461 config->warning_freq = atol(warnfreq_str); 07462 07463 if (!config->timelimit) { 07464 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07465 config->timelimit = config->play_warning = config->warning_freq = 0; 07466 config->warning_sound = NULL; 07467 return -1; /* error */ 07468 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07469 int w = config->warning_freq; 07470 07471 /* 07472 * If the first warning is requested _after_ the entire call 07473 * would end, and no warning frequency is requested, then turn 07474 * off the warning. If a warning frequency is requested, reduce 07475 * the 'first warning' time by that frequency until it falls 07476 * within the call's total time limit. 07477 * 07478 * Graphically: 07479 * timelim->| delta |<-playwarning 07480 * 0__________________|_________________| 07481 * | w | | | | 07482 * 07483 * so the number of intervals to cut is 1+(delta-1)/w 07484 */ 07485 if (w == 0) { 07486 config->play_warning = 0; 07487 } else { 07488 config->play_warning -= w * ( 1 + (delta-1)/w ); 07489 if (config->play_warning < 1) 07490 config->play_warning = config->warning_freq = 0; 07491 } 07492 } 07493 07494 ast_channel_lock(chan); 07495 07496 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07497 play_to_caller = var ? ast_true(var) : 1; 07498 07499 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07500 play_to_callee = var ? ast_true(var) : 0; 07501 07502 if (!play_to_caller && !play_to_callee) 07503 play_to_caller = 1; 07504 07505 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07506 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07507 07508 /* The code looking at config wants a NULL, not just "", to decide 07509 * that the message should not be played, so we replace "" with NULL. 07510 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07511 * not found. 07512 */ 07513 07514 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07515 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07516 07517 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07518 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07519 07520 ast_channel_unlock(chan); 07521 07522 /* undo effect of S(x) in case they are both used */ 07523 calldurationlimit->tv_sec = 0; 07524 calldurationlimit->tv_usec = 0; 07525 07526 /* more efficient to do it like S(x) does since no advanced opts */ 07527 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07528 calldurationlimit->tv_sec = config->timelimit / 1000; 07529 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07530 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07531 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07532 config->timelimit = play_to_caller = play_to_callee = 07533 config->play_warning = config->warning_freq = 0; 07534 } else { 07535 ast_verb(4, "Limit Data for this call:\n"); 07536 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07537 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07538 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07539 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07540 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07541 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07542 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07543 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07544 } 07545 if (play_to_caller) 07546 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07547 if (play_to_callee) 07548 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07549 return 0; 07550 }
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 7250 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().
07251 { 07252 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07253 && (chan->_state == AST_STATE_RINGING 07254 || chan->_state == AST_STATE_RING 07255 /* 07256 * Check the down state as well because some SIP devices do not 07257 * give 180 ringing when they can just give 183 session progress 07258 * instead. Issue 14005. (Some ISDN switches as well for that 07259 * matter.) 07260 */ 07261 || chan->_state == AST_STATE_DOWN) 07262 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07263 return 1; 07264 } 07265 return 0; 07266 }
void ast_channel_log | ( | char * | title, | |
struct ast_channel * | chan | |||
) |
Definition at line 3799 of file features.c.
References ast_log(), and LOG_NOTICE.
Referenced by ast_bridge_call().
03800 { 03801 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan); 03802 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n", 03803 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority); 03804 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n", 03805 chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority); 03806 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n", 03807 chan->masq, chan->masqr, 03808 chan->_bridge, chan->uniqueid, chan->linkedid); 03809 if (chan->masqr) 03810 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n", 03811 chan->masqr->name, chan->masqr->cdr); 03812 if (chan->_bridge) 03813 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name); 03814 03815 ast_log(LOG_NOTICE, "===== done ====\n"); 03816 }
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 7326 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().
07327 { 07328 struct ast_party_connected_line connected_caller; 07329 struct ast_channel *chans[2] = { chan, target }; 07330 struct ast_datastore *ds_pickup; 07331 const char *chan_name;/*!< A masquerade changes channel names. */ 07332 const char *target_name;/*!< A masquerade changes channel names. */ 07333 int res = -1; 07334 07335 target_name = ast_strdupa(target->name); 07336 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name); 07337 07338 /* Mark the target to block any call pickup race. */ 07339 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07340 if (!ds_pickup) { 07341 ast_log(LOG_WARNING, 07342 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07343 return -1; 07344 } 07345 ast_channel_datastore_add(target, ds_pickup); 07346 07347 ast_party_connected_line_init(&connected_caller); 07348 ast_party_connected_line_copy(&connected_caller, &target->connected); 07349 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07350 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07351 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07352 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07353 } 07354 ast_party_connected_line_free(&connected_caller); 07355 07356 ast_channel_lock(chan); 07357 chan_name = ast_strdupa(chan->name); 07358 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07359 ast_channel_unlock(chan); 07360 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07361 07362 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07363 07364 if (ast_answer(chan)) { 07365 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07366 goto pickup_failed; 07367 } 07368 07369 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07370 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07371 goto pickup_failed; 07372 } 07373 07374 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07375 07376 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07377 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07378 07379 if (ast_channel_masquerade(target, chan)) { 07380 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07381 target_name); 07382 goto pickup_failed; 07383 } 07384 07385 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07386 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07387 "Channel: %s\r\n" 07388 "TargetChannel: %s\r\n", 07389 chan_name, target_name); 07390 07391 /* Do the masquerade manually to make sure that it is completed. */ 07392 ast_do_masquerade(target); 07393 res = 0; 07394 07395 pickup_failed: 07396 ast_channel_lock(target); 07397 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07398 ast_datastore_free(ds_pickup); 07399 } 07400 ast_party_connected_line_free(&connected_caller); 07401 07402 return res; 07403 }
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 3401 of file features.c.
References feature_group_exten::feature, FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03401 { 03402 03403 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03404 }
int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 8224 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().
08225 { 08226 int res; 08227 08228 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 08229 if (!parkinglots) { 08230 return -1; 08231 } 08232 08233 res = load_config(0); 08234 if (res) { 08235 return res; 08236 } 08237 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); 08238 if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) { 08239 return -1; 08240 } 08241 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); 08242 res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL); 08243 if (!res) 08244 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); 08245 if (!res) { 08246 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status); 08247 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park); 08248 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge); 08249 } 08250 08251 res |= ast_devstate_prov_add("Park", metermaidstate); 08252 #if defined(TEST_FRAMEWORK) 08253 res |= AST_TEST_REGISTER(features_test); 08254 #endif /* defined(TEST_FRAMEWORK) */ 08255 08256 return res; 08257 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6791 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().
06792 { 06793 struct ast_context *con; 06794 int res; 06795 06796 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06797 06798 /* 06799 * Always destroy the parking_con_dial context to remove buildup 06800 * of recalled extensions in the context. At worst, the parked 06801 * call gets hungup attempting to run an invalid extension when 06802 * we are trying to callback the parker or the preset return 06803 * extension. This is a small window of opportunity on an 06804 * execution chain that is not expected to happen very often. 06805 */ 06806 con = ast_context_find(parking_con_dial); 06807 if (con) { 06808 ast_context_destroy(con, registrar); 06809 } 06810 06811 res = load_config(1); 06812 ast_mutex_unlock(&features_reload_lock); 06813 06814 return res; 06815 }
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 3133 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
03134 { 03135 int x; 03136 for (x = 0; x < FEATURES_COUNT; x++) { 03137 if (!strcasecmp(name, builtin_features[x].sname)) 03138 return &builtin_features[x]; 03139 } 03140 return NULL; 03141 }
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 1845 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(), and parkandannounce_exec().
01846 { 01847 struct ast_park_call_args args = { 01848 .timeout = timeout, 01849 .extout = extout, 01850 }; 01851 01852 if (peer) { 01853 args.orig_chan_name = ast_strdupa(peer->name); 01854 } 01855 return masq_park_call(rchan, peer, &args); 01856 }
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 1791 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().
01792 { 01793 int res; 01794 char *parse; 01795 const char *app_data; 01796 struct ast_exten *exten; 01797 struct park_app_args app_args; 01798 struct ast_park_call_args args = { 01799 .timeout = timeout, 01800 .extout = extout, 01801 }; 01802 01803 if (parker) { 01804 args.orig_chan_name = ast_strdupa(parker->name); 01805 } 01806 if (!park_exten || !park_context) { 01807 return masq_park_call(park_me, parker, &args); 01808 } 01809 01810 /* 01811 * Determiine if the specified park extension has an exclusive 01812 * parking lot to use. 01813 */ 01814 if (parker && parker != park_me) { 01815 ast_autoservice_start(park_me); 01816 } 01817 exten = get_parking_exten(park_exten, parker, park_context); 01818 if (exten) { 01819 app_data = ast_get_extension_app_data(exten); 01820 if (!app_data) { 01821 app_data = ""; 01822 } 01823 parse = ast_strdupa(app_data); 01824 AST_STANDARD_APP_ARGS(app_args, parse); 01825 01826 if (!ast_strlen_zero(app_args.pl_name)) { 01827 /* Find the specified exclusive parking lot */ 01828 args.parkinglot = find_parkinglot(app_args.pl_name); 01829 if (!args.parkinglot && parkeddynamic) { 01830 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01831 } 01832 } 01833 } 01834 if (parker && parker != park_me) { 01835 ast_autoservice_stop(park_me); 01836 } 01837 01838 res = masq_park_call(park_me, parker, &args); 01839 if (args.parkinglot) { 01840 parkinglot_unref(args.parkinglot); 01841 } 01842 return res; 01843 }
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 1694 of file features.c.
References args, and park_call_full().
01695 { 01696 struct ast_park_call_args args = { 01697 .timeout = timeout, 01698 .extout = extout, 01699 }; 01700 01701 return park_call_full(park_me, parker, &args); 01702 }
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 1643 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().
01644 { 01645 int res; 01646 char *parse; 01647 const char *app_data; 01648 struct ast_exten *exten; 01649 struct park_app_args app_args; 01650 struct ast_park_call_args args = { 01651 .timeout = timeout, 01652 .extout = extout, 01653 }; 01654 01655 if (!park_exten || !park_context) { 01656 return park_call_full(park_me, parker, &args); 01657 } 01658 01659 /* 01660 * Determiine if the specified park extension has an exclusive 01661 * parking lot to use. 01662 */ 01663 if (parker && parker != park_me) { 01664 ast_autoservice_start(park_me); 01665 } 01666 exten = get_parking_exten(park_exten, parker, park_context); 01667 if (exten) { 01668 app_data = ast_get_extension_app_data(exten); 01669 if (!app_data) { 01670 app_data = ""; 01671 } 01672 parse = ast_strdupa(app_data); 01673 AST_STANDARD_APP_ARGS(app_args, parse); 01674 01675 if (!ast_strlen_zero(app_args.pl_name)) { 01676 /* Find the specified exclusive parking lot */ 01677 args.parkinglot = find_parkinglot(app_args.pl_name); 01678 if (!args.parkinglot && parkeddynamic) { 01679 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01680 } 01681 } 01682 } 01683 if (parker && parker != park_me) { 01684 ast_autoservice_stop(park_me); 01685 } 01686 01687 res = park_call_full(park_me, parker, &args); 01688 if (args.parkinglot) { 01689 parkinglot_unref(args.parkinglot); 01690 } 01691 return res; 01692 }
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 840 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().
00841 { 00842 return get_parking_exten(exten_str, chan, context) ? 1 : 0; 00843 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
< Potential pickup target
Definition at line 7292 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().
07293 { 07294 struct ast_channel *target;/*!< Potential pickup target */ 07295 int res = -1; 07296 ast_debug(1, "pickup attempt by %s\n", chan->name); 07297 07298 /* The found channel is already locked. */ 07299 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07300 if (target) { 07301 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name); 07302 07303 res = ast_do_pickup(chan, target); 07304 ast_channel_unlock(target); 07305 if (!res) { 07306 if (!ast_strlen_zero(pickupsound)) { 07307 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07308 } 07309 } else { 07310 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name); 07311 } 07312 target = ast_channel_unref(target); 07313 } 07314 07315 if (res < 0) { 07316 ast_debug(1, "No call pickup possible... for %s\n", chan->name); 07317 if (!ast_strlen_zero(pickupfailsound)) { 07318 ast_answer(chan); 07319 ast_stream_and_wait(chan, pickupfailsound, ""); 07320 } 07321 } 07322 07323 return res; 07324 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 845 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().
00846 { 00847 return pickup_ext; 00848 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 3123 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
03124 { 03125 ast_rwlock_rdlock(&features_lock); 03126 }
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 2967 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().
02968 { 02969 if (!feature) { 02970 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02971 return; 02972 } 02973 02974 AST_RWLIST_WRLOCK(&feature_list); 02975 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 02976 AST_RWLIST_UNLOCK(&feature_list); 02977 02978 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 02979 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 3128 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
03129 { 03130 ast_rwlock_unlock(&features_lock); 03131 }
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 3047 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
03048 { 03049 if (!feature) { 03050 return; 03051 } 03052 03053 AST_RWLIST_WRLOCK(&feature_list); 03054 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 03055 AST_RWLIST_UNLOCK(&feature_list); 03056 03057 ast_free(feature); 03058 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 3061 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.
03062 { 03063 struct ast_call_feature *feature; 03064 03065 AST_RWLIST_WRLOCK(&feature_list); 03066 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 03067 ast_free(feature); 03068 } 03069 AST_RWLIST_UNLOCK(&feature_list); 03070 }
static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 3087 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.
03088 { 03089 struct feature_group *fg; 03090 struct feature_group_exten *fge; 03091 03092 AST_RWLIST_WRLOCK(&feature_groups); 03093 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 03094 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 03095 ast_string_field_free_memory(fge); 03096 ast_free(fge); 03097 } 03098 03099 ast_string_field_free_memory(fg); 03100 ast_free(fg); 03101 } 03102 AST_RWLIST_UNLOCK(&feature_groups); 03103 }
static void atxfer_fail_cleanup | ( | struct ast_channel * | transferee, | |
struct ast_channel * | transferer, | |||
struct ast_party_connected_line * | connected_line | |||
) | [static] |
Definition at line 2469 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().
02470 { 02471 finishup(transferee); 02472 02473 /* 02474 * Restore party B connected line info about party A. 02475 * 02476 * Party B was the caller to party C and is the last known mode 02477 * for party B. 02478 */ 02479 if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) { 02480 ast_channel_update_connected_line(transferer, connected_line, NULL); 02481 } 02482 ast_party_connected_line_free(connected_line); 02483 }
static void* bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
data | thread bridge. |
Definition at line 983 of file features.c.
References ast_channel::appl, ast_bridge_call(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), 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, ast_bridge_thread_obj::return_to_pbx, and set_chan_app_data().
Referenced by bridge_call_thread_launch().
00984 { 00985 struct ast_bridge_thread_obj *tobj = data; 00986 00987 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00988 if (set_chan_app_data(tobj->chan, tobj->peer->name)) { 00989 tobj->chan->data = "(Empty)"; 00990 } 00991 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00992 if (set_chan_app_data(tobj->peer, tobj->chan->name)) { 00993 tobj->peer->data = "(Empty)"; 00994 } 00995 00996 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00997 00998 if (tobj->return_to_pbx) { 00999 if (!ast_check_hangup(tobj->peer)) { 01000 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 01001 if (ast_pbx_start(tobj->peer)) { 01002 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 01003 ast_hangup(tobj->peer); 01004 } 01005 } else { 01006 ast_hangup(tobj->peer); 01007 } 01008 if (!ast_check_hangup(tobj->chan)) { 01009 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 01010 if (ast_pbx_start(tobj->chan)) { 01011 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 01012 ast_hangup(tobj->chan); 01013 } 01014 } else { 01015 ast_hangup(tobj->chan); 01016 } 01017 } else { 01018 ast_hangup(tobj->chan); 01019 ast_hangup(tobj->peer); 01020 } 01021 01022 ast_free(tobj); 01023 01024 return NULL; 01025 }
static void bridge_call_thread_launch | ( | struct ast_bridge_thread_obj * | data | ) | [static] |
create thread for the parked call
data | Create thread and attributes, call bridge_call_thread |
Definition at line 1033 of file features.c.
References ast_hangup(), ast_log(), ast_pthread_create, bridge_call_thread(), ast_bridge_thread_obj::chan, LOG_ERROR, ast_bridge_thread_obj::peer, and thread.
Referenced by action_bridge(), and builtin_atxfer().
01034 { 01035 pthread_t thread; 01036 pthread_attr_t attr; 01037 struct sched_param sched; 01038 01039 pthread_attr_init(&attr); 01040 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 01041 if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) { 01042 ast_hangup(data->chan); 01043 ast_hangup(data->peer); 01044 ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n"); 01045 } 01046 pthread_attr_destroy(&attr); 01047 memset(&sched, 0, sizeof(sched)); 01048 pthread_setschedparam(thread, SCHED_RR, &sched); 01049 }
static int bridge_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Bridge channels.
chan | ||
data | channel to bridge with. |
Definition at line 7562 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_FLAG_BRIDGE_HANGUP_DONT, ast_free, ast_hangup(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_pbx_start(), 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().
07563 { 07564 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2]; 07565 char *tmp_data = NULL; 07566 struct ast_flags opts = { 0, }; 07567 struct ast_bridge_config bconfig = { { 0, }, }; 07568 char *opt_args[OPT_ARG_ARRAY_SIZE]; 07569 struct timeval calldurationlimit = { 0, }; 07570 07571 AST_DECLARE_APP_ARGS(args, 07572 AST_APP_ARG(dest_chan); 07573 AST_APP_ARG(options); 07574 ); 07575 07576 if (ast_strlen_zero(data)) { 07577 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 07578 return -1; 07579 } 07580 07581 tmp_data = ast_strdupa(data); 07582 AST_STANDARD_APP_ARGS(args, tmp_data); 07583 if (!ast_strlen_zero(args.options)) 07584 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options); 07585 07586 /* avoid bridge with ourselves */ 07587 if (!strcmp(chan->name, args.dest_chan)) { 07588 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 07589 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07590 "Response: Failed\r\n" 07591 "Reason: Unable to bridge channel to itself\r\n" 07592 "Channel1: %s\r\n" 07593 "Channel2: %s\r\n", 07594 chan->name, args.dest_chan); 07595 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 07596 return 0; 07597 } 07598 07599 /* make sure we have a valid end point */ 07600 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan, 07601 strlen(args.dest_chan)))) { 07602 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n", 07603 args.dest_chan); 07604 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07605 "Response: Failed\r\n" 07606 "Reason: Channel2 does not exist\r\n" 07607 "Channel1: %s\r\n" 07608 "Channel2: %s\r\n", chan->name, args.dest_chan); 07609 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 07610 return 0; 07611 } 07612 07613 /* try to allocate a place holder where current_dest_chan will be placed */ 07614 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 07615 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) { 07616 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 07617 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07618 "Response: Failed\r\n" 07619 "Reason: Cannot create placeholder channel\r\n" 07620 "Channel1: %s\r\n" 07621 "Channel2: %s\r\n", chan->name, args.dest_chan); 07622 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 07623 ast_channel_unref(current_dest_chan); 07624 return 0; 07625 } 07626 07627 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) 07628 && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT]) 07629 && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) { 07630 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07631 "Response: Failed\r\n" 07632 "Reason: Cannot setup bridge time limit\r\n" 07633 "Channel1: %s\r\n" 07634 "Channel2: %s\r\n", chan->name, args.dest_chan); 07635 ast_hangup(final_dest_chan); 07636 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 07637 current_dest_chan = ast_channel_unref(current_dest_chan); 07638 goto done; 07639 } 07640 07641 if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) { 07642 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07643 "Response: Failed\r\n" 07644 "Reason: Cannot masquerade channels\r\n" 07645 "Channel1: %s\r\n" 07646 "Channel2: %s\r\n", chan->name, args.dest_chan); 07647 ast_hangup(final_dest_chan); 07648 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 07649 current_dest_chan = ast_channel_unref(current_dest_chan); 07650 goto done; 07651 } 07652 07653 /* answer the channel if needed */ 07654 if (final_dest_chan->_state != AST_STATE_UP) { 07655 ast_answer(final_dest_chan); 07656 } 07657 07658 chans[0] = current_dest_chan; 07659 chans[1] = final_dest_chan; 07660 07661 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 07662 /* try to make compatible, send error if we fail */ 07663 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 07664 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 07665 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07666 "Response: Failed\r\n" 07667 "Reason: Could not make channels compatible for bridge\r\n" 07668 "Channel1: %s\r\n" 07669 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 07670 07671 /* Maybe we should return this channel to the PBX? */ 07672 ast_hangup(final_dest_chan); 07673 07674 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 07675 current_dest_chan = ast_channel_unref(current_dest_chan); 07676 goto done; 07677 } 07678 07679 /* Report that the bridge will be successfull */ 07680 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07681 "Response: Success\r\n" 07682 "Channel1: %s\r\n" 07683 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 07684 07685 current_dest_chan = ast_channel_unref(current_dest_chan); 07686 07687 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 07688 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 07689 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 07690 if (ast_waitstream(final_dest_chan, "") < 0) 07691 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 07692 } 07693 } 07694 07695 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) 07696 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT); 07697 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) 07698 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT); 07699 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) 07700 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 07701 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) 07702 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 07703 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR)) 07704 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON); 07705 if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 07706 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON); 07707 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) 07708 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL); 07709 if (ast_test_flag(&opts, OPT_CALLER_PARK)) 07710 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL); 07711 07712 /* 07713 * Don't let the after-bridge code run the h-exten. We want to 07714 * continue in the dialplan. 07715 */ 07716 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 07717 ast_bridge_call(chan, final_dest_chan, &bconfig); 07718 07719 /* The bridge has ended, set BRIDGERESULT to SUCCESS. */ 07720 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 07721 07722 /* If the other channel has not been hung up, return it to the PBX */ 07723 if (!ast_check_hangup(final_dest_chan)) { 07724 if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) { 07725 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 07726 final_dest_chan->context, final_dest_chan->exten, 07727 final_dest_chan->priority, final_dest_chan->name); 07728 07729 if (ast_pbx_start(final_dest_chan)) { 07730 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 07731 ast_hangup(final_dest_chan); 07732 } else { 07733 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 07734 } 07735 } else { 07736 ast_hangup(final_dest_chan); 07737 } 07738 } else { 07739 ast_debug(1, "chan %s was hungup\n", final_dest_chan->name); 07740 ast_hangup(final_dest_chan); 07741 } 07742 done: 07743 ast_free((char *) bconfig.warning_sound); 07744 ast_free((char *) bconfig.end_sound); 07745 ast_free((char *) bconfig.start_sound); 07746 07747 return 0; 07748 }
static struct parking_dp_context* build_dialplan_useage_context | ( | struct ast_parkinglot * | lot | ) | [static] |
Definition at line 6235 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().
06236 { 06237 struct parking_dp_context *ctx_node; 06238 06239 ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con)); 06240 if (!ctx_node) { 06241 return NULL; 06242 } 06243 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) { 06244 destroy_dialplan_usage_context(ctx_node); 06245 return NULL; 06246 } 06247 strcpy(ctx_node->context, lot->cfg.parking_con); 06248 return ctx_node; 06249 }
static int build_dialplan_useage_map | ( | struct parking_dp_map * | usage_map, | |
int | complain | |||
) | [static] |
Definition at line 6307 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().
06308 { 06309 int status = 0; 06310 struct ao2_iterator iter; 06311 struct ast_parkinglot *curlot; 06312 06313 /* For all parking lots */ 06314 iter = ao2_iterator_init(parkinglots, 0); 06315 for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) { 06316 /* Add the parking lot to the map. */ 06317 if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) { 06318 ao2_ref(curlot, -1); 06319 status = -1; 06320 break; 06321 } 06322 } 06323 ao2_iterator_destroy(&iter); 06324 06325 return status; 06326 }
static struct parking_dp_ramp* build_dialplan_useage_ramp | ( | const char * | exten, | |
int | exclusive | |||
) | [static] |
Definition at line 5998 of file features.c.
References ast_calloc.
Referenced by usage_context_add_ramp().
05999 { 06000 struct parking_dp_ramp *ramp_node; 06001 06002 ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten)); 06003 if (!ramp_node) { 06004 return NULL; 06005 } 06006 ramp_node->exclusive = exclusive; 06007 strcpy(ramp_node->exten, exten); 06008 return ramp_node; 06009 }
static struct parking_dp_spaces* build_dialplan_useage_spaces | ( | int | start, | |
int | stop | |||
) | [static] |
Definition at line 6079 of file features.c.
References ast_calloc.
Referenced by usage_context_add_spaces().
06080 { 06081 struct parking_dp_spaces *spaces_node; 06082 06083 spaces_node = ast_calloc(1, sizeof(*spaces_node)); 06084 if (!spaces_node) { 06085 return NULL; 06086 } 06087 spaces_node->start = start; 06088 spaces_node->stop = stop; 06089 return spaces_node; 06090 }
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 5600 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().
05601 { 05602 struct ast_parkinglot *parkinglot; 05603 const struct parkinglot_cfg *cfg_defaults; 05604 struct parkinglot_cfg new_cfg; 05605 int cfg_error; 05606 int oldparkinglot = 0; 05607 05608 parkinglot = find_parkinglot(pl_name); 05609 if (parkinglot) { 05610 oldparkinglot = 1; 05611 } else { 05612 parkinglot = create_parkinglot(pl_name); 05613 if (!parkinglot) { 05614 return NULL; 05615 } 05616 } 05617 if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) { 05618 cfg_defaults = &parkinglot_cfg_default_default; 05619 } else { 05620 cfg_defaults = &parkinglot_cfg_default; 05621 } 05622 new_cfg = *cfg_defaults; 05623 05624 ast_debug(1, "Building parking lot %s\n", parkinglot->name); 05625 05626 ao2_lock(parkinglot); 05627 05628 /* Do some config stuff */ 05629 cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var); 05630 if (oldparkinglot) { 05631 if (cfg_error) { 05632 /* Bad configuration read. Keep using the original config. */ 05633 ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n", 05634 parkinglot->name); 05635 cfg_error = 0; 05636 } else if (!AST_LIST_EMPTY(&parkinglot->parkings) 05637 && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) { 05638 /* Try reloading later when parking lot is empty. */ 05639 ast_log(LOG_WARNING, 05640 "Parking lot %s has parked calls. Parking lot changes discarded.\n", 05641 parkinglot->name); 05642 force_reload_load = 1; 05643 } else { 05644 /* Accept the new config */ 05645 parkinglot->cfg = new_cfg; 05646 } 05647 } else { 05648 /* Load the initial parking lot config. */ 05649 parkinglot->cfg = new_cfg; 05650 } 05651 parkinglot->the_mark = 0; 05652 05653 ao2_unlock(parkinglot); 05654 05655 if (cfg_error) { 05656 /* Only new parking lots could have config errors here. */ 05657 ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name); 05658 parkinglot_unref(parkinglot); 05659 return NULL; 05660 } 05661 05662 /* Move it into the list, if it wasn't already there */ 05663 if (!oldparkinglot) { 05664 ao2_link(parkinglots, parkinglot); 05665 } 05666 parkinglot_unref(parkinglot); 05667 05668 return parkinglot; 05669 }
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 2500 of file features.c.
References ast_channel::_state, add_features_datastore(), 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_bridge_config::features_caller, finishup(), get_parking_exten(), ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_dial_features::my_features, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_dial_features::peer_features, 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.
02501 { 02502 struct ast_channel *transferer;/* Party B */ 02503 struct ast_channel *transferee;/* Party A */ 02504 struct ast_exten *park_exten; 02505 const char *chan1_attended_sound; 02506 const char *chan2_attended_sound; 02507 const char *transferer_real_context; 02508 char xferto[256] = ""; 02509 int res; 02510 int outstate=0; 02511 struct ast_channel *newchan; 02512 struct ast_channel *xferchan; 02513 struct ast_bridge_thread_obj *tobj; 02514 struct ast_bridge_config bconfig; 02515 int l; 02516 struct ast_party_connected_line connected_line; 02517 struct ast_datastore *features_datastore; 02518 struct ast_dial_features *dialfeatures; 02519 char *transferer_tech; 02520 char *transferer_name; 02521 char *transferer_name_orig; 02522 char *dash; 02523 02524 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 02525 set_peers(&transferer, &transferee, peer, chan, sense); 02526 transferer_real_context = real_ctx(transferer, transferee); 02527 02528 /* Start autoservice on transferee while we talk to the transferer */ 02529 ast_autoservice_start(transferee); 02530 ast_indicate(transferee, AST_CONTROL_HOLD); 02531 02532 /* Transfer */ 02533 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02534 if (res < 0) { 02535 finishup(transferee); 02536 return -1; 02537 } 02538 if (res > 0) { /* If they've typed a digit already, handle it */ 02539 xferto[0] = (char) res; 02540 } 02541 02542 /* this is specific of atxfer */ 02543 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02544 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02545 finishup(transferee); 02546 return -1; 02547 } 02548 l = strlen(xferto); 02549 if (res == 0) { 02550 if (l) { 02551 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02552 xferto, transferer_real_context); 02553 } else { 02554 /* Does anyone care about this case? */ 02555 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n"); 02556 } 02557 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02558 finishup(transferee); 02559 return AST_FEATURE_RETURN_SUCCESS; 02560 } 02561 02562 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02563 if (park_exten) { 02564 /* We are transfering the transferee to a parking lot. */ 02565 return xfer_park_call_helper(transferee, transferer, park_exten); 02566 } 02567 02568 /* 02569 * Append context to dialed transfer number. 02570 * 02571 * NOTE: The local channel needs the /n flag so party C will use 02572 * the feature flags set by the dialplan when calling that 02573 * party. 02574 */ 02575 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); 02576 02577 /* If we are performing an attended transfer and we have two channels involved then 02578 copy sound file information to play upon attended transfer completion */ 02579 chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02580 chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02581 if (!ast_strlen_zero(chan1_attended_sound)) { 02582 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 02583 } 02584 if (!ast_strlen_zero(chan2_attended_sound)) { 02585 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 02586 } 02587 02588 /* Extract redial transferer information from the channel name. */ 02589 transferer_name_orig = ast_strdupa(transferer->name); 02590 transferer_name = ast_strdupa(transferer_name_orig); 02591 transferer_tech = strsep(&transferer_name, "/"); 02592 dash = strrchr(transferer_name, '-'); 02593 if (dash) { 02594 /* Trim off channel name sequence/serial number. */ 02595 *dash = '\0'; 02596 } 02597 02598 /* Stop autoservice so we can monitor all parties involved in the transfer. */ 02599 if (ast_autoservice_stop(transferee) < 0) { 02600 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02601 return -1; 02602 } 02603 02604 /* Save connected line info for party B about party A in case transfer fails. */ 02605 ast_party_connected_line_init(&connected_line); 02606 ast_channel_lock(transferer); 02607 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02608 ast_channel_unlock(transferer); 02609 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02610 02611 /* Dial party C */ 02612 newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer, 02613 transferee, "Local", ast_best_codec(transferer->nativeformats), xferto, 02614 atxfernoanswertimeout, &outstate, transferer->language); 02615 ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate); 02616 02617 if (!ast_check_hangup(transferer)) { 02618 int hangup_dont = 0; 02619 02620 /* Transferer (party B) is up */ 02621 ast_debug(1, "Actually doing an attended transfer.\n"); 02622 02623 /* Start autoservice on transferee while the transferer deals with party C. */ 02624 ast_autoservice_start(transferee); 02625 02626 ast_indicate(transferer, -1); 02627 if (!newchan) { 02628 /* any reason besides user requested cancel and busy triggers the failed sound */ 02629 switch (outstate) { 02630 case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */ 02631 case AST_CONTROL_BUSY: 02632 case AST_CONTROL_CONGESTION: 02633 if (ast_stream_and_wait(transferer, xfersound, "")) { 02634 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02635 } 02636 break; 02637 default: 02638 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02639 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02640 } 02641 break; 02642 } 02643 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02644 return AST_FEATURE_RETURN_SUCCESS; 02645 } 02646 02647 if (check_compat(transferer, newchan)) { 02648 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02649 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02650 } 02651 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02652 return AST_FEATURE_RETURN_SUCCESS; 02653 } 02654 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 02655 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 02656 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 02657 02658 /* 02659 * ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we 02660 * don't want that to happen here because the transferer is in 02661 * another bridge already. 02662 */ 02663 if (ast_test_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT)) { 02664 hangup_dont = 1; 02665 } 02666 02667 /* 02668 * Don't let the after-bridge code run the h-exten. It is the 02669 * wrong bridge to run the h-exten after. 02670 */ 02671 ast_set_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT); 02672 02673 /* 02674 * Let party B and C talk as long as they want while party A 02675 * languishes in autoservice listening to MOH. 02676 */ 02677 ast_bridge_call(transferer, newchan, &bconfig); 02678 02679 if (hangup_dont) { 02680 /* Restore the AST_FLAG_BRIDGE_HANGUP_DONT flag */ 02681 ast_set_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT); 02682 } 02683 02684 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 02685 ast_hangup(newchan); 02686 if (ast_stream_and_wait(transferer, xfersound, "")) { 02687 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02688 } 02689 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02690 return AST_FEATURE_RETURN_SUCCESS; 02691 } 02692 02693 /* Transferer (party B) is confirmed hung up at this point. */ 02694 if (check_compat(transferee, newchan)) { 02695 finishup(transferee); 02696 ast_party_connected_line_free(&connected_line); 02697 return -1; 02698 } 02699 02700 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02701 if ((ast_autoservice_stop(transferee) < 0) 02702 || (ast_waitfordigit(transferee, 100) < 0) 02703 || (ast_waitfordigit(newchan, 100) < 0) 02704 || ast_check_hangup(transferee) 02705 || ast_check_hangup(newchan)) { 02706 ast_hangup(newchan); 02707 ast_party_connected_line_free(&connected_line); 02708 return -1; 02709 } 02710 } else if (!ast_check_hangup(transferee)) { 02711 /* Transferer (party B) has hung up at this point. Doing blonde transfer. */ 02712 ast_debug(1, "Actually doing a blonde transfer.\n"); 02713 02714 if (!newchan && !atxferdropcall) { 02715 /* Party C is not available, try to call party B back. */ 02716 unsigned int tries = 0; 02717 02718 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 02719 ast_log(LOG_WARNING, 02720 "Transferer channel name: '%s' cannot be used for callback.\n", 02721 transferer_name_orig); 02722 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02723 ast_party_connected_line_free(&connected_line); 02724 return -1; 02725 } 02726 02727 tries = 0; 02728 for (;;) { 02729 /* Try to get party B back. */ 02730 ast_debug(1, "We're trying to callback %s/%s\n", 02731 transferer_tech, transferer_name); 02732 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02733 transferee, transferee, transferer_tech, 02734 ast_best_codec(transferee->nativeformats), transferer_name, 02735 atxfernoanswertimeout, &outstate, transferer->language); 02736 ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n", 02737 !!newchan, outstate); 02738 if (newchan) { 02739 /* 02740 * We have recalled party B (newchan). We need to give this 02741 * call leg the same feature flags as the original party B call 02742 * leg. 02743 */ 02744 ast_channel_lock(transferer); 02745 features_datastore = ast_channel_datastore_find(transferer, 02746 &dial_features_info, NULL); 02747 if (features_datastore && (dialfeatures = features_datastore->data)) { 02748 struct ast_flags my_features = { 0 }; 02749 struct ast_flags peer_features = { 0 }; 02750 02751 ast_copy_flags(&my_features, &dialfeatures->my_features, 02752 AST_FLAGS_ALL); 02753 ast_copy_flags(&peer_features, &dialfeatures->peer_features, 02754 AST_FLAGS_ALL); 02755 ast_channel_unlock(transferer); 02756 add_features_datastore(newchan, &my_features, &peer_features); 02757 } else { 02758 ast_channel_unlock(transferer); 02759 } 02760 break; 02761 } 02762 if (ast_check_hangup(transferee)) { 02763 break; 02764 } 02765 02766 ++tries; 02767 if (atxfercallbackretries <= tries) { 02768 /* No more callback tries remaining. */ 02769 break; 02770 } 02771 02772 if (atxferloopdelay) { 02773 /* Transfer failed, sleeping */ 02774 ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n", 02775 atxferloopdelay); 02776 ast_safe_sleep(transferee, atxferloopdelay); 02777 if (ast_check_hangup(transferee)) { 02778 ast_party_connected_line_free(&connected_line); 02779 return -1; 02780 } 02781 } 02782 02783 /* Retry dialing party C. */ 02784 ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto); 02785 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02786 transferer, transferee, "Local", 02787 ast_best_codec(transferee->nativeformats), xferto, 02788 atxfernoanswertimeout, &outstate, transferer->language); 02789 ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n", 02790 !!newchan, outstate); 02791 if (newchan || ast_check_hangup(transferee)) { 02792 break; 02793 } 02794 } 02795 } 02796 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02797 if (!newchan) { 02798 /* No party C or could not callback party B. */ 02799 ast_party_connected_line_free(&connected_line); 02800 return -1; 02801 } 02802 02803 /* newchan is up, we should prepare transferee and bridge them */ 02804 if (ast_check_hangup(newchan)) { 02805 ast_hangup(newchan); 02806 ast_party_connected_line_free(&connected_line); 02807 return -1; 02808 } 02809 if (check_compat(transferee, newchan)) { 02810 ast_party_connected_line_free(&connected_line); 02811 return -1; 02812 } 02813 } else { 02814 /* 02815 * Both the transferer and transferee have hungup. If newchan 02816 * is up, hang it up as it has no one to talk to. 02817 */ 02818 ast_debug(1, "Everyone is hungup.\n"); 02819 if (newchan) { 02820 ast_hangup(newchan); 02821 } 02822 ast_party_connected_line_free(&connected_line); 02823 return -1; 02824 } 02825 02826 /* Initiate the channel transfer of party A to party C (or recalled party B). */ 02827 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan); 02828 02829 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name); 02830 if (!xferchan) { 02831 ast_hangup(newchan); 02832 ast_party_connected_line_free(&connected_line); 02833 return -1; 02834 } 02835 02836 /* Give party A a momentary ringback tone during transfer. */ 02837 xferchan->visible_indication = AST_CONTROL_RINGING; 02838 02839 /* Make formats okay */ 02840 xferchan->readformat = transferee->readformat; 02841 xferchan->writeformat = transferee->writeformat; 02842 02843 if (ast_channel_masquerade(xferchan, transferee)) { 02844 ast_hangup(xferchan); 02845 ast_hangup(newchan); 02846 ast_party_connected_line_free(&connected_line); 02847 return -1; 02848 } 02849 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 02850 xferchan->_state = AST_STATE_UP; 02851 ast_clear_flag(xferchan, AST_FLAGS_ALL); 02852 02853 /* Do the masquerade manually to make sure that is is completed. */ 02854 ast_do_masquerade(xferchan); 02855 02856 newchan->_state = AST_STATE_UP; 02857 ast_clear_flag(newchan, AST_FLAGS_ALL); 02858 tobj = ast_calloc(1, sizeof(*tobj)); 02859 if (!tobj) { 02860 ast_hangup(xferchan); 02861 ast_hangup(newchan); 02862 ast_party_connected_line_free(&connected_line); 02863 return -1; 02864 } 02865 02866 tobj->chan = newchan; 02867 tobj->peer = xferchan; 02868 tobj->bconfig = *config; 02869 02870 ast_channel_lock(newchan); 02871 features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL); 02872 if (features_datastore && (dialfeatures = features_datastore->data)) { 02873 ast_copy_flags(&tobj->bconfig.features_callee, &dialfeatures->my_features, 02874 AST_FLAGS_ALL); 02875 } 02876 ast_channel_unlock(newchan); 02877 02878 ast_channel_lock(xferchan); 02879 features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL); 02880 if (features_datastore && (dialfeatures = features_datastore->data)) { 02881 ast_copy_flags(&tobj->bconfig.features_caller, &dialfeatures->my_features, 02882 AST_FLAGS_ALL); 02883 } 02884 ast_channel_unlock(xferchan); 02885 02886 if (tobj->bconfig.end_bridge_callback_data_fixup) { 02887 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 02888 } 02889 02890 /* 02891 * xferchan is transferee, and newchan is the transfer target 02892 * So...in a transfer, who is the caller and who is the callee? 02893 * 02894 * When the call is originally made, it is clear who is caller and callee. 02895 * When a transfer occurs, it is my humble opinion that the transferee becomes 02896 * the caller, and the transfer target is the callee. 02897 * 02898 * The problem is that these macros were set with the intention of the original 02899 * caller and callee taking those roles. A transfer can totally mess things up, 02900 * to be technical. What sucks even more is that you can't effectively change 02901 * the macros in the dialplan during the call from the transferer to the transfer 02902 * target because the transferee is stuck with whatever role he originally had. 02903 * 02904 * I think the answer here is just to make sure that it is well documented that 02905 * during a transfer, the transferee is the "caller" and the transfer target 02906 * is the "callee." 02907 * 02908 * This means that if party B calls party A, and party B transfers party A to 02909 * party C, then A has switched roles for the call. Now party A will have the 02910 * caller macro called on his channel instead of the callee macro. 02911 * 02912 * Luckily, the method by which the party B to party C bridge is 02913 * launched above ensures that the transferee is the "chan" on 02914 * the bridge and the transfer target is the "peer," so my idea 02915 * for the roles post-transfer does not require extensive code 02916 * changes. 02917 */ 02918 02919 /* Transfer party C connected line to party A */ 02920 ast_channel_lock(transferer); 02921 /* 02922 * Due to a limitation regarding when callerID is set on a Local channel, 02923 * we use the transferer's connected line information here. 02924 */ 02925 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02926 ast_channel_unlock(transferer); 02927 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02928 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { 02929 ast_channel_update_connected_line(xferchan, &connected_line, NULL); 02930 } 02931 02932 /* Transfer party A connected line to party C */ 02933 ast_channel_lock(xferchan); 02934 ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller); 02935 ast_channel_unlock(xferchan); 02936 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02937 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { 02938 ast_channel_update_connected_line(newchan, &connected_line, NULL); 02939 } 02940 02941 if (ast_stream_and_wait(newchan, xfersound, "")) 02942 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02943 bridge_call_thread_launch(tobj); 02944 02945 ast_party_connected_line_free(&connected_line); 02946 return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */ 02947 }
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 2179 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_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.
02180 { 02181 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02182 int x = 0; 02183 size_t len; 02184 struct ast_channel *caller_chan, *callee_chan; 02185 const char *mixmonitor_spy_type = "MixMonitor"; 02186 const char *touch_format; 02187 const char *touch_monitor; 02188 int count = 0; 02189 02190 if (!mixmonitor_ok) { 02191 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02192 return -1; 02193 } 02194 02195 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 02196 mixmonitor_ok = 0; 02197 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02198 return -1; 02199 } 02200 02201 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02202 02203 if (!ast_strlen_zero(courtesytone)) { 02204 if (ast_autoservice_start(callee_chan)) 02205 return -1; 02206 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END); 02207 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 02208 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02209 ast_autoservice_stop(callee_chan); 02210 return -1; 02211 } 02212 if (ast_autoservice_stop(callee_chan)) 02213 return -1; 02214 } 02215 02216 ast_channel_lock(callee_chan); 02217 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02218 ast_channel_unlock(callee_chan); 02219 02220 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 02221 if (count > 0) { 02222 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 02223 02224 /* Make sure they are running */ 02225 ast_channel_lock(callee_chan); 02226 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02227 ast_channel_unlock(callee_chan); 02228 if (count > 0) { 02229 if (!stopmixmonitor_ok) { 02230 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02231 return -1; 02232 } 02233 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 02234 stopmixmonitor_ok = 0; 02235 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02236 return -1; 02237 } else { 02238 pbx_exec(callee_chan, stopmixmonitor_app, ""); 02239 return AST_FEATURE_RETURN_SUCCESS; 02240 } 02241 } 02242 02243 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 02244 } 02245 02246 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 02247 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 02248 02249 if (!touch_format) 02250 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 02251 02252 if (!touch_monitor) 02253 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 02254 02255 if (touch_monitor) { 02256 len = strlen(touch_monitor) + 50; 02257 args = alloca(len); 02258 touch_filename = alloca(len); 02259 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 02260 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 02261 } else { 02262 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 02263 caller_chan->caller.id.number.str, caller_chan->name)); 02264 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 02265 callee_chan->caller.id.number.str, callee_chan->name)); 02266 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02267 args = alloca(len); 02268 touch_filename = alloca(len); 02269 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 02270 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 02271 } 02272 02273 for( x = 0; x < strlen(args); x++) { 02274 if (args[x] == '/') 02275 args[x] = '-'; 02276 } 02277 02278 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 02279 02280 pbx_exec(callee_chan, mixmonitor_app, args); 02281 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02282 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02283 return AST_FEATURE_RETURN_SUCCESS; 02284 }
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 2086 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, 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.
02087 { 02088 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02089 int x = 0; 02090 size_t len; 02091 struct ast_channel *caller_chan, *callee_chan; 02092 const char *automon_message_start = NULL; 02093 const char *automon_message_stop = NULL; 02094 const char *touch_format = NULL; 02095 const char *touch_monitor = NULL; 02096 const char *touch_monitor_prefix = NULL; 02097 02098 if (!monitor_ok) { 02099 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02100 return -1; 02101 } 02102 02103 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 02104 monitor_ok = 0; 02105 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02106 return -1; 02107 } 02108 02109 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02110 02111 /* Find extra messages */ 02112 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 02113 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 02114 02115 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 02116 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 02117 return -1; 02118 } 02119 } 02120 02121 if (callee_chan->monitor) { 02122 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 02123 if (!ast_strlen_zero(automon_message_stop)) { 02124 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 02125 } 02126 callee_chan->monitor->stop(callee_chan, 1); 02127 return AST_FEATURE_RETURN_SUCCESS; 02128 } 02129 02130 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 02131 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 02132 touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 02133 02134 if (!touch_format) 02135 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 02136 02137 if (!touch_monitor) 02138 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 02139 02140 if (!touch_monitor_prefix) 02141 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 02142 02143 if (touch_monitor) { 02144 len = strlen(touch_monitor) + 50; 02145 args = alloca(len); 02146 touch_filename = alloca(len); 02147 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 02148 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02149 } else { 02150 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 02151 caller_chan->caller.id.number.str, caller_chan->name)); 02152 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 02153 callee_chan->caller.id.number.str, callee_chan->name)); 02154 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02155 args = alloca(len); 02156 touch_filename = alloca(len); 02157 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 02158 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02159 } 02160 02161 for(x = 0; x < strlen(args); x++) { 02162 if (args[x] == '/') 02163 args[x] = '-'; 02164 } 02165 02166 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 02167 02168 pbx_exec(callee_chan, monitor_app, args); 02169 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02170 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02171 02172 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 02173 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 02174 } 02175 02176 return AST_FEATURE_RETURN_SUCCESS; 02177 }
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 2329 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().
02330 { 02331 struct ast_channel *transferer; 02332 struct ast_channel *transferee; 02333 struct ast_exten *park_exten; 02334 const char *transferer_real_context; 02335 char xferto[256] = ""; 02336 int res; 02337 02338 ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 02339 set_peers(&transferer, &transferee, peer, chan, sense); 02340 transferer_real_context = real_ctx(transferer, transferee); 02341 02342 /* Start autoservice on transferee while we talk to the transferer */ 02343 ast_autoservice_start(transferee); 02344 ast_indicate(transferee, AST_CONTROL_HOLD); 02345 02346 /* Transfer */ 02347 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02348 if (res < 0) { 02349 finishup(transferee); 02350 return -1; /* error ? */ 02351 } 02352 if (res > 0) { /* If they've typed a digit already, handle it */ 02353 xferto[0] = (char) res; 02354 } 02355 02356 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02357 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02358 finishup(transferee); 02359 return -1; 02360 } 02361 if (res == 0) { 02362 if (xferto[0]) { 02363 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02364 xferto, transferer_real_context); 02365 } else { 02366 /* Does anyone care about this case? */ 02367 ast_log(LOG_WARNING, "No digits dialed.\n"); 02368 } 02369 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02370 finishup(transferee); 02371 return AST_FEATURE_RETURN_SUCCESS; 02372 } 02373 02374 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02375 if (park_exten) { 02376 /* We are transfering the transferee to a parking lot. */ 02377 return xfer_park_call_helper(transferee, transferer, park_exten); 02378 } 02379 02380 /* Do blind transfer. */ 02381 ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n", 02382 transferee->name, xferto, transferer_real_context); 02383 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee); 02384 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 02385 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 02386 finishup(transferee); 02387 ast_channel_lock(transferer); 02388 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 02389 transferer->cdr = ast_cdr_alloc(); 02390 if (transferer->cdr) { 02391 ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */ 02392 ast_cdr_start(transferer->cdr); 02393 } 02394 } 02395 ast_channel_unlock(transferer); 02396 if (transferer->cdr) { 02397 struct ast_cdr *swap = transferer->cdr; 02398 02399 ast_debug(1, 02400 "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 02401 transferer->name, transferee->name, transferer->cdr->lastapp, 02402 transferer->cdr->lastdata, transferer->cdr->channel, 02403 transferer->cdr->dstchannel); 02404 ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 02405 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, 02406 transferee->cdr->dstchannel); 02407 ast_debug(1, "transferer_real_context=%s; xferto=%s\n", 02408 transferer_real_context, xferto); 02409 /* swap cdrs-- it will save us some time & work */ 02410 transferer->cdr = transferee->cdr; 02411 transferee->cdr = swap; 02412 } 02413 if (!transferee->pbx) { 02414 /* Doh! Use our handy async_goto functions */ 02415 ast_debug(1, "About to ast_async_goto %s.\n", transferee->name); 02416 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) { 02417 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 02418 } 02419 02420 /* The transferee is masqueraded and the original bridged channels can be hungup. */ 02421 res = -1; 02422 } else { 02423 /* Set the transferee's new extension, since it exists, using transferer context */ 02424 ast_debug(1, "About to explicit goto %s, it has a PBX.\n", transferee->name); 02425 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 02426 set_c_e_p(transferee, transferer_real_context, xferto, 0); 02427 02428 /* 02429 * Break the bridge. The transferee needs to resume executing 02430 * dialplan at the xferto location. 02431 */ 02432 res = AST_FEATURE_RETURN_SUCCESSBREAK; 02433 } 02434 check_goto_on_transfer(transferer); 02435 return res; 02436 }
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 2286 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
02287 { 02288 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 02289 return AST_FEATURE_RETURN_HANGUP; 02290 }
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 1964 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().
01965 { 01966 struct ast_channel *parker; 01967 struct ast_channel *parkee; 01968 struct ast_park_call_args args = { 0, }; 01969 01970 /* 01971 * We used to set chan's exten and priority to "s" and 1 here, 01972 * but this generates (in some cases) an invalid extension, and 01973 * if "s" exists, could errantly cause execution of extensions 01974 * you don't expect. It makes more sense to let nature take its 01975 * course when chan finishes, and let the pbx do its thing and 01976 * hang up when the park is over. 01977 */ 01978 01979 /* Answer if call is not up */ 01980 if (chan->_state != AST_STATE_UP) { 01981 /* 01982 * XXX Why are we doing this? Both of the channels should be up 01983 * since you cannot do DTMF features unless you are bridged. 01984 */ 01985 if (ast_answer(chan)) { 01986 return -1; 01987 } 01988 01989 /* Sleep to allow VoIP streams to settle down */ 01990 if (ast_safe_sleep(chan, 1000)) { 01991 return -1; 01992 } 01993 } 01994 01995 /* one direction used to call park_call.... */ 01996 set_peers(&parker, &parkee, peer, chan, sense); 01997 return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1; 01998 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 4586 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().
04587 { 04588 int i = 0; 04589 enum { 04590 OPT_CALLEE_REDIRECT = 't', 04591 OPT_CALLER_REDIRECT = 'T', 04592 OPT_CALLEE_AUTOMON = 'w', 04593 OPT_CALLER_AUTOMON = 'W', 04594 OPT_CALLEE_DISCONNECT = 'h', 04595 OPT_CALLER_DISCONNECT = 'H', 04596 OPT_CALLEE_PARKCALL = 'k', 04597 OPT_CALLER_PARKCALL = 'K', 04598 }; 04599 04600 memset(options, 0, len); 04601 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 04602 options[i++] = OPT_CALLER_REDIRECT; 04603 } 04604 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 04605 options[i++] = OPT_CALLER_AUTOMON; 04606 } 04607 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 04608 options[i++] = OPT_CALLER_DISCONNECT; 04609 } 04610 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 04611 options[i++] = OPT_CALLER_PARKCALL; 04612 } 04613 04614 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 04615 options[i++] = OPT_CALLEE_REDIRECT; 04616 } 04617 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 04618 options[i++] = OPT_CALLEE_AUTOMON; 04619 } 04620 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 04621 options[i++] = OPT_CALLEE_DISCONNECT; 04622 } 04623 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 04624 options[i++] = OPT_CALLEE_PARKCALL; 04625 } 04626 04627 return options; 04628 }
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 2445 of file features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by builtin_atxfer().
02446 { 02447 if (ast_channel_make_compatible(c, newchan) < 0) { 02448 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 02449 c->name, newchan->name); 02450 ast_hangup(newchan); 02451 return -1; 02452 } 02453 return 0; 02454 }
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 892 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().
00893 { 00894 struct ast_channel *xferchan; 00895 const char *val; 00896 char *goto_on_transfer; 00897 char *x; 00898 00899 ast_channel_lock(chan); 00900 val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00901 if (ast_strlen_zero(val)) { 00902 ast_channel_unlock(chan); 00903 return; 00904 } 00905 goto_on_transfer = ast_strdupa(val); 00906 ast_channel_unlock(chan); 00907 00908 ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, chan->name); 00909 00910 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, 00911 "%s", chan->name); 00912 if (!xferchan) { 00913 return; 00914 } 00915 00916 /* Make formats okay */ 00917 xferchan->readformat = chan->readformat; 00918 xferchan->writeformat = chan->writeformat; 00919 00920 if (ast_channel_masquerade(xferchan, chan)) { 00921 /* Failed to setup masquerade. */ 00922 ast_hangup(xferchan); 00923 return; 00924 } 00925 00926 for (x = goto_on_transfer; *x; ++x) { 00927 if (*x == '^') { 00928 *x = ','; 00929 } 00930 } 00931 ast_parseable_goto(xferchan, goto_on_transfer); 00932 xferchan->_state = AST_STATE_UP; 00933 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00934 ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL); 00935 00936 ast_do_masquerade(xferchan); 00937 if (ast_pbx_start(xferchan)) { 00938 /* Failed to start PBX. */ 00939 ast_hangup(xferchan); 00940 } 00941 }
static void clear_dialed_interfaces | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 3878 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().
03879 { 03880 struct ast_datastore *di_datastore; 03881 03882 ast_channel_lock(chan); 03883 if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) { 03884 if (option_debug) { 03885 ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name); 03886 } 03887 if (!ast_channel_datastore_remove(chan, di_datastore)) { 03888 ast_datastore_free(di_datastore); 03889 } 03890 } 03891 ast_channel_unlock(chan); 03892 }
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 4951 of file features.c.
References ao2_ref, ast_debug, ast_parkinglot::cfg, create_parkinglot(), find_parkinglot(), and parkinglot.
Referenced by create_dynamic_parkinglot().
04952 { 04953 struct ast_parkinglot *copylot; 04954 04955 if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */ 04956 ao2_ref(copylot, -1); 04957 return NULL; 04958 } 04959 04960 copylot = create_parkinglot(name); 04961 if (!copylot) { 04962 return NULL; 04963 } 04964 04965 ast_debug(1, "Building parking lot %s\n", name); 04966 04967 /* Copy the source parking lot configuration. */ 04968 copylot->cfg = parkinglot->cfg; 04969 04970 return copylot; 04971 }
static struct ast_parkinglot* create_dynamic_parkinglot | ( | const char * | name, | |
struct ast_channel * | chan | |||
) | [static] |
Definition at line 1161 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().
01162 { 01163 const char *dyn_context; 01164 const char *dyn_exten; 01165 const char *dyn_range; 01166 const char *template_name; 01167 struct ast_parkinglot *template_parkinglot = NULL; 01168 struct ast_parkinglot *parkinglot; 01169 int dyn_start; 01170 int dyn_end; 01171 01172 ast_channel_lock(chan); 01173 template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), "")); 01174 dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), "")); 01175 dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), "")); 01176 dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), "")); 01177 ast_channel_unlock(chan); 01178 01179 if (!ast_strlen_zero(template_name)) { 01180 template_parkinglot = find_parkinglot(template_name); 01181 if (!template_parkinglot) { 01182 ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n", 01183 template_name); 01184 } else if (template_parkinglot->cfg.is_invalid) { 01185 ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n", 01186 template_name); 01187 parkinglot_unref(template_parkinglot); 01188 template_parkinglot = NULL; 01189 } 01190 } 01191 if (!template_parkinglot) { 01192 template_parkinglot = parkinglot_addref(default_parkinglot); 01193 ast_debug(1, "Using default parking lot for template\n"); 01194 } 01195 01196 parkinglot = copy_parkinglot(name, template_parkinglot); 01197 if (!parkinglot) { 01198 ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n"); 01199 } else { 01200 /* Configure the dynamic parking lot. */ 01201 if (!ast_strlen_zero(dyn_context)) { 01202 ast_copy_string(parkinglot->cfg.parking_con, dyn_context, 01203 sizeof(parkinglot->cfg.parking_con)); 01204 } 01205 if (!ast_strlen_zero(dyn_exten)) { 01206 ast_copy_string(parkinglot->cfg.parkext, dyn_exten, 01207 sizeof(parkinglot->cfg.parkext)); 01208 } 01209 if (!ast_strlen_zero(dyn_range)) { 01210 if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) { 01211 ast_log(LOG_WARNING, 01212 "Format for parking positions is a-b, where a and b are numbers\n"); 01213 } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) { 01214 ast_log(LOG_WARNING, 01215 "Format for parking positions is a-b, where a <= b\n"); 01216 } else { 01217 parkinglot->cfg.parking_start = dyn_start; 01218 parkinglot->cfg.parking_stop = dyn_end; 01219 } 01220 } 01221 01222 /* 01223 * Sanity check for dynamic parking lot configuration. 01224 * 01225 * XXX It may be desirable to instead check if the dynamic 01226 * parking lot overlaps any existing lots like what is done for 01227 * a reload. 01228 */ 01229 if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) { 01230 if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext) 01231 && parkinglot->cfg.parkext_exclusive) { 01232 ast_log(LOG_WARNING, 01233 "Parking lot '%s' conflicts with template parking lot '%s'!\n" 01234 "Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n", 01235 parkinglot->name, template_parkinglot->name); 01236 } 01237 if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start 01238 && parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop) 01239 || (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop 01240 && parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop) 01241 || (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start 01242 && template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) { 01243 ast_log(LOG_WARNING, 01244 "Parking lot '%s' parking spaces overlap template parking lot '%s'!\n" 01245 "Change PARKINGDYNPOS.\n", 01246 parkinglot->name, template_parkinglot->name); 01247 } 01248 } 01249 01250 parkinglot_activate(parkinglot); 01251 ao2_link(parkinglots, parkinglot); 01252 } 01253 parkinglot_unref(template_parkinglot); 01254 01255 return parkinglot; 01256 }
static struct ast_parkinglot * create_parkinglot | ( | const char * | name | ) | [static] |
Allocate parking lot structure.
Definition at line 5376 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().
05377 { 05378 struct ast_parkinglot *newlot; 05379 05380 if (ast_strlen_zero(name)) { /* No name specified */ 05381 return NULL; 05382 } 05383 05384 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 05385 if (!newlot) 05386 return NULL; 05387 05388 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 05389 newlot->cfg.is_invalid = 1;/* No config is set yet. */ 05390 AST_LIST_HEAD_INIT(&newlot->parkings); 05391 05392 return newlot; 05393 }
static void destroy_dialplan_usage_context | ( | struct parking_dp_context * | doomed | ) | [static] |
Definition at line 5954 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().
05955 { 05956 struct parking_dp_ramp *ramp; 05957 struct parking_dp_spaces *spaces; 05958 05959 while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) { 05960 ast_free(ramp); 05961 } 05962 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) { 05963 ast_free(spaces); 05964 } 05965 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) { 05966 ast_free(spaces); 05967 } 05968 ast_free(doomed); 05969 }
static void destroy_dialplan_usage_map | ( | struct parking_dp_map * | doomed | ) | [static] |
Definition at line 5979 of file features.c.
References AST_LIST_REMOVE_HEAD, destroy_dialplan_usage_context(), and parking_dp_context::node.
Referenced by load_config().
05980 { 05981 struct parking_dp_context *item; 05982 05983 while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) { 05984 destroy_dialplan_usage_context(item); 05985 } 05986 }
static void destroy_space | ( | const char * | context, | |
int | space | |||
) | [static] |
Definition at line 6409 of file features.c.
References AST_MAX_EXTENSION, PRIORITY_HINT, and remove_exten_if_exist().
Referenced by remove_dead_spaces_usage().
06410 { 06411 char exten[AST_MAX_EXTENSION]; 06412 06413 /* Destroy priorities of the parking space that we registered. */ 06414 snprintf(exten, sizeof(exten), "%d", space); 06415 remove_exten_if_exist(context, exten, PRIORITY_HINT); 06416 remove_exten_if_exist(context, exten, 1); 06417 }
static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 740 of file features.c.
References ast_free.
00741 { 00742 struct ast_dial_features *df = data; 00743 if (df) { 00744 ast_free(df); 00745 } 00746 }
static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 727 of file features.c.
References ast_calloc.
00728 { 00729 struct ast_dial_features *df = data, *df_copy; 00730 00731 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00732 return NULL; 00733 } 00734 00735 memcpy(df_copy, df, sizeof(*df)); 00736 00737 return df_copy; 00738 }
static int dialplan_usage_add_parkinglot | ( | struct parking_dp_map * | usage_map, | |
struct ast_parkinglot * | lot, | |||
int | complain | |||
) | [static] |
Definition at line 6262 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().
06263 { 06264 struct parking_dp_context *cur_ctx; 06265 struct parking_dp_context *new_ctx; 06266 int cmp; 06267 06268 AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) { 06269 cmp = strcmp(lot->cfg.parking_con, cur_ctx->context); 06270 if (cmp > 0) { 06271 /* The parking lot context goes after this node. */ 06272 continue; 06273 } 06274 if (cmp == 0) { 06275 /* This is the node we will add parking lot spaces to the map. */ 06276 return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain); 06277 } 06278 /* The new parking lot context goes before this node. */ 06279 new_ctx = build_dialplan_useage_context(lot); 06280 if (!new_ctx) { 06281 return -1; 06282 } 06283 AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node); 06284 return 0; 06285 } 06286 AST_LIST_TRAVERSE_SAFE_END; 06287 06288 /* New parking lot context goes on the end. */ 06289 new_ctx = build_dialplan_useage_context(lot); 06290 if (!new_ctx) { 06291 return -1; 06292 } 06293 AST_LIST_INSERT_TAIL(usage_map, new_ctx, node); 06294 return 0; 06295 }
static int dialplan_usage_add_parkinglot_data | ( | struct parking_dp_context * | ctx_node, | |
struct ast_parkinglot * | lot, | |||
int | complain | |||
) | [static] |
Definition at line 6208 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().
06209 { 06210 if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext, 06211 lot->cfg.parkext_exclusive, lot, complain)) { 06212 return -1; 06213 } 06214 if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start, 06215 lot->cfg.parking_stop, lot, complain)) { 06216 return -1; 06217 } 06218 if (lot->cfg.parkaddhints 06219 && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start, 06220 lot->cfg.parking_stop, lot, 0)) { 06221 return -1; 06222 } 06223 return 0; 06224 }
static int 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. |
0 | on success. | |
-1 | on error. |
Definition at line 6845 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_strdupa, ast_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
Referenced by action_bridge(), and bridge_exec().
06846 { 06847 const char *context; 06848 const char *exten; 06849 int priority; 06850 06851 ast_moh_stop(chan); 06852 ast_channel_lock_both(chan, tmpchan); 06853 context = ast_strdupa(chan->context); 06854 exten = ast_strdupa(chan->exten); 06855 priority = chan->priority; 06856 ast_setstate(tmpchan, chan->_state); 06857 tmpchan->readformat = chan->readformat; 06858 tmpchan->writeformat = chan->writeformat; 06859 ast_channel_unlock(chan); 06860 ast_channel_unlock(tmpchan); 06861 06862 /* Masquerade setup and execution must be done without any channel locks held */ 06863 if (ast_channel_masquerade(tmpchan, chan)) { 06864 return -1; 06865 } 06866 ast_do_masquerade(tmpchan); 06867 06868 /* when returning from bridge, the channel will continue at the next priority */ 06869 ast_explicit_goto(tmpchan, context, exten, priority + 1); 06870 06871 return 0; 06872 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
ignore | unused var. |
Definition at line 4901 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().
04902 { 04903 struct pollfd *pfds = NULL, *new_pfds = NULL; 04904 int nfds = 0, new_nfds = 0; 04905 04906 for (;;) { 04907 struct ao2_iterator iter; 04908 struct ast_parkinglot *curlot; 04909 int ms = -1; /* poll2 timeout, uninitialized */ 04910 04911 iter = ao2_iterator_init(parkinglots, 0); 04912 while ((curlot = ao2_iterator_next(&iter))) { 04913 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms); 04914 ao2_ref(curlot, -1); 04915 } 04916 ao2_iterator_destroy(&iter); 04917 04918 /* Recycle */ 04919 ast_free(pfds); 04920 pfds = new_pfds; 04921 nfds = new_nfds; 04922 new_pfds = NULL; 04923 new_nfds = 0; 04924 04925 /* Wait for something to happen */ 04926 ast_poll(pfds, nfds, ms); 04927 pthread_testcancel(); 04928 } 04929 /* If this WERE reached, we'd need to free(pfds) */ 04930 return NULL; /* Never reached */ 04931 }
static int feature_check | ( | struct ast_channel * | chan, | |
struct ast_flags * | features, | |||
char * | code | |||
) | [static] |
Check if a feature exists.
Definition at line 3407 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().
03407 { 03408 char *chan_dynamic_features; 03409 ast_channel_lock(chan); 03410 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03411 ast_channel_unlock(chan); 03412 03413 return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL); 03414 }
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 3152 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().
03153 { 03154 struct ast_app *app; 03155 struct ast_call_feature *feature = data; 03156 struct ast_channel *work, *idle; 03157 int res; 03158 03159 if (!feature) { /* shouldn't ever happen! */ 03160 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 03161 return -1; 03162 } 03163 03164 if (sense == FEATURE_SENSE_CHAN) { 03165 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 03166 return AST_FEATURE_RETURN_KEEPTRYING; 03167 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03168 work = chan; 03169 idle = peer; 03170 } else { 03171 work = peer; 03172 idle = chan; 03173 } 03174 } else { 03175 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 03176 return AST_FEATURE_RETURN_KEEPTRYING; 03177 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03178 work = peer; 03179 idle = chan; 03180 } else { 03181 work = chan; 03182 idle = peer; 03183 } 03184 } 03185 03186 if (!(app = pbx_findapp(feature->app))) { 03187 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 03188 return -2; 03189 } 03190 03191 ast_autoservice_start(idle); 03192 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END); 03193 03194 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name); 03195 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name); 03196 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname); 03197 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname); 03198 03199 if (!ast_strlen_zero(feature->moh_class)) 03200 ast_moh_start(idle, feature->moh_class, NULL); 03201 03202 res = pbx_exec(work, app, feature->app_args); 03203 03204 if (!ast_strlen_zero(feature->moh_class)) 03205 ast_moh_stop(idle); 03206 03207 ast_autoservice_stop(idle); 03208 03209 if (res) { 03210 return AST_FEATURE_RETURN_SUCCESSBREAK; 03211 } 03212 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 03213 }
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 3370 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().
03370 { 03371 03372 char dynamic_features_buf[128]; 03373 const char *peer_dynamic_features, *chan_dynamic_features; 03374 struct ast_flags features; 03375 struct ast_call_feature feature; 03376 if (sense == FEATURE_SENSE_CHAN) { 03377 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 03378 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 03379 } 03380 else { 03381 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 03382 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 03383 } 03384 03385 ast_channel_lock(peer); 03386 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 03387 ast_channel_unlock(peer); 03388 03389 ast_channel_lock(chan); 03390 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03391 ast_channel_unlock(chan); 03392 03393 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,"")); 03394 03395 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); 03396 03397 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature); 03398 }
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 3253 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().
03256 { 03257 int x; 03258 struct feature_group *fg = NULL; 03259 struct feature_group_exten *fge; 03260 struct ast_call_feature *tmpfeature; 03261 char *tmp, *tok; 03262 int res = AST_FEATURE_RETURN_PASSDIGITS; 03263 int feature_detected = 0; 03264 03265 if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) { 03266 return -1; /* can not run feature operation */ 03267 } 03268 03269 ast_rwlock_rdlock(&features_lock); 03270 for (x = 0; x < FEATURES_COUNT; x++) { 03271 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 03272 !ast_strlen_zero(builtin_features[x].exten)) { 03273 /* Feature is up for consideration */ 03274 if (!strcmp(builtin_features[x].exten, code)) { 03275 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 03276 if (operation == FEATURE_INTERPRET_CHECK) { 03277 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03278 } else if (operation == FEATURE_INTERPRET_DO) { 03279 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 03280 } 03281 if (feature) { 03282 memcpy(feature, &builtin_features[x], sizeof(*feature)); 03283 } 03284 feature_detected = 1; 03285 break; 03286 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 03287 if (res == AST_FEATURE_RETURN_PASSDIGITS) { 03288 res = AST_FEATURE_RETURN_STOREDIGITS; 03289 } 03290 } 03291 } 03292 } 03293 ast_rwlock_unlock(&features_lock); 03294 03295 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 03296 return res; 03297 } 03298 03299 tmp = dynamic_features_buf; 03300 03301 while ((tok = strsep(&tmp, "#"))) { 03302 AST_RWLIST_RDLOCK(&feature_groups); 03303 03304 fg = find_group(tok); 03305 03306 if (fg) { 03307 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03308 if (!strcmp(fge->exten, code)) { 03309 if (operation) { 03310 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 03311 } 03312 if (feature) { 03313 memcpy(feature, fge->feature, sizeof(*feature)); 03314 } 03315 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03316 AST_RWLIST_UNLOCK(&feature_groups); 03317 break; 03318 } 03319 res = AST_FEATURE_RETURN_PASSDIGITS; 03320 } else if (!strncmp(fge->exten, code, strlen(code))) { 03321 res = AST_FEATURE_RETURN_STOREDIGITS; 03322 } 03323 } 03324 if (fge) { 03325 break; 03326 } 03327 } 03328 03329 AST_RWLIST_UNLOCK(&feature_groups); 03330 03331 AST_RWLIST_RDLOCK(&feature_list); 03332 03333 if (!(tmpfeature = find_dynamic_feature(tok))) { 03334 AST_RWLIST_UNLOCK(&feature_list); 03335 continue; 03336 } 03337 03338 /* Feature is up for consideration */ 03339 if (!strcmp(tmpfeature->exten, code)) { 03340 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 03341 if (operation == FEATURE_INTERPRET_CHECK) { 03342 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03343 } else if (operation == FEATURE_INTERPRET_DO) { 03344 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 03345 } 03346 if (feature) { 03347 memcpy(feature, tmpfeature, sizeof(*feature)); 03348 } 03349 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03350 AST_RWLIST_UNLOCK(&feature_list); 03351 break; 03352 } 03353 res = AST_FEATURE_RETURN_PASSDIGITS; 03354 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 03355 res = AST_FEATURE_RETURN_STOREDIGITS; 03356 03357 AST_RWLIST_UNLOCK(&feature_list); 03358 } 03359 03360 return res; 03361 }
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 3511 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().
03515 { 03516 int state = 0; 03517 int cause = 0; 03518 int to; 03519 int caller_hungup; 03520 int transferee_hungup; 03521 struct ast_channel *chan; 03522 struct ast_channel *monitor_chans[3]; 03523 struct ast_channel *active_channel; 03524 int res; 03525 int ready = 0; 03526 struct timeval started; 03527 int x, len = 0; 03528 char *disconnect_code = NULL, *dialed_code = NULL; 03529 struct ast_frame *f; 03530 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; 03531 03532 caller_hungup = ast_check_hangup(caller); 03533 03534 if (!(chan = ast_request(type, format, requestor, data, &cause))) { 03535 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 03536 switch (cause) { 03537 case AST_CAUSE_BUSY: 03538 state = AST_CONTROL_BUSY; 03539 break; 03540 case AST_CAUSE_CONGESTION: 03541 state = AST_CONTROL_CONGESTION; 03542 break; 03543 default: 03544 state = 0; 03545 break; 03546 } 03547 goto done; 03548 } 03549 03550 ast_string_field_set(chan, language, language); 03551 ast_channel_inherit_variables(caller, chan); 03552 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name); 03553 03554 ast_channel_lock(chan); 03555 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller); 03556 ast_channel_unlock(chan); 03557 03558 if (ast_call(chan, data, timeout)) { 03559 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 03560 switch (chan->hangupcause) { 03561 case AST_CAUSE_BUSY: 03562 state = AST_CONTROL_BUSY; 03563 break; 03564 case AST_CAUSE_CONGESTION: 03565 state = AST_CONTROL_CONGESTION; 03566 break; 03567 default: 03568 state = 0; 03569 break; 03570 } 03571 goto done; 03572 } 03573 03574 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 03575 ast_rwlock_rdlock(&features_lock); 03576 for (x = 0; x < FEATURES_COUNT; x++) { 03577 if (strcasecmp(builtin_features[x].sname, "disconnect")) 03578 continue; 03579 03580 disconnect_code = builtin_features[x].exten; 03581 len = strlen(disconnect_code) + 1; 03582 dialed_code = alloca(len); 03583 memset(dialed_code, 0, len); 03584 break; 03585 } 03586 ast_rwlock_unlock(&features_lock); 03587 x = 0; 03588 started = ast_tvnow(); 03589 to = timeout; 03590 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); 03591 03592 ast_poll_channel_add(caller, chan); 03593 03594 transferee_hungup = 0; 03595 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) { 03596 int num_chans = 0; 03597 03598 monitor_chans[num_chans++] = transferee; 03599 monitor_chans[num_chans++] = chan; 03600 if (!caller_hungup) { 03601 if (ast_check_hangup(caller)) { 03602 caller_hungup = 1; 03603 03604 #if defined(ATXFER_NULL_TECH) 03605 /* Change caller's name to ensure that it will remain unique. */ 03606 set_new_chan_name(caller); 03607 03608 /* 03609 * Get rid of caller's physical technology so it is free for 03610 * other calls. 03611 */ 03612 set_kill_chan_tech(caller); 03613 #endif /* defined(ATXFER_NULL_TECH) */ 03614 } else { 03615 /* caller is not hungup so monitor it. */ 03616 monitor_chans[num_chans++] = caller; 03617 } 03618 } 03619 03620 /* see if the timeout has been violated */ 03621 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 03622 state = AST_CONTROL_UNHOLD; 03623 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name); 03624 break; /*doh! timeout*/ 03625 } 03626 03627 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to); 03628 if (!active_channel) 03629 continue; 03630 03631 f = NULL; 03632 if (transferee == active_channel) { 03633 struct ast_frame *dup_f; 03634 03635 f = ast_read(transferee); 03636 if (f == NULL) { /*doh! where'd he go?*/ 03637 transferee_hungup = 1; 03638 state = 0; 03639 break; 03640 } 03641 if (ast_is_deferrable_frame(f)) { 03642 dup_f = ast_frisolate(f); 03643 if (dup_f) { 03644 if (dup_f == f) { 03645 f = NULL; 03646 } 03647 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); 03648 } 03649 } 03650 } else if (chan == active_channel) { 03651 if (!ast_strlen_zero(chan->call_forward)) { 03652 state = 0; 03653 ast_autoservice_start(transferee); 03654 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state); 03655 ast_autoservice_stop(transferee); 03656 if (!chan) { 03657 break; 03658 } 03659 continue; 03660 } 03661 f = ast_read(chan); 03662 if (f == NULL) { /*doh! where'd he go?*/ 03663 switch (chan->hangupcause) { 03664 case AST_CAUSE_BUSY: 03665 state = AST_CONTROL_BUSY; 03666 break; 03667 case AST_CAUSE_CONGESTION: 03668 state = AST_CONTROL_CONGESTION; 03669 break; 03670 default: 03671 state = 0; 03672 break; 03673 } 03674 break; 03675 } 03676 03677 if (f->frametype == AST_FRAME_CONTROL) { 03678 if (f->subclass.integer == AST_CONTROL_RINGING) { 03679 ast_verb(3, "%s is ringing\n", chan->name); 03680 ast_indicate(caller, AST_CONTROL_RINGING); 03681 } else if (f->subclass.integer == AST_CONTROL_BUSY) { 03682 state = f->subclass.integer; 03683 ast_verb(3, "%s is busy\n", chan->name); 03684 ast_indicate(caller, AST_CONTROL_BUSY); 03685 ast_frfree(f); 03686 break; 03687 } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) { 03688 ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", chan->name, chan->exten); 03689 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) { 03690 state = f->subclass.integer; 03691 ast_verb(3, "%s is congested\n", chan->name); 03692 ast_indicate(caller, AST_CONTROL_CONGESTION); 03693 ast_frfree(f); 03694 break; 03695 } else if (f->subclass.integer == AST_CONTROL_ANSWER) { 03696 /* This is what we are hoping for */ 03697 state = f->subclass.integer; 03698 ast_frfree(f); 03699 ready=1; 03700 break; 03701 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) { 03702 if (caller_hungup) { 03703 struct ast_party_connected_line connected; 03704 03705 /* Just save it for the transfer. */ 03706 ast_party_connected_line_set_init(&connected, &caller->connected); 03707 res = ast_connected_line_parse_data(f->data.ptr, f->datalen, 03708 &connected); 03709 if (!res) { 03710 ast_channel_set_connected_line(caller, &connected, NULL); 03711 } 03712 ast_party_connected_line_free(&connected); 03713 } else { 03714 ast_autoservice_start(transferee); 03715 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { 03716 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, 03717 f->data.ptr, f->datalen); 03718 } 03719 ast_autoservice_stop(transferee); 03720 } 03721 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) { 03722 if (!caller_hungup) { 03723 ast_autoservice_start(transferee); 03724 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { 03725 ast_indicate_data(caller, AST_CONTROL_REDIRECTING, 03726 f->data.ptr, f->datalen); 03727 } 03728 ast_autoservice_stop(transferee); 03729 } 03730 } else if (f->subclass.integer != -1 03731 && f->subclass.integer != AST_CONTROL_PROGRESS 03732 && f->subclass.integer != AST_CONTROL_PROCEEDING) { 03733 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer); 03734 } 03735 /* else who cares */ 03736 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03737 ast_write(caller, f); 03738 } 03739 } else if (caller == active_channel) { 03740 f = ast_read(caller); 03741 if (f) { 03742 if (f->frametype == AST_FRAME_DTMF) { 03743 dialed_code[x++] = f->subclass.integer; 03744 dialed_code[x] = '\0'; 03745 if (strlen(dialed_code) == len) { 03746 x = 0; 03747 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 03748 x = 0; 03749 dialed_code[x] = '\0'; 03750 } 03751 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 03752 /* Caller Canceled the call */ 03753 state = AST_CONTROL_UNHOLD; 03754 ast_frfree(f); 03755 break; 03756 } 03757 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03758 ast_write(chan, f); 03759 } 03760 } 03761 } 03762 if (f) 03763 ast_frfree(f); 03764 } /* end while */ 03765 03766 ast_poll_channel_del(caller, chan); 03767 03768 /* 03769 * We need to free all the deferred frames, but we only need to 03770 * queue the deferred frames if no hangup was received. 03771 */ 03772 ast_channel_lock(transferee); 03773 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee)); 03774 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { 03775 if (!transferee_hungup) { 03776 ast_queue_frame_head(transferee, f); 03777 } 03778 ast_frfree(f); 03779 } 03780 ast_channel_unlock(transferee); 03781 03782 done: 03783 ast_indicate(caller, -1); 03784 if (chan && (ready || chan->_state == AST_STATE_UP)) { 03785 state = AST_CONTROL_ANSWER; 03786 } else if (chan) { 03787 ast_hangup(chan); 03788 chan = NULL; 03789 } 03790 03791 if (outstate) 03792 *outstate = state; 03793 03794 return chan; 03795 }
static int find_channel_by_group | ( | void * | obj, | |
void * | arg, | |||
void * | data, | |||
int | flags | |||
) | [static] |
Definition at line 7268 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.
07269 { 07270 struct ast_channel *target = obj;/*!< Potential pickup target */ 07271 struct ast_channel *chan = data;/*!< Channel wanting to pickup call */ 07272 07273 ast_channel_lock(target); 07274 if (chan != target && (chan->pickupgroup & target->callgroup) 07275 && ast_can_pickup(target)) { 07276 /* Return with the channel still locked on purpose */ 07277 return CMP_MATCH | CMP_STOP; 07278 } 07279 ast_channel_unlock(target); 07280 07281 return 0; 07282 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a call feature by name
Definition at line 3073 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().
03074 { 03075 struct ast_call_feature *tmp; 03076 03077 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 03078 if (!strcasecmp(tmp->sname, name)) { 03079 break; 03080 } 03081 } 03082 03083 return tmp; 03084 }
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 3111 of file features.c.
References AST_LIST_TRAVERSE, feature_group_exten::entry, and feature_group::gname.
Referenced by feature_interpret_helper().
03112 { 03113 struct feature_group *fg = NULL; 03114 03115 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 03116 if (!strcasecmp(fg->gname, name)) 03117 break; 03118 } 03119 03120 return fg; 03121 }
static struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) | [static] |
Find parkinglot by name.
Definition at line 4934 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().
04935 { 04936 struct ast_parkinglot *parkinglot; 04937 04938 if (ast_strlen_zero(name)) { 04939 return NULL; 04940 } 04941 04942 parkinglot = ao2_find(parkinglots, (void *) name, 0); 04943 if (parkinglot) { 04944 ast_debug(1, "Found Parking lot: %s\n", parkinglot->name); 04945 } 04946 04947 return parkinglot; 04948 }
static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 1078 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().
01079 { 01080 const char *name; 01081 01082 /* The channel variable overrides everything */ 01083 name = pbx_builtin_getvar_helper(chan, "PARKINGLOT"); 01084 if (!name && !ast_strlen_zero(chan->parkinglot)) { 01085 /* Use the channel's parking lot. */ 01086 name = chan->parkinglot; 01087 } 01088 return name; 01089 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1858 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().
01859 { 01860 ast_indicate(chan, AST_CONTROL_UNHOLD); 01861 01862 return ast_autoservice_stop(chan); 01863 }
static struct ast_exten* get_parking_exten | ( | const char * | exten_str, | |
struct ast_channel * | chan, | |||
const char * | context | |||
) | [static] |
Definition at line 819 of file features.c.
References ast_debug, 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().
00820 { 00821 struct ast_exten *exten; 00822 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 00823 const char *app_at_exten; 00824 00825 ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context); 00826 exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, 00827 E_MATCH); 00828 if (!exten) { 00829 return NULL; 00830 } 00831 00832 app_at_exten = ast_get_extension_app(exten); 00833 if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) { 00834 return NULL; 00835 } 00836 00837 return exten; 00838 }
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 6711 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.
06712 { 06713 int i; 06714 struct ast_call_feature *feature; 06715 struct ao2_iterator iter; 06716 struct ast_parkinglot *curlot; 06717 #define HFS_FORMAT "%-25s %-7s %-7s\n" 06718 06719 switch (cmd) { 06720 06721 case CLI_INIT: 06722 e->command = "features show"; 06723 e->usage = 06724 "Usage: features show\n" 06725 " Lists configured features\n"; 06726 return NULL; 06727 case CLI_GENERATE: 06728 return NULL; 06729 } 06730 06731 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 06732 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06733 06734 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 06735 06736 ast_rwlock_rdlock(&features_lock); 06737 for (i = 0; i < FEATURES_COUNT; i++) 06738 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 06739 ast_rwlock_unlock(&features_lock); 06740 06741 ast_cli(a->fd, "\n"); 06742 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 06743 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06744 if (AST_RWLIST_EMPTY(&feature_list)) { 06745 ast_cli(a->fd, "(none)\n"); 06746 } else { 06747 AST_RWLIST_RDLOCK(&feature_list); 06748 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 06749 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 06750 } 06751 AST_RWLIST_UNLOCK(&feature_list); 06752 } 06753 06754 ast_cli(a->fd, "\nFeature Groups:\n"); 06755 ast_cli(a->fd, "---------------\n"); 06756 if (AST_RWLIST_EMPTY(&feature_groups)) { 06757 ast_cli(a->fd, "(none)\n"); 06758 } else { 06759 struct feature_group *fg; 06760 struct feature_group_exten *fge; 06761 06762 AST_RWLIST_RDLOCK(&feature_groups); 06763 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 06764 ast_cli(a->fd, "===> Group: %s\n", fg->gname); 06765 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 06766 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten); 06767 } 06768 } 06769 AST_RWLIST_UNLOCK(&feature_groups); 06770 } 06771 06772 iter = ao2_iterator_init(parkinglots, 0); 06773 while ((curlot = ao2_iterator_next(&iter))) { 06774 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 06775 ast_cli(a->fd, "------------\n"); 06776 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->cfg.parkext); 06777 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->cfg.parking_con); 06778 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", 06779 curlot->cfg.parking_start, curlot->cfg.parking_stop); 06780 ast_cli(a->fd,"%-22s: %d ms\n", "Parkingtime", curlot->cfg.parkingtime); 06781 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->cfg.mohclass); 06782 ast_cli(a->fd,"%-22s: %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled)); 06783 ast_cli(a->fd,"\n"); 06784 ao2_ref(curlot, -1); 06785 } 06786 ao2_iterator_destroy(&iter); 06787 06788 return CLI_SUCCESS; 06789 }
static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6817 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
06818 { 06819 switch (cmd) { 06820 case CLI_INIT: 06821 e->command = "features reload"; 06822 e->usage = 06823 "Usage: features reload\n" 06824 " Reloads configured call features from features.conf\n"; 06825 return NULL; 06826 case CLI_GENERATE: 06827 return NULL; 06828 } 06829 ast_features_reload(); 06830 06831 return CLI_SUCCESS; 06832 }
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 7021 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.
07022 { 07023 struct parkeduser *cur; 07024 int numparked = 0; 07025 struct ao2_iterator iter; 07026 struct ast_parkinglot *curlot; 07027 07028 switch (cmd) { 07029 case CLI_INIT: 07030 e->command = "parkedcalls show"; 07031 e->usage = 07032 "Usage: parkedcalls show\n" 07033 " List currently parked calls\n"; 07034 return NULL; 07035 case CLI_GENERATE: 07036 return NULL; 07037 } 07038 07039 if (a->argc > e->args) 07040 return CLI_SHOWUSAGE; 07041 07042 ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel", 07043 "Context", "Extension", "Pri", "Timeout"); 07044 07045 iter = ao2_iterator_init(parkinglots, 0); 07046 while ((curlot = ao2_iterator_next(&iter))) { 07047 int lotparked = 0; 07048 07049 /* subtract ref for iterator and for configured parking lot */ 07050 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, 07051 ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot)); 07052 07053 AST_LIST_LOCK(&curlot->parkings); 07054 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 07055 ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n", 07056 cur->parkingexten, cur->chan->name, cur->context, cur->exten, 07057 cur->priority, 07058 (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL))); 07059 ++lotparked; 07060 } 07061 AST_LIST_UNLOCK(&curlot->parkings); 07062 if (lotparked) { 07063 numparked += lotparked; 07064 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, 07065 ESS(lotparked), curlot->name); 07066 } 07067 07068 ao2_ref(curlot, -1); 07069 } 07070 ao2_iterator_destroy(&iter); 07071 07072 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 07073 07074 return CLI_SUCCESS; 07075 }
static int load_config | ( | int | reload | ) | [static] |
Definition at line 6628 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_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().
06629 { 06630 struct ast_flags config_flags = { 06631 reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06632 struct ast_config *cfg; 06633 struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06634 struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06635 06636 /* We are reloading now and have already determined if we will force the reload. */ 06637 force_reload_load = 0; 06638 06639 if (!default_parkinglot) { 06640 /* Must create the default default parking lot */ 06641 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 06642 if (!default_parkinglot) { 06643 ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n"); 06644 return -1; 06645 } 06646 ast_debug(1, "Configuration of default default parking lot done.\n"); 06647 parkinglot_addref(default_parkinglot); 06648 } 06649 06650 cfg = ast_config_load2("features.conf", "features", config_flags); 06651 if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06652 /* No sense in asking for reload trouble if nothing changed. */ 06653 ast_debug(1, "features.conf did not change.\n"); 06654 return 0; 06655 } 06656 if (cfg == CONFIG_STATUS_FILEMISSING 06657 || cfg == CONFIG_STATUS_FILEINVALID) { 06658 ast_log(LOG_WARNING, "Could not load features.conf\n"); 06659 return 0; 06660 } 06661 06662 /* Save current parking lot dialplan needs. */ 06663 if (build_dialplan_useage_map(&old_usage_map, 0)) { 06664 destroy_dialplan_usage_map(&old_usage_map); 06665 06666 /* Allow reloading later to see if conditions have improved. */ 06667 force_reload_load = 1; 06668 return -1; 06669 } 06670 06671 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, 06672 "callback to mark all parking lots"); 06673 process_config(cfg); 06674 ast_config_destroy(cfg); 06675 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, 06676 "callback to remove marked parking lots"); 06677 06678 /* Save updated parking lot dialplan needs. */ 06679 if (build_dialplan_useage_map(&new_usage_map, 1)) { 06680 /* 06681 * Yuck, if this failure caused any parking lot dialplan items 06682 * to be lost, they will likely remain lost until Asterisk is 06683 * restarted. 06684 */ 06685 destroy_dialplan_usage_map(&old_usage_map); 06686 destroy_dialplan_usage_map(&new_usage_map); 06687 return -1; 06688 } 06689 06690 /* Remove no longer needed parking lot dialplan usage. */ 06691 remove_dead_dialplan_useage(&old_usage_map, &new_usage_map); 06692 06693 destroy_dialplan_usage_map(&old_usage_map); 06694 destroy_dialplan_usage_map(&new_usage_map); 06695 06696 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL, 06697 "callback to activate all parking lots"); 06698 06699 return 0; 06700 }
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 4638 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_channel::generatordata, parkeduser::hold_method, LOG_ERROR, LOG_NOTICE, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, parkinglot_cfg::mohclass, ast_dial_features::my_features, ast_parkinglot::name, ast_channel::name, parkeduser::options_specified, parking_con_dial, parkeduser::parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_setvar_helper(), ast_dial_features::peer_features, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), and parkeduser::start.
Referenced by manage_parkinglot().
04639 { 04640 struct ast_channel *chan = pu->chan; /* shorthand */ 04641 int tms; /* timeout for this item */ 04642 int x; /* fd index in channel */ 04643 04644 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 04645 if (tms > pu->parkingtime) { 04646 /* 04647 * Call has been parked too long. 04648 * Stop entertaining the caller. 04649 */ 04650 switch (pu->hold_method) { 04651 case AST_CONTROL_HOLD: 04652 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 04653 break; 04654 case AST_CONTROL_RINGING: 04655 ast_indicate(pu->chan, -1); 04656 break; 04657 default: 04658 break; 04659 } 04660 pu->hold_method = 0; 04661 04662 /* Get chan, exten from derived kludge */ 04663 if (pu->peername[0]) { 04664 char *peername; 04665 char *dash; 04666 char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 04667 int i; 04668 04669 peername = ast_strdupa(pu->peername); 04670 dash = strrchr(peername, '-'); 04671 if (dash) { 04672 *dash = '\0'; 04673 } 04674 04675 peername_flat = ast_strdupa(peername); 04676 for (i = 0; peername_flat[i]; i++) { 04677 if (peername_flat[i] == '/') { 04678 peername_flat[i] = '_'; 04679 } 04680 } 04681 04682 if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) { 04683 ast_log(LOG_ERROR, 04684 "Parking dial context '%s' does not exist and unable to create\n", 04685 parking_con_dial); 04686 } else { 04687 char returnexten[AST_MAX_EXTENSION]; 04688 struct ast_datastore *features_datastore; 04689 struct ast_dial_features *dialfeatures; 04690 04691 if (!strncmp(peername, "Parked/", 7)) { 04692 peername += 7; 04693 } 04694 04695 ast_channel_lock(chan); 04696 features_datastore = ast_channel_datastore_find(chan, &dial_features_info, 04697 NULL); 04698 if (features_datastore && (dialfeatures = features_datastore->data)) { 04699 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 04700 04701 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, 04702 callback_dialoptions(&dialfeatures->peer_features, 04703 &dialfeatures->my_features, buf, sizeof(buf))); 04704 } else { /* Existing default */ 04705 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", 04706 chan->name); 04707 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername); 04708 } 04709 ast_channel_unlock(chan); 04710 04711 if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL, 04712 "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) { 04713 ast_log(LOG_ERROR, 04714 "Could not create parking return dial exten: %s@%s\n", 04715 peername_flat, parking_con_dial); 04716 } 04717 } 04718 if (pu->options_specified) { 04719 /* 04720 * Park() was called with overriding return arguments, respect 04721 * those arguments. 04722 */ 04723 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04724 } else if (comebacktoorigin) { 04725 set_c_e_p(chan, parking_con_dial, peername_flat, 1); 04726 } else { 04727 char parkingslot[AST_MAX_EXTENSION]; 04728 04729 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 04730 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 04731 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 04732 } 04733 } else { 04734 /* 04735 * They've been waiting too long, send them back to where they 04736 * came. Theoretically they should have their original 04737 * extensions and such, but we copy to be on the safe side. 04738 */ 04739 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04740 } 04741 post_manager_event("ParkedCallTimeOut", pu); 04742 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL); 04743 04744 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", 04745 pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, 04746 pu->chan->exten, pu->chan->priority); 04747 04748 /* Start up the PBX, or hang them up */ 04749 if (ast_pbx_start(chan)) { 04750 ast_log(LOG_WARNING, 04751 "Unable to restart the PBX for user on '%s', hanging them up...\n", 04752 pu->chan->name); 04753 ast_hangup(chan); 04754 } 04755 04756 /* And take them out of the parking lot */ 04757 return 1; 04758 } 04759 04760 /* still within parking time, process descriptors */ 04761 if (pfds) { 04762 for (x = 0; x < AST_MAX_FDS; x++) { 04763 struct ast_frame *f; 04764 int y; 04765 04766 if (chan->fds[x] == -1) { 04767 continue; /* nothing on this descriptor */ 04768 } 04769 04770 for (y = 0; y < nfds; y++) { 04771 if (pfds[y].fd == chan->fds[x]) { 04772 /* Found poll record! */ 04773 break; 04774 } 04775 } 04776 if (y == nfds) { 04777 /* Not found */ 04778 continue; 04779 } 04780 04781 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) { 04782 /* Next x */ 04783 continue; 04784 } 04785 04786 if (pfds[y].revents & POLLPRI) { 04787 ast_set_flag(chan, AST_FLAG_EXCEPTION); 04788 } else { 04789 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 04790 } 04791 chan->fdno = x; 04792 04793 /* See if they need servicing */ 04794 f = ast_read(pu->chan); 04795 /* Hangup? */ 04796 if (!f || (f->frametype == AST_FRAME_CONTROL 04797 && f->subclass.integer == AST_CONTROL_HANGUP)) { 04798 if (f) { 04799 ast_frfree(f); 04800 } 04801 post_manager_event("ParkedCallGiveUp", pu); 04802 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", 04803 NULL); 04804 04805 /* There's a problem, hang them up */ 04806 ast_verb(2, "%s got tired of being parked\n", chan->name); 04807 ast_hangup(chan); 04808 04809 /* And take them out of the parking lot */ 04810 return 1; 04811 } else { 04812 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 04813 ast_frfree(f); 04814 if (pu->hold_method == AST_CONTROL_HOLD 04815 && pu->moh_trys < 3 04816 && !chan->generatordata) { 04817 ast_debug(1, 04818 "MOH on parked call stopped by outside source. Restarting on channel %s.\n", 04819 chan->name); 04820 ast_indicate_data(chan, AST_CONTROL_HOLD, 04821 S_OR(pu->parkinglot->cfg.mohclass, NULL), 04822 (!ast_strlen_zero(pu->parkinglot->cfg.mohclass) 04823 ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0)); 04824 pu->moh_trys++; 04825 } 04826 break; 04827 } 04828 } /* End for */ 04829 } 04830 04831 /* mark fds for next round */ 04832 for (x = 0; x < AST_MAX_FDS; x++) { 04833 if (chan->fds[x] > -1) { 04834 void *tmp = ast_realloc(*new_pfds, 04835 (*new_nfds + 1) * sizeof(struct pollfd)); 04836 04837 if (!tmp) { 04838 continue; 04839 } 04840 *new_pfds = tmp; 04841 (*new_pfds)[*new_nfds].fd = chan->fds[x]; 04842 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI; 04843 (*new_pfds)[*new_nfds].revents = 0; 04844 (*new_nfds)++; 04845 } 04846 } 04847 /* Keep track of our shortest wait */ 04848 if (tms < *ms || *ms < 0) { 04849 *ms = tms; 04850 } 04851 04852 /* Stay in the parking lot. */ 04853 return 0; 04854 }
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 4857 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().
04858 { 04859 struct parkeduser *pu; 04860 struct ast_context *con; 04861 04862 /* Lock parkings list */ 04863 AST_LIST_LOCK(&curlot->parkings); 04864 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 04865 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 04866 continue; 04867 } 04868 if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) { 04869 /* Parking is complete for this call so remove it from the parking lot. */ 04870 con = ast_context_find(pu->parkinglot->cfg.parking_con); 04871 if (con) { 04872 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 04873 ast_log(LOG_WARNING, 04874 "Whoa, failed to remove the parking extension %s@%s!\n", 04875 pu->parkingexten, pu->parkinglot->cfg.parking_con); 04876 } 04877 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, 04878 AST_DEVICE_NOT_INUSE); 04879 } else { 04880 ast_log(LOG_WARNING, 04881 "Whoa, parking lot '%s' context '%s' does not exist.\n", 04882 pu->parkinglot->name, pu->parkinglot->cfg.parking_con); 04883 } 04884 AST_LIST_REMOVE_CURRENT(list); 04885 parkinglot_unref(pu->parkinglot); 04886 ast_free(pu); 04887 } 04888 } 04889 AST_LIST_TRAVERSE_SAFE_END; 04890 AST_LIST_UNLOCK(&curlot->parkings); 04891 }
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 7157 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().
07158 { 07159 const char *channel = astman_get_header(m, "Channel"); 07160 const char *channel2 = astman_get_header(m, "Channel2"); 07161 const char *timeout = astman_get_header(m, "Timeout"); 07162 const char *parkinglotname = astman_get_header(m, "Parkinglot"); 07163 char buf[BUFSIZ]; 07164 int res = 0; 07165 struct ast_channel *ch1, *ch2; 07166 struct ast_park_call_args args = { 07167 /* 07168 * Don't say anything to ch2 since AMI is a third party parking 07169 * a call and we will likely crash if we do. 07170 * 07171 * XXX When the AMI action was originally implemented, the 07172 * parking space was announced to ch2. Unfortunately, grabbing 07173 * the ch2 lock and holding it while the announcement is played 07174 * was not really a good thing to do to begin with since it 07175 * could hold up the system. Also holding the lock is no longer 07176 * possible with a masquerade. 07177 * 07178 * Restoring the announcement to ch2 is not easily doable for 07179 * the following reasons: 07180 * 07181 * 1) The AMI manager is not the thread processing ch2. 07182 * 07183 * 2) ch2 could be the same as ch1, bridged to ch1, or some 07184 * random uninvolved channel. 07185 */ 07186 .flags = AST_PARK_OPT_SILENCE, 07187 }; 07188 07189 if (ast_strlen_zero(channel)) { 07190 astman_send_error(s, m, "Channel not specified"); 07191 return 0; 07192 } 07193 07194 if (ast_strlen_zero(channel2)) { 07195 astman_send_error(s, m, "Channel2 not specified"); 07196 return 0; 07197 } 07198 07199 if (!ast_strlen_zero(timeout)) { 07200 if (sscanf(timeout, "%30d", &args.timeout) != 1) { 07201 astman_send_error(s, m, "Invalid timeout value."); 07202 return 0; 07203 } 07204 } 07205 07206 if (!(ch1 = ast_channel_get_by_name(channel))) { 07207 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 07208 astman_send_error(s, m, buf); 07209 return 0; 07210 } 07211 07212 if (!(ch2 = ast_channel_get_by_name(channel2))) { 07213 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 07214 astman_send_error(s, m, buf); 07215 ast_channel_unref(ch1); 07216 return 0; 07217 } 07218 07219 if (!ast_strlen_zero(parkinglotname)) { 07220 args.parkinglot = find_parkinglot(parkinglotname); 07221 } 07222 07223 res = masq_park_call(ch1, ch2, &args); 07224 if (!res) { 07225 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 07226 astman_send_ack(s, m, "Park successful"); 07227 } else { 07228 astman_send_error(s, m, "Park failure"); 07229 } 07230 07231 if (args.parkinglot) { 07232 parkinglot_unref(args.parkinglot); 07233 } 07234 ch1 = ast_channel_unref(ch1); 07235 ch2 = ast_channel_unref(ch2); 07236 07237 return 0; 07238 }
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 7091 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().
07092 { 07093 struct parkeduser *cur; 07094 const char *id = astman_get_header(m, "ActionID"); 07095 char idText[256] = ""; 07096 struct ao2_iterator iter; 07097 struct ast_parkinglot *curlot; 07098 int numparked = 0; 07099 07100 if (!ast_strlen_zero(id)) 07101 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 07102 07103 astman_send_ack(s, m, "Parked calls will follow"); 07104 07105 iter = ao2_iterator_init(parkinglots, 0); 07106 while ((curlot = ao2_iterator_next(&iter))) { 07107 AST_LIST_LOCK(&curlot->parkings); 07108 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 07109 astman_append(s, "Event: ParkedCall\r\n" 07110 "Parkinglot: %s\r\n" 07111 "Exten: %d\r\n" 07112 "Channel: %s\r\n" 07113 "From: %s\r\n" 07114 "Timeout: %ld\r\n" 07115 "CallerIDNum: %s\r\n" 07116 "CallerIDName: %s\r\n" 07117 "ConnectedLineNum: %s\r\n" 07118 "ConnectedLineName: %s\r\n" 07119 "%s" 07120 "\r\n", 07121 curlot->name, 07122 cur->parkingnum, cur->chan->name, cur->peername, 07123 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 07124 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""), /* XXX in other places it is <unknown> */ 07125 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""), 07126 S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""), /* XXX in other places it is <unknown> */ 07127 S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""), 07128 idText); 07129 ++numparked; 07130 } 07131 AST_LIST_UNLOCK(&curlot->parkings); 07132 ao2_ref(curlot, -1); 07133 } 07134 ao2_iterator_destroy(&iter); 07135 07136 astman_append(s, 07137 "Event: ParkedCallsComplete\r\n" 07138 "Total: %d\r\n" 07139 "%s" 07140 "\r\n", 07141 numparked, idText); 07142 07143 return RESULT_SUCCESS; 07144 }
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 1714 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().
01715 { 01716 struct ast_channel *chan; 01717 01718 /* Make a new, channel that we'll use to masquerade in the real one */ 01719 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, 01720 rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s", rchan->name); 01721 if (!chan) { 01722 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 01723 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01724 if (peer == rchan) { 01725 /* Only have one channel to worry about. */ 01726 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01727 } else if (peer) { 01728 /* Have two different channels to worry about. */ 01729 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01730 } 01731 } 01732 return -1; 01733 } 01734 01735 args->pu = park_space_reserve(rchan, peer, args); 01736 if (!args->pu) { 01737 ast_hangup(chan); 01738 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01739 if (peer == rchan) { 01740 /* Only have one channel to worry about. */ 01741 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01742 } else if (peer) { 01743 /* Have two different channels to worry about. */ 01744 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01745 } 01746 } 01747 return -1; 01748 } 01749 01750 /* Make formats okay */ 01751 chan->readformat = rchan->readformat; 01752 chan->writeformat = rchan->writeformat; 01753 01754 if (ast_channel_masquerade(chan, rchan)) { 01755 park_space_abort(args->pu); 01756 args->pu = NULL; 01757 ast_hangup(chan); 01758 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01759 if (peer == rchan) { 01760 /* Only have one channel to worry about. */ 01761 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01762 } else if (peer) { 01763 /* Have two different channels to worry about. */ 01764 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01765 } 01766 } 01767 return -1; 01768 } 01769 01770 /* Setup the extensions and such */ 01771 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 01772 01773 /* Setup the macro extension and such */ 01774 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext)); 01775 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten)); 01776 chan->macropriority = rchan->macropriority; 01777 01778 /* Manually do the masquerade to make sure it is complete. */ 01779 ast_do_masquerade(chan); 01780 01781 if (peer == rchan) { 01782 peer = chan; 01783 } 01784 01785 /* parking space reserved, return code check unnecessary */ 01786 park_call_full(chan, peer, args); 01787 01788 return 0; 01789 }
static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 1101 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().
01102 { 01103 char *context; 01104 char *exten; 01105 01106 context = ast_strdupa(data); 01107 01108 exten = strsep(&context, "@"); 01109 if (!context) 01110 return AST_DEVICE_INVALID; 01111 01112 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 01113 01114 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 01115 return AST_DEVICE_NOT_INUSE; 01116 01117 return AST_DEVICE_INUSE; 01118 }
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 1092 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().
01093 { 01094 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 01095 exten, context, ast_devstate2str(state)); 01096 01097 ast_devstate_changed(state, "park:%s@%s", exten, context); 01098 }
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 5401 of file features.c.
References ast_add_extension(), AST_MAX_EXTENSION, PRIORITY_HINT, and registrar.
Referenced by parkinglot_activate().
05402 { 05403 int numext; 05404 char device[AST_MAX_EXTENSION]; 05405 char exten[10]; 05406 05407 for (numext = start; numext <= stop; numext++) { 05408 snprintf(exten, sizeof(exten), "%d", numext); 05409 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 05410 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 05411 } 05412 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Park a call.
Definition at line 4980 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(), pbx_builtin_getvar_helper(), park_app_args::pl_name, ast_channel::priority, park_app_args::return_con, park_app_args::return_ext, park_app_args::return_pri, S_OR, and park_app_args::timeout.
Referenced by ast_features_init().
04981 { 04982 struct ast_park_call_args args = { 0, }; 04983 struct ast_flags flags = { 0 }; 04984 char orig_exten[AST_MAX_EXTENSION]; 04985 int orig_priority; 04986 int res; 04987 const char *pl_name; 04988 char *parse; 04989 struct park_app_args app_args; 04990 04991 /* 04992 * Cache the original channel name because we are going to 04993 * masquerade the channel. Prefer the BLINDTRANSFER channel 04994 * name over this channel name. BLINDTRANSFER could be set if 04995 * the parking access extension did not get detected and we are 04996 * executing the Park application from the dialplan. 04997 * 04998 * The orig_chan_name is used to return the call to the 04999 * originator on parking timeout. 05000 */ 05001 args.orig_chan_name = ast_strdupa(S_OR( 05002 pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name)); 05003 05004 /* Answer if call is not up */ 05005 if (chan->_state != AST_STATE_UP) { 05006 if (ast_answer(chan)) { 05007 return -1; 05008 } 05009 05010 /* Sleep to allow VoIP streams to settle down */ 05011 if (ast_safe_sleep(chan, 1000)) { 05012 return -1; 05013 } 05014 } 05015 05016 /* Process the dialplan application options. */ 05017 parse = ast_strdupa(data); 05018 AST_STANDARD_APP_ARGS(app_args, parse); 05019 05020 if (!ast_strlen_zero(app_args.timeout)) { 05021 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) { 05022 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 05023 args.timeout = 0; 05024 } 05025 } 05026 if (!ast_strlen_zero(app_args.return_con)) { 05027 args.return_con = app_args.return_con; 05028 } 05029 if (!ast_strlen_zero(app_args.return_ext)) { 05030 args.return_ext = app_args.return_ext; 05031 } 05032 if (!ast_strlen_zero(app_args.return_pri)) { 05033 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) { 05034 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 05035 args.return_pri = 0; 05036 } 05037 } 05038 05039 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 05040 args.flags = flags.flags; 05041 05042 /* 05043 * Setup the exten/priority to be s/1 since we don't know where 05044 * this call should return. 05045 */ 05046 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 05047 orig_priority = chan->priority; 05048 strcpy(chan->exten, "s"); 05049 chan->priority = 1; 05050 05051 /* Park the call */ 05052 if (!ast_strlen_zero(app_args.pl_name)) { 05053 pl_name = app_args.pl_name; 05054 } else { 05055 pl_name = findparkinglotname(chan); 05056 } 05057 if (ast_strlen_zero(pl_name)) { 05058 /* Parking lot is not specified, so use the default parking lot. */ 05059 args.parkinglot = parkinglot_addref(default_parkinglot); 05060 } else { 05061 args.parkinglot = find_parkinglot(pl_name); 05062 if (!args.parkinglot && parkeddynamic) { 05063 args.parkinglot = create_dynamic_parkinglot(pl_name, chan); 05064 } 05065 } 05066 if (args.parkinglot) { 05067 res = masq_park_call(chan, chan, &args); 05068 parkinglot_unref(args.parkinglot); 05069 } else { 05070 /* Parking failed because the parking lot does not exist. */ 05071 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { 05072 ast_stream_and_wait(chan, "pbx-parkingfailed", ""); 05073 } 05074 res = -1; 05075 } 05076 if (res) { 05077 /* Park failed, try to continue in the dialplan. */ 05078 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 05079 chan->priority = orig_priority; 05080 res = 0; 05081 } else { 05082 /* Park succeeded. */ 05083 res = -1; 05084 } 05085 05086 return res; 05087 }
static int park_call_full | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 1466 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_debug, 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().
01467 { 01468 struct parkeduser *pu = args->pu; 01469 const char *event_from; /*!< Channel name that is parking the call. */ 01470 char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT]; 01471 01472 if (pu == NULL) { 01473 args->pu = pu = park_space_reserve(chan, peer, args); 01474 if (pu == NULL) { 01475 return -1; 01476 } 01477 } 01478 01479 chan->appl = "Parked Call"; 01480 chan->data = NULL; 01481 01482 pu->chan = chan; 01483 01484 /* Put the parked channel on hold if we have two different channels */ 01485 if (chan != peer) { 01486 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 01487 pu->hold_method = AST_CONTROL_RINGING; 01488 ast_indicate(chan, AST_CONTROL_RINGING); 01489 } else { 01490 pu->hold_method = AST_CONTROL_HOLD; 01491 ast_indicate_data(chan, AST_CONTROL_HOLD, 01492 S_OR(pu->parkinglot->cfg.mohclass, NULL), 01493 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0); 01494 } 01495 } 01496 01497 pu->start = ast_tvnow(); 01498 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->cfg.parkingtime; 01499 if (args->extout) 01500 *(args->extout) = pu->parkingnum; 01501 01502 if (peer) { 01503 event_from = S_OR(args->orig_chan_name, peer->name); 01504 01505 /* 01506 * This is so ugly that it hurts, but implementing 01507 * get_base_channel() on local channels could have ugly side 01508 * effects. We could have 01509 * transferer<->local,1<->local,2<->parking and we need the 01510 * callback name to be that of transferer. Since local,1/2 have 01511 * the same name we can be tricky and just grab the bridged 01512 * channel from the other side of the local. 01513 */ 01514 if (!strcasecmp(peer->tech->type, "Local")) { 01515 struct ast_channel *tmpchan, *base_peer; 01516 char other_side[AST_CHANNEL_NAME]; 01517 char *c; 01518 01519 ast_copy_string(other_side, event_from, sizeof(other_side)); 01520 if ((c = strrchr(other_side, ';'))) { 01521 *++c = '1'; 01522 } 01523 if ((tmpchan = ast_channel_get_by_name(other_side))) { 01524 ast_channel_lock(tmpchan); 01525 if ((base_peer = ast_bridged_channel(tmpchan))) { 01526 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 01527 } 01528 ast_channel_unlock(tmpchan); 01529 tmpchan = ast_channel_unref(tmpchan); 01530 } 01531 } else { 01532 ast_copy_string(pu->peername, event_from, sizeof(pu->peername)); 01533 } 01534 } else { 01535 event_from = S_OR(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name); 01536 } 01537 01538 /* 01539 * Remember what had been dialed, so that if the parking 01540 * expires, we try to come back to the same place 01541 */ 01542 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri); 01543 01544 /* 01545 * If extension has options specified, they override all other 01546 * possibilities such as the returntoorigin flag and transferred 01547 * context. Information on extension options is lost here, so 01548 * we set a flag 01549 */ 01550 ast_copy_string(pu->context, 01551 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 01552 sizeof(pu->context)); 01553 ast_copy_string(pu->exten, 01554 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 01555 sizeof(pu->exten)); 01556 pu->priority = args->return_pri ? args->return_pri : 01557 (chan->macropriority ? chan->macropriority : chan->priority); 01558 01559 /* 01560 * If parking a channel directly, don't quite yet get parking 01561 * running on it. All parking lot entries are put into the 01562 * parking lot with notquiteyet on. 01563 */ 01564 if (peer != chan) { 01565 pu->notquiteyet = 0; 01566 } 01567 01568 /* Wake up the (presumably select()ing) thread */ 01569 pthread_kill(parking_thread, SIGURG); 01570 ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", 01571 chan->name, pu->parkingnum, pu->parkinglot->name, 01572 pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000)); 01573 01574 ast_cel_report_event(chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer); 01575 01576 ast_manager_event(chan, EVENT_FLAG_CALL, "ParkedCall", 01577 "Exten: %s\r\n" 01578 "Channel: %s\r\n" 01579 "Parkinglot: %s\r\n" 01580 "From: %s\r\n" 01581 "Timeout: %ld\r\n" 01582 "CallerIDNum: %s\r\n" 01583 "CallerIDName: %s\r\n" 01584 "ConnectedLineNum: %s\r\n" 01585 "ConnectedLineName: %s\r\n" 01586 "Uniqueid: %s\r\n", 01587 pu->parkingexten, chan->name, pu->parkinglot->name, event_from, 01588 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 01589 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<unknown>"), 01590 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>"), 01591 S_COR(chan->connected.id.number.valid, chan->connected.id.number.str, "<unknown>"), 01592 S_COR(chan->connected.id.name.valid, chan->connected.id.name.str, "<unknown>"), 01593 chan->uniqueid 01594 ); 01595 ast_debug(4, "peer->name: %s\n", peer ? peer->name : "-No peer-"); 01596 ast_debug(4, "args->orig_chan_name: %s\n", args->orig_chan_name ? args->orig_chan_name : "-none-"); 01597 ast_debug(4, "pu->peername: %s\n", pu->peername); 01598 ast_debug(4, "AMI ParkedCall Channel: %s\n", chan->name); 01599 ast_debug(4, "AMI ParkedCall From: %s\n", event_from); 01600 01601 if (peer && adsipark && ast_adsi_available(peer)) { 01602 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 01603 ast_adsi_unload_session(peer); 01604 } 01605 01606 snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten, 01607 pu->parkinglot->name); 01608 if (ast_add_extension(pu->parkinglot->cfg.parking_con, 1, pu->parkingexten, 1, 01609 NULL, NULL, parkedcall, ast_strdup(app_data), ast_free_ptr, registrar)) { 01610 ast_log(LOG_ERROR, "Could not create parked call exten: %s@%s\n", 01611 pu->parkingexten, pu->parkinglot->cfg.parking_con); 01612 } else { 01613 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE); 01614 } 01615 01616 AST_LIST_UNLOCK(&pu->parkinglot->parkings); 01617 01618 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 01619 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) 01620 && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) { 01621 /* 01622 * If a channel is masqueraded into peer while playing back the 01623 * parking space number do not continue playing it back. This 01624 * is the case if an attended transfer occurs. 01625 */ 01626 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01627 /* Tell the peer channel the number of the parking space */ 01628 ast_say_digits(peer, pu->parkingnum, "", peer->language); 01629 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01630 } 01631 if (peer == chan) { /* pu->notquiteyet = 1 */ 01632 /* Wake up parking thread if we're really done */ 01633 pu->hold_method = AST_CONTROL_HOLD; 01634 ast_indicate_data(chan, AST_CONTROL_HOLD, 01635 S_OR(pu->parkinglot->cfg.mohclass, NULL), 01636 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0); 01637 pu->notquiteyet = 0; 01638 pthread_kill(parking_thread, SIGURG); 01639 } 01640 return 0; 01641 }
static void park_space_abort | ( | struct parkeduser * | pu | ) | [static] |
Definition at line 1268 of file features.c.
References ast_free, AST_LIST_REMOVE, AST_LIST_UNLOCK, parkeduser::parkinglot, parkinglot, and parkinglot_unref().
Referenced by masq_park_call().
01269 { 01270 struct ast_parkinglot *parkinglot; 01271 01272 parkinglot = pu->parkinglot; 01273 01274 /* Put back the parking space just allocated. */ 01275 --parkinglot->next_parking_space; 01276 01277 AST_LIST_REMOVE(&parkinglot->parkings, pu, list); 01278 01279 AST_LIST_UNLOCK(&parkinglot->parkings); 01280 parkinglot_unref(parkinglot); 01281 ast_free(pu); 01282 }
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 1295 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().
01296 { 01297 struct parkeduser *pu; 01298 int i; 01299 int parking_space = -1; 01300 const char *parkinglotname; 01301 const char *parkingexten; 01302 struct parkeduser *cur; 01303 struct ast_parkinglot *parkinglot = NULL; 01304 01305 if (args->parkinglot) { 01306 parkinglot = parkinglot_addref(args->parkinglot); 01307 parkinglotname = parkinglot->name; 01308 } else { 01309 if (parker) { 01310 parkinglotname = findparkinglotname(parker); 01311 } else { /* parker was NULL, check park_me (ParkAndAnnounce / res_agi) */ 01312 parkinglotname = findparkinglotname(park_me); 01313 } 01314 if (!ast_strlen_zero(parkinglotname)) { 01315 parkinglot = find_parkinglot(parkinglotname); 01316 } else { 01317 /* Parking lot is not specified, so use the default parking lot. */ 01318 ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n"); 01319 parkinglot = parkinglot_addref(default_parkinglot); 01320 } 01321 } 01322 01323 /* Dynamically create parkinglot */ 01324 if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) { 01325 parkinglot = create_dynamic_parkinglot(parkinglotname, park_me); 01326 } 01327 01328 if (!parkinglot) { 01329 ast_log(LOG_WARNING, "Parking lot not available to park %s.\n", park_me->name); 01330 return NULL; 01331 } 01332 01333 ast_debug(1, "Parking lot: %s\n", parkinglot->name); 01334 if (parkinglot->disabled || parkinglot->cfg.is_invalid) { 01335 ast_log(LOG_WARNING, "Parking lot %s is not in a useable state.\n", 01336 parkinglot->name); 01337 parkinglot_unref(parkinglot); 01338 return NULL; 01339 } 01340 01341 /* Allocate memory for parking data */ 01342 if (!(pu = ast_calloc(1, sizeof(*pu)))) { 01343 parkinglot_unref(parkinglot); 01344 return NULL; 01345 } 01346 01347 /* Lock parking list */ 01348 AST_LIST_LOCK(&parkinglot->parkings); 01349 01350 /* Check for channel variable PARKINGEXTEN */ 01351 parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(park_me, "PARKINGEXTEN"), "")); 01352 if (!ast_strlen_zero(parkingexten)) { 01353 /*! 01354 * \note The API forces us to specify a numeric parking slot, even 01355 * though the architecture would tend to support non-numeric extensions 01356 * (as are possible with SIP, for example). Hence, we enforce that 01357 * limitation here. If extout was not numeric, we could permit 01358 * arbitrary non-numeric extensions. 01359 */ 01360 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space <= 0) { 01361 ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", 01362 parkingexten); 01363 AST_LIST_UNLOCK(&parkinglot->parkings); 01364 parkinglot_unref(parkinglot); 01365 ast_free(pu); 01366 return NULL; 01367 } 01368 01369 if (parking_space < parkinglot->cfg.parking_start 01370 || parkinglot->cfg.parking_stop < parking_space) { 01371 /* 01372 * Cannot allow park because parking lots are not setup for 01373 * spaces outside of the lot. (Things like dialplan hints don't 01374 * exist for outside lot space.) 01375 */ 01376 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is not in %s (%d-%d).\n", 01377 parking_space, parkinglot->name, parkinglot->cfg.parking_start, 01378 parkinglot->cfg.parking_stop); 01379 AST_LIST_UNLOCK(&parkinglot->parkings); 01380 parkinglot_unref(parkinglot); 01381 ast_free(pu); 01382 return NULL; 01383 } 01384 01385 /* Check if requested parking space is in use. */ 01386 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 01387 if (cur->parkingnum == parking_space) { 01388 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is already in use in %s\n", 01389 parking_space, parkinglot->name); 01390 AST_LIST_UNLOCK(&parkinglot->parkings); 01391 parkinglot_unref(parkinglot); 01392 ast_free(pu); 01393 return NULL; 01394 } 01395 } 01396 } else { 01397 /* PARKINGEXTEN is empty, so find a usable extension in the lot to park the call */ 01398 int start; /* The first slot we look in the parkinglot. It can be randomized. */ 01399 int start_checked = 0; /* flag raised once the first slot is checked */ 01400 01401 /* If using randomize mode, set start to random position on parking range */ 01402 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) { 01403 start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1); 01404 start += parkinglot->cfg.parking_start; 01405 } else if (parkinglot->cfg.parkfindnext 01406 && parkinglot->cfg.parking_start <= parkinglot->next_parking_space 01407 && parkinglot->next_parking_space <= parkinglot->cfg.parking_stop) { 01408 /* Start looking with the next parking space in the lot. */ 01409 start = parkinglot->next_parking_space; 01410 } else { 01411 /* Otherwise, just set it to the start position. */ 01412 start = parkinglot->cfg.parking_start; 01413 } 01414 01415 /* free parking extension linear search: O(n^2) */ 01416 for (i = start; ; i++) { 01417 /* If we are past the end, wrap around to the first parking slot*/ 01418 if (i == parkinglot->cfg.parking_stop + 1) { 01419 i = parkinglot->cfg.parking_start; 01420 } 01421 01422 if (i == start) { 01423 /* At this point, if start_checked, we've exhausted all the possible slots. */ 01424 if (start_checked) { 01425 break; 01426 } else { 01427 start_checked = 1; 01428 } 01429 } 01430 01431 /* Search the list of parked calls already in use for i. If we find it, it's in use. */ 01432 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 01433 if (cur->parkingnum == i) { 01434 break; 01435 } 01436 } 01437 if (!cur) { 01438 /* We found a parking space. */ 01439 parking_space = i; 01440 break; 01441 } 01442 } 01443 if (parking_space == -1) { 01444 /* We did not find a parking space. Lot is full. */ 01445 ast_log(LOG_WARNING, "No more parking spaces in %s\n", parkinglot->name); 01446 AST_LIST_UNLOCK(&parkinglot->parkings); 01447 parkinglot_unref(parkinglot); 01448 ast_free(pu); 01449 return NULL; 01450 } 01451 } 01452 01453 /* Prepare for next parking space search. */ 01454 parkinglot->next_parking_space = parking_space + 1; 01455 01456 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 01457 pu->notquiteyet = 1; 01458 pu->parkingnum = parking_space; 01459 pu->parkinglot = parkinglot; 01460 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list); 01461 01462 return pu; 01463 }
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 5090 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, dummy(), EVENT_FLAG_CALL, find_parkinglot(), findparkinglotname(), parkeduser::hold_method, ast_party_connected_line::id, ast_party_caller::id, LOG_WARNING, ast_dial_features::my_features, ast_party_id::name, ast_parkinglot::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_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.
Referenced by ast_features_init().
05091 { 05092 int res; 05093 struct ast_channel *peer = NULL; 05094 struct parkeduser *pu; 05095 struct ast_context *con; 05096 char *parse; 05097 const char *pl_name; 05098 int park = 0; 05099 struct ast_bridge_config config; 05100 struct ast_parkinglot *parkinglot; 05101 AST_DECLARE_APP_ARGS(app_args, 05102 AST_APP_ARG(pl_space); /*!< Parking lot space to retrieve if present. */ 05103 AST_APP_ARG(pl_name); /*!< Parking lot name to use if present. */ 05104 AST_APP_ARG(dummy); /*!< Place to put any remaining args string. */ 05105 ); 05106 05107 parse = ast_strdupa(data); 05108 AST_STANDARD_APP_ARGS(app_args, parse); 05109 05110 if (!ast_strlen_zero(app_args.pl_space)) { 05111 if (sscanf(app_args.pl_space, "%30u", &park) != 1) { 05112 ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n", 05113 app_args.pl_space); 05114 park = -1; 05115 } 05116 } 05117 05118 if (!ast_strlen_zero(app_args.pl_name)) { 05119 pl_name = app_args.pl_name; 05120 } else { 05121 pl_name = findparkinglotname(chan); 05122 } 05123 if (ast_strlen_zero(pl_name)) { 05124 /* Parking lot is not specified, so use the default parking lot. */ 05125 parkinglot = parkinglot_addref(default_parkinglot); 05126 } else { 05127 parkinglot = find_parkinglot(pl_name); 05128 if (!parkinglot) { 05129 /* It helps to answer the channel if not already up. :) */ 05130 if (chan->_state != AST_STATE_UP) { 05131 ast_answer(chan); 05132 } 05133 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05134 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", 05135 "pbx-invalidpark", chan->name); 05136 } 05137 ast_log(LOG_WARNING, 05138 "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n", 05139 chan->name, pl_name); 05140 return -1; 05141 } 05142 } 05143 05144 AST_LIST_LOCK(&parkinglot->parkings); 05145 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 05146 if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park) 05147 && !pu->notquiteyet && !pu->chan->pbx) { 05148 /* The parking space has a call and can be picked up now. */ 05149 AST_LIST_REMOVE_CURRENT(list); 05150 break; 05151 } 05152 } 05153 AST_LIST_TRAVERSE_SAFE_END; 05154 if (pu) { 05155 /* Found a parked call to pickup. */ 05156 peer = pu->chan; 05157 con = ast_context_find(parkinglot->cfg.parking_con); 05158 if (con) { 05159 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 05160 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 05161 } else { 05162 notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE); 05163 } 05164 } else { 05165 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 05166 } 05167 05168 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan); 05169 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall", 05170 "Exten: %s\r\n" 05171 "Channel: %s\r\n" 05172 "Parkinglot: %s\r\n" 05173 "From: %s\r\n" 05174 "CallerIDNum: %s\r\n" 05175 "CallerIDName: %s\r\n" 05176 "ConnectedLineNum: %s\r\n" 05177 "ConnectedLineName: %s\r\n" 05178 "Uniqueid: %s\r\n", 05179 pu->parkingexten, pu->chan->name, pu->parkinglot->name, chan->name, 05180 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 05181 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 05182 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 05183 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 05184 pu->chan->uniqueid 05185 ); 05186 05187 /* Stop entertaining the caller. */ 05188 switch (pu->hold_method) { 05189 case AST_CONTROL_HOLD: 05190 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 05191 break; 05192 case AST_CONTROL_RINGING: 05193 ast_indicate(pu->chan, -1); 05194 break; 05195 default: 05196 break; 05197 } 05198 pu->hold_method = 0; 05199 05200 parkinglot_unref(pu->parkinglot); 05201 ast_free(pu); 05202 } 05203 AST_LIST_UNLOCK(&parkinglot->parkings); 05204 05205 if (peer) { 05206 /* Update connected line between retrieving call and parked call. */ 05207 struct ast_party_connected_line connected; 05208 05209 ast_party_connected_line_init(&connected); 05210 05211 /* Send our caller-id to peer. */ 05212 ast_channel_lock(chan); 05213 ast_connected_line_copy_from_caller(&connected, &chan->caller); 05214 ast_channel_unlock(chan); 05215 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05216 if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) { 05217 ast_channel_update_connected_line(peer, &connected, NULL); 05218 } 05219 05220 /* 05221 * Get caller-id from peer. 05222 * 05223 * Update the retrieving call before it is answered if possible 05224 * for best results. Some phones do not support updating the 05225 * connected line information after connection. 05226 */ 05227 ast_channel_lock(peer); 05228 ast_connected_line_copy_from_caller(&connected, &peer->caller); 05229 ast_channel_unlock(peer); 05230 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05231 if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) { 05232 ast_channel_update_connected_line(chan, &connected, NULL); 05233 } 05234 05235 ast_party_connected_line_free(&connected); 05236 } 05237 05238 /* JK02: it helps to answer the channel if not already up */ 05239 if (chan->_state != AST_STATE_UP) { 05240 ast_answer(chan); 05241 } 05242 05243 if (peer) { 05244 struct ast_datastore *features_datastore; 05245 struct ast_dial_features *dialfeatures; 05246 05247 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 05248 if (!ast_strlen_zero(courtesytone)) { 05249 static const char msg[] = "courtesy tone"; 05250 05251 switch (parkedplay) { 05252 case 0:/* Courtesy tone to pickup chan */ 05253 res = play_message_to_chans(chan, peer, -1, msg, courtesytone); 05254 break; 05255 case 1:/* Courtesy tone to parked chan */ 05256 res = play_message_to_chans(chan, peer, 1, msg, courtesytone); 05257 break; 05258 case 2:/* Courtesy tone to both chans */ 05259 res = play_message_to_chans(chan, peer, 0, msg, courtesytone); 05260 break; 05261 default: 05262 res = 0; 05263 break; 05264 } 05265 if (res) { 05266 ast_hangup(peer); 05267 parkinglot_unref(parkinglot); 05268 return -1; 05269 } 05270 } 05271 05272 res = ast_channel_make_compatible(chan, peer); 05273 if (res < 0) { 05274 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 05275 ast_hangup(peer); 05276 parkinglot_unref(parkinglot); 05277 return -1; 05278 } 05279 /* This runs sorta backwards, since we give the incoming channel control, as if it 05280 were the person called. */ 05281 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park); 05282 05283 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 05284 ast_cdr_setdestchan(chan->cdr, peer->name); 05285 memset(&config, 0, sizeof(struct ast_bridge_config)); 05286 05287 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 05288 ast_channel_lock(peer); 05289 features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL); 05290 if (features_datastore && (dialfeatures = features_datastore->data)) { 05291 ast_copy_flags(&config.features_callee, &dialfeatures->my_features, 05292 AST_FLAGS_ALL); 05293 } 05294 ast_channel_unlock(peer); 05295 05296 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05297 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 05298 } 05299 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05300 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 05301 } 05302 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05303 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 05304 } 05305 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05306 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 05307 } 05308 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05309 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 05310 } 05311 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05312 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 05313 } 05314 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05315 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 05316 } 05317 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05318 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 05319 } 05320 05321 res = ast_bridge_call(chan, peer, &config); 05322 05323 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 05324 ast_cdr_setdestchan(chan->cdr, peer->name); 05325 05326 /* Simulate the PBX hanging up */ 05327 ast_hangup(peer); 05328 } else { 05329 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05330 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", 05331 chan->name); 05332 } 05333 ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n", 05334 chan->name, park); 05335 res = -1; 05336 } 05337 05338 parkinglot_unref(parkinglot); 05339 return res; 05340 }
static int parkinglot_activate | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 5551 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().
05552 { 05553 int disabled = 0; 05554 char app_data[5 + AST_MAX_CONTEXT]; 05555 05556 /* Create Park option list. Must match with struct park_app_args options. */ 05557 if (parkinglot->cfg.parkext_exclusive) { 05558 /* Specify the parking lot this parking extension parks calls. */ 05559 snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name); 05560 } else { 05561 /* The dialplan must specify which parking lot to use. */ 05562 app_data[0] = '\0'; 05563 } 05564 05565 /* Create context */ 05566 if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) { 05567 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", 05568 parkinglot->cfg.parking_con); 05569 disabled = 1; 05570 05571 /* Add a parking extension into the context */ 05572 } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext, 05573 1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) { 05574 ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n", 05575 parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con); 05576 disabled = 1; 05577 } else { 05578 /* Add parking hints */ 05579 if (parkinglot->cfg.parkaddhints) { 05580 park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start, 05581 parkinglot->cfg.parking_stop); 05582 } 05583 05584 /* 05585 * XXX Not sure why we should need to notify the metermaids for 05586 * this exten. It was originally done for the default parking 05587 * lot entry exten only but should be done for all entry extens 05588 * if we do it for one. 05589 */ 05590 /* Notify metermaids about parking lot entry exten state. */ 05591 notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con, 05592 AST_DEVICE_INUSE); 05593 } 05594 05595 parkinglot->disabled = disabled; 05596 return disabled ? -1 : 0; 05597 }
static int parkinglot_activate_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6600 of file features.c.
References ast_debug, ast_log(), force_reload_load, LOG_WARNING, parkinglot, and parkinglot_activate().
Referenced by load_config().
06601 { 06602 struct ast_parkinglot *parkinglot = obj; 06603 06604 if (parkinglot->the_mark) { 06605 /* 06606 * Don't activate a parking lot that still bears the_mark since 06607 * it is effectively deleted. 06608 */ 06609 return 0; 06610 } 06611 06612 if (parkinglot_activate(parkinglot)) { 06613 /* 06614 * The parking lot failed to activate. Allow reloading later to 06615 * see if that fixes it. 06616 */ 06617 force_reload_load = 1; 06618 ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name); 06619 } else { 06620 ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n", 06621 parkinglot->name, parkinglot->cfg.parking_start, 06622 parkinglot->cfg.parking_stop); 06623 } 06624 06625 return 0; 06626 }
static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 5352 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().
05353 { 05354 int refcount; 05355 05356 refcount = ao2_ref(parkinglot, +1); 05357 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1); 05358 return parkinglot; 05359 }
static int parkinglot_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 865 of file features.c.
References CMP_MATCH, CMP_STOP, ast_parkinglot::name, and parkinglot.
Referenced by ast_features_init().
00866 { 00867 struct ast_parkinglot *parkinglot = obj; 00868 struct ast_parkinglot *parkinglot2 = arg; 00869 00870 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0; 00871 }
static int parkinglot_config_read | ( | const char * | pl_name, | |
struct parkinglot_cfg * | cfg, | |||
struct ast_variable * | var | |||
) | [static] |
Definition at line 5463 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().
05464 { 05465 int error = 0; 05466 05467 while (var) { 05468 if (!strcasecmp(var->name, "context")) { 05469 ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con)); 05470 } else if (!strcasecmp(var->name, "parkext")) { 05471 ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext)); 05472 } else if (!strcasecmp(var->name, "parkext_exclusive")) { 05473 cfg->parkext_exclusive = ast_true(var->value); 05474 } else if (!strcasecmp(var->name, "parkinghints")) { 05475 cfg->parkaddhints = ast_true(var->value); 05476 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 05477 ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass)); 05478 } else if (!strcasecmp(var->name, "parkingtime")) { 05479 int parkingtime = 0; 05480 05481 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) { 05482 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 05483 error = -1; 05484 } else { 05485 cfg->parkingtime = parkingtime * 1000; 05486 } 05487 } else if (!strcasecmp(var->name, "parkpos")) { 05488 int start = 0; 05489 int end = 0; 05490 05491 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 05492 ast_log(LOG_WARNING, 05493 "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n", 05494 var->lineno, var->file); 05495 error = -1; 05496 } else if (end < start || start <= 0 || end <= 0) { 05497 ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n", 05498 var->lineno, var->file); 05499 error = -1; 05500 } else { 05501 cfg->parking_start = start; 05502 cfg->parking_stop = end; 05503 } 05504 } else if (!strcasecmp(var->name, "findslot")) { 05505 cfg->parkfindnext = (!strcasecmp(var->value, "next")); 05506 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 05507 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var); 05508 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 05509 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var); 05510 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 05511 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var); 05512 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 05513 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var); 05514 } 05515 var = var->next; 05516 } 05517 05518 /* Check for configuration errors */ 05519 if (ast_strlen_zero(cfg->parking_con)) { 05520 ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name); 05521 error = -1; 05522 } 05523 if (ast_strlen_zero(cfg->parkext)) { 05524 ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name); 05525 error = -1; 05526 } 05527 if (!cfg->parking_start) { 05528 ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name); 05529 error = -1; 05530 } 05531 if (error) { 05532 cfg->is_invalid = 1; 05533 } 05534 05535 return error; 05536 }
static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 5362 of file features.c.
References ast_assert, AST_LIST_EMPTY, AST_LIST_HEAD_DESTROY, and ast_parkinglot::parkings.
Referenced by create_parkinglot().
05363 { 05364 struct ast_parkinglot *doomed = obj; 05365 05366 /* 05367 * No need to destroy parked calls here because any parked call 05368 * holds a parking lot reference. Therefore the parkings list 05369 * must be empty. 05370 */ 05371 ast_assert(AST_LIST_EMPTY(&doomed->parkings)); 05372 AST_LIST_HEAD_DESTROY(&doomed->parkings); 05373 }
static void parkinglot_feature_flag_cfg | ( | const char * | pl_name, | |
int * | param, | |||
struct ast_variable * | var | |||
) | [static] |
Definition at line 5440 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().
05441 { 05442 ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value); 05443 if (!strcasecmp(var->value, "both")) { 05444 *param = AST_FEATURE_FLAG_BYBOTH; 05445 } else if (!strcasecmp(var->value, "caller")) { 05446 *param = AST_FEATURE_FLAG_BYCALLER; 05447 } else if (!strcasecmp(var->value, "callee")) { 05448 *param = AST_FEATURE_FLAG_BYCALLEE; 05449 } 05450 }
static int parkinglot_hash_cb | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 858 of file features.c.
References ast_str_case_hash(), and parkinglot.
Referenced by ast_features_init().
00859 { 00860 const struct ast_parkinglot *parkinglot = obj; 00861 00862 return ast_str_case_hash(parkinglot->name); 00863 }
static int parkinglot_is_marked_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6580 of file features.c.
References AST_LIST_EMPTY, ast_log(), CMP_MATCH, force_reload_load, LOG_WARNING, and parkinglot.
Referenced by load_config().
06581 { 06582 struct ast_parkinglot *parkinglot = obj; 06583 06584 if (parkinglot->the_mark) { 06585 if (AST_LIST_EMPTY(&parkinglot->parkings)) { 06586 /* This parking lot can actually be deleted. */ 06587 return CMP_MATCH; 06588 } 06589 /* Try reloading later when parking lot is empty. */ 06590 ast_log(LOG_WARNING, 06591 "Parking lot %s has parked calls. Could not remove.\n", 06592 parkinglot->name); 06593 parkinglot->disabled = 1; 06594 force_reload_load = 1; 06595 } 06596 06597 return 0; 06598 }
static int parkinglot_markall_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6572 of file features.c.
References parkinglot.
Referenced by load_config().
06573 { 06574 struct ast_parkinglot *parkinglot = obj; 06575 06576 parkinglot->the_mark = 1; 06577 return 0; 06578 }
static void parkinglot_unref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Unreference parkinglot object.
Definition at line 5345 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().
05346 { 05347 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, 05348 ao2_ref(parkinglot, 0) - 1); 05349 ao2_ref(parkinglot, -1); 05350 }
return the first unlocked cdr in a possible chain
Definition at line 3821 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
03822 { 03823 struct ast_cdr *cdr_orig = cdr; 03824 while (cdr) { 03825 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 03826 return cdr; 03827 cdr = cdr->next; 03828 } 03829 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 03830 }
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 2066 of file features.c.
References play_message_to_chans().
Referenced by builtin_automonitor().
02067 { 02068 return play_message_to_chans(caller_chan, callee_chan, 0, "automon message", 02069 audiofile); 02070 }
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 2012 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().
02013 { 02014 /* Put other channel in autoservice. */ 02015 if (ast_autoservice_start(other)) { 02016 return -1; 02017 } 02018 ast_autoservice_ignore(other, AST_FRAME_DTMF_BEGIN); 02019 ast_autoservice_ignore(other, AST_FRAME_DTMF_END); 02020 if (ast_stream_and_wait(play_to, audiofile, "")) { 02021 ast_log(LOG_WARNING, "Failed to play %s '%s'!\n", msg, audiofile); 02022 ast_autoservice_stop(other); 02023 return -1; 02024 } 02025 if (ast_autoservice_stop(other)) { 02026 return -1; 02027 } 02028 return 0; 02029 }
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 2047 of file features.c.
References play_message_on_chan().
Referenced by parked_call_exec(), and play_message_in_bridged_call().
02048 { 02049 /* First play the file to the left channel if requested. */ 02050 if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) { 02051 return -1; 02052 } 02053 02054 /* Then play the file to the right channel if requested. */ 02055 if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) { 02056 return -1; 02057 } 02058 02059 return 0; 02060 }
static void post_manager_event | ( | const char * | s, | |
struct parkeduser * | pu | |||
) | [static] |
Output parking event to manager.
Definition at line 4564 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().
04565 { 04566 manager_event(EVENT_FLAG_CALL, s, 04567 "Exten: %s\r\n" 04568 "Channel: %s\r\n" 04569 "Parkinglot: %s\r\n" 04570 "CallerIDNum: %s\r\n" 04571 "CallerIDName: %s\r\n" 04572 "ConnectedLineNum: %s\r\n" 04573 "ConnectedLineName: %s\r\n" 04574 "UniqueID: %s\r\n", 04575 pu->parkingexten, 04576 pu->chan->name, 04577 pu->parkinglot->name, 04578 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 04579 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 04580 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 04581 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 04582 pu->chan->uniqueid 04583 ); 04584 }
static void process_applicationmap_line | ( | struct ast_variable * | var | ) | [static] |
Definition at line 5679 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_free, 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.
05680 { 05681 char *tmp_val = ast_strdupa(var->value); 05682 char *activateon, *new_syn; 05683 struct ast_call_feature *feature; 05684 AST_DECLARE_APP_ARGS(args, 05685 AST_APP_ARG(exten); 05686 AST_APP_ARG(activatedby); 05687 AST_APP_ARG(app); 05688 AST_APP_ARG(app_args); 05689 AST_APP_ARG(moh_class); 05690 ); 05691 05692 AST_STANDARD_APP_ARGS(args, tmp_val); 05693 if ((new_syn = strchr(args.app, '('))) { 05694 /* New syntax */ 05695 args.moh_class = args.app_args; 05696 args.app_args = new_syn; 05697 *args.app_args++ = '\0'; 05698 if (args.app_args[strlen(args.app_args) - 1] == ')') { 05699 args.app_args[strlen(args.app_args) - 1] = '\0'; 05700 } 05701 } 05702 05703 activateon = strsep(&args.activatedby, "/"); 05704 05705 /*! \todo XXX var_name or app_args ? */ 05706 if (ast_strlen_zero(args.app) 05707 || ast_strlen_zero(args.exten) 05708 || ast_strlen_zero(activateon) 05709 || ast_strlen_zero(var->name)) { 05710 ast_log(LOG_NOTICE, 05711 "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 05712 args.app, args.exten, activateon, var->name); 05713 return; 05714 } 05715 05716 AST_RWLIST_RDLOCK(&feature_list); 05717 if (find_dynamic_feature(var->name)) { 05718 AST_RWLIST_UNLOCK(&feature_list); 05719 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", 05720 var->name); 05721 return; 05722 } 05723 AST_RWLIST_UNLOCK(&feature_list); 05724 05725 if (!(feature = ast_calloc(1, sizeof(*feature)))) { 05726 return; 05727 } 05728 05729 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 05730 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN); 05731 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN); 05732 05733 if (args.app_args) { 05734 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN); 05735 } 05736 05737 if (args.moh_class) { 05738 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN); 05739 } 05740 05741 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten)); 05742 feature->operation = feature_exec_app; 05743 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 05744 05745 /* Allow caller and callee to be specified for backwards compatability */ 05746 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) { 05747 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 05748 } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) { 05749 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 05750 } else { 05751 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 05752 " must be 'self', or 'peer'\n", var->name); 05753 ast_free(feature); 05754 return; 05755 } 05756 05757 if (ast_strlen_zero(args.activatedby)) { 05758 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05759 } else if (!strcasecmp(args.activatedby, "caller")) { 05760 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 05761 } else if (!strcasecmp(args.activatedby, "callee")) { 05762 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 05763 } else if (!strcasecmp(args.activatedby, "both")) { 05764 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05765 } else { 05766 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 05767 " must be 'caller', or 'callee', or 'both'\n", var->name); 05768 ast_free(feature); 05769 return; 05770 } 05771 05772 ast_register_feature(feature); 05773 05774 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", 05775 var->name, args.app, args.app_args, args.exten); 05776 }
static int process_config | ( | struct ast_config * | cfg | ) | [static] |
Definition at line 5778 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().
05779 { 05780 int i; 05781 struct ast_variable *var = NULL; 05782 struct feature_group *fg = NULL; 05783 char *ctg; 05784 static const char * const categories[] = { 05785 /* Categories in features.conf that are not 05786 * to be parsed as group categories 05787 */ 05788 "general", 05789 "featuremap", 05790 "applicationmap" 05791 }; 05792 05793 /* Set general features global defaults. */ 05794 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05795 05796 /* Set global call pickup defaults. */ 05797 strcpy(pickup_ext, "*8"); 05798 pickupsound[0] = '\0'; 05799 pickupfailsound[0] = '\0'; 05800 05801 /* Set global call transfer defaults. */ 05802 strcpy(xfersound, "beep"); 05803 strcpy(xferfailsound, "beeperr"); 05804 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05805 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05806 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05807 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 05808 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05809 05810 /* Set global call parking defaults. */ 05811 comebacktoorigin = 1; 05812 courtesytone[0] = '\0'; 05813 parkedplay = 0; 05814 adsipark = 0; 05815 parkeddynamic = 0; 05816 05817 var = ast_variable_browse(cfg, "general"); 05818 build_parkinglot(DEFAULT_PARKINGLOT, var); 05819 for (; var; var = var->next) { 05820 if (!strcasecmp(var->name, "parkeddynamic")) { 05821 parkeddynamic = ast_true(var->value); 05822 } else if (!strcasecmp(var->name, "adsipark")) { 05823 adsipark = ast_true(var->value); 05824 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 05825 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 05826 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 05827 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05828 } else { 05829 transferdigittimeout = transferdigittimeout * 1000; 05830 } 05831 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 05832 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 05833 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 05834 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05835 } 05836 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 05837 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 05838 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 05839 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05840 } else { 05841 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 05842 } 05843 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 05844 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 05845 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 05846 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05847 } else { 05848 atxferloopdelay *= 1000; 05849 } 05850 } else if (!strcasecmp(var->name, "atxferdropcall")) { 05851 atxferdropcall = ast_true(var->value); 05852 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 05853 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) { 05854 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 05855 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05856 } 05857 } else if (!strcasecmp(var->name, "courtesytone")) { 05858 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 05859 } else if (!strcasecmp(var->name, "parkedplay")) { 05860 if (!strcasecmp(var->value, "both")) { 05861 parkedplay = 2; 05862 } else if (!strcasecmp(var->value, "parked")) { 05863 parkedplay = 1; 05864 } else { 05865 parkedplay = 0; 05866 } 05867 } else if (!strcasecmp(var->name, "xfersound")) { 05868 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 05869 } else if (!strcasecmp(var->name, "xferfailsound")) { 05870 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 05871 } else if (!strcasecmp(var->name, "pickupexten")) { 05872 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 05873 } else if (!strcasecmp(var->name, "pickupsound")) { 05874 ast_copy_string(pickupsound, var->value, sizeof(pickupsound)); 05875 } else if (!strcasecmp(var->name, "pickupfailsound")) { 05876 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound)); 05877 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 05878 comebacktoorigin = ast_true(var->value); 05879 } 05880 } 05881 05882 unmap_features(); 05883 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 05884 if (remap_feature(var->name, var->value)) { 05885 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 05886 } 05887 } 05888 05889 /* Map a key combination to an application */ 05890 ast_unregister_features(); 05891 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 05892 process_applicationmap_line(var); 05893 } 05894 05895 ast_unregister_groups(); 05896 AST_RWLIST_WRLOCK(&feature_groups); 05897 05898 ctg = NULL; 05899 while ((ctg = ast_category_browse(cfg, ctg))) { 05900 /* Is this a parkinglot definition ? */ 05901 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 05902 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 05903 if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) { 05904 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 05905 } else { 05906 ast_debug(1, "Configured parking context %s\n", ctg); 05907 } 05908 continue; 05909 } 05910 05911 /* No, check if it's a group */ 05912 for (i = 0; i < ARRAY_LEN(categories); i++) { 05913 if (!strcasecmp(categories[i], ctg)) { 05914 break; 05915 } 05916 } 05917 if (i < ARRAY_LEN(categories)) { 05918 continue; 05919 } 05920 05921 if (!(fg = register_group(ctg))) { 05922 continue; 05923 } 05924 05925 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 05926 struct ast_call_feature *feature; 05927 05928 AST_RWLIST_RDLOCK(&feature_list); 05929 if (!(feature = find_dynamic_feature(var->name)) && 05930 !(feature = ast_find_call_feature(var->name))) { 05931 AST_RWLIST_UNLOCK(&feature_list); 05932 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 05933 continue; 05934 } 05935 AST_RWLIST_UNLOCK(&feature_list); 05936 05937 register_group_feature(fg, var->value, feature); 05938 } 05939 } 05940 05941 AST_RWLIST_UNLOCK(&feature_groups); 05942 05943 return 0; 05944 }
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 2300 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().
02301 { 02302 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 02303 if (ast_strlen_zero(s)) { 02304 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 02305 } 02306 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 02307 s = transferer->macrocontext; 02308 } 02309 if (ast_strlen_zero(s)) { 02310 s = transferer->context; 02311 } 02312 return s; 02313 }
static struct feature_group* register_group | ( | const char * | fgname | ) | [static] |
Add new feature group.
fgname | feature group name. |
Definition at line 2988 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.
02989 { 02990 struct feature_group *fg; 02991 02992 if (!fgname) { 02993 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 02994 return NULL; 02995 } 02996 02997 if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) { 02998 return NULL; 02999 } 03000 03001 ast_string_field_set(fg, gname, fgname); 03002 03003 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 03004 03005 ast_verb(2, "Registered group '%s'\n", fg->gname); 03006 03007 return fg; 03008 }
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 3019 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.
03020 { 03021 struct feature_group_exten *fge; 03022 03023 if (!fg) { 03024 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 03025 return; 03026 } 03027 03028 if (!feature) { 03029 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 03030 return; 03031 } 03032 03033 if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) { 03034 return; 03035 } 03036 03037 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 03038 03039 fge->feature = feature; 03040 03041 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 03042 03043 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 03044 feature->sname, fg->gname, fge->exten); 03045 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 3225 of file features.c.
References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, FEATURES_COUNT, and features_lock.
03226 { 03227 int x, res = -1; 03228 03229 ast_rwlock_wrlock(&features_lock); 03230 for (x = 0; x < FEATURES_COUNT; x++) { 03231 if (strcasecmp(builtin_features[x].sname, name)) 03232 continue; 03233 03234 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 03235 res = 0; 03236 break; 03237 } 03238 ast_rwlock_unlock(&features_lock); 03239 03240 return res; 03241 }
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 6505 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().
06506 { 06507 remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens); 06508 remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space); 06509 #if 0 06510 /* I don't think we should destroy hints if the parking space still exists. */ 06511 remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint); 06512 #endif 06513 }
static void remove_dead_dialplan_useage | ( | struct parking_dp_map * | old_map, | |
struct parking_dp_map * | new_map | |||
) | [static] |
Definition at line 6528 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().
06529 { 06530 struct parking_dp_context *old_ctx; 06531 struct parking_dp_context *new_ctx; 06532 struct ast_context *con; 06533 int cmp; 06534 06535 old_ctx = AST_LIST_FIRST(old_map); 06536 new_ctx = AST_LIST_FIRST(new_map); 06537 06538 while (new_ctx) { 06539 if (!old_ctx) { 06540 /* No old contexts left, so no dead stuff can remain. */ 06541 return; 06542 } 06543 cmp = strcmp(old_ctx->context, new_ctx->context); 06544 if (cmp < 0) { 06545 /* New map does not have old map context. */ 06546 con = ast_context_find(old_ctx->context); 06547 if (con) { 06548 ast_context_destroy(con, registrar); 06549 } 06550 old_ctx = AST_LIST_NEXT(old_ctx, node); 06551 continue; 06552 } 06553 if (cmp == 0) { 06554 /* Old and new map have this context. */ 06555 remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx); 06556 old_ctx = AST_LIST_NEXT(old_ctx, node); 06557 } else { 06558 /* Old map does not have new map context. */ 06559 } 06560 new_ctx = AST_LIST_NEXT(new_ctx, node); 06561 } 06562 06563 /* Any old contexts left must be dead. */ 06564 for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) { 06565 con = ast_context_find(old_ctx->context); 06566 if (con) { 06567 ast_context_destroy(con, registrar); 06568 } 06569 } 06570 }
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 6364 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().
06365 { 06366 struct parking_dp_ramp *old_ramp; 06367 struct parking_dp_ramp *new_ramp; 06368 int cmp; 06369 06370 old_ramp = AST_LIST_FIRST(old_ramps); 06371 new_ramp = AST_LIST_FIRST(new_ramps); 06372 06373 while (new_ramp) { 06374 if (!old_ramp) { 06375 /* No old ramps left, so no dead ramps can remain. */ 06376 return; 06377 } 06378 cmp = strcmp(old_ramp->exten, new_ramp->exten); 06379 if (cmp < 0) { 06380 /* New map does not have old ramp. */ 06381 remove_exten_if_exist(context, old_ramp->exten, 1); 06382 old_ramp = AST_LIST_NEXT(old_ramp, node); 06383 continue; 06384 } 06385 if (cmp == 0) { 06386 /* Old and new map have this ramp. */ 06387 old_ramp = AST_LIST_NEXT(old_ramp, node); 06388 } else { 06389 /* Old map does not have new ramp. */ 06390 } 06391 new_ramp = AST_LIST_NEXT(new_ramp, node); 06392 } 06393 06394 /* Any old ramps left must be dead. */ 06395 for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) { 06396 remove_exten_if_exist(context, old_ramp->exten, 1); 06397 } 06398 }
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 6434 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().
06437 { 06438 struct parking_dp_spaces *old_range; 06439 struct parking_dp_spaces *new_range; 06440 int space;/*!< Current position in the current old range. */ 06441 int stop; 06442 06443 old_range = AST_LIST_FIRST(old_spaces); 06444 new_range = AST_LIST_FIRST(new_spaces); 06445 space = -1; 06446 06447 while (old_range) { 06448 if (space < old_range->start) { 06449 space = old_range->start; 06450 } 06451 if (new_range) { 06452 if (space < new_range->start) { 06453 /* Current position in old range starts before new range. */ 06454 if (old_range->stop < new_range->start) { 06455 /* Old range ends before new range. */ 06456 stop = old_range->stop; 06457 old_range = AST_LIST_NEXT(old_range, node); 06458 } else { 06459 /* Tail of old range overlaps new range. */ 06460 stop = new_range->start - 1; 06461 } 06462 } else if (/* new_range->start <= space && */ space <= new_range->stop) { 06463 /* Current position in old range overlaps new range. */ 06464 if (old_range->stop <= new_range->stop) { 06465 /* Old range ends at or before new range. */ 06466 old_range = AST_LIST_NEXT(old_range, node); 06467 } else { 06468 /* Old range extends beyond end of new range. */ 06469 space = new_range->stop + 1; 06470 new_range = AST_LIST_NEXT(new_range, node); 06471 } 06472 continue; 06473 } else /* if (new_range->stop < space) */ { 06474 /* Current position in old range starts after new range. */ 06475 new_range = AST_LIST_NEXT(new_range, node); 06476 continue; 06477 } 06478 } else { 06479 /* No more new ranges. All remaining old spaces are dead. */ 06480 stop = old_range->stop; 06481 old_range = AST_LIST_NEXT(old_range, node); 06482 } 06483 06484 /* Destroy dead parking spaces. */ 06485 for (; space <= stop; ++space) { 06486 destroy_space(context, space); 06487 } 06488 } 06489 }
static void remove_exten_if_exist | ( | const char * | context, | |
const char * | exten, | |||
int | priority | |||
) | [static] |
Definition at line 6338 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().
06339 { 06340 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 06341 06342 if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL, 06343 E_MATCH)) { 06344 ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n", 06345 context, exten, priority); 06346 ast_context_remove_extension(context, exten, priority, registrar); 06347 } 06348 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 3832 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().
03833 { 03834 const char *feature; 03835 03836 if (ast_strlen_zero(features)) { 03837 return; 03838 } 03839 03840 for (feature = features; *feature; feature++) { 03841 switch (*feature) { 03842 case 'T' : 03843 case 't' : 03844 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 03845 break; 03846 case 'K' : 03847 case 'k' : 03848 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 03849 break; 03850 case 'H' : 03851 case 'h' : 03852 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 03853 break; 03854 case 'W' : 03855 case 'w' : 03856 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 03857 break; 03858 default : 03859 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 03860 } 03861 } 03862 }
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 877 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().
00878 { 00879 ast_copy_string(chan->context, context, sizeof(chan->context)); 00880 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00881 chan->priority = pri; 00882 }
static int set_chan_app_data | ( | struct ast_channel * | chan, | |
const char * | src_app_data | |||
) | [static] |
Definition at line 953 of file features.c.
References ast_channel_datastore_add(), ast_datastore_alloc, ast_datastore_free(), ast_malloc, channel_app_data_datastore, ast_datastore::data, and ast_channel::data.
Referenced by bridge_call_thread().
00954 { 00955 struct ast_datastore *datastore; 00956 char *dst_app_data; 00957 00958 datastore = ast_datastore_alloc(&channel_app_data_datastore, NULL); 00959 if (!datastore) { 00960 return -1; 00961 } 00962 00963 dst_app_data = ast_malloc(strlen(src_app_data) + 1); 00964 if (!dst_app_data) { 00965 ast_datastore_free(datastore); 00966 return -1; 00967 } 00968 00969 chan->data = strcpy(dst_app_data, src_app_data); 00970 datastore->data = dst_app_data; 00971 ast_channel_datastore_add(chan, datastore); 00972 return 0; 00973 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 3416 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().
03417 { 03418 int x; 03419 03420 ast_clear_flag(config, AST_FLAGS_ALL); 03421 03422 ast_rwlock_rdlock(&features_lock); 03423 for (x = 0; x < FEATURES_COUNT; x++) { 03424 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 03425 continue; 03426 03427 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 03428 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03429 03430 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 03431 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03432 } 03433 ast_rwlock_unlock(&features_lock); 03434 03435 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 03436 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 03437 03438 if (dynamic_features) { 03439 char *tmp = ast_strdupa(dynamic_features); 03440 char *tok; 03441 struct ast_call_feature *feature; 03442 03443 /* while we have a feature */ 03444 while ((tok = strsep(&tmp, "#"))) { 03445 struct feature_group *fg; 03446 03447 AST_RWLIST_RDLOCK(&feature_groups); 03448 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 03449 struct feature_group_exten *fge; 03450 03451 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03452 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) { 03453 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03454 } 03455 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) { 03456 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03457 } 03458 } 03459 } 03460 AST_RWLIST_UNLOCK(&feature_groups); 03461 03462 AST_RWLIST_RDLOCK(&feature_list); 03463 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 03464 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) { 03465 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03466 } 03467 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) { 03468 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03469 } 03470 } 03471 AST_RWLIST_UNLOCK(&feature_list); 03472 } 03473 } 03474 } 03475 }
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 1939 of file features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
01941 { 01942 if (sense == FEATURE_SENSE_PEER) { 01943 *caller = peer; 01944 *callee = chan; 01945 } else { 01946 *callee = peer; 01947 *caller = chan; 01948 } 01949 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 3215 of file features.c.
References ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, FEATURES_COUNT, and features_lock.
03216 { 03217 int x; 03218 03219 ast_rwlock_wrlock(&features_lock); 03220 for (x = 0; x < FEATURES_COUNT; x++) 03221 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 03222 ast_rwlock_unlock(&features_lock); 03223 }
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 6024 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().
06025 { 06026 struct parking_dp_ramp *cur_ramp; 06027 struct parking_dp_ramp *new_ramp; 06028 int cmp; 06029 06030 /* Make sure that exclusive is only 0 or 1 */ 06031 if (exclusive) { 06032 exclusive = 1; 06033 } 06034 06035 AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) { 06036 cmp = strcmp(exten, cur_ramp->exten); 06037 if (cmp > 0) { 06038 /* The parking lot ramp goes after this node. */ 06039 continue; 06040 } 06041 if (cmp == 0) { 06042 /* The ramp is already in the map. */ 06043 if (complain && (cur_ramp->exclusive || exclusive)) { 06044 ast_log(LOG_WARNING, 06045 "Parking lot '%s' parkext %s@%s used by another parking lot.\n", 06046 lot->name, exten, lot->cfg.parking_con); 06047 } 06048 return 0; 06049 } 06050 /* The new parking lot ramp goes before this node. */ 06051 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 06052 if (!new_ramp) { 06053 return -1; 06054 } 06055 AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node); 06056 return 0; 06057 } 06058 AST_LIST_TRAVERSE_SAFE_END; 06059 06060 /* New parking lot access ramp goes on the end. */ 06061 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 06062 if (!new_ramp) { 06063 return -1; 06064 } 06065 AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node); 06066 return 0; 06067 }
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 6105 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().
06106 { 06107 struct parking_dp_spaces *cur_node; 06108 struct parking_dp_spaces *expand_node; 06109 struct parking_dp_spaces *new_node; 06110 06111 expand_node = NULL; 06112 AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) { 06113 /* NOTE: stop + 1 to combine immediately adjacent nodes into one. */ 06114 if (expand_node) { 06115 /* The previous node is expanding to possibly eat following nodes. */ 06116 if (expand_node->stop + 1 < cur_node->start) { 06117 /* Current node is completely after expanding node. */ 06118 return 0; 06119 } 06120 06121 if (complain 06122 && ((cur_node->start <= start && start <= cur_node->stop) 06123 || (cur_node->start <= stop && stop <= cur_node->stop) 06124 || (start < cur_node->start && cur_node->stop < stop))) { 06125 /* Only complain once per range add. */ 06126 complain = 0; 06127 ast_log(LOG_WARNING, 06128 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06129 lot->name, start, stop, lot->cfg.parking_con); 06130 } 06131 06132 /* Current node is eaten by the expanding node. */ 06133 if (expand_node->stop < cur_node->stop) { 06134 expand_node->stop = cur_node->stop; 06135 } 06136 AST_LIST_REMOVE_CURRENT(node); 06137 ast_free(cur_node); 06138 continue; 06139 } 06140 06141 if (cur_node->stop + 1 < start) { 06142 /* New range is completely after current node. */ 06143 continue; 06144 } 06145 if (stop + 1 < cur_node->start) { 06146 /* New range is completely before current node. */ 06147 new_node = build_dialplan_useage_spaces(start, stop); 06148 if (!new_node) { 06149 return -1; 06150 } 06151 AST_LIST_INSERT_BEFORE_CURRENT(new_node, node); 06152 return 0; 06153 } 06154 06155 if (complain 06156 && ((cur_node->start <= start && start <= cur_node->stop) 06157 || (cur_node->start <= stop && stop <= cur_node->stop) 06158 || (start < cur_node->start && cur_node->stop < stop))) { 06159 /* Only complain once per range add. */ 06160 complain = 0; 06161 ast_log(LOG_WARNING, 06162 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06163 lot->name, start, stop, lot->cfg.parking_con); 06164 } 06165 06166 /* Current node range overlaps or is immediately adjacent to new range. */ 06167 if (start < cur_node->start) { 06168 /* Expand the current node in the front. */ 06169 cur_node->start = start; 06170 } 06171 if (stop <= cur_node->stop) { 06172 /* Current node is not expanding in the rear. */ 06173 return 0; 06174 } 06175 cur_node->stop = stop; 06176 expand_node = cur_node; 06177 } 06178 AST_LIST_TRAVERSE_SAFE_END; 06179 06180 if (expand_node) { 06181 /* 06182 * The previous node expanded and either ate all following nodes 06183 * or it was the last node. 06184 */ 06185 return 0; 06186 } 06187 06188 /* New range goes on the end. */ 06189 new_node = build_dialplan_useage_spaces(start, stop); 06190 if (!new_node) { 06191 return -1; 06192 } 06193 AST_LIST_INSERT_TAIL(space_map, new_node, node); 06194 return 0; 06195 }
static int xfer_park_call_helper | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
struct ast_exten * | park_exten | |||
) | [static] |
Definition at line 1879 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().
01880 { 01881 char *parse; 01882 const char *app_data; 01883 const char *pl_name; 01884 struct ast_park_call_args args = { 0, }; 01885 struct park_app_args app_args; 01886 int res; 01887 01888 app_data = ast_get_extension_app_data(park_exten); 01889 if (!app_data) { 01890 app_data = ""; 01891 } 01892 parse = ast_strdupa(app_data); 01893 AST_STANDARD_APP_ARGS(app_args, parse); 01894 01895 /* Find the parking lot */ 01896 if (!ast_strlen_zero(app_args.pl_name)) { 01897 pl_name = app_args.pl_name; 01898 } else { 01899 pl_name = findparkinglotname(parker); 01900 } 01901 if (ast_strlen_zero(pl_name)) { 01902 /* Parking lot is not specified, so use the default parking lot. */ 01903 args.parkinglot = parkinglot_addref(default_parkinglot); 01904 } else { 01905 args.parkinglot = find_parkinglot(pl_name); 01906 if (!args.parkinglot && parkeddynamic) { 01907 args.parkinglot = create_dynamic_parkinglot(pl_name, park_me); 01908 } 01909 } 01910 01911 if (args.parkinglot) { 01912 /* Park the call */ 01913 res = finishup(park_me); 01914 if (res) { 01915 /* park_me hungup on us. */ 01916 parkinglot_unref(args.parkinglot); 01917 return -1; 01918 } 01919 res = masq_park_call(park_me, parker, &args); 01920 parkinglot_unref(args.parkinglot); 01921 } else { 01922 /* Parking failed because parking lot does not exist. */ 01923 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { 01924 ast_stream_and_wait(parker, "pbx-parkingfailed", ""); 01925 } 01926 finishup(park_me); 01927 res = -1; 01928 } 01929 01930 return res ? AST_FEATURE_RETURN_SUCCESS : -1; 01931 }
int adsipark [static] |
char* app_bridge = "Bridge" [static] |
Definition at line 7405 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 2954 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_datastore_info channel_app_data_datastore [static] |
Initial value:
{ .type = "Channel appdata datastore", .destroy = ast_free_ptr, }
Definition at line 948 of file features.c.
Referenced by set_chan_app_data().
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 7077 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 748 of file features.c.
Referenced by add_features_datastore(), 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 2952 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 5425 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 5415 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 7246 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().