#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_ds |
| struct | feature_exten |
| 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_COMEBACK_CONTEXT "parkedcallstimeout" |
| #define | DEFAULT_COMEBACK_DIAL_TIME 30 |
| #define | DEFAULT_COMEBACK_TO_ORIGIN 1 |
| #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), OPT_CALLEE_GO_ON = (1 << 12) } |
| enum | { OPT_ARG_DURATION_LIMIT = 0, OPT_ARG_DURATION_STOP, OPT_ARG_CALLEE_GO_ON, 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 void | __fini_feature_groups (void) |
| static void | __fini_feature_list (void) |
| static void | __init_feature_groups (void) |
| static void | __init_feature_list (void) |
| 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 the call and set CDR | |
| 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. | |
| struct 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. | |
| struct ast_channel * | ast_pickup_find_by_group (struct ast_channel *chan) |
| Find a pickup channel target by group. | |
| void | ast_rdlock_call_features (void) |
| void | ast_register_feature (struct ast_call_feature *feature) |
| register new feature into feature_list | |
| 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_feature_get_exten (struct ast_channel *chan, const char *feature_name, char *buf, size_t len) |
| 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 void | feature_ds_destroy (void *data) |
| 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_exten_cmp (void *obj, void *arg, int flags) |
| static int | feature_exten_hash (const void *obj, int flags) |
| 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 int | feature_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| 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, struct ast_format_cap *cap, const char *addr, int timeout, int *outstate, const char *language) |
| static int | feature_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
| static int | featuremap_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| static int | featuremap_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
| static void | features_shutdown (void) |
| 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 feature_ds * | get_feature_ds (struct ast_channel *chan) |
| static struct ast_exten * | get_parking_exten (const char *exten_str, struct ast_channel *chan, const char *context) |
| static unsigned int | get_parkingtime (struct ast_channel *chan, struct ast_parkinglot *parkinglot) |
| 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 | manager_parkinglot_list (struct mansession *s, const struct message *m) |
| 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_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 }, [ 'F' ] = { .flag = OPT_CALLEE_GO_ON , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ '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 char | courtesytone [256] |
| static struct ast_parkinglot * | default_parkinglot |
| Default parking lot. | |
| static struct ast_datastore_info | dial_features_info |
| static struct ast_datastore_info | feature_ds_info |
| static struct ast_custom_function | feature_function |
| static int | featuredigittimeout |
| static struct ast_custom_function | featuremap_function |
| static ast_rwlock_t | features_lock = { {0} , NULL, 1 } |
| static ast_mutex_t | features_reload_lock = { PTHREAD_MUTEX_INITIALIZER , 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 528 of file features.c.
| #define DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
| #define DEFAULT_ATXFER_DROP_CALL 0 |
| #define DEFAULT_ATXFER_LOOP_DELAY 10000 |
| #define DEFAULT_COMEBACK_CONTEXT "parkedcallstimeout" |
Definition at line 524 of file features.c.
| #define DEFAULT_COMEBACK_DIAL_TIME 30 |
| #define DEFAULT_COMEBACK_TO_ORIGIN 1 |
Definition at line 525 of file features.c.
| #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
| #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
| #define DEFAULT_PARK_EXTENSION "700" |
Definition at line 517 of file features.c.
| #define DEFAULT_PARK_TIME 45000 |
ms
Definition at line 516 of file features.c.
| #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
| #define FEATURES_COUNT ARRAY_LEN(builtin_features) |
Definition at line 3124 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 7940 of file features.c.
07940 { 07941 BRIDGE_OPT_PLAYTONE = (1 << 0), 07942 OPT_CALLEE_HANGUP = (1 << 1), 07943 OPT_CALLER_HANGUP = (1 << 2), 07944 OPT_DURATION_LIMIT = (1 << 3), 07945 OPT_DURATION_STOP = (1 << 4), 07946 OPT_CALLEE_TRANSFER = (1 << 5), 07947 OPT_CALLER_TRANSFER = (1 << 6), 07948 OPT_CALLEE_MONITOR = (1 << 7), 07949 OPT_CALLER_MONITOR = (1 << 8), 07950 OPT_CALLEE_PARK = (1 << 9), 07951 OPT_CALLER_PARK = (1 << 10), 07952 OPT_CALLEE_KILL = (1 << 11), 07953 OPT_CALLEE_GO_ON = (1 << 12), 07954 };
| anonymous enum |
Definition at line 7956 of file features.c.
07956 { 07957 OPT_ARG_DURATION_LIMIT = 0, 07958 OPT_ARG_DURATION_STOP, 07959 OPT_ARG_CALLEE_GO_ON, 07960 /* note: this entry _MUST_ be the last one in the enum */ 07961 OPT_ARG_ARRAY_SIZE, 07962 };
Options to pass to park_call_full
| AST_PARK_OPT_RINGING | Provide ringing to the parked caller instead of music on hold |
| AST_PARK_OPT_RANDOMIZE | Randomly choose a parking spot for the caller instead of choosing the first one that is available. |
| AST_PARK_OPT_SILENCE | Do not announce the parking number |
Definition at line 1275 of file features.c.
01275 { 01276 /*! Provide ringing to the parked caller instead of music on hold */ 01277 AST_PARK_OPT_RINGING = (1 << 0), 01278 /*! Randomly choose a parking spot for the caller instead of choosing 01279 * the first one that is available. */ 01280 AST_PARK_OPT_RANDOMIZE = (1 << 1), 01281 /*! Do not announce the parking number */ 01282 AST_PARK_OPT_SILENCE = (1 << 2), 01283 };
| enum feature_interpret_op |
Definition at line 549 of file features.c.
00549 { 00550 FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */ 00551 FEATURE_INTERPRET_DO, /* Used by feature_interpret */ 00552 FEATURE_INTERPRET_CHECK, /* Used by feature_check */ 00553 } feature_interpret_op;
| static void __fini_feature_groups | ( | void | ) | [static] |
| static void __fini_feature_list | ( | void | ) | [static] |
| static void __init_feature_groups | ( | void | ) | [static] |
| static void __init_feature_list | ( | void | ) | [static] |
| 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 7272 of file features.c.
References ast_answer(), ast_calloc, ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_language(), ast_channel_linkedid(), ast_channel_make_compatible(), ast_channel_name(), 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(), ast_bridge_thread_obj::chan, do_bridge_masquerade(), errno, EVENT_FLAG_CALL, LOG_WARNING, ast_bridge_thread_obj::peer, playtone(), ast_bridge_thread_obj::return_to_pbx, and xfersound.
Referenced by ast_features_init().
07273 { 07274 const char *channela = astman_get_header(m, "Channel1"); 07275 const char *channelb = astman_get_header(m, "Channel2"); 07276 const char *playtone = astman_get_header(m, "Tone"); 07277 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2]; 07278 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 07279 struct ast_bridge_thread_obj *tobj = NULL; 07280 char buf[256]; 07281 07282 /* make sure valid channels were specified */ 07283 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 07284 astman_send_error(s, m, "Missing channel parameter in request"); 07285 return 0; 07286 } 07287 07288 /* Start with chana */ 07289 chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); 07290 if (!chana) { 07291 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 07292 astman_send_error(s, m, buf); 07293 return 0; 07294 } 07295 07296 /* Answer the channels if needed */ 07297 if (ast_channel_state(chana) != AST_STATE_UP) 07298 ast_answer(chana); 07299 07300 /* create the placeholder channels and grab the other channels */ 07301 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 07302 NULL, NULL, ast_channel_linkedid(chana), 0, "Bridge/%s", ast_channel_name(chana)))) { 07303 astman_send_error(s, m, "Unable to create temporary channel!"); 07304 chana = ast_channel_unref(chana); 07305 return 0; 07306 } 07307 07308 if (do_bridge_masquerade(chana, tmpchana)) { 07309 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela); 07310 astman_send_error(s, m, buf); 07311 ast_hangup(tmpchana); 07312 chana = ast_channel_unref(chana); 07313 return 0; 07314 } 07315 07316 chana = ast_channel_unref(chana); 07317 07318 /* now do chanb */ 07319 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); 07320 if (!chanb) { 07321 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 07322 astman_send_error(s, m, buf); 07323 ast_hangup(tmpchana); 07324 return 0; 07325 } 07326 07327 /* Answer the channels if needed */ 07328 if (ast_channel_state(chanb) != AST_STATE_UP) 07329 ast_answer(chanb); 07330 07331 /* create the placeholder channels and grab the other channels */ 07332 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 07333 NULL, NULL, ast_channel_linkedid(chanb), 0, "Bridge/%s", ast_channel_name(chanb)))) { 07334 astman_send_error(s, m, "Unable to create temporary channels!"); 07335 ast_hangup(tmpchana); 07336 chanb = ast_channel_unref(chanb); 07337 return 0; 07338 } 07339 07340 if (do_bridge_masquerade(chanb, tmpchanb)) { 07341 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb); 07342 astman_send_error(s, m, buf); 07343 ast_hangup(tmpchana); 07344 ast_hangup(tmpchanb); 07345 chanb = ast_channel_unref(chanb); 07346 return 0; 07347 } 07348 07349 chanb = ast_channel_unref(chanb); 07350 07351 /* make the channels compatible, send error if we fail doing so */ 07352 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 07353 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb)); 07354 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 07355 ast_hangup(tmpchana); 07356 ast_hangup(tmpchanb); 07357 return 0; 07358 } 07359 07360 /* setup the bridge thread object and start the bridge */ 07361 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 07362 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb), strerror(errno)); 07363 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 07364 ast_hangup(tmpchana); 07365 ast_hangup(tmpchanb); 07366 return 0; 07367 } 07368 07369 tobj->chan = tmpchana; 07370 tobj->peer = tmpchanb; 07371 tobj->return_to_pbx = 1; 07372 07373 if (ast_true(playtone)) { 07374 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, ast_channel_language(tmpchanb))) { 07375 if (ast_waitstream(tmpchanb, "") < 0) 07376 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", ast_channel_name(tmpchanb)); 07377 } 07378 } 07379 07380 chans[0] = tmpchana; 07381 chans[1] = tmpchanb; 07382 /*** DOCUMENTATION 07383 <managerEventInstance> 07384 <synopsis>Raised when a bridge is successfully created due to a manager action.</synopsis> 07385 <syntax> 07386 <parameter name="Response"> 07387 <enumlist> 07388 <enum name="Success"/> 07389 <enum name="Failed"/> 07390 </enumlist> 07391 </parameter> 07392 </syntax> 07393 <see-also> 07394 <ref type="manager">Bridge</ref> 07395 </see-also> 07396 </managerEventInstance> 07397 ***/ 07398 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans, 07399 "Response: Success\r\n" 07400 "Channel1: %s\r\n" 07401 "Channel2: %s\r\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb)); 07402 07403 bridge_call_thread_launch(tobj); 07404 07405 astman_send_ack(s, m, "Launched bridge thread with success"); 07406 07407 return 0; 07408 }
| 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 905 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().
00906 { 00907 struct ast_datastore *datastore; 00908 struct ast_dial_features *dialfeatures; 00909 00910 ast_channel_lock(chan); 00911 datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL); 00912 ast_channel_unlock(chan); 00913 if (datastore) { 00914 /* Already exists. */ 00915 return 1; 00916 } 00917 00918 /* Create a new datastore with specified feature flags. */ 00919 datastore = ast_datastore_alloc(&dial_features_info, NULL); 00920 if (!datastore) { 00921 ast_log(LOG_WARNING, "Unable to create channel features datastore.\n"); 00922 return 0; 00923 } 00924 dialfeatures = ast_calloc(1, sizeof(*dialfeatures)); 00925 if (!dialfeatures) { 00926 ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n"); 00927 ast_datastore_free(datastore); 00928 return 0; 00929 } 00930 ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL); 00931 ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL); 00932 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 00933 datastore->data = dialfeatures; 00934 ast_channel_lock(chan); 00935 ast_channel_datastore_add(chan, datastore); 00936 ast_channel_unlock(chan); 00937 return 0; 00938 }
| static void add_features_datastores | ( | struct ast_channel * | caller, | |
| struct ast_channel * | callee, | |||
| struct ast_bridge_config * | config | |||
| ) | [static] |
Definition at line 4208 of file features.c.
References add_features_datastore(), ast_bridge_config::features_callee, and ast_bridge_config::features_caller.
Referenced by ast_bridge_call().
04209 { 04210 if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) { 04211 /* 04212 * If we don't return here, then when we do a builtin_atxfer we 04213 * will copy the disconnect flags over from the atxfer to the 04214 * callee (Party C). 04215 */ 04216 return; 04217 } 04218 04219 add_features_datastore(callee, &config->features_callee, &config->features_caller); 04220 }
| static int adsi_announce_park | ( | struct ast_channel * | chan, | |
| char * | parkingexten | |||
| ) | [static] |
Announce call parking by ADSI.
| 0 | on success. | |
| -1 | on failure. |
Definition at line 1213 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
01214 { 01215 int res; 01216 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 01217 char tmp[256]; 01218 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 01219 01220 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 01221 message[0] = tmp; 01222 res = ast_adsi_load_session(chan, NULL, 0, 1); 01223 if (res == -1) 01224 return res; 01225 return ast_adsi_print(chan, message, justify, 1); 01226 }
| int ast_bridge_call | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config | |||
| ) |
bridge the call and set CDR
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. |
TRUE if h-exten or hangup handlers run.
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 4250 of file features.c.
References ast_cdr::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_cdr::answer, ast_autoservice_start(), ast_autoservice_stop(), 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_accountcode(), ast_channel_amaflags(), ast_channel_appl(), ast_channel_bridge(), ast_channel_caller(), ast_channel_cdr(), ast_channel_cdr_set(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_context(), ast_channel_context_set(), ast_channel_data(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_lock_both, ast_channel_log(), ast_channel_macrocontext(), ast_channel_name(), AST_CHANNEL_NAME, ast_channel_priority(), ast_channel_priority_set(), ast_channel_redirecting_macro(), ast_channel_redirecting_sub(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_softhangup_internal_flag(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_uniqueid(), ast_channel_unlock, ast_channel_unref, ast_channel_visible_indication(), 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_MCID, AST_CONTROL_OPTION, AST_CONTROL_PVT_CAUSE_CODE, 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_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_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_pbx_h_exten_run(), ast_pbx_hangup_handler_run(), ast_raw_answer(), ast_set_flag, AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_UNBRIDGE, AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_write(), ast_cdr::channel, clear_dialed_interfaces(), ast_option_header::data, ast_frame::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_start_time, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_frame::frametype, ast_frame_subclass::integer, ast_cdr::lastapp, ast_cdr::lastdata, ast_frame::len, LOG_DEBUG, LOG_WARNING, monitor_app, monitor_ok, ast_cdr::next, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_frame::ptr, S_COR, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_frame::subclass, ast_bridge_config::timelimit, ast_cdr::uniqueid, ast_cdr::userfield, and ast_channel::userfield.
Referenced by app_exec(), bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), parked_call_exec(), and try_calling().
04251 { 04252 /* Copy voice back and forth between the two channels. Give the peer 04253 the ability to transfer calls with '#<extension' syntax. */ 04254 struct ast_frame *f; 04255 struct ast_channel *who; 04256 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 04257 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 04258 char orig_channame[AST_CHANNEL_NAME]; 04259 char orig_peername[AST_CHANNEL_NAME]; 04260 int res; 04261 int diff; 04262 int hasfeatures=0; 04263 int hadfeatures=0; 04264 int sendingdtmfdigit = 0; 04265 int we_disabled_peer_cdr = 0; 04266 struct ast_option_header *aoh; 04267 struct ast_cdr *bridge_cdr = NULL; 04268 struct ast_cdr *chan_cdr = ast_channel_cdr(chan); /* the proper chan cdr, if there are forked cdrs */ 04269 struct ast_cdr *peer_cdr = ast_channel_cdr(peer); /* the proper chan cdr, if there are forked cdrs */ 04270 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 04271 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 04272 struct ast_silence_generator *silgen = NULL; 04273 /*! TRUE if h-exten or hangup handlers run. */ 04274 int hangup_run = 0; 04275 04276 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer)); 04277 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan)); 04278 04279 /* Clear any BLINDTRANSFER since the transfer has completed. */ 04280 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 04281 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL); 04282 04283 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 04284 add_features_datastores(chan, peer, config); 04285 04286 /* This is an interesting case. One example is if a ringing channel gets redirected to 04287 * an extension that picks up a parked call. This will make sure that the call taken 04288 * out of parking gets told that the channel it just got bridged to is still ringing. */ 04289 if (ast_channel_state(chan) == AST_STATE_RINGING && ast_channel_visible_indication(peer) != AST_CONTROL_RINGING) { 04290 ast_indicate(peer, AST_CONTROL_RINGING); 04291 } 04292 04293 if (monitor_ok) { 04294 const char *monitor_exec; 04295 struct ast_channel *src = NULL; 04296 if (!monitor_app) { 04297 if (!(monitor_app = pbx_findapp("Monitor"))) 04298 monitor_ok=0; 04299 } 04300 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 04301 src = chan; 04302 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 04303 src = peer; 04304 if (monitor_app && src) { 04305 char *tmp = ast_strdupa(monitor_exec); 04306 pbx_exec(src, monitor_app, tmp); 04307 } 04308 } 04309 04310 set_config_flags(chan, config); 04311 04312 /* Answer if need be */ 04313 if (ast_channel_state(chan) != AST_STATE_UP) { 04314 if (ast_raw_answer(chan, 1)) { 04315 return -1; 04316 } 04317 } 04318 04319 #ifdef FOR_DEBUG 04320 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 04321 ast_channel_log("Pre-bridge CHAN Channel info", chan); 04322 ast_channel_log("Pre-bridge PEER Channel info", peer); 04323 #endif 04324 /* two channels are being marked as linked here */ 04325 ast_channel_set_linkgroup(chan,peer); 04326 04327 /* copy the userfield from the B-leg to A-leg if applicable */ 04328 if (ast_channel_cdr(chan) && ast_channel_cdr(peer) && !ast_strlen_zero(ast_channel_cdr(peer)->userfield)) { 04329 char tmp[256]; 04330 04331 ast_channel_lock(chan); 04332 if (!ast_strlen_zero(ast_channel_cdr(chan)->userfield)) { 04333 snprintf(tmp, sizeof(tmp), "%s;%s", ast_channel_cdr(chan)->userfield, ast_channel_cdr(peer)->userfield); 04334 ast_cdr_appenduserfield(chan, tmp); 04335 } else { 04336 ast_cdr_setuserfield(chan, ast_channel_cdr(peer)->userfield); 04337 } 04338 ast_channel_unlock(chan); 04339 /* Don't delete the CDR; just disable it. */ 04340 ast_set_flag(ast_channel_cdr(peer), AST_CDR_FLAG_POST_DISABLED); 04341 we_disabled_peer_cdr = 1; 04342 } 04343 ast_copy_string(orig_channame,ast_channel_name(chan),sizeof(orig_channame)); 04344 ast_copy_string(orig_peername,ast_channel_name(peer),sizeof(orig_peername)); 04345 04346 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 04347 ast_channel_lock_both(chan, peer); 04348 if (chan_cdr) { 04349 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 04350 ast_cdr_update(chan); 04351 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 04352 /* rip any forked CDR's off of the chan_cdr and attach 04353 * them to the bridge_cdr instead */ 04354 bridge_cdr->next = chan_cdr->next; 04355 chan_cdr->next = NULL; 04356 ast_copy_string(bridge_cdr->lastapp, S_OR(ast_channel_appl(chan), ""), sizeof(bridge_cdr->lastapp)); 04357 ast_copy_string(bridge_cdr->lastdata, S_OR(ast_channel_data(chan), ""), sizeof(bridge_cdr->lastdata)); 04358 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 04359 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04360 } 04361 ast_cdr_setaccount(peer, ast_channel_accountcode(chan)); 04362 } else { 04363 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 04364 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 04365 ast_copy_string(bridge_cdr->channel, ast_channel_name(chan), sizeof(bridge_cdr->channel)); 04366 ast_copy_string(bridge_cdr->dstchannel, ast_channel_name(peer), sizeof(bridge_cdr->dstchannel)); 04367 ast_copy_string(bridge_cdr->uniqueid, ast_channel_uniqueid(chan), sizeof(bridge_cdr->uniqueid)); 04368 ast_copy_string(bridge_cdr->lastapp, S_OR(ast_channel_appl(chan), ""), sizeof(bridge_cdr->lastapp)); 04369 ast_copy_string(bridge_cdr->lastdata, S_OR(ast_channel_data(chan), ""), sizeof(bridge_cdr->lastdata)); 04370 ast_cdr_setcid(bridge_cdr, chan); 04371 bridge_cdr->disposition = (ast_channel_state(chan) == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 04372 bridge_cdr->amaflags = ast_channel_amaflags(chan) ? ast_channel_amaflags(chan) : ast_default_amaflags; 04373 ast_copy_string(bridge_cdr->accountcode, ast_channel_accountcode(chan), sizeof(bridge_cdr->accountcode)); 04374 /* Destination information */ 04375 ast_copy_string(bridge_cdr->dst, ast_channel_exten(chan), sizeof(bridge_cdr->dst)); 04376 ast_copy_string(bridge_cdr->dcontext, ast_channel_context(chan), sizeof(bridge_cdr->dcontext)); 04377 if (peer_cdr) { 04378 bridge_cdr->start = peer_cdr->start; 04379 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04380 } else { 04381 ast_cdr_start(bridge_cdr); 04382 } 04383 } 04384 ast_channel_unlock(chan); 04385 ast_channel_unlock(peer); 04386 04387 ast_debug(4, "bridge answer set, chan answer set\n"); 04388 /* peer_cdr->answer will be set when a macro runs on the peer; 04389 in that case, the bridge answer will be delayed while the 04390 macro plays on the peer channel. The peer answered the call 04391 before the macro started playing. To the phone system, 04392 this is billable time for the call, even tho the caller 04393 hears nothing but ringing while the macro does its thing. */ 04394 04395 /* Another case where the peer cdr's time will be set, is when 04396 A self-parks by pickup up phone and dialing 700, then B 04397 picks up A by dialing its parking slot; there may be more 04398 practical paths that get the same result, tho... in which 04399 case you get the previous answer time from the Park... which 04400 is before the bridge's start time, so I added in the 04401 tvcmp check to the if below */ 04402 04403 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 04404 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 04405 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 04406 if (chan_cdr) { 04407 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 04408 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 04409 } 04410 } else { 04411 ast_cdr_answer(bridge_cdr); 04412 if (chan_cdr) { 04413 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 04414 } 04415 } 04416 if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 04417 if (chan_cdr) { 04418 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 04419 } 04420 if (peer_cdr) { 04421 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 04422 } 04423 } 04424 /* the DIALED flag may be set if a dialed channel is transfered 04425 * and then bridged to another channel. In order for the 04426 * bridge CDR to be written, the DIALED flag must not be 04427 * present. */ 04428 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04429 } 04430 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04431 04432 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04433 * a call is being bridged, that the humans in charge know what they're doing. If they 04434 * don't, well, what can we do about that? */ 04435 clear_dialed_interfaces(chan); 04436 clear_dialed_interfaces(peer); 04437 04438 for (;;) { 04439 struct ast_channel *other; /* used later */ 04440 04441 res = ast_channel_bridge(chan, peer, config, &f, &who); 04442 04443 if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) 04444 || ast_test_flag(ast_channel_flags(peer), AST_FLAG_ZOMBIE)) { 04445 /* Zombies are present time to leave! */ 04446 res = -1; 04447 if (f) { 04448 ast_frfree(f); 04449 } 04450 goto before_you_go; 04451 } 04452 04453 /* When frame is not set, we are probably involved in a situation 04454 where we've timed out. 04455 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04456 and also for DTMF_END. If we flow into the following 'if' for both, then 04457 our wait times are cut in half, as both will subtract from the 04458 feature_timer. Not good! 04459 */ 04460 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04461 /* Update feature timer for next pass */ 04462 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04463 if (res == AST_BRIDGE_RETRY) { 04464 /* The feature fully timed out but has not been updated. Skip 04465 * the potential round error from the diff calculation and 04466 * explicitly set to expired. */ 04467 config->feature_timer = -1; 04468 } else { 04469 config->feature_timer -= diff; 04470 } 04471 04472 if (hasfeatures) { 04473 if (config->feature_timer <= 0) { 04474 /* Not *really* out of time, just out of time for 04475 digits to come in for features. */ 04476 ast_debug(1, "Timed out for feature!\n"); 04477 if (!ast_strlen_zero(peer_featurecode)) { 04478 ast_dtmf_stream(chan, peer, peer_featurecode, 0, f ? f->len : 0); 04479 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04480 } 04481 if (!ast_strlen_zero(chan_featurecode)) { 04482 ast_dtmf_stream(peer, chan, chan_featurecode, 0, f ? f->len : 0); 04483 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04484 } 04485 if (f) 04486 ast_frfree(f); 04487 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04488 if (!hasfeatures) { 04489 /* No more digits expected - reset the timer */ 04490 config->feature_timer = 0; 04491 } 04492 hadfeatures = hasfeatures; 04493 /* Continue as we were */ 04494 continue; 04495 } else if (!f) { 04496 /* The bridge returned without a frame and there is a feature in progress. 04497 * However, we don't think the feature has quite yet timed out, so just 04498 * go back into the bridge. */ 04499 continue; 04500 } 04501 } else { 04502 if (config->feature_timer <=0) { 04503 /* We ran out of time */ 04504 config->feature_timer = 0; 04505 who = chan; 04506 if (f) 04507 ast_frfree(f); 04508 f = NULL; 04509 res = 0; 04510 } 04511 } 04512 } 04513 if (res < 0) { 04514 if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) && !ast_test_flag(ast_channel_flags(peer), AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04515 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", ast_channel_name(chan), ast_channel_name(peer)); 04516 } 04517 goto before_you_go; 04518 } 04519 04520 if (!f || (f->frametype == AST_FRAME_CONTROL && 04521 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04522 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04523 /* 04524 * If the bridge was broken for a hangup that isn't real, 04525 * then don't run the h extension, because the channel isn't 04526 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04527 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04528 */ 04529 ast_channel_lock(chan); 04530 if (ast_channel_softhangup_internal_flag(chan) & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04531 ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); 04532 } 04533 ast_channel_unlock(chan); 04534 res = -1; 04535 break; 04536 } 04537 /* many things should be sent to the 'other' channel */ 04538 other = (who == chan) ? peer : chan; 04539 if (f->frametype == AST_FRAME_CONTROL) { 04540 switch (f->subclass.integer) { 04541 case AST_CONTROL_RINGING: 04542 case AST_CONTROL_FLASH: 04543 case AST_CONTROL_MCID: 04544 case -1: 04545 ast_indicate(other, f->subclass.integer); 04546 break; 04547 case AST_CONTROL_CONNECTED_LINE: 04548 if (ast_channel_connected_line_sub(who, other, f, 1) && 04549 ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04550 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04551 } 04552 break; 04553 case AST_CONTROL_REDIRECTING: 04554 if (ast_channel_redirecting_sub(who, other, f, 1) && 04555 ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04556 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04557 } 04558 break; 04559 case AST_CONTROL_PVT_CAUSE_CODE: 04560 case AST_CONTROL_AOC: 04561 case AST_CONTROL_HOLD: 04562 case AST_CONTROL_UNHOLD: 04563 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04564 break; 04565 case AST_CONTROL_OPTION: 04566 aoh = f->data.ptr; 04567 /* Forward option Requests, but only ones we know are safe 04568 * These are ONLY sent by chan_iax2 and I'm not convinced that 04569 * they are useful. I haven't deleted them entirely because I 04570 * just am not sure of the ramifications of removing them. */ 04571 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04572 switch (ntohs(aoh->option)) { 04573 case AST_OPTION_TONE_VERIFY: 04574 case AST_OPTION_TDD: 04575 case AST_OPTION_RELAXDTMF: 04576 case AST_OPTION_AUDIO_MODE: 04577 case AST_OPTION_DIGIT_DETECT: 04578 case AST_OPTION_FAX_DETECT: 04579 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04580 f->datalen - sizeof(struct ast_option_header), 0); 04581 } 04582 } 04583 break; 04584 } 04585 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04586 struct ast_flags *cfg; 04587 char dtmfcode[2] = { f->subclass.integer, }; 04588 size_t featurelen; 04589 04590 if (who == chan) { 04591 featurelen = strlen(chan_featurecode); 04592 cfg = &(config->features_caller); 04593 } else { 04594 featurelen = strlen(peer_featurecode); 04595 cfg = &(config->features_callee); 04596 } 04597 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04598 * DTMF along untouched. If this is not the first digit of a multi-digit code 04599 * then we need to fall through and stream the characters if it matches */ 04600 if (featurelen == 0 04601 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04602 if (option_debug > 3) { 04603 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04604 } 04605 ast_write(other, f); 04606 sendingdtmfdigit = 1; 04607 } else { 04608 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04609 * transmitting something while we hold on to the DTMF waiting for a 04610 * feature. */ 04611 if (!silgen && ast_opt_transmit_silence) { 04612 silgen = ast_channel_start_silence_generator(other); 04613 } 04614 if (option_debug > 3) { 04615 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04616 } 04617 } 04618 } else if (f->frametype == AST_FRAME_DTMF_END) { 04619 char *featurecode; 04620 int sense; 04621 unsigned int dtmfduration = f->len; 04622 04623 hadfeatures = hasfeatures; 04624 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04625 if (who == chan) { 04626 sense = FEATURE_SENSE_CHAN; 04627 featurecode = chan_featurecode; 04628 } else { 04629 sense = FEATURE_SENSE_PEER; 04630 featurecode = peer_featurecode; 04631 } 04632 04633 if (sendingdtmfdigit == 1) { 04634 /* We let the BEGIN go through happily, so let's not bother with the END, 04635 * since we already know it's not something we bother with */ 04636 ast_write(other, f); 04637 sendingdtmfdigit = 0; 04638 } else { 04639 /*! append the event to featurecode. we rely on the string being zero-filled, and 04640 * not overflowing it. 04641 * \todo XXX how do we guarantee the latter ? 04642 */ 04643 featurecode[strlen(featurecode)] = f->subclass.integer; 04644 /* Get rid of the frame before we start doing "stuff" with the channels */ 04645 ast_frfree(f); 04646 f = NULL; 04647 if (silgen) { 04648 ast_channel_stop_silence_generator(other, silgen); 04649 silgen = NULL; 04650 } 04651 config->feature_timer = 0; 04652 res = feature_interpret(chan, peer, config, featurecode, sense); 04653 switch(res) { 04654 case AST_FEATURE_RETURN_PASSDIGITS: 04655 ast_dtmf_stream(other, who, featurecode, 0, dtmfduration); 04656 /* Fall through */ 04657 case AST_FEATURE_RETURN_SUCCESS: 04658 memset(featurecode, 0, sizeof(chan_featurecode)); 04659 break; 04660 } 04661 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04662 res = 0; 04663 } else { 04664 break; 04665 } 04666 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04667 if (hadfeatures && !hasfeatures) { 04668 /* Feature completed or timed out */ 04669 config->feature_timer = 0; 04670 } else if (hasfeatures) { 04671 if (config->timelimit) { 04672 /* No warning next time - we are waiting for feature code */ 04673 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04674 } 04675 config->feature_start_time = ast_tvnow(); 04676 config->feature_timer = featuredigittimeout; 04677 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04678 } 04679 } 04680 } 04681 if (f) 04682 ast_frfree(f); 04683 } 04684 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04685 04686 before_you_go: 04687 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04688 if (silgen) { 04689 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04690 silgen = NULL; 04691 } 04692 04693 if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT)) { 04694 ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04695 if (bridge_cdr) { 04696 ast_cdr_discard(bridge_cdr); 04697 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04698 } 04699 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04700 } 04701 04702 if (config->end_bridge_callback) { 04703 config->end_bridge_callback(config->end_bridge_callback_data); 04704 } 04705 04706 if (!ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04707 struct ast_cdr *swapper = NULL; 04708 char savelastapp[AST_MAX_EXTENSION]; 04709 char savelastdata[AST_MAX_EXTENSION]; 04710 char save_context[AST_MAX_CONTEXT]; 04711 char save_exten[AST_MAX_EXTENSION]; 04712 int save_prio; 04713 04714 ast_channel_lock(chan); 04715 if (bridge_cdr) { 04716 /* 04717 * Swap the bridge_cdr and the chan cdr for a moment, and let 04718 * the hangup dialplan code operate on it. 04719 */ 04720 swapper = ast_channel_cdr(chan); 04721 ast_channel_cdr_set(chan, bridge_cdr); 04722 04723 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04724 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04725 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04726 } 04727 ast_copy_string(save_context, ast_channel_context(chan), sizeof(save_context)); 04728 ast_copy_string(save_exten, ast_channel_exten(chan), sizeof(save_exten)); 04729 save_prio = ast_channel_priority(chan); 04730 ast_channel_unlock(chan); 04731 04732 ast_autoservice_start(peer); 04733 if (ast_exists_extension(chan, ast_channel_context(chan), "h", 1, 04734 S_COR(ast_channel_caller(chan)->id.number.valid, 04735 ast_channel_caller(chan)->id.number.str, NULL))) { 04736 ast_pbx_h_exten_run(chan, ast_channel_context(chan)); 04737 hangup_run = 1; 04738 } else if (!ast_strlen_zero(ast_channel_macrocontext(chan)) 04739 && ast_exists_extension(chan, ast_channel_macrocontext(chan), "h", 1, 04740 S_COR(ast_channel_caller(chan)->id.number.valid, 04741 ast_channel_caller(chan)->id.number.str, NULL))) { 04742 ast_pbx_h_exten_run(chan, ast_channel_macrocontext(chan)); 04743 hangup_run = 1; 04744 } 04745 if (ast_pbx_hangup_handler_run(chan)) { 04746 /* Indicate hangup handlers were run. */ 04747 hangup_run = 1; 04748 } 04749 ast_autoservice_stop(peer); 04750 04751 ast_channel_lock(chan); 04752 04753 /* swap it back */ 04754 ast_channel_context_set(chan, save_context); 04755 ast_channel_exten_set(chan, save_exten); 04756 ast_channel_priority_set(chan, save_prio); 04757 if (bridge_cdr) { 04758 if (ast_channel_cdr(chan) == bridge_cdr) { 04759 ast_channel_cdr_set(chan, swapper); 04760 04761 /* Restore the lastapp/lastdata */ 04762 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04763 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04764 } else { 04765 bridge_cdr = NULL; 04766 } 04767 } 04768 ast_channel_unlock(chan); 04769 } 04770 04771 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04772 new_chan_cdr = pick_unlocked_cdr(ast_channel_cdr(chan)); /* the proper chan cdr, if there are forked cdrs */ 04773 04774 /* 04775 * If the channel CDR has been modified during the call, record 04776 * the changes in the bridge cdr, BUT, if hangup_run, the CDR 04777 * got swapped so don't overwrite what was done in the 04778 * h-extension or hangup handlers. What a mess. This is why 04779 * you never touch CDR code. 04780 */ 04781 if (new_chan_cdr && bridge_cdr && !hangup_run) { 04782 ast_cdr_copy_vars(bridge_cdr, new_chan_cdr); 04783 ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield)); 04784 bridge_cdr->amaflags = new_chan_cdr->amaflags; 04785 ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode)); 04786 if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 04787 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04788 } 04789 } 04790 04791 /* we can post the bridge CDR at this point */ 04792 if (bridge_cdr) { 04793 ast_cdr_end(bridge_cdr); 04794 ast_cdr_detach(bridge_cdr); 04795 } 04796 04797 /* do a specialized reset on the beginning channel 04798 CDR's, if they still exist, so as not to mess up 04799 issues in future bridges; 04800 04801 Here are the rules of the game: 04802 1. The chan and peer channel pointers will not change 04803 during the life of the bridge. 04804 2. But, in transfers, the channel names will change. 04805 between the time the bridge is started, and the 04806 time the channel ends. 04807 Usually, when a channel changes names, it will 04808 also change CDR pointers. 04809 3. Usually, only one of the two channels (chan or peer) 04810 will change names. 04811 4. Usually, if a channel changes names during a bridge, 04812 it is because of a transfer. Usually, in these situations, 04813 it is normal to see 2 bridges running simultaneously, and 04814 it is not unusual to see the two channels that change 04815 swapped between bridges. 04816 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04817 to attend to; if the chan or peer changed names, 04818 we have the before and after attached CDR's. 04819 */ 04820 04821 if (new_chan_cdr) { 04822 struct ast_channel *chan_ptr = NULL; 04823 04824 if (strcasecmp(orig_channame, ast_channel_name(chan)) != 0) { 04825 /* old channel */ 04826 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04827 ast_channel_lock(chan_ptr); 04828 if (!ast_bridged_channel(chan_ptr)) { 04829 struct ast_cdr *cur; 04830 for (cur = ast_channel_cdr(chan_ptr); cur; cur = cur->next) { 04831 if (cur == chan_cdr) { 04832 break; 04833 } 04834 } 04835 if (cur) { 04836 ast_cdr_specialized_reset(chan_cdr, 0); 04837 } 04838 } 04839 ast_channel_unlock(chan_ptr); 04840 chan_ptr = ast_channel_unref(chan_ptr); 04841 } 04842 /* new channel */ 04843 ast_cdr_specialized_reset(new_chan_cdr, 0); 04844 } else { 04845 ast_cdr_specialized_reset(ast_channel_cdr(chan), 0); /* nothing changed, reset the chan cdr */ 04846 } 04847 } 04848 04849 { 04850 struct ast_channel *chan_ptr = NULL; 04851 new_peer_cdr = pick_unlocked_cdr(ast_channel_cdr(peer)); /* the proper chan cdr, if there are forked cdrs */ 04852 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)) 04853 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04854 if (strcasecmp(orig_peername, ast_channel_name(peer)) != 0) { 04855 /* old channel */ 04856 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04857 ast_channel_lock(chan_ptr); 04858 if (!ast_bridged_channel(chan_ptr)) { 04859 struct ast_cdr *cur; 04860 for (cur = ast_channel_cdr(chan_ptr); cur; cur = cur->next) { 04861 if (cur == peer_cdr) { 04862 break; 04863 } 04864 } 04865 if (cur) { 04866 ast_cdr_specialized_reset(peer_cdr, 0); 04867 } 04868 } 04869 ast_channel_unlock(chan_ptr); 04870 chan_ptr = ast_channel_unref(chan_ptr); 04871 } 04872 /* new channel */ 04873 if (new_peer_cdr) { 04874 ast_cdr_specialized_reset(new_peer_cdr, 0); 04875 } 04876 } else { 04877 if (we_disabled_peer_cdr) { 04878 ast_clear_flag(ast_channel_cdr(peer), AST_CDR_FLAG_POST_DISABLED); 04879 } 04880 ast_cdr_specialized_reset(ast_channel_cdr(peer), 0); /* nothing changed, reset the peer cdr */ 04881 } 04882 } 04883 04884 return res; 04885 }
| 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 7980 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, ast_bridge_config::end_sound, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, pbx_builtin_getvar_helper(), ast_bridge_config::play_warning, S_OR, ast_bridge_config::start_sound, strsep(), ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by bridge_exec(), and dial_exec_full().
07982 { 07983 char *stringp = ast_strdupa(parse); 07984 char *limit_str, *warning_str, *warnfreq_str; 07985 const char *var; 07986 int play_to_caller = 0, play_to_callee = 0; 07987 int delta; 07988 07989 limit_str = strsep(&stringp, ":"); 07990 warning_str = strsep(&stringp, ":"); 07991 warnfreq_str = strsep(&stringp, ":"); 07992 07993 config->timelimit = atol(limit_str); 07994 if (warning_str) 07995 config->play_warning = atol(warning_str); 07996 if (warnfreq_str) 07997 config->warning_freq = atol(warnfreq_str); 07998 07999 if (!config->timelimit) { 08000 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 08001 config->timelimit = config->play_warning = config->warning_freq = 0; 08002 config->warning_sound = NULL; 08003 return -1; /* error */ 08004 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 08005 int w = config->warning_freq; 08006 08007 /* 08008 * If the first warning is requested _after_ the entire call 08009 * would end, and no warning frequency is requested, then turn 08010 * off the warning. If a warning frequency is requested, reduce 08011 * the 'first warning' time by that frequency until it falls 08012 * within the call's total time limit. 08013 * 08014 * Graphically: 08015 * timelim->| delta |<-playwarning 08016 * 0__________________|_________________| 08017 * | w | | | | 08018 * 08019 * so the number of intervals to cut is 1+(delta-1)/w 08020 */ 08021 if (w == 0) { 08022 config->play_warning = 0; 08023 } else { 08024 config->play_warning -= w * ( 1 + (delta-1)/w ); 08025 if (config->play_warning < 1) 08026 config->play_warning = config->warning_freq = 0; 08027 } 08028 } 08029 08030 ast_channel_lock(chan); 08031 08032 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 08033 play_to_caller = var ? ast_true(var) : 1; 08034 08035 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 08036 play_to_callee = var ? ast_true(var) : 0; 08037 08038 if (!play_to_caller && !play_to_callee) 08039 play_to_caller = 1; 08040 08041 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 08042 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 08043 08044 /* The code looking at config wants a NULL, not just "", to decide 08045 * that the message should not be played, so we replace "" with NULL. 08046 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 08047 * not found. 08048 */ 08049 08050 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 08051 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 08052 08053 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 08054 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 08055 08056 ast_channel_unlock(chan); 08057 08058 /* undo effect of S(x) in case they are both used */ 08059 calldurationlimit->tv_sec = 0; 08060 calldurationlimit->tv_usec = 0; 08061 08062 /* more efficient to do it like S(x) does since no advanced opts */ 08063 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 08064 calldurationlimit->tv_sec = config->timelimit / 1000; 08065 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 08066 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 08067 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 08068 config->timelimit = play_to_caller = play_to_callee = 08069 config->play_warning = config->warning_freq = 0; 08070 } else { 08071 ast_verb(4, "Limit Data for this call:\n"); 08072 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 08073 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 08074 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 08075 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 08076 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 08077 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 08078 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 08079 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 08080 } 08081 if (play_to_caller) 08082 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 08083 if (play_to_callee) 08084 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 08085 return 0; 08086 }
| 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 7688 of file features.c.
References ast_channel_datastore_find(), ast_channel_flags(), ast_channel_masq(), ast_channel_pbx(), AST_FLAG_ZOMBIE, AST_STATE_DOWN, AST_STATE_RING, AST_STATE_RINGING, and ast_test_flag.
Referenced by ast_pickup_find_by_group(), find_by_mark(), find_by_part(), find_channel_by_group(), pickup_by_exten(), and pickup_by_name_cb().
07689 { 07690 if (!ast_channel_pbx(chan) && !ast_channel_masq(chan) && !ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) 07691 && (ast_channel_state(chan) == AST_STATE_RINGING 07692 || ast_channel_state(chan) == AST_STATE_RING 07693 /* 07694 * Check the down state as well because some SIP devices do not 07695 * give 180 ringing when they can just give 183 session progress 07696 * instead. Issue 14005. (Some ISDN switches as well for that 07697 * matter.) 07698 */ 07699 || ast_channel_state(chan) == AST_STATE_DOWN) 07700 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07701 return 1; 07702 } 07703 return 0; 07704 }
| void ast_channel_log | ( | char * | title, | |
| struct ast_channel * | chan | |||
| ) |
Definition at line 4141 of file features.c.
References ast_channel_accountcode(), ast_channel_amaflags(), ast_channel_appl(), ast_channel_cdr(), ast_channel_context(), ast_channel_data(), ast_channel_dialcontext(), ast_channel_exten(), ast_channel_internal_bridged_channel(), ast_channel_linkedid(), ast_channel_macrocontext(), ast_channel_macroexten(), ast_channel_macropriority(), ast_channel_masq(), ast_channel_masqr(), ast_channel_name(), ast_channel_priority(), ast_channel_uniqueid(), ast_log(), and LOG_NOTICE.
Referenced by ast_bridge_call().
04142 { 04143 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long) chan); 04144 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n", 04145 ast_channel_name(chan), ast_channel_appl(chan), ast_channel_data(chan), ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan)); 04146 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n", 04147 ast_channel_accountcode(chan), ast_channel_dialcontext(chan), ast_channel_amaflags(chan), ast_channel_macrocontext(chan), ast_channel_macroexten(chan), ast_channel_macropriority(chan)); 04148 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n", 04149 ast_channel_masq(chan), ast_channel_masqr(chan), 04150 ast_channel_internal_bridged_channel(chan), ast_channel_uniqueid(chan), ast_channel_linkedid(chan)); 04151 if (ast_channel_masqr(chan)) { 04152 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n", 04153 ast_channel_name(ast_channel_masqr(chan)), ast_channel_cdr(ast_channel_masqr(chan))); 04154 } 04155 if (ast_channel_internal_bridged_channel(chan)) { 04156 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", ast_channel_name(ast_channel_internal_bridged_channel(chan))); 04157 } 04158 04159 ast_log(LOG_NOTICE, "===== done ====\n"); 04160 }
| 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 7846 of file features.c.
References ast_answer(), AST_CAUSE_ANSWERED_ELSEWHERE, AST_CEL_PICKUP, ast_cel_report_event(), ast_channel_caller(), ast_channel_connected(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_datastore_add(), ast_channel_datastore_remove(), ast_channel_hangupcause_set(), ast_channel_lock, ast_channel_masquerade(), ast_channel_name(), 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_log(), ast_manager_event_multichan, ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_party_id_reset(), ast_queue_control(), ast_strdupa, EVENT_FLAG_CALL, LOG_WARNING, ast_party_connected_line::priv, 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().
07847 { 07848 struct ast_party_connected_line connected_caller; 07849 struct ast_channel *chans[2] = { chan, target }; 07850 struct ast_datastore *ds_pickup; 07851 const char *chan_name;/*!< A masquerade changes channel names. */ 07852 const char *target_name;/*!< A masquerade changes channel names. */ 07853 int res = -1; 07854 07855 target_name = ast_strdupa(ast_channel_name(target)); 07856 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan)); 07857 07858 /* Mark the target to block any call pickup race. */ 07859 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07860 if (!ds_pickup) { 07861 ast_log(LOG_WARNING, 07862 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07863 return -1; 07864 } 07865 ast_channel_datastore_add(target, ds_pickup); 07866 07867 ast_party_connected_line_init(&connected_caller); 07868 ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target)); 07869 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07870 /* Reset any earlier private connected id representation */ 07871 ast_party_id_reset(&connected_caller.priv); 07872 07873 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07874 if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) && 07875 ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07876 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07877 } 07878 ast_party_connected_line_free(&connected_caller); 07879 07880 ast_channel_lock(chan); 07881 chan_name = ast_strdupa(ast_channel_name(chan)); 07882 ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan)); 07883 ast_channel_unlock(chan); 07884 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07885 07886 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07887 07888 if (ast_answer(chan)) { 07889 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07890 goto pickup_failed; 07891 } 07892 07893 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07894 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07895 goto pickup_failed; 07896 } 07897 07898 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07899 07900 /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */ 07901 ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE); 07902 07903 if (ast_channel_masquerade(target, chan)) { 07904 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07905 target_name); 07906 goto pickup_failed; 07907 } 07908 07909 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07910 /*** DOCUMENTATION 07911 <managerEventInstance> 07912 <synopsis>Raised when a call pickup occurs.</synopsis> 07913 <syntax> 07914 <parameter name="Channel"><para>The name of the channel that initiated the pickup.</para></parameter> 07915 <parameter name="TargetChannel"><para>The name of the channel that is being picked up.</para></parameter> 07916 </syntax> 07917 </managerEventInstance> 07918 ***/ 07919 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07920 "Channel: %s\r\n" 07921 "TargetChannel: %s\r\n", 07922 chan_name, target_name); 07923 07924 /* Do the masquerade manually to make sure that it is completed. */ 07925 ast_do_masquerade(target); 07926 res = 0; 07927 07928 pickup_failed: 07929 ast_channel_lock(target); 07930 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07931 ast_datastore_free(ds_pickup); 07932 } 07933 ast_party_connected_line_free(&connected_caller); 07934 07935 return res; 07936 }
| 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 3725 of file features.c.
References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03725 { 03726 03727 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03728 }
| int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 8978 of file features.c.
References __ast_custom_function_register(), action_bridge(), ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register_xml_core, ast_pthread_create, ast_register_application2(), ast_register_atexit(), AST_TEST_REGISTER, bridge_exec(), do_parking_thread(), EVENT_FLAG_CALL, features_shutdown(), load_config(), manager_park(), manager_parking_status(), manager_parkinglot_list(), metermaidstate(), park_call_exec(), parkcall, parked_call_exec(), parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), and parkinglots.
Referenced by main().
08979 { 08980 int res; 08981 08982 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 08983 if (!parkinglots) { 08984 return -1; 08985 } 08986 08987 res = load_config(0); 08988 if (res) { 08989 return res; 08990 } 08991 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); 08992 if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) { 08993 return -1; 08994 } 08995 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); 08996 res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL); 08997 if (!res) 08998 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); 08999 if (!res) { 09000 ast_manager_register_xml_core("ParkedCalls", 0, manager_parking_status); 09001 ast_manager_register_xml_core("Parkinglots", 0, manager_parkinglot_list); 09002 ast_manager_register_xml_core("Park", EVENT_FLAG_CALL, manager_park); 09003 ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge); 09004 } 09005 res |= __ast_custom_function_register(&feature_function, NULL); 09006 res |= __ast_custom_function_register(&featuremap_function, NULL); 09007 09008 res |= ast_devstate_prov_add("Park", metermaidstate); 09009 #if defined(TEST_FRAMEWORK) 09010 res |= AST_TEST_REGISTER(features_test); 09011 #endif /* defined(TEST_FRAMEWORK) */ 09012 09013 ast_register_atexit(features_shutdown); 09014 09015 return res; 09016 }
| int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 7176 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().
07177 { 07178 struct ast_context *con; 07179 int res; 07180 07181 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 07182 07183 /* 07184 * Always destroy the parking_con_dial context to remove buildup 07185 * of recalled extensions in the context. At worst, the parked 07186 * call gets hungup attempting to run an invalid extension when 07187 * we are trying to callback the parker or the preset return 07188 * extension. This is a small window of opportunity on an 07189 * execution chain that is not expected to happen very often. 07190 */ 07191 con = ast_context_find(parking_con_dial); 07192 if (con) { 07193 ast_context_destroy(con, registrar); 07194 } 07195 07196 res = load_config(1); 07197 ast_mutex_unlock(&features_reload_lock); 07198 07199 return res; 07200 }
| struct ast_call_feature* ast_find_call_feature | ( | const char * | name | ) | [read] |
look for a call feature entry by its sname
| name | a string ptr, should match "automon", "blindxfer", "atxfer", etc. |
Definition at line 3311 of file features.c.
References FEATURES_COUNT, find_dynamic_feature(), and ast_call_feature::sname.
Referenced by action_atxfer(), builtin_feature_get_exten(), featuremap_write(), handle_request_info(), and process_config().
03312 { 03313 int x; 03314 for (x = 0; x < FEATURES_COUNT; x++) { 03315 if (!strcasecmp(name, builtin_features[x].sname)) 03316 return &builtin_features[x]; 03317 } 03318 03319 return find_dynamic_feature(name); 03320 }
| 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 2023 of file features.c.
References ast_channel_name(), ast_strdupa, masq_park_call(), ast_park_call_args::orig_chan_name, and ast_park_call_args::timeout.
Referenced by handle_soft_key_event_message(), handle_stimulus_message(), and parkandannounce_exec().
02024 { 02025 struct ast_park_call_args args = { 02026 .timeout = timeout, 02027 .extout = extout, 02028 }; 02029 02030 if (peer) { 02031 args.orig_chan_name = ast_strdupa(ast_channel_name(peer)); 02032 } 02033 return masq_park_call(rchan, peer, &args); 02034 }
| 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 1969 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), find_parkinglot(), get_parking_exten(), masq_park_call(), ast_park_call_args::orig_chan_name, parkeddynamic, ast_park_call_args::parkinglot, parkinglot_unref(), parse(), park_app_args::pl_name, and ast_park_call_args::timeout.
Referenced by __analog_ss_thread(), analog_ss_thread(), and mgcp_ss().
01970 { 01971 int res; 01972 char *parse; 01973 const char *app_data; 01974 struct ast_exten *exten; 01975 struct park_app_args app_args; 01976 struct ast_park_call_args args = { 01977 .timeout = timeout, 01978 .extout = extout, 01979 }; 01980 01981 if (parker) { 01982 args.orig_chan_name = ast_strdupa(ast_channel_name(parker)); 01983 } 01984 if (!park_exten || !park_context) { 01985 return masq_park_call(park_me, parker, &args); 01986 } 01987 01988 /* 01989 * Determiine if the specified park extension has an exclusive 01990 * parking lot to use. 01991 */ 01992 if (parker && parker != park_me) { 01993 ast_autoservice_start(park_me); 01994 } 01995 exten = get_parking_exten(park_exten, parker, park_context); 01996 if (exten) { 01997 app_data = ast_get_extension_app_data(exten); 01998 if (!app_data) { 01999 app_data = ""; 02000 } 02001 parse = ast_strdupa(app_data); 02002 AST_STANDARD_APP_ARGS(app_args, parse); 02003 02004 if (!ast_strlen_zero(app_args.pl_name)) { 02005 /* Find the specified exclusive parking lot */ 02006 args.parkinglot = find_parkinglot(app_args.pl_name); 02007 if (!args.parkinglot && parkeddynamic) { 02008 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 02009 } 02010 } 02011 } 02012 if (parker && parker != park_me) { 02013 ast_autoservice_stop(park_me); 02014 } 02015 02016 res = masq_park_call(park_me, parker, &args); 02017 if (args.parkinglot) { 02018 parkinglot_unref(args.parkinglot); 02019 } 02020 return res; 02021 }
| 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 1872 of file features.c.
References park_call_full(), and ast_park_call_args::timeout.
01873 { 01874 struct ast_park_call_args args = { 01875 .timeout = timeout, 01876 .extout = extout, 01877 }; 01878 01879 return park_call_full(park_me, parker, &args); 01880 }
| 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 1821 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), find_parkinglot(), get_parking_exten(), park_call_full(), parkeddynamic, ast_park_call_args::parkinglot, parkinglot_unref(), parse(), park_app_args::pl_name, and ast_park_call_args::timeout.
Referenced by iax_park_thread(), and sip_park_thread().
01822 { 01823 int res; 01824 char *parse; 01825 const char *app_data; 01826 struct ast_exten *exten; 01827 struct park_app_args app_args; 01828 struct ast_park_call_args args = { 01829 .timeout = timeout, 01830 .extout = extout, 01831 }; 01832 01833 if (!park_exten || !park_context) { 01834 return park_call_full(park_me, parker, &args); 01835 } 01836 01837 /* 01838 * Determiine if the specified park extension has an exclusive 01839 * parking lot to use. 01840 */ 01841 if (parker && parker != park_me) { 01842 ast_autoservice_start(park_me); 01843 } 01844 exten = get_parking_exten(park_exten, parker, park_context); 01845 if (exten) { 01846 app_data = ast_get_extension_app_data(exten); 01847 if (!app_data) { 01848 app_data = ""; 01849 } 01850 parse = ast_strdupa(app_data); 01851 AST_STANDARD_APP_ARGS(app_args, parse); 01852 01853 if (!ast_strlen_zero(app_args.pl_name)) { 01854 /* Find the specified exclusive parking lot */ 01855 args.parkinglot = find_parkinglot(app_args.pl_name); 01856 if (!args.parkinglot && parkeddynamic) { 01857 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01858 } 01859 } 01860 } 01861 if (parker && parker != park_me) { 01862 ast_autoservice_stop(park_me); 01863 } 01864 01865 res = park_call_full(park_me, parker, &args); 01866 if (args.parkinglot) { 01867 parkinglot_unref(args.parkinglot); 01868 } 01869 return res; 01870 }
| 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.
Definition at line 981 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_helper().
00982 { 00983 return get_parking_exten(exten_str, chan, context) ? 1 : 0; 00984 }
| int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
| chan | channel that initiated pickup. |
< Potential pickup target
Definition at line 7811 of file features.c.
References ast_answer(), ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_debug, ast_do_pickup(), ast_log(), ast_pickup_find_by_group(), ast_stream_and_wait(), ast_strlen_zero(), LOG_NOTICE, LOG_WARNING, pbx_builtin_setvar_helper(), pickupfailsound, and pickupsound.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), handle_call_outgoing(), mgcp_ss(), and sip_pickup_thread().
07812 { 07813 struct ast_channel *target;/*!< Potential pickup target */ 07814 int res = -1; 07815 07816 ast_debug(1, "pickup attempt by %s\n", ast_channel_name(chan)); 07817 07818 /* The found channel is already locked. */ 07819 target = ast_pickup_find_by_group(chan); 07820 if (target) { 07821 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan)); 07822 07823 res = ast_do_pickup(chan, target); 07824 ast_channel_unlock(target); 07825 if (!res) { 07826 if (!ast_strlen_zero(pickupsound)) { 07827 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07828 } 07829 } else { 07830 ast_log(LOG_WARNING, "pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan)); 07831 } 07832 target = ast_channel_unref(target); 07833 } 07834 07835 if (res < 0) { 07836 ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan)); 07837 if (!ast_strlen_zero(pickupfailsound)) { 07838 ast_answer(chan); 07839 ast_stream_and_wait(chan, pickupfailsound, ""); 07840 } 07841 } 07842 07843 return res; 07844 }
| const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 986 of file features.c.
Referenced by __analog_ss_thread(), analog_canmatch_featurecode(), analog_ss_thread(), canmatch_featurecode(), cb_events(), get_destination(), handle_call_outgoing(), handle_feature_show(), handle_request_invite(), key_main_page(), and mgcp_ss().
00987 { 00988 return pickup_ext; 00989 }
| struct ast_channel* ast_pickup_find_by_group | ( | struct ast_channel * | chan | ) | [read] |
Find a pickup channel target by group.
| chan | channel that initiated pickup. |
| target | on success. The returned channel is locked and reffed. | |
| NULL | on error. |
< Candidate channels found to pickup.
< Potential pickup target
< Potential new older target
Definition at line 7744 of file features.c.
References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_container_alloc_options, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, ast_can_pickup(), ast_channel_callback(), ast_channel_creationtime(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_tvcmp(), and find_channel_by_group().
Referenced by ast_pickup_call(), and pickup_by_group().
07745 { 07746 struct ao2_container *candidates;/*!< Candidate channels found to pickup. */ 07747 struct ast_channel *target;/*!< Potential pickup target */ 07748 07749 candidates = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL); 07750 if (!candidates) { 07751 return NULL; 07752 } 07753 07754 /* Find all candidate targets by group. */ 07755 ast_channel_callback(find_channel_by_group, chan, candidates, 0); 07756 07757 /* Find the oldest pickup target candidate */ 07758 target = NULL; 07759 for (;;) { 07760 struct ast_channel *candidate;/*!< Potential new older target */ 07761 struct ao2_iterator iter; 07762 07763 iter = ao2_iterator_init(candidates, 0); 07764 while ((candidate = ao2_iterator_next(&iter))) { 07765 if (!target) { 07766 /* First target. */ 07767 target = candidate; 07768 continue; 07769 } 07770 if (ast_tvcmp(ast_channel_creationtime(candidate), ast_channel_creationtime(target)) < 0) { 07771 /* We have a new target. */ 07772 ast_channel_unref(target); 07773 target = candidate; 07774 continue; 07775 } 07776 ast_channel_unref(candidate); 07777 } 07778 ao2_iterator_destroy(&iter); 07779 if (!target) { 07780 /* No candidates found. */ 07781 break; 07782 } 07783 07784 /* The found channel must be locked and ref'd. */ 07785 ast_channel_lock(target); 07786 07787 /* Recheck pickup ability */ 07788 if (ast_can_pickup(target)) { 07789 /* This is the channel to pickup. */ 07790 break; 07791 } 07792 07793 /* Someone else picked it up or the call went away. */ 07794 ast_channel_unlock(target); 07795 ao2_unlink(candidates, target); 07796 target = ast_channel_unref(target); 07797 } 07798 ao2_ref(candidates, -1); 07799 07800 return target; 07801 }
| void ast_rdlock_call_features | ( | void | ) |
Definition at line 3297 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by builtin_feature_get_exten(), featuremap_read(), and handle_request_info().
03298 { 03299 ast_rwlock_rdlock(&features_lock); 03300 }
| void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_list
register new feature into feature_set
Definition at line 3141 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
Referenced by process_applicationmap_line().
03142 { 03143 if (!feature) { 03144 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 03145 return; 03146 } 03147 03148 AST_RWLIST_WRLOCK(&feature_list); 03149 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 03150 AST_RWLIST_UNLOCK(&feature_list); 03151 03152 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 03153 }
| void ast_unlock_call_features | ( | void | ) |
Definition at line 3302 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by builtin_feature_get_exten(), featuremap_read(), and handle_request_info().
03303 { 03304 ast_rwlock_unlock(&features_lock); 03305 }
| 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 3221 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
03222 { 03223 if (!feature) { 03224 return; 03225 } 03226 03227 AST_RWLIST_WRLOCK(&feature_list); 03228 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 03229 AST_RWLIST_UNLOCK(&feature_list); 03230 03231 ast_free(feature); 03232 }
| static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 3235 of file features.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_call_feature::feature_entry.
Referenced by process_config().
03236 { 03237 struct ast_call_feature *feature; 03238 03239 AST_RWLIST_WRLOCK(&feature_list); 03240 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 03241 ast_free(feature); 03242 } 03243 AST_RWLIST_UNLOCK(&feature_list); 03244 }
| static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 3261 of file features.c.
References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, and feature_group::features.
Referenced by process_config().
03262 { 03263 struct feature_group *fg; 03264 struct feature_group_exten *fge; 03265 03266 AST_RWLIST_WRLOCK(&feature_groups); 03267 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 03268 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 03269 ast_string_field_free_memory(fge); 03270 ast_free(fge); 03271 } 03272 03273 ast_string_field_free_memory(fg); 03274 ast_free(fg); 03275 } 03276 AST_RWLIST_UNLOCK(&feature_groups); 03277 }
| static void atxfer_fail_cleanup | ( | struct ast_channel * | transferee, | |
| struct ast_channel * | transferer, | |||
| struct ast_party_connected_line * | connected_line | |||
| ) | [static] |
Definition at line 2640 of file features.c.
References ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_update_connected_line(), ast_party_connected_line_free(), and finishup().
Referenced by builtin_atxfer().
02641 { 02642 finishup(transferee); 02643 02644 /* 02645 * Restore party B connected line info about party A. 02646 * 02647 * Party B was the caller to party C and is the last known mode 02648 * for party B. 02649 */ 02650 if (ast_channel_connected_line_sub(transferee, transferer, connected_line, 0) && 02651 ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) { 02652 ast_channel_update_connected_line(transferer, connected_line, NULL); 02653 } 02654 ast_party_connected_line_free(connected_line); 02655 }
| static void* bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
| data | thread bridge. |
Definition at line 1125 of file features.c.
References ast_autoservice_chan_hangup_peer(), ast_bridge_call(), ast_callid_threadassoc_add(), ast_callid_unref, ast_channel_appl_set(), ast_channel_data_set(), ast_channel_name(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::callid, ast_bridge_thread_obj::chan, LOG_VERBOSE, LOG_WARNING, ast_bridge_thread_obj::peer, ast_bridge_thread_obj::return_to_pbx, and set_chan_app_data().
Referenced by bridge_call_thread_launch().
01126 { 01127 struct ast_bridge_thread_obj *tobj = data; 01128 01129 if (tobj->callid) { 01130 ast_callid_threadassoc_add(tobj->callid); 01131 /* Need to deref and set to null since ast_bridge_thread_obj has no common destructor */ 01132 tobj->callid = ast_callid_unref(tobj->callid); 01133 } 01134 01135 ast_channel_appl_set(tobj->chan, !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"); 01136 if (set_chan_app_data(tobj->chan, ast_channel_name(tobj->peer))) { 01137 ast_channel_data_set(tobj->chan, "(Empty)"); 01138 } 01139 ast_channel_appl_set(tobj->peer, !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"); 01140 if (set_chan_app_data(tobj->peer, ast_channel_name(tobj->chan))) { 01141 ast_channel_data_set(tobj->peer, "(Empty)"); 01142 } 01143 01144 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 01145 01146 if (tobj->return_to_pbx) { 01147 if (!ast_check_hangup(tobj->peer)) { 01148 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", ast_channel_name(tobj->peer)); 01149 if (ast_pbx_start(tobj->peer)) { 01150 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", ast_channel_name(tobj->peer)); 01151 ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer); 01152 } 01153 } else { 01154 ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer); 01155 } 01156 if (!ast_check_hangup(tobj->chan)) { 01157 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", ast_channel_name(tobj->chan)); 01158 if (ast_pbx_start(tobj->chan)) { 01159 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", ast_channel_name(tobj->chan)); 01160 ast_hangup(tobj->chan); 01161 } 01162 } else { 01163 ast_hangup(tobj->chan); 01164 } 01165 } else { 01166 ast_hangup(tobj->chan); 01167 ast_hangup(tobj->peer); 01168 } 01169 01170 ast_free(tobj); 01171 01172 return NULL; 01173 }
| 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 1181 of file features.c.
References ast_callid_unref, ast_hangup(), ast_log(), ast_pthread_create, ast_read_threadstorage_callid(), bridge_call_thread(), ast_bridge_thread_obj::callid, ast_bridge_thread_obj::chan, LOG_ERROR, ast_bridge_thread_obj::peer, and thread.
Referenced by action_bridge(), and builtin_atxfer().
01182 { 01183 pthread_t thread; 01184 pthread_attr_t attr; 01185 struct sched_param sched; 01186 01187 /* This needs to be unreffed once it has been associated with the new thread. */ 01188 data->callid = ast_read_threadstorage_callid(); 01189 01190 pthread_attr_init(&attr); 01191 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 01192 if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) { 01193 /* Failed to create thread. Ditch the reference to callid. */ 01194 ast_callid_unref(data->callid); 01195 ast_hangup(data->chan); 01196 ast_hangup(data->peer); 01197 ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n"); 01198 return; 01199 } 01200 pthread_attr_destroy(&attr); 01201 memset(&sched, 0, sizeof(sched)); 01202 pthread_setschedparam(thread, SCHED_RR, &sched); 01203 }
| static int bridge_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Bridge channels.
| chan | ||
| data | channel to bridge with. |
Definition at line 8098 of file features.c.
References args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_autoservice_chan_hangup_peer(), ast_bridge_call(), ast_bridge_timelimit(), ast_channel_alloc, ast_channel_context(), ast_channel_exten(), ast_channel_flags(), ast_channel_get_by_name_prefix(), ast_channel_language(), ast_channel_linkedid(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_name(), ast_channel_priority(), ast_channel_unlock, 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_goto_if_exists(), ast_hangup(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_parseable_goto(), ast_pbx_start(), ast_replace_subargument_delimiter(), 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, do_bridge_masquerade(), ast_bridge_config::end_sound, EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_CALLEE_GO_ON, OPT_ARG_DURATION_LIMIT, OPT_CALLEE_GO_ON, 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_bridge_config::start_sound, ast_bridge_config::warning_sound, and xfersound.
Referenced by ast_features_init().
08099 { 08100 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2]; 08101 char *tmp_data = NULL; 08102 struct ast_flags opts = { 0, }; 08103 struct ast_bridge_config bconfig = { { 0, }, }; 08104 char *opt_args[OPT_ARG_ARRAY_SIZE]; 08105 struct timeval calldurationlimit = { 0, }; 08106 08107 AST_DECLARE_APP_ARGS(args, 08108 AST_APP_ARG(dest_chan); 08109 AST_APP_ARG(options); 08110 ); 08111 08112 if (ast_strlen_zero(data)) { 08113 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 08114 return -1; 08115 } 08116 08117 tmp_data = ast_strdupa(data); 08118 AST_STANDARD_APP_ARGS(args, tmp_data); 08119 if (!ast_strlen_zero(args.options)) 08120 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options); 08121 08122 /* avoid bridge with ourselves */ 08123 if (!strcmp(ast_channel_name(chan), args.dest_chan)) { 08124 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", ast_channel_name(chan)); 08125 /*** DOCUMENTATION 08126 <managerEventInstance> 08127 <synopsis>Raised when an error occurs during bridge creation.</synopsis> 08128 <see-also> 08129 <ref type="application">Bridge</ref> 08130 </see-also> 08131 </managerEventInstance> 08132 ***/ 08133 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 08134 "Response: Failed\r\n" 08135 "Reason: Unable to bridge channel to itself\r\n" 08136 "Channel1: %s\r\n" 08137 "Channel2: %s\r\n", 08138 ast_channel_name(chan), args.dest_chan); 08139 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 08140 return 0; 08141 } 08142 08143 /* make sure we have a valid end point */ 08144 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan, 08145 strlen(args.dest_chan)))) { 08146 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n", 08147 args.dest_chan); 08148 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 08149 "Response: Failed\r\n" 08150 "Reason: Channel2 does not exist\r\n" 08151 "Channel1: %s\r\n" 08152 "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan); 08153 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 08154 return 0; 08155 } 08156 08157 /* try to allocate a place holder where current_dest_chan will be placed */ 08158 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 08159 NULL, NULL, ast_channel_linkedid(current_dest_chan), 0, "Bridge/%s", ast_channel_name(current_dest_chan)))) { 08160 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 08161 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 08162 "Response: Failed\r\n" 08163 "Reason: Cannot create placeholder channel\r\n" 08164 "Channel1: %s\r\n" 08165 "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan); 08166 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 08167 ast_channel_unref(current_dest_chan); 08168 return 0; 08169 } 08170 08171 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) 08172 && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT]) 08173 && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) { 08174 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 08175 "Response: Failed\r\n" 08176 "Reason: Cannot setup bridge time limit\r\n" 08177 "Channel1: %s\r\n" 08178 "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan); 08179 ast_hangup(final_dest_chan); 08180 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 08181 current_dest_chan = ast_channel_unref(current_dest_chan); 08182 goto done; 08183 } 08184 08185 if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) { 08186 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 08187 "Response: Failed\r\n" 08188 "Reason: Cannot masquerade channels\r\n" 08189 "Channel1: %s\r\n" 08190 "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan); 08191 ast_hangup(final_dest_chan); 08192 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 08193 current_dest_chan = ast_channel_unref(current_dest_chan); 08194 goto done; 08195 } 08196 08197 /* answer the channel if needed */ 08198 if (ast_channel_state(final_dest_chan) != AST_STATE_UP) { 08199 ast_answer(final_dest_chan); 08200 } 08201 08202 chans[0] = current_dest_chan; 08203 chans[1] = final_dest_chan; 08204 08205 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 08206 /* try to make compatible, send error if we fail */ 08207 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 08208 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(final_dest_chan)); 08209 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 08210 "Response: Failed\r\n" 08211 "Reason: Could not make channels compatible for bridge\r\n" 08212 "Channel1: %s\r\n" 08213 "Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan)); 08214 08215 /* Maybe we should return this channel to the PBX? */ 08216 ast_autoservice_chan_hangup_peer(chan, final_dest_chan); 08217 08218 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 08219 current_dest_chan = ast_channel_unref(current_dest_chan); 08220 goto done; 08221 } 08222 08223 /* Report that the bridge will be successfull */ 08224 /*** DOCUMENTATION 08225 <managerEventInstance> 08226 <synopsis>Raised when the bridge is created successfully.</synopsis> 08227 <see-also> 08228 <ref type="application">Bridge</ref> 08229 </see-also> 08230 </managerEventInstance> 08231 ***/ 08232 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 08233 "Response: Success\r\n" 08234 "Channel1: %s\r\n" 08235 "Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan)); 08236 08237 current_dest_chan = ast_channel_unref(current_dest_chan); 08238 08239 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 08240 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 08241 if (!ast_streamfile(final_dest_chan, xfersound, ast_channel_language(final_dest_chan))) { 08242 if (ast_waitstream(final_dest_chan, "") < 0) 08243 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", ast_channel_name(final_dest_chan)); 08244 } 08245 } 08246 08247 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) 08248 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT); 08249 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) 08250 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT); 08251 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) 08252 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 08253 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) 08254 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 08255 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR)) 08256 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON); 08257 if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 08258 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON); 08259 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) 08260 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL); 08261 if (ast_test_flag(&opts, OPT_CALLER_PARK)) 08262 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL); 08263 08264 /* 08265 * Don't let the after-bridge code run the h-exten. We want to 08266 * continue in the dialplan. 08267 */ 08268 ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); 08269 ast_bridge_call(chan, final_dest_chan, &bconfig); 08270 08271 /* The bridge has ended, set BRIDGERESULT to SUCCESS. */ 08272 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 08273 08274 /* If the other channel has not been hung up, return it to the PBX */ 08275 if (!ast_check_hangup(final_dest_chan)) { 08276 if (ast_test_flag(&opts, OPT_CALLEE_GO_ON)) { 08277 char *caller_context; 08278 char *caller_extension; 08279 int caller_priority; 08280 int goto_opt; 08281 08282 ast_channel_lock(chan); 08283 caller_context = ast_strdupa(ast_channel_context(chan)); 08284 caller_extension = ast_strdupa(ast_channel_exten(chan)); 08285 caller_priority = ast_channel_priority(chan); 08286 ast_channel_unlock(chan); 08287 08288 if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) { 08289 ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]); 08290 /* Set current dialplan position to bridger dialplan position */ 08291 goto_opt = ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority) 08292 /* Then perform the goto */ 08293 || ast_parseable_goto(final_dest_chan, opt_args[OPT_ARG_CALLEE_GO_ON]); 08294 } else { /* F() */ 08295 goto_opt = ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority + 1); 08296 } 08297 if (goto_opt || ast_pbx_start(final_dest_chan)) { 08298 ast_autoservice_chan_hangup_peer(chan, final_dest_chan); 08299 } 08300 } else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) { 08301 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 08302 ast_channel_context(final_dest_chan), ast_channel_exten(final_dest_chan), 08303 ast_channel_priority(final_dest_chan), ast_channel_name(final_dest_chan)); 08304 08305 if (ast_pbx_start(final_dest_chan)) { 08306 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", ast_channel_name(final_dest_chan)); 08307 ast_autoservice_chan_hangup_peer(chan, final_dest_chan); 08308 } else { 08309 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", ast_channel_name(final_dest_chan)); 08310 } 08311 } else { 08312 ast_autoservice_chan_hangup_peer(chan, final_dest_chan); 08313 } 08314 } else { 08315 ast_debug(1, "chan %s was hungup\n", ast_channel_name(final_dest_chan)); 08316 ast_autoservice_chan_hangup_peer(chan, final_dest_chan); 08317 } 08318 done: 08319 ast_free((char *) bconfig.warning_sound); 08320 ast_free((char *) bconfig.end_sound); 08321 ast_free((char *) bconfig.start_sound); 08322 08323 return 0; 08324 }
| static struct parking_dp_context* build_dialplan_useage_context | ( | struct ast_parkinglot * | lot | ) | [static, read] |
Definition at line 6614 of file features.c.
References ast_calloc, ast_parkinglot::cfg, parking_dp_context::context, destroy_dialplan_usage_context(), dialplan_usage_add_parkinglot_data(), and parkinglot_cfg::parking_con.
Referenced by dialplan_usage_add_parkinglot().
06615 { 06616 struct parking_dp_context *ctx_node; 06617 06618 ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con)); 06619 if (!ctx_node) { 06620 return NULL; 06621 } 06622 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) { 06623 destroy_dialplan_usage_context(ctx_node); 06624 return NULL; 06625 } 06626 strcpy(ctx_node->context, lot->cfg.parking_con); 06627 return ctx_node; 06628 }
| static int build_dialplan_useage_map | ( | struct parking_dp_map * | usage_map, | |
| int | complain | |||
| ) | [static] |
Definition at line 6686 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().
06687 { 06688 int status = 0; 06689 struct ao2_iterator iter; 06690 struct ast_parkinglot *curlot; 06691 06692 /* For all parking lots */ 06693 iter = ao2_iterator_init(parkinglots, 0); 06694 for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) { 06695 /* Add the parking lot to the map. */ 06696 if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) { 06697 ao2_ref(curlot, -1); 06698 status = -1; 06699 break; 06700 } 06701 } 06702 ao2_iterator_destroy(&iter); 06703 06704 return status; 06705 }
| static struct parking_dp_ramp* build_dialplan_useage_ramp | ( | const char * | exten, | |
| int | exclusive | |||
| ) | [static, read] |
Definition at line 6377 of file features.c.
References ast_calloc, parking_dp_ramp::exclusive, and parking_dp_ramp::exten.
Referenced by usage_context_add_ramp().
06378 { 06379 struct parking_dp_ramp *ramp_node; 06380 06381 ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten)); 06382 if (!ramp_node) { 06383 return NULL; 06384 } 06385 ramp_node->exclusive = exclusive; 06386 strcpy(ramp_node->exten, exten); 06387 return ramp_node; 06388 }
| static struct parking_dp_spaces* build_dialplan_useage_spaces | ( | int | start, | |
| int | stop | |||
| ) | [static, read] |
Definition at line 6458 of file features.c.
References ast_calloc, parking_dp_spaces::start, and parking_dp_spaces::stop.
Referenced by usage_context_add_spaces().
06459 { 06460 struct parking_dp_spaces *spaces_node; 06461 06462 spaces_node = ast_calloc(1, sizeof(*spaces_node)); 06463 if (!spaces_node) { 06464 return NULL; 06465 } 06466 spaces_node->start = start; 06467 spaces_node->stop = stop; 06468 return spaces_node; 06469 }
| static struct ast_parkinglot* build_parkinglot | ( | const char * | pl_name, | |
| struct ast_variable * | var | |||
| ) | [static, read] |
Build parkinglot from configuration and chain it in if it doesn't already exist.
Definition at line 5982 of file features.c.
References ao2_link, ao2_lock, ao2_unlock, ast_debug, AST_LIST_EMPTY, ast_log(), ast_parkinglot::cfg, create_parkinglot(), DEFAULT_PARKINGLOT, find_parkinglot(), force_reload_load, LOG_WARNING, ast_parkinglot::name, parkinglot_config_read(), parkinglot_unref(), parkinglots, ast_parkinglot::parkings, and ast_parkinglot::the_mark.
Referenced by load_config(), and process_config().
05983 { 05984 struct ast_parkinglot *parkinglot; 05985 const struct parkinglot_cfg *cfg_defaults; 05986 struct parkinglot_cfg new_cfg; 05987 int cfg_error; 05988 int oldparkinglot = 0; 05989 05990 parkinglot = find_parkinglot(pl_name); 05991 if (parkinglot) { 05992 oldparkinglot = 1; 05993 } else { 05994 parkinglot = create_parkinglot(pl_name); 05995 if (!parkinglot) { 05996 return NULL; 05997 } 05998 } 05999 if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) { 06000 cfg_defaults = &parkinglot_cfg_default_default; 06001 } else { 06002 cfg_defaults = &parkinglot_cfg_default; 06003 } 06004 new_cfg = *cfg_defaults; 06005 06006 ast_debug(1, "Building parking lot %s\n", parkinglot->name); 06007 06008 ao2_lock(parkinglot); 06009 06010 /* Do some config stuff */ 06011 cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var); 06012 if (oldparkinglot) { 06013 if (cfg_error) { 06014 /* Bad configuration read. Keep using the original config. */ 06015 ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n", 06016 parkinglot->name); 06017 cfg_error = 0; 06018 } else if (!AST_LIST_EMPTY(&parkinglot->parkings) 06019 && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) { 06020 /* Try reloading later when parking lot is empty. */ 06021 ast_log(LOG_WARNING, 06022 "Parking lot %s has parked calls. Parking lot changes discarded.\n", 06023 parkinglot->name); 06024 force_reload_load = 1; 06025 } else { 06026 /* Accept the new config */ 06027 parkinglot->cfg = new_cfg; 06028 } 06029 } else { 06030 /* Load the initial parking lot config. */ 06031 parkinglot->cfg = new_cfg; 06032 } 06033 parkinglot->the_mark = 0; 06034 06035 ao2_unlock(parkinglot); 06036 06037 if (cfg_error) { 06038 /* Only new parking lots could have config errors here. */ 06039 ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name); 06040 parkinglot_unref(parkinglot); 06041 return NULL; 06042 } 06043 06044 /* Move it into the list, if it wasn't already there */ 06045 if (!oldparkinglot) { 06046 ao2_link(parkinglots, parkinglot); 06047 } 06048 parkinglot_unref(parkinglot); 06049 06050 return parkinglot; 06051 }
| 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 2672 of file features.c.
References add_features_datastore(), ast_app_dtget(), ast_autoservice_chan_hangup_peer(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_calloc, AST_CEL_ATTENDEDTRANSFER, ast_cel_report_event(), ast_channel_alloc, ast_channel_caller(), ast_channel_connected(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_context(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_flags(), ast_channel_language(), ast_channel_linkedid(), ast_channel_lock, ast_channel_masquerade(), ast_channel_name(), ast_channel_nativeformats(), ast_channel_priority(), ast_channel_readformat(), ast_channel_state_set(), ast_channel_unlock, ast_channel_update_connected_line(), ast_channel_visible_indication_set(), ast_channel_writeformat(), 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_format_copy(), 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, ast_bridge_thread_obj::bconfig, bridge_call_thread_launch(), ast_bridge_thread_obj::chan, check_compat(), ast_datastore::data, dial_features_info, ast_bridge_config::end_bridge_callback_data_fixup, feature_request_and_dial(), ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), get_parking_exten(), LOG_WARNING, ast_dial_features::my_features, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_bridge_thread_obj::peer, ast_dial_features::peer_features, real_ctx(), set_peers(), ast_party_connected_line::source, strsep(), transferdigittimeout, xfer_park_call_helper(), xferfailsound, and xfersound.
02673 { 02674 struct ast_channel *transferer;/* Party B */ 02675 struct ast_channel *transferee;/* Party A */ 02676 struct ast_exten *park_exten; 02677 const char *chan1_attended_sound; 02678 const char *chan2_attended_sound; 02679 const char *transferer_real_context; 02680 char xferto[256] = ""; 02681 int res; 02682 int outstate=0; 02683 struct ast_channel *newchan; 02684 struct ast_channel *xferchan; 02685 struct ast_bridge_thread_obj *tobj; 02686 struct ast_bridge_config bconfig; 02687 int l; 02688 struct ast_party_connected_line connected_line; 02689 struct ast_datastore *features_datastore; 02690 struct ast_dial_features *dialfeatures; 02691 char *transferer_tech; 02692 char *transferer_name; 02693 char *transferer_name_orig; 02694 char *dash; 02695 02696 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", ast_channel_name(chan), ast_channel_name(peer), sense); 02697 set_peers(&transferer, &transferee, peer, chan, sense); 02698 transferer_real_context = real_ctx(transferer, transferee); 02699 02700 /* Start autoservice on transferee while we talk to the transferer */ 02701 ast_autoservice_start(transferee); 02702 ast_indicate(transferee, AST_CONTROL_HOLD); 02703 02704 /* Transfer */ 02705 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02706 if (res < 0) { 02707 finishup(transferee); 02708 return -1; 02709 } 02710 if (res > 0) { /* If they've typed a digit already, handle it */ 02711 xferto[0] = (char) res; 02712 } 02713 02714 /* this is specific of atxfer */ 02715 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02716 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02717 finishup(transferee); 02718 return -1; 02719 } 02720 l = strlen(xferto); 02721 if (res == 0) { 02722 if (l) { 02723 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02724 xferto, transferer_real_context); 02725 } else { 02726 /* Does anyone care about this case? */ 02727 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n"); 02728 } 02729 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02730 finishup(transferee); 02731 return AST_FEATURE_RETURN_SUCCESS; 02732 } 02733 02734 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02735 if (park_exten) { 02736 /* We are transfering the transferee to a parking lot. */ 02737 return xfer_park_call_helper(transferee, transferer, park_exten); 02738 } 02739 02740 /* 02741 * Append context to dialed transfer number. 02742 * 02743 * NOTE: The local channel needs the /n flag so party C will use 02744 * the feature flags set by the dialplan when calling that 02745 * party. 02746 */ 02747 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); 02748 02749 /* If we are performing an attended transfer and we have two channels involved then 02750 copy sound file information to play upon attended transfer completion */ 02751 chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02752 chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02753 if (!ast_strlen_zero(chan1_attended_sound)) { 02754 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 02755 } 02756 if (!ast_strlen_zero(chan2_attended_sound)) { 02757 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 02758 } 02759 02760 /* Extract redial transferer information from the channel name. */ 02761 transferer_name_orig = ast_strdupa(ast_channel_name(transferer)); 02762 transferer_name = ast_strdupa(transferer_name_orig); 02763 transferer_tech = strsep(&transferer_name, "/"); 02764 dash = strrchr(transferer_name, '-'); 02765 if (dash) { 02766 /* Trim off channel name sequence/serial number. */ 02767 *dash = '\0'; 02768 } 02769 02770 /* Stop autoservice so we can monitor all parties involved in the transfer. */ 02771 if (ast_autoservice_stop(transferee) < 0) { 02772 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02773 return -1; 02774 } 02775 02776 /* Save connected line info for party B about party A in case transfer fails. */ 02777 ast_party_connected_line_init(&connected_line); 02778 ast_channel_lock(transferer); 02779 ast_party_connected_line_copy(&connected_line, ast_channel_connected(transferer)); 02780 ast_channel_unlock(transferer); 02781 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02782 02783 /* Dial party C */ 02784 newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer, 02785 transferee, "Local", ast_channel_nativeformats(transferer), xferto, 02786 atxfernoanswertimeout, &outstate, ast_channel_language(transferer)); 02787 ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate); 02788 02789 if (!ast_check_hangup(transferer)) { 02790 int hangup_dont = 0; 02791 02792 /* Transferer (party B) is up */ 02793 ast_debug(1, "Actually doing an attended transfer.\n"); 02794 02795 /* Start autoservice on transferee while the transferer deals with party C. */ 02796 ast_autoservice_start(transferee); 02797 02798 ast_indicate(transferer, -1); 02799 if (!newchan) { 02800 /* any reason besides user requested cancel and busy triggers the failed sound */ 02801 switch (outstate) { 02802 case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */ 02803 case AST_CONTROL_BUSY: 02804 case AST_CONTROL_CONGESTION: 02805 if (ast_stream_and_wait(transferer, xfersound, "")) { 02806 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02807 } 02808 break; 02809 default: 02810 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02811 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02812 } 02813 break; 02814 } 02815 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02816 return AST_FEATURE_RETURN_SUCCESS; 02817 } 02818 02819 if (check_compat(transferer, newchan)) { 02820 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02821 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02822 } 02823 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02824 return AST_FEATURE_RETURN_SUCCESS; 02825 } 02826 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 02827 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 02828 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 02829 02830 /* 02831 * ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we 02832 * don't want that to happen here because the transferer is in 02833 * another bridge already. 02834 */ 02835 if (ast_test_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT)) { 02836 hangup_dont = 1; 02837 } 02838 02839 /* 02840 * Don't let the after-bridge code run the h-exten. It is the 02841 * wrong bridge to run the h-exten after. 02842 */ 02843 ast_set_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT); 02844 02845 /* 02846 * Let party B and C talk as long as they want while party A 02847 * languishes in autoservice listening to MOH. 02848 */ 02849 ast_bridge_call(transferer, newchan, &bconfig); 02850 02851 if (hangup_dont) { 02852 /* Restore the AST_FLAG_BRIDGE_HANGUP_DONT flag */ 02853 ast_set_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT); 02854 } 02855 02856 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 02857 ast_autoservice_chan_hangup_peer(transferer, newchan); 02858 if (ast_stream_and_wait(transferer, xfersound, "")) { 02859 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02860 } 02861 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02862 return AST_FEATURE_RETURN_SUCCESS; 02863 } 02864 02865 /* Transferer (party B) is confirmed hung up at this point. */ 02866 if (check_compat(transferee, newchan)) { 02867 finishup(transferee); 02868 ast_party_connected_line_free(&connected_line); 02869 return -1; 02870 } 02871 02872 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02873 if ((ast_autoservice_stop(transferee) < 0) 02874 || (ast_waitfordigit(transferee, 100) < 0) 02875 || (ast_waitfordigit(newchan, 100) < 0) 02876 || ast_check_hangup(transferee) 02877 || ast_check_hangup(newchan)) { 02878 ast_hangup(newchan); 02879 ast_party_connected_line_free(&connected_line); 02880 return -1; 02881 } 02882 } else if (!ast_check_hangup(transferee)) { 02883 /* Transferer (party B) has hung up at this point. Doing blonde transfer. */ 02884 ast_debug(1, "Actually doing a blonde transfer.\n"); 02885 02886 if (!newchan && !atxferdropcall) { 02887 /* Party C is not available, try to call party B back. */ 02888 unsigned int tries = 0; 02889 02890 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 02891 ast_log(LOG_WARNING, 02892 "Transferer channel name: '%s' cannot be used for callback.\n", 02893 transferer_name_orig); 02894 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02895 ast_party_connected_line_free(&connected_line); 02896 return -1; 02897 } 02898 02899 tries = 0; 02900 for (;;) { 02901 /* Try to get party B back. */ 02902 ast_debug(1, "We're trying to callback %s/%s\n", 02903 transferer_tech, transferer_name); 02904 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02905 transferee, transferee, transferer_tech, 02906 ast_channel_nativeformats(transferee), transferer_name, 02907 atxfernoanswertimeout, &outstate, ast_channel_language(transferer)); 02908 ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n", 02909 !!newchan, outstate); 02910 if (newchan) { 02911 /* 02912 * We have recalled party B (newchan). We need to give this 02913 * call leg the same feature flags as the original party B call 02914 * leg. 02915 */ 02916 ast_channel_lock(transferer); 02917 features_datastore = ast_channel_datastore_find(transferer, 02918 &dial_features_info, NULL); 02919 if (features_datastore && (dialfeatures = features_datastore->data)) { 02920 struct ast_flags my_features = { 0 }; 02921 struct ast_flags peer_features = { 0 }; 02922 02923 ast_copy_flags(&my_features, &dialfeatures->my_features, 02924 AST_FLAGS_ALL); 02925 ast_copy_flags(&peer_features, &dialfeatures->peer_features, 02926 AST_FLAGS_ALL); 02927 ast_channel_unlock(transferer); 02928 add_features_datastore(newchan, &my_features, &peer_features); 02929 } else { 02930 ast_channel_unlock(transferer); 02931 } 02932 break; 02933 } 02934 if (ast_check_hangup(transferee)) { 02935 break; 02936 } 02937 02938 ++tries; 02939 if (atxfercallbackretries <= tries) { 02940 /* No more callback tries remaining. */ 02941 break; 02942 } 02943 02944 if (atxferloopdelay) { 02945 /* Transfer failed, sleeping */ 02946 ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n", 02947 atxferloopdelay); 02948 ast_safe_sleep(transferee, atxferloopdelay); 02949 if (ast_check_hangup(transferee)) { 02950 ast_party_connected_line_free(&connected_line); 02951 return -1; 02952 } 02953 } 02954 02955 /* Retry dialing party C. */ 02956 ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto); 02957 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02958 transferer, transferee, "Local", 02959 ast_channel_nativeformats(transferee), xferto, 02960 atxfernoanswertimeout, &outstate, ast_channel_language(transferer)); 02961 ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n", 02962 !!newchan, outstate); 02963 if (newchan || ast_check_hangup(transferee)) { 02964 break; 02965 } 02966 } 02967 } 02968 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02969 if (!newchan) { 02970 /* No party C or could not callback party B. */ 02971 ast_party_connected_line_free(&connected_line); 02972 return -1; 02973 } 02974 02975 /* newchan is up, we should prepare transferee and bridge them */ 02976 if (ast_check_hangup(newchan)) { 02977 ast_autoservice_chan_hangup_peer(transferee, newchan); 02978 ast_party_connected_line_free(&connected_line); 02979 return -1; 02980 } 02981 if (check_compat(transferee, newchan)) { 02982 ast_party_connected_line_free(&connected_line); 02983 return -1; 02984 } 02985 } else { 02986 /* 02987 * Both the transferer and transferee have hungup. If newchan 02988 * is up, hang it up as it has no one to talk to. 02989 */ 02990 ast_debug(1, "Everyone is hungup.\n"); 02991 if (newchan) { 02992 ast_hangup(newchan); 02993 } 02994 ast_party_connected_line_free(&connected_line); 02995 return -1; 02996 } 02997 02998 /* Initiate the channel transfer of party A to party C (or recalled party B). */ 02999 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan); 03000 03001 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(transferee), 0, "Transfered/%s", ast_channel_name(transferee)); 03002 if (!xferchan) { 03003 ast_autoservice_chan_hangup_peer(transferee, newchan); 03004 ast_party_connected_line_free(&connected_line); 03005 return -1; 03006 } 03007 03008 /* Give party A a momentary ringback tone during transfer. */ 03009 ast_channel_visible_indication_set(xferchan, AST_CONTROL_RINGING); 03010 03011 /* Make formats okay */ 03012 ast_format_copy(ast_channel_readformat(xferchan), ast_channel_readformat(transferee)); 03013 ast_format_copy(ast_channel_writeformat(xferchan), ast_channel_writeformat(transferee)); 03014 03015 if (ast_channel_masquerade(xferchan, transferee)) { 03016 ast_hangup(xferchan); 03017 ast_autoservice_chan_hangup_peer(transferee, newchan); 03018 ast_party_connected_line_free(&connected_line); 03019 return -1; 03020 } 03021 ast_explicit_goto(xferchan, ast_channel_context(transferee), ast_channel_exten(transferee), ast_channel_priority(transferee)); 03022 ast_channel_state_set(xferchan, AST_STATE_UP); 03023 ast_clear_flag(ast_channel_flags(xferchan), AST_FLAGS_ALL); 03024 03025 /* Do the masquerade manually to make sure that is is completed. */ 03026 ast_do_masquerade(xferchan); 03027 03028 ast_channel_state_set(newchan, AST_STATE_UP); 03029 ast_clear_flag(ast_channel_flags(newchan), AST_FLAGS_ALL); 03030 tobj = ast_calloc(1, sizeof(*tobj)); 03031 if (!tobj) { 03032 ast_hangup(xferchan); 03033 ast_hangup(newchan); 03034 ast_party_connected_line_free(&connected_line); 03035 return -1; 03036 } 03037 03038 tobj->chan = newchan; 03039 tobj->peer = xferchan; 03040 tobj->bconfig = *config; 03041 03042 ast_channel_lock(newchan); 03043 features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL); 03044 if (features_datastore && (dialfeatures = features_datastore->data)) { 03045 ast_copy_flags(&tobj->bconfig.features_callee, &dialfeatures->my_features, 03046 AST_FLAGS_ALL); 03047 } 03048 ast_channel_unlock(newchan); 03049 03050 ast_channel_lock(xferchan); 03051 features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL); 03052 if (features_datastore && (dialfeatures = features_datastore->data)) { 03053 ast_copy_flags(&tobj->bconfig.features_caller, &dialfeatures->my_features, 03054 AST_FLAGS_ALL); 03055 } 03056 ast_channel_unlock(xferchan); 03057 03058 if (tobj->bconfig.end_bridge_callback_data_fixup) { 03059 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 03060 } 03061 03062 /* 03063 * xferchan is transferee, and newchan is the transfer target 03064 * So...in a transfer, who is the caller and who is the callee? 03065 * 03066 * When the call is originally made, it is clear who is caller and callee. 03067 * When a transfer occurs, it is my humble opinion that the transferee becomes 03068 * the caller, and the transfer target is the callee. 03069 * 03070 * The problem is that these macros were set with the intention of the original 03071 * caller and callee taking those roles. A transfer can totally mess things up, 03072 * to be technical. What sucks even more is that you can't effectively change 03073 * the macros in the dialplan during the call from the transferer to the transfer 03074 * target because the transferee is stuck with whatever role he originally had. 03075 * 03076 * I think the answer here is just to make sure that it is well documented that 03077 * during a transfer, the transferee is the "caller" and the transfer target 03078 * is the "callee." 03079 * 03080 * This means that if party B calls party A, and party B transfers party A to 03081 * party C, then A has switched roles for the call. Now party A will have the 03082 * caller macro called on his channel instead of the callee macro. 03083 * 03084 * Luckily, the method by which the party B to party C bridge is 03085 * launched above ensures that the transferee is the "chan" on 03086 * the bridge and the transfer target is the "peer," so my idea 03087 * for the roles post-transfer does not require extensive code 03088 * changes. 03089 */ 03090 03091 /* Transfer party C connected line to party A */ 03092 ast_channel_lock(transferer); 03093 /* 03094 * Due to a limitation regarding when callerID is set on a Local channel, 03095 * we use the transferer's connected line information here. 03096 */ 03097 ast_party_connected_line_copy(&connected_line, ast_channel_connected(transferer)); 03098 ast_channel_unlock(transferer); 03099 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 03100 if (ast_channel_connected_line_sub(newchan, xferchan, &connected_line, 0) && 03101 ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { 03102 ast_channel_update_connected_line(xferchan, &connected_line, NULL); 03103 } 03104 03105 /* Transfer party A connected line to party C */ 03106 ast_channel_lock(xferchan); 03107 ast_connected_line_copy_from_caller(&connected_line, ast_channel_caller(xferchan)); 03108 ast_channel_unlock(xferchan); 03109 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 03110 if (ast_channel_connected_line_sub(xferchan, newchan, &connected_line, 0) && 03111 ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { 03112 ast_channel_update_connected_line(newchan, &connected_line, NULL); 03113 } 03114 03115 if (ast_stream_and_wait(newchan, xfersound, "")) 03116 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 03117 bridge_call_thread_launch(tobj); 03118 03119 ast_party_connected_line_free(&connected_line); 03120 return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */ 03121 }
| 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 2357 of file features.c.
References args, ast_alloca, 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_caller(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, AST_FEATURE_RETURN_SUCCESS, AST_FRAME_DTMF_END, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, courtesytone, LOG_ERROR, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_COR, S_OR, set_peers(), stopmixmonitor_app, and stopmixmonitor_ok.
02358 { 02359 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02360 int x = 0; 02361 size_t len; 02362 struct ast_channel *caller_chan, *callee_chan; 02363 const char *mixmonitor_spy_type = "MixMonitor"; 02364 const char *touch_format; 02365 const char *touch_monitor; 02366 int count = 0; 02367 02368 if (!mixmonitor_ok) { 02369 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02370 return -1; 02371 } 02372 02373 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 02374 mixmonitor_ok = 0; 02375 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02376 return -1; 02377 } 02378 02379 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02380 02381 if (!ast_strlen_zero(courtesytone)) { 02382 if (ast_autoservice_start(callee_chan)) 02383 return -1; 02384 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END); 02385 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 02386 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02387 ast_autoservice_stop(callee_chan); 02388 return -1; 02389 } 02390 if (ast_autoservice_stop(callee_chan)) 02391 return -1; 02392 } 02393 02394 ast_channel_lock(callee_chan); 02395 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02396 ast_channel_unlock(callee_chan); 02397 02398 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 02399 if (count > 0) { 02400 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 02401 02402 /* Make sure they are running */ 02403 ast_channel_lock(callee_chan); 02404 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02405 ast_channel_unlock(callee_chan); 02406 if (count > 0) { 02407 if (!stopmixmonitor_ok) { 02408 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02409 return -1; 02410 } 02411 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 02412 stopmixmonitor_ok = 0; 02413 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02414 return -1; 02415 } else { 02416 pbx_exec(callee_chan, stopmixmonitor_app, ""); 02417 return AST_FEATURE_RETURN_SUCCESS; 02418 } 02419 } 02420 02421 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 02422 } 02423 02424 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 02425 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 02426 02427 if (!touch_format) 02428 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 02429 02430 if (!touch_monitor) 02431 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 02432 02433 if (touch_monitor) { 02434 len = strlen(touch_monitor) + 50; 02435 args = ast_alloca(len); 02436 touch_filename = ast_alloca(len); 02437 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 02438 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 02439 } else { 02440 caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(caller_chan)->id.number.valid, 02441 ast_channel_caller(caller_chan)->id.number.str, ast_channel_name(caller_chan))); 02442 callee_chan_id = ast_strdupa(S_COR(ast_channel_caller(callee_chan)->id.number.valid, 02443 ast_channel_caller(callee_chan)->id.number.str, ast_channel_name(callee_chan))); 02444 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02445 args = ast_alloca(len); 02446 touch_filename = ast_alloca(len); 02447 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 02448 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 02449 } 02450 02451 for( x = 0; x < strlen(args); x++) { 02452 if (args[x] == '/') 02453 args[x] = '-'; 02454 } 02455 02456 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 02457 02458 pbx_exec(callee_chan, mixmonitor_app, args); 02459 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02460 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02461 return AST_FEATURE_RETURN_SUCCESS; 02462 }
| 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 2264 of file features.c.
References args, ast_alloca, ast_channel_caller(), ast_channel_monitor(), ast_channel_name(), AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, courtesytone, LOG_ERROR, monitor_app, monitor_ok, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_COR, S_OR, set_peers(), and ast_channel_monitor::stop.
02265 { 02266 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02267 int x = 0; 02268 size_t len; 02269 struct ast_channel *caller_chan, *callee_chan; 02270 const char *automon_message_start = NULL; 02271 const char *automon_message_stop = NULL; 02272 const char *touch_format = NULL; 02273 const char *touch_monitor = NULL; 02274 const char *touch_monitor_prefix = NULL; 02275 02276 if (!monitor_ok) { 02277 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02278 return -1; 02279 } 02280 02281 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 02282 monitor_ok = 0; 02283 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02284 return -1; 02285 } 02286 02287 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02288 02289 /* Find extra messages */ 02290 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 02291 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 02292 02293 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 02294 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 02295 return -1; 02296 } 02297 } 02298 02299 if (ast_channel_monitor(callee_chan)) { 02300 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 02301 if (!ast_strlen_zero(automon_message_stop)) { 02302 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 02303 } 02304 ast_channel_monitor(callee_chan)->stop(callee_chan, 1); 02305 return AST_FEATURE_RETURN_SUCCESS; 02306 } 02307 02308 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 02309 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 02310 touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 02311 02312 if (!touch_format) 02313 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 02314 02315 if (!touch_monitor) 02316 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 02317 02318 if (!touch_monitor_prefix) 02319 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 02320 02321 if (touch_monitor) { 02322 len = strlen(touch_monitor) + 50; 02323 args = ast_alloca(len); 02324 touch_filename = ast_alloca(len); 02325 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 02326 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02327 } else { 02328 caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(caller_chan)->id.number.valid, 02329 ast_channel_caller(caller_chan)->id.number.str, ast_channel_name(caller_chan))); 02330 callee_chan_id = ast_strdupa(S_COR(ast_channel_caller(callee_chan)->id.number.valid, 02331 ast_channel_caller(callee_chan)->id.number.str, ast_channel_name(callee_chan))); 02332 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02333 args = ast_alloca(len); 02334 touch_filename = ast_alloca(len); 02335 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 02336 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02337 } 02338 02339 for(x = 0; x < strlen(args); x++) { 02340 if (args[x] == '/') 02341 args[x] = '-'; 02342 } 02343 02344 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 02345 02346 pbx_exec(callee_chan, monitor_app, args); 02347 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02348 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02349 02350 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 02351 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 02352 } 02353 02354 return AST_FEATURE_RETURN_SUCCESS; 02355 }
| 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 2507 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_cdr(), ast_channel_cdr_set(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_pbx(), 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_strdupa, ast_stream_and_wait(), ast_verb, ast_cdr::channel, check_goto_on_transfer(), ast_cdr::dstchannel, finishup(), get_parking_exten(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, pbx_builtin_setvar_helper(), real_ctx(), set_peers(), transferdigittimeout, and xfer_park_call_helper().
02508 { 02509 struct ast_channel *transferer; 02510 struct ast_channel *transferee; 02511 struct ast_exten *park_exten; 02512 const char *transferer_real_context; 02513 char xferto[256] = ""; 02514 int res; 02515 02516 ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", ast_channel_name(chan), ast_channel_name(peer), sense); 02517 set_peers(&transferer, &transferee, peer, chan, sense); 02518 transferer_real_context = ast_strdupa(real_ctx(transferer, transferee)); 02519 02520 /* Start autoservice on transferee while we talk to the transferer */ 02521 ast_autoservice_start(transferee); 02522 ast_indicate(transferee, AST_CONTROL_HOLD); 02523 02524 /* Transfer */ 02525 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02526 if (res < 0) { 02527 finishup(transferee); 02528 return -1; /* error ? */ 02529 } 02530 if (res > 0) { /* If they've typed a digit already, handle it */ 02531 xferto[0] = (char) res; 02532 } 02533 02534 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02535 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02536 finishup(transferee); 02537 return -1; 02538 } 02539 if (res == 0) { 02540 if (xferto[0]) { 02541 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02542 xferto, transferer_real_context); 02543 } else { 02544 /* Does anyone care about this case? */ 02545 ast_log(LOG_WARNING, "No digits dialed.\n"); 02546 } 02547 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02548 finishup(transferee); 02549 return AST_FEATURE_RETURN_SUCCESS; 02550 } 02551 02552 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02553 if (park_exten) { 02554 /* We are transfering the transferee to a parking lot. */ 02555 return xfer_park_call_helper(transferee, transferer, park_exten); 02556 } 02557 02558 /* Do blind transfer. */ 02559 ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n", 02560 ast_channel_name(transferee), xferto, transferer_real_context); 02561 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee); 02562 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", ast_channel_name(transferee)); 02563 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", ast_channel_name(transferer)); 02564 finishup(transferee); 02565 ast_channel_lock(transferer); 02566 if (!ast_channel_cdr(transferer)) { 02567 /* this code should never get called (in a perfect world) */ 02568 ast_channel_cdr_set(transferer, ast_cdr_alloc()); 02569 if (ast_channel_cdr(transferer)) { 02570 ast_cdr_init(ast_channel_cdr(transferer), transferer); /* initialize our channel's cdr */ 02571 ast_cdr_start(ast_channel_cdr(transferer)); 02572 } 02573 } 02574 ast_channel_unlock(transferer); 02575 if (ast_channel_cdr(transferer)) { 02576 struct ast_cdr *swap = ast_channel_cdr(transferer); 02577 02578 ast_debug(1, 02579 "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 02580 ast_channel_name(transferer), ast_channel_name(transferee), ast_channel_cdr(transferer)->lastapp, 02581 ast_channel_cdr(transferer)->lastdata, ast_channel_cdr(transferer)->channel, 02582 ast_channel_cdr(transferer)->dstchannel); 02583 ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 02584 ast_channel_cdr(transferee)->lastapp, ast_channel_cdr(transferee)->lastdata, ast_channel_cdr(transferee)->channel, 02585 ast_channel_cdr(transferee)->dstchannel); 02586 ast_debug(1, "transferer_real_context=%s; xferto=%s\n", 02587 transferer_real_context, xferto); 02588 /* swap cdrs-- it will save us some time & work */ 02589 ast_channel_cdr_set(transferer, ast_channel_cdr(transferee)); 02590 ast_channel_cdr_set(transferee, swap); 02591 } 02592 02593 res = ast_channel_pbx(transferee) ? AST_FEATURE_RETURN_SUCCESSBREAK : -1; 02594 02595 /* Doh! Use our handy async_goto functions */ 02596 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) { 02597 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 02598 res = -1; 02599 } else if (res == AST_FEATURE_RETURN_SUCCESSBREAK) { 02600 /* Don't let the after-bridge code run the h-exten */ 02601 ast_channel_lock(transferee); 02602 ast_set_flag(ast_channel_flags(transferee), AST_FLAG_BRIDGE_HANGUP_DONT); 02603 ast_channel_unlock(transferee); 02604 } 02605 check_goto_on_transfer(transferer); 02606 return res; 02607 }
| 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 2464 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
02465 { 02466 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 02467 return AST_FEATURE_RETURN_HANGUP; 02468 }
| static int builtin_feature_get_exten | ( | struct ast_channel * | chan, | |
| const char * | feature_name, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 3423 of file features.c.
References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_find_call_feature(), ast_rdlock_call_features(), ast_unlock_call_features(), feature_exten::exten, ast_call_feature::exten, feature_ds::feature_map, get_feature_ds(), and OBJ_KEY.
Referenced by feature_interpret_helper(), and featuremap_read().
03425 { 03426 struct ast_call_feature *feature; 03427 struct feature_ds *feature_ds; 03428 struct feature_exten *fe = NULL; 03429 03430 *buf = '\0'; 03431 03432 if (!(feature = ast_find_call_feature(feature_name))) { 03433 return -1; 03434 } 03435 03436 ast_copy_string(buf, feature->exten, len); 03437 03438 ast_unlock_call_features(); 03439 03440 ast_channel_lock(chan); 03441 if ((feature_ds = get_feature_ds(chan))) { 03442 fe = ao2_find(feature_ds->feature_map, feature_name, OBJ_KEY); 03443 } 03444 ast_channel_unlock(chan); 03445 03446 ast_rdlock_call_features(); 03447 03448 if (fe) { 03449 ao2_lock(fe); 03450 ast_copy_string(buf, fe->exten, len); 03451 ao2_unlock(fe); 03452 ao2_ref(fe, -1); 03453 fe = NULL; 03454 } 03455 03456 return 0; 03457 }
| 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 2142 of file features.c.
References ast_answer(), AST_FEATURE_RETURN_SUCCESS, ast_safe_sleep(), AST_STATE_UP, masq_park_call(), and set_peers().
02143 { 02144 struct ast_channel *parker; 02145 struct ast_channel *parkee; 02146 struct ast_park_call_args args = { 0, }; 02147 02148 /* 02149 * We used to set chan's exten and priority to "s" and 1 here, 02150 * but this generates (in some cases) an invalid extension, and 02151 * if "s" exists, could errantly cause execution of extensions 02152 * you don't expect. It makes more sense to let nature take its 02153 * course when chan finishes, and let the pbx do its thing and 02154 * hang up when the park is over. 02155 */ 02156 02157 /* Answer if call is not up */ 02158 if (ast_channel_state(chan) != AST_STATE_UP) { 02159 /* 02160 * XXX Why are we doing this? Both of the channels should be up 02161 * since you cannot do DTMF features unless you are bridged. 02162 */ 02163 if (ast_answer(chan)) { 02164 return -1; 02165 } 02166 02167 /* Sleep to allow VoIP streams to settle down */ 02168 if (ast_safe_sleep(chan, 1000)) { 02169 return -1; 02170 } 02171 } 02172 02173 /* one direction used to call park_call.... */ 02174 set_peers(&parker, &parkee, peer, chan, sense); 02175 return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1; 02176 }
| static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
| struct ast_flags * | features_caller, | |||
| char * | options, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 4910 of file features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_test_flag, OPT_CALLEE_AUTOMON, and OPT_CALLER_AUTOMON.
Referenced by manage_parked_call().
04911 { 04912 int i = 0; 04913 enum { 04914 OPT_CALLEE_REDIRECT = 't', 04915 OPT_CALLER_REDIRECT = 'T', 04916 OPT_CALLEE_AUTOMON = 'w', 04917 OPT_CALLER_AUTOMON = 'W', 04918 OPT_CALLEE_DISCONNECT = 'h', 04919 OPT_CALLER_DISCONNECT = 'H', 04920 OPT_CALLEE_PARKCALL = 'k', 04921 OPT_CALLER_PARKCALL = 'K', 04922 }; 04923 04924 memset(options, 0, len); 04925 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 04926 options[i++] = OPT_CALLER_REDIRECT; 04927 } 04928 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 04929 options[i++] = OPT_CALLER_AUTOMON; 04930 } 04931 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 04932 options[i++] = OPT_CALLER_DISCONNECT; 04933 } 04934 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 04935 options[i++] = OPT_CALLER_PARKCALL; 04936 } 04937 04938 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 04939 options[i++] = OPT_CALLEE_REDIRECT; 04940 } 04941 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 04942 options[i++] = OPT_CALLEE_AUTOMON; 04943 } 04944 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 04945 options[i++] = OPT_CALLEE_DISCONNECT; 04946 } 04947 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 04948 options[i++] = OPT_CALLEE_PARKCALL; 04949 } 04950 04951 return options; 04952 }
| 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 2616 of file features.c.
References ast_autoservice_chan_hangup_peer(), ast_channel_make_compatible(), ast_channel_name(), ast_log(), and LOG_WARNING.
Referenced by builtin_atxfer().
02617 { 02618 if (ast_channel_make_compatible(c, newchan) < 0) { 02619 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 02620 ast_channel_name(c), ast_channel_name(newchan)); 02621 ast_autoservice_chan_hangup_peer(c, newchan); 02622 return -1; 02623 } 02624 return 0; 02625 }
| 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 1034 of file features.c.
References ast_channel_alloc, ast_channel_clear_softhangup(), ast_channel_flags(), ast_channel_linkedid(), ast_channel_lock, ast_channel_masquerade(), ast_channel_name(), ast_channel_readformat(), ast_channel_state_set(), ast_channel_unlock, ast_channel_writeformat(), ast_clear_flag, ast_debug, ast_do_masquerade(), AST_FLAGS_ALL, ast_format_copy(), ast_hangup(), ast_parseable_goto(), ast_pbx_start(), AST_SOFTHANGUP_ALL, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), and pbx_builtin_getvar_helper().
Referenced by builtin_blindtransfer().
01035 { 01036 struct ast_channel *xferchan; 01037 const char *val; 01038 char *goto_on_transfer; 01039 char *x; 01040 01041 ast_channel_lock(chan); 01042 val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 01043 if (ast_strlen_zero(val)) { 01044 ast_channel_unlock(chan); 01045 return; 01046 } 01047 goto_on_transfer = ast_strdupa(val); 01048 ast_channel_unlock(chan); 01049 01050 ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, ast_channel_name(chan)); 01051 01052 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(chan), 0, 01053 "%s", ast_channel_name(chan)); 01054 if (!xferchan) { 01055 return; 01056 } 01057 01058 /* Make formats okay */ 01059 ast_format_copy(ast_channel_readformat(xferchan), ast_channel_readformat(chan)); 01060 ast_format_copy(ast_channel_writeformat(xferchan), ast_channel_writeformat(chan)); 01061 01062 if (ast_channel_masquerade(xferchan, chan)) { 01063 /* Failed to setup masquerade. */ 01064 ast_hangup(xferchan); 01065 return; 01066 } 01067 01068 for (x = goto_on_transfer; *x; ++x) { 01069 if (*x == '^') { 01070 *x = ','; 01071 } 01072 } 01073 ast_parseable_goto(xferchan, goto_on_transfer); 01074 ast_channel_state_set(xferchan, AST_STATE_UP); 01075 ast_clear_flag(ast_channel_flags(xferchan), AST_FLAGS_ALL); 01076 ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL); 01077 01078 ast_do_masquerade(xferchan); 01079 if (ast_pbx_start(xferchan)) { 01080 /* Failed to start PBX. */ 01081 ast_hangup(xferchan); 01082 } 01083 }
| static void clear_dialed_interfaces | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 4222 of file features.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_datastore_free(), ast_log(), dialed_interface_info, LOG_DEBUG, and option_debug.
Referenced by ast_bridge_call().
04223 { 04224 struct ast_datastore *di_datastore; 04225 04226 ast_channel_lock(chan); 04227 if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) { 04228 if (option_debug) { 04229 ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", ast_channel_name(chan)); 04230 } 04231 if (!ast_channel_datastore_remove(chan, di_datastore)) { 04232 ast_datastore_free(di_datastore); 04233 } 04234 } 04235 ast_channel_unlock(chan); 04236 }
| static struct ast_parkinglot * copy_parkinglot | ( | const char * | name, | |
| const struct ast_parkinglot * | parkinglot | |||
| ) | [static, read] |
Copy parkinglot and store it with new name.
Definition at line 5285 of file features.c.
References ao2_ref, ast_debug, ast_parkinglot::cfg, create_parkinglot(), and find_parkinglot().
Referenced by create_dynamic_parkinglot().
05286 { 05287 struct ast_parkinglot *copylot; 05288 05289 if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */ 05290 ao2_ref(copylot, -1); 05291 return NULL; 05292 } 05293 05294 copylot = create_parkinglot(name); 05295 if (!copylot) { 05296 return NULL; 05297 } 05298 05299 ast_debug(1, "Building parking lot %s\n", name); 05300 05301 /* Copy the source parking lot configuration. */ 05302 copylot->cfg = parkinglot->cfg; 05303 05304 return copylot; 05305 }
| static struct ast_parkinglot* create_dynamic_parkinglot | ( | const char * | name, | |
| struct ast_channel * | chan | |||
| ) | [static, read] |
Definition at line 1315 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::parkext_exclusive, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, 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().
01316 { 01317 const char *dyn_context; 01318 const char *dyn_exten; 01319 const char *dyn_range; 01320 const char *template_name; 01321 struct ast_parkinglot *template_parkinglot = NULL; 01322 struct ast_parkinglot *parkinglot; 01323 int dyn_start; 01324 int dyn_end; 01325 01326 ast_channel_lock(chan); 01327 template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), "")); 01328 dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), "")); 01329 dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), "")); 01330 dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), "")); 01331 ast_channel_unlock(chan); 01332 01333 if (!ast_strlen_zero(template_name)) { 01334 template_parkinglot = find_parkinglot(template_name); 01335 if (!template_parkinglot) { 01336 ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n", 01337 template_name); 01338 } else if (template_parkinglot->cfg.is_invalid) { 01339 ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n", 01340 template_name); 01341 parkinglot_unref(template_parkinglot); 01342 template_parkinglot = NULL; 01343 } 01344 } 01345 if (!template_parkinglot) { 01346 template_parkinglot = parkinglot_addref(default_parkinglot); 01347 ast_debug(1, "Using default parking lot for template\n"); 01348 } 01349 01350 parkinglot = copy_parkinglot(name, template_parkinglot); 01351 if (!parkinglot) { 01352 ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n"); 01353 } else { 01354 /* Configure the dynamic parking lot. */ 01355 if (!ast_strlen_zero(dyn_context)) { 01356 ast_copy_string(parkinglot->cfg.parking_con, dyn_context, 01357 sizeof(parkinglot->cfg.parking_con)); 01358 } 01359 if (!ast_strlen_zero(dyn_exten)) { 01360 ast_copy_string(parkinglot->cfg.parkext, dyn_exten, 01361 sizeof(parkinglot->cfg.parkext)); 01362 } 01363 if (!ast_strlen_zero(dyn_range)) { 01364 if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) { 01365 ast_log(LOG_WARNING, 01366 "Format for parking positions is a-b, where a and b are numbers\n"); 01367 } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) { 01368 ast_log(LOG_WARNING, 01369 "Format for parking positions is a-b, where a <= b\n"); 01370 } else { 01371 parkinglot->cfg.parking_start = dyn_start; 01372 parkinglot->cfg.parking_stop = dyn_end; 01373 } 01374 } 01375 01376 /* 01377 * Sanity check for dynamic parking lot configuration. 01378 * 01379 * XXX It may be desirable to instead check if the dynamic 01380 * parking lot overlaps any existing lots like what is done for 01381 * a reload. 01382 */ 01383 if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) { 01384 if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext) 01385 && parkinglot->cfg.parkext_exclusive) { 01386 ast_log(LOG_WARNING, 01387 "Parking lot '%s' conflicts with template parking lot '%s'!\n" 01388 "Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n", 01389 parkinglot->name, template_parkinglot->name); 01390 } 01391 if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start 01392 && parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop) 01393 || (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop 01394 && parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop) 01395 || (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start 01396 && template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) { 01397 ast_log(LOG_WARNING, 01398 "Parking lot '%s' parking spaces overlap template parking lot '%s'!\n" 01399 "Change PARKINGDYNPOS.\n", 01400 parkinglot->name, template_parkinglot->name); 01401 } 01402 } 01403 01404 parkinglot_activate(parkinglot); 01405 ao2_link(parkinglots, parkinglot); 01406 } 01407 parkinglot_unref(template_parkinglot); 01408 01409 return parkinglot; 01410 }
| static struct ast_parkinglot * create_parkinglot | ( | const char * | name | ) | [static, read] |
Allocate parking lot structure.
Definition at line 5736 of file features.c.
References ao2_alloc, ast_copy_string(), AST_LIST_HEAD_INIT, ast_strlen_zero(), ast_parkinglot::cfg, parkinglot_cfg::is_invalid, ast_parkinglot::name, parkinglot_destroy(), and ast_parkinglot::parkings.
Referenced by build_parkinglot(), and copy_parkinglot().
05737 { 05738 struct ast_parkinglot *newlot; 05739 05740 if (ast_strlen_zero(name)) { /* No name specified */ 05741 return NULL; 05742 } 05743 05744 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 05745 if (!newlot) 05746 return NULL; 05747 05748 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 05749 newlot->cfg.is_invalid = 1;/* No config is set yet. */ 05750 AST_LIST_HEAD_INIT(&newlot->parkings); 05751 05752 return newlot; 05753 }
| static void destroy_dialplan_usage_context | ( | struct parking_dp_context * | doomed | ) | [static] |
Definition at line 6333 of file features.c.
References parking_dp_context::access_extens, ast_free, AST_LIST_REMOVE_HEAD, parking_dp_context::hints, and parking_dp_context::spaces.
Referenced by build_dialplan_useage_context(), and destroy_dialplan_usage_map().
06334 { 06335 struct parking_dp_ramp *ramp; 06336 struct parking_dp_spaces *spaces; 06337 06338 while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) { 06339 ast_free(ramp); 06340 } 06341 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) { 06342 ast_free(spaces); 06343 } 06344 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) { 06345 ast_free(spaces); 06346 } 06347 ast_free(doomed); 06348 }
| static void destroy_dialplan_usage_map | ( | struct parking_dp_map * | doomed | ) | [static] |
Definition at line 6358 of file features.c.
References AST_LIST_REMOVE_HEAD, and destroy_dialplan_usage_context().
Referenced by load_config().
06359 { 06360 struct parking_dp_context *item; 06361 06362 while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) { 06363 destroy_dialplan_usage_context(item); 06364 } 06365 }
| static void destroy_space | ( | const char * | context, | |
| int | space | |||
| ) | [static] |
Definition at line 6788 of file features.c.
References AST_MAX_EXTENSION, PRIORITY_HINT, and remove_exten_if_exist().
Referenced by remove_dead_context_usage(), and remove_dead_spaces_usage().
06789 { 06790 char exten[AST_MAX_EXTENSION]; 06791 06792 /* Destroy priorities of the parking space that we registered. */ 06793 snprintf(exten, sizeof(exten), "%d", space); 06794 remove_exten_if_exist(context, exten, PRIORITY_HINT); 06795 remove_exten_if_exist(context, exten, 1); 06796 }
| static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 881 of file features.c.
References ast_free.
00882 { 00883 struct ast_dial_features *df = data; 00884 if (df) { 00885 ast_free(df); 00886 } 00887 }
| static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 868 of file features.c.
References ast_calloc.
00869 { 00870 struct ast_dial_features *df = data, *df_copy; 00871 00872 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00873 return NULL; 00874 } 00875 00876 memcpy(df_copy, df, sizeof(*df)); 00877 00878 return df_copy; 00879 }
| static int dialplan_usage_add_parkinglot | ( | struct parking_dp_map * | usage_map, | |
| struct ast_parkinglot * | lot, | |||
| int | complain | |||
| ) | [static] |
Definition at line 6641 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(), and parkinglot_cfg::parking_con.
Referenced by build_dialplan_useage_map().
06642 { 06643 struct parking_dp_context *cur_ctx; 06644 struct parking_dp_context *new_ctx; 06645 int cmp; 06646 06647 AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) { 06648 cmp = strcmp(lot->cfg.parking_con, cur_ctx->context); 06649 if (cmp > 0) { 06650 /* The parking lot context goes after this node. */ 06651 continue; 06652 } 06653 if (cmp == 0) { 06654 /* This is the node we will add parking lot spaces to the map. */ 06655 return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain); 06656 } 06657 /* The new parking lot context goes before this node. */ 06658 new_ctx = build_dialplan_useage_context(lot); 06659 if (!new_ctx) { 06660 return -1; 06661 } 06662 AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node); 06663 return 0; 06664 } 06665 AST_LIST_TRAVERSE_SAFE_END; 06666 06667 /* New parking lot context goes on the end. */ 06668 new_ctx = build_dialplan_useage_context(lot); 06669 if (!new_ctx) { 06670 return -1; 06671 } 06672 AST_LIST_INSERT_TAIL(usage_map, new_ctx, node); 06673 return 0; 06674 }
| static int dialplan_usage_add_parkinglot_data | ( | struct parking_dp_context * | ctx_node, | |
| struct ast_parkinglot * | lot, | |||
| int | complain | |||
| ) | [static] |
Definition at line 6587 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().
06588 { 06589 if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext, 06590 lot->cfg.parkext_exclusive, lot, complain)) { 06591 return -1; 06592 } 06593 if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start, 06594 lot->cfg.parking_stop, lot, complain)) { 06595 return -1; 06596 } 06597 if (lot->cfg.parkaddhints 06598 && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start, 06599 lot->cfg.parking_stop, lot, 0)) { 06600 return -1; 06601 } 06602 return 0; 06603 }
| 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 7230 of file features.c.
References ast_channel_context(), ast_channel_exten(), ast_channel_lock_both, ast_channel_masquerade(), ast_channel_priority(), ast_channel_readformat(), ast_channel_unlock, ast_channel_writeformat(), ast_do_masquerade(), ast_explicit_goto(), ast_format_copy(), ast_moh_stop(), ast_setstate(), and ast_strdupa.
Referenced by action_bridge(), and bridge_exec().
07231 { 07232 const char *context; 07233 const char *exten; 07234 int priority; 07235 07236 ast_moh_stop(chan); 07237 ast_channel_lock_both(chan, tmpchan); 07238 context = ast_strdupa(ast_channel_context(chan)); 07239 exten = ast_strdupa(ast_channel_exten(chan)); 07240 priority = ast_channel_priority(chan); 07241 ast_setstate(tmpchan, ast_channel_state(chan)); 07242 ast_format_copy(ast_channel_readformat(tmpchan), ast_channel_readformat(chan)); 07243 ast_format_copy(ast_channel_writeformat(tmpchan), ast_channel_writeformat(chan)); 07244 ast_channel_unlock(chan); 07245 ast_channel_unlock(tmpchan); 07246 07247 /* Masquerade setup and execution must be done without any channel locks held */ 07248 if (ast_channel_masquerade(tmpchan, chan)) { 07249 return -1; 07250 } 07251 ast_do_masquerade(tmpchan); 07252 07253 /* when returning from bridge, the channel will continue at the next priority */ 07254 ast_explicit_goto(tmpchan, context, exten, priority + 1); 07255 07256 return 0; 07257 }
| static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
| ignore | unused var. |
Definition at line 5235 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().
05236 { 05237 struct pollfd *pfds = NULL, *new_pfds = NULL; 05238 int nfds = 0, new_nfds = 0; 05239 05240 for (;;) { 05241 struct ao2_iterator iter; 05242 struct ast_parkinglot *curlot; 05243 int ms = -1; /* poll2 timeout, uninitialized */ 05244 05245 iter = ao2_iterator_init(parkinglots, 0); 05246 while ((curlot = ao2_iterator_next(&iter))) { 05247 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms); 05248 ao2_ref(curlot, -1); 05249 } 05250 ao2_iterator_destroy(&iter); 05251 05252 /* Recycle */ 05253 ast_free(pfds); 05254 pfds = new_pfds; 05255 nfds = new_nfds; 05256 new_pfds = NULL; 05257 new_nfds = 0; 05258 05259 /* Wait for something to happen */ 05260 ast_poll(pfds, nfds, ms); 05261 pthread_testcancel(); 05262 } 05263 /* If this WERE reached, we'd need to free(pfds) */ 05264 return NULL; /* Never reached */ 05265 }
| static int feature_check | ( | struct ast_channel * | chan, | |
| struct ast_flags * | features, | |||
| char * | code | |||
| ) | [static] |
Check if a feature exists.
Definition at line 3731 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().
03731 { 03732 char *chan_dynamic_features; 03733 ast_channel_lock(chan); 03734 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03735 ast_channel_unlock(chan); 03736 03737 return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL); 03738 }
| static void feature_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 3341 of file features.c.
References ao2_ref, ast_free, and feature_ds::feature_map.
Referenced by get_feature_ds().
03342 { 03343 struct feature_ds *feature_ds = data; 03344 03345 if (feature_ds->feature_map) { 03346 ao2_ref(feature_ds->feature_map, -1); 03347 feature_ds->feature_map = NULL; 03348 } 03349 03350 ast_free(feature_ds); 03351 }
| 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 3468 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_channel_name(), 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_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), and ast_call_feature::sname.
Referenced by process_applicationmap_line().
03469 { 03470 struct ast_app *app; 03471 struct ast_call_feature *feature = data; 03472 struct ast_channel *work, *idle; 03473 int res; 03474 03475 if (!feature) { /* shouldn't ever happen! */ 03476 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 03477 return -1; 03478 } 03479 03480 if (sense == FEATURE_SENSE_CHAN) { 03481 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 03482 return AST_FEATURE_RETURN_KEEPTRYING; 03483 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03484 work = chan; 03485 idle = peer; 03486 } else { 03487 work = peer; 03488 idle = chan; 03489 } 03490 } else { 03491 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 03492 return AST_FEATURE_RETURN_KEEPTRYING; 03493 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03494 work = peer; 03495 idle = chan; 03496 } else { 03497 work = chan; 03498 idle = peer; 03499 } 03500 } 03501 03502 if (!(app = pbx_findapp(feature->app))) { 03503 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 03504 return -2; 03505 } 03506 03507 ast_autoservice_start(idle); 03508 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END); 03509 03510 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", ast_channel_name(idle)); 03511 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", ast_channel_name(work)); 03512 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname); 03513 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname); 03514 03515 if (!ast_strlen_zero(feature->moh_class)) 03516 ast_moh_start(idle, feature->moh_class, NULL); 03517 03518 res = pbx_exec(work, app, feature->app_args); 03519 03520 if (!ast_strlen_zero(feature->moh_class)) 03521 ast_moh_stop(idle); 03522 03523 ast_autoservice_stop(idle); 03524 03525 if (res) { 03526 return AST_FEATURE_RETURN_SUCCESSBREAK; 03527 } 03528 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 03529 }
| static int feature_exten_cmp | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 3366 of file features.c.
References CMP_MATCH, CMP_STOP, OBJ_KEY, and feature_exten::sname.
Referenced by get_feature_ds().
03367 { 03368 const struct feature_exten *fe = obj, *fe2 = arg; 03369 const char *sname = arg; 03370 03371 return !strcmp(fe->sname, flags & OBJ_KEY ? sname : fe2->sname) ? 03372 CMP_MATCH | CMP_STOP : 0; 03373 }
| static int feature_exten_hash | ( | const void * | obj, | |
| int | flags | |||
| ) | [static] |
Definition at line 3358 of file features.c.
References ast_str_hash(), OBJ_KEY, and feature_exten::sname.
Referenced by get_feature_ds().
03359 { 03360 const struct feature_exten *fe = obj; 03361 const char *sname = obj; 03362 03363 return ast_str_hash(flags & OBJ_KEY ? sname : fe->sname); 03364 }
| 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 3694 of file features.c.
References ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, FEATURE_INTERPRET_DO, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_flags::flags, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
03694 { 03695 03696 char dynamic_features_buf[128]; 03697 const char *peer_dynamic_features, *chan_dynamic_features; 03698 struct ast_flags features; 03699 struct ast_call_feature feature; 03700 if (sense == FEATURE_SENSE_CHAN) { 03701 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 03702 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 03703 } 03704 else { 03705 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 03706 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 03707 } 03708 03709 ast_channel_lock(peer); 03710 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 03711 ast_channel_unlock(peer); 03712 03713 ast_channel_lock(chan); 03714 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03715 ast_channel_unlock(chan); 03716 03717 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,"")); 03718 03719 ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", ast_channel_name(chan), ast_channel_name(peer), code, sense, features.flags, dynamic_features_buf); 03720 03721 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature); 03722 }
| 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 3569 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_feature_get_exten(), ast_call_feature::exten, feature_group_exten::exten, feature_group_exten::feature, FEATURE_INTERPRET_CHECK, FEATURE_INTERPRET_DO, ast_call_feature::feature_mask, FEATURE_MAX_LEN, 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().
03572 { 03573 int x; 03574 struct feature_group *fg = NULL; 03575 struct feature_group_exten *fge; 03576 struct ast_call_feature *tmpfeature; 03577 char *tmp, *tok; 03578 int res = AST_FEATURE_RETURN_PASSDIGITS; 03579 int feature_detected = 0; 03580 03581 if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) { 03582 return -1; /* can not run feature operation */ 03583 } 03584 03585 ast_rwlock_rdlock(&features_lock); 03586 for (x = 0; x < FEATURES_COUNT; x++) { 03587 char feature_exten[FEATURE_MAX_LEN] = ""; 03588 03589 if (!ast_test_flag(features, builtin_features[x].feature_mask)) { 03590 continue; 03591 } 03592 03593 if (builtin_feature_get_exten(chan, builtin_features[x].sname, feature_exten, sizeof(feature_exten))) { 03594 continue; 03595 } 03596 03597 /* Feature is up for consideration */ 03598 03599 if (!strcmp(feature_exten, code)) { 03600 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, feature_exten); 03601 if (operation == FEATURE_INTERPRET_CHECK) { 03602 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03603 } else if (operation == FEATURE_INTERPRET_DO) { 03604 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 03605 } 03606 if (feature) { 03607 memcpy(feature, &builtin_features[x], sizeof(*feature)); 03608 } 03609 feature_detected = 1; 03610 break; 03611 } else if (!strncmp(feature_exten, code, strlen(code))) { 03612 if (res == AST_FEATURE_RETURN_PASSDIGITS) { 03613 res = AST_FEATURE_RETURN_STOREDIGITS; 03614 } 03615 } 03616 } 03617 ast_rwlock_unlock(&features_lock); 03618 03619 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 03620 return res; 03621 } 03622 03623 tmp = dynamic_features_buf; 03624 03625 while ((tok = strsep(&tmp, "#"))) { 03626 AST_RWLIST_RDLOCK(&feature_groups); 03627 03628 fg = find_group(tok); 03629 03630 if (fg) { 03631 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03632 if (!strcmp(fge->exten, code)) { 03633 if (operation) { 03634 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 03635 } 03636 if (feature) { 03637 memcpy(feature, fge->feature, sizeof(*feature)); 03638 } 03639 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03640 AST_RWLIST_UNLOCK(&feature_groups); 03641 break; 03642 } 03643 res = AST_FEATURE_RETURN_PASSDIGITS; 03644 } else if (!strncmp(fge->exten, code, strlen(code))) { 03645 res = AST_FEATURE_RETURN_STOREDIGITS; 03646 } 03647 } 03648 if (fge) { 03649 break; 03650 } 03651 } 03652 03653 AST_RWLIST_UNLOCK(&feature_groups); 03654 03655 AST_RWLIST_RDLOCK(&feature_list); 03656 03657 if (!(tmpfeature = find_dynamic_feature(tok))) { 03658 AST_RWLIST_UNLOCK(&feature_list); 03659 continue; 03660 } 03661 03662 /* Feature is up for consideration */ 03663 if (!strcmp(tmpfeature->exten, code)) { 03664 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 03665 if (operation == FEATURE_INTERPRET_CHECK) { 03666 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03667 } else if (operation == FEATURE_INTERPRET_DO) { 03668 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 03669 } 03670 if (feature) { 03671 memcpy(feature, tmpfeature, sizeof(*feature)); 03672 } 03673 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03674 AST_RWLIST_UNLOCK(&feature_list); 03675 break; 03676 } 03677 res = AST_FEATURE_RETURN_PASSDIGITS; 03678 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 03679 res = AST_FEATURE_RETURN_STOREDIGITS; 03680 03681 AST_RWLIST_UNLOCK(&feature_list); 03682 } 03683 03684 return res; 03685 }
| static int feature_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 8846 of file features.c.
References ast_log(), get_parkingtime(), and LOG_WARNING.
08848 { 08849 int res = 0; 08850 08851 if (!strcasecmp(data, "parkingtime")) { 08852 snprintf(buf, len, "%u", get_parkingtime(chan, NULL) / 1000); 08853 } else { 08854 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data); 08855 res = -1; 08856 } 08857 08858 return res; 08859 }
| 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, | |||
| struct ast_format_cap * | cap, | |||
| const char * | addr, | |||
| int | timeout, | |||
| int * | outstate, | |||
| const char * | language | |||
| ) | [static, read] |
Definition at line 3835 of file features.c.
References ast_alloca, ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_call_forward(), ast_channel_caller(), ast_channel_connected(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_exten(), ast_channel_hangupcause(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_name(), ast_channel_redirecting_macro(), ast_channel_redirecting_sub(), 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_PVT_CAUSE_CODE, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_format_cap_add(), ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), 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_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), cause, ast_frame::data, ast_frame::datalen, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_frame::frametype, ast_frame_subclass::integer, LOG_NOTICE, pbx_builtin_setvar_helper(), ast_frame::ptr, and ast_frame::subclass.
Referenced by builtin_atxfer().
03839 { 03840 int state = 0; 03841 int cause = 0; 03842 int to; 03843 int caller_hungup; 03844 int transferee_hungup; 03845 struct ast_channel *chan; 03846 struct ast_channel *monitor_chans[3]; 03847 struct ast_channel *active_channel; 03848 int res; 03849 int ready = 0; 03850 struct timeval started; 03851 int x, len = 0; 03852 char *disconnect_code = NULL, *dialed_code = NULL; 03853 struct ast_format_cap *tmp_cap; 03854 struct ast_format best_audio_fmt; 03855 struct ast_frame *f; 03856 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; 03857 03858 tmp_cap = ast_format_cap_alloc_nolock(); 03859 if (!tmp_cap) { 03860 if (outstate) { 03861 *outstate = 0; 03862 } 03863 return NULL; 03864 } 03865 ast_best_codec(cap, &best_audio_fmt); 03866 ast_format_cap_add(tmp_cap, &best_audio_fmt); 03867 03868 caller_hungup = ast_check_hangup(caller); 03869 03870 if (!(chan = ast_request(type, tmp_cap, requestor, addr, &cause))) { 03871 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, addr); 03872 switch (cause) { 03873 case AST_CAUSE_BUSY: 03874 state = AST_CONTROL_BUSY; 03875 break; 03876 case AST_CAUSE_CONGESTION: 03877 state = AST_CONTROL_CONGESTION; 03878 break; 03879 default: 03880 state = 0; 03881 break; 03882 } 03883 goto done; 03884 } 03885 03886 ast_channel_language_set(chan, language); 03887 ast_channel_inherit_variables(caller, chan); 03888 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name); 03889 03890 ast_channel_lock(chan); 03891 ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(requestor)); 03892 ast_channel_unlock(chan); 03893 03894 if (ast_call(chan, addr, timeout)) { 03895 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, addr); 03896 switch (ast_channel_hangupcause(chan)) { 03897 case AST_CAUSE_BUSY: 03898 state = AST_CONTROL_BUSY; 03899 break; 03900 case AST_CAUSE_CONGESTION: 03901 state = AST_CONTROL_CONGESTION; 03902 break; 03903 default: 03904 state = 0; 03905 break; 03906 } 03907 goto done; 03908 } 03909 03910 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 03911 ast_rwlock_rdlock(&features_lock); 03912 for (x = 0; x < FEATURES_COUNT; x++) { 03913 if (strcasecmp(builtin_features[x].sname, "disconnect")) 03914 continue; 03915 03916 disconnect_code = builtin_features[x].exten; 03917 len = strlen(disconnect_code) + 1; 03918 dialed_code = ast_alloca(len); 03919 memset(dialed_code, 0, len); 03920 break; 03921 } 03922 ast_rwlock_unlock(&features_lock); 03923 x = 0; 03924 started = ast_tvnow(); 03925 to = timeout; 03926 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); 03927 03928 ast_poll_channel_add(caller, chan); 03929 03930 transferee_hungup = 0; 03931 while (!ast_check_hangup(transferee) && (ast_channel_state(chan) != AST_STATE_UP)) { 03932 int num_chans = 0; 03933 03934 monitor_chans[num_chans++] = transferee; 03935 monitor_chans[num_chans++] = chan; 03936 if (!caller_hungup) { 03937 if (ast_check_hangup(caller)) { 03938 caller_hungup = 1; 03939 03940 #if defined(ATXFER_NULL_TECH) 03941 /* Change caller's name to ensure that it will remain unique. */ 03942 set_new_chan_name(caller); 03943 03944 /* 03945 * Get rid of caller's physical technology so it is free for 03946 * other calls. 03947 */ 03948 set_kill_chan_tech(caller); 03949 #endif /* defined(ATXFER_NULL_TECH) */ 03950 } else { 03951 /* caller is not hungup so monitor it. */ 03952 monitor_chans[num_chans++] = caller; 03953 } 03954 } 03955 03956 /* see if the timeout has been violated */ 03957 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 03958 state = AST_CONTROL_UNHOLD; 03959 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", ast_channel_name(chan)); 03960 break; /*doh! timeout*/ 03961 } 03962 03963 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to); 03964 if (!active_channel) 03965 continue; 03966 03967 f = NULL; 03968 if (transferee == active_channel) { 03969 struct ast_frame *dup_f; 03970 03971 f = ast_read(transferee); 03972 if (f == NULL) { /*doh! where'd he go?*/ 03973 transferee_hungup = 1; 03974 state = 0; 03975 break; 03976 } 03977 if (ast_is_deferrable_frame(f)) { 03978 dup_f = ast_frisolate(f); 03979 if (dup_f) { 03980 if (dup_f == f) { 03981 f = NULL; 03982 } 03983 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); 03984 } 03985 } 03986 } else if (chan == active_channel) { 03987 if (!ast_strlen_zero(ast_channel_call_forward(chan))) { 03988 state = 0; 03989 ast_autoservice_start(transferee); 03990 chan = ast_call_forward(caller, chan, NULL, tmp_cap, NULL, &state); 03991 ast_autoservice_stop(transferee); 03992 if (!chan) { 03993 break; 03994 } 03995 continue; 03996 } 03997 f = ast_read(chan); 03998 if (f == NULL) { /*doh! where'd he go?*/ 03999 switch (ast_channel_hangupcause(chan)) { 04000 case AST_CAUSE_BUSY: 04001 state = AST_CONTROL_BUSY; 04002 break; 04003 case AST_CAUSE_CONGESTION: 04004 state = AST_CONTROL_CONGESTION; 04005 break; 04006 default: 04007 state = 0; 04008 break; 04009 } 04010 break; 04011 } 04012 04013 if (f->frametype == AST_FRAME_CONTROL) { 04014 if (f->subclass.integer == AST_CONTROL_RINGING) { 04015 ast_verb(3, "%s is ringing\n", ast_channel_name(chan)); 04016 ast_indicate(caller, AST_CONTROL_RINGING); 04017 } else if (f->subclass.integer == AST_CONTROL_BUSY) { 04018 state = f->subclass.integer; 04019 ast_verb(3, "%s is busy\n", ast_channel_name(chan)); 04020 ast_indicate(caller, AST_CONTROL_BUSY); 04021 ast_frfree(f); 04022 break; 04023 } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) { 04024 ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", ast_channel_name(chan), ast_channel_exten(chan)); 04025 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) { 04026 state = f->subclass.integer; 04027 ast_verb(3, "%s is congested\n", ast_channel_name(chan)); 04028 ast_indicate(caller, AST_CONTROL_CONGESTION); 04029 ast_frfree(f); 04030 break; 04031 } else if (f->subclass.integer == AST_CONTROL_ANSWER) { 04032 /* This is what we are hoping for */ 04033 state = f->subclass.integer; 04034 ast_frfree(f); 04035 ready=1; 04036 break; 04037 } else if (f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) { 04038 ast_indicate_data(caller, AST_CONTROL_PVT_CAUSE_CODE, f->data.ptr, f->datalen); 04039 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) { 04040 if (caller_hungup) { 04041 struct ast_party_connected_line connected; 04042 04043 /* Just save it for the transfer. */ 04044 ast_party_connected_line_set_init(&connected, ast_channel_connected(caller)); 04045 res = ast_connected_line_parse_data(f->data.ptr, f->datalen, 04046 &connected); 04047 if (!res) { 04048 ast_channel_set_connected_line(caller, &connected, NULL); 04049 } 04050 ast_party_connected_line_free(&connected); 04051 } else { 04052 ast_autoservice_start(transferee); 04053 if (ast_channel_connected_line_sub(chan, caller, f, 1) && 04054 ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { 04055 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, 04056 f->data.ptr, f->datalen); 04057 } 04058 ast_autoservice_stop(transferee); 04059 } 04060 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) { 04061 if (!caller_hungup) { 04062 ast_autoservice_start(transferee); 04063 if (ast_channel_redirecting_sub(chan, caller, f, 1) && 04064 ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { 04065 ast_indicate_data(caller, AST_CONTROL_REDIRECTING, 04066 f->data.ptr, f->datalen); 04067 } 04068 ast_autoservice_stop(transferee); 04069 } 04070 } else if (f->subclass.integer != -1 04071 && f->subclass.integer != AST_CONTROL_PROGRESS 04072 && f->subclass.integer != AST_CONTROL_PROCEEDING) { 04073 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer); 04074 } 04075 /* else who cares */ 04076 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 04077 ast_write(caller, f); 04078 } 04079 } else if (caller == active_channel) { 04080 f = ast_read(caller); 04081 if (f) { 04082 if (f->frametype == AST_FRAME_DTMF) { 04083 dialed_code[x++] = f->subclass.integer; 04084 dialed_code[x] = '\0'; 04085 if (strlen(dialed_code) == len) { 04086 x = 0; 04087 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 04088 x = 0; 04089 dialed_code[x] = '\0'; 04090 } 04091 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 04092 /* Caller Canceled the call */ 04093 state = AST_CONTROL_UNHOLD; 04094 ast_frfree(f); 04095 break; 04096 } 04097 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 04098 ast_write(chan, f); 04099 } 04100 } 04101 } 04102 if (f) 04103 ast_frfree(f); 04104 } /* end while */ 04105 04106 ast_poll_channel_del(caller, chan); 04107 04108 /* 04109 * We need to free all the deferred frames, but we only need to 04110 * queue the deferred frames if no hangup was received. 04111 */ 04112 ast_channel_lock(transferee); 04113 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee)); 04114 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { 04115 if (!transferee_hungup) { 04116 ast_queue_frame_head(transferee, f); 04117 } 04118 ast_frfree(f); 04119 } 04120 ast_channel_unlock(transferee); 04121 04122 done: 04123 ast_indicate(caller, -1); 04124 if (chan && (ready || ast_channel_state(chan) == AST_STATE_UP)) { 04125 state = AST_CONTROL_ANSWER; 04126 } else if (chan) { 04127 ast_hangup(chan); 04128 chan = NULL; 04129 } 04130 04131 tmp_cap = ast_format_cap_destroy(tmp_cap); 04132 04133 if (outstate) 04134 *outstate = state; 04135 04136 return chan; 04137 }
| static int feature_write | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 8861 of file features.c.
References ast_channel_lock, ast_channel_unlock, ast_log(), get_feature_ds(), LOG_WARNING, feature_ds::parkingtime, and feature_ds::parkingtime_is_set.
08863 { 08864 int res = 0; 08865 struct feature_ds *feature_ds; 08866 08867 ast_channel_lock(chan); 08868 08869 if (!(feature_ds = get_feature_ds(chan))) { 08870 res = -1; 08871 goto return_cleanup; 08872 } 08873 08874 if (!strcasecmp(data, "parkingtime")) { 08875 feature_ds->parkingtime_is_set = 1; 08876 if (sscanf(value, "%30u", &feature_ds->parkingtime) == 1) { 08877 feature_ds->parkingtime *= 1000; /* stored in ms */ 08878 } else { 08879 ast_log(LOG_WARNING, "'%s' is not a valid parkingtime\n", value); 08880 feature_ds->parkingtime_is_set = 0; 08881 res = -1; 08882 } 08883 } else { 08884 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data); 08885 res = -1; 08886 } 08887 08888 return_cleanup: 08889 ast_channel_unlock(chan); 08890 08891 return res; 08892 }
| static int featuremap_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 8894 of file features.c.
References ast_log(), ast_rdlock_call_features(), ast_unlock_call_features(), builtin_feature_get_exten(), and LOG_WARNING.
08896 { 08897 int res; 08898 08899 ast_rdlock_call_features(); 08900 08901 if ((res = builtin_feature_get_exten(chan, data, buf, len))) { 08902 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data); 08903 } 08904 08905 ast_unlock_call_features(); 08906 08907 return res; 08908 }
| static int featuremap_write | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 8910 of file features.c.
References ao2_alloc, ao2_find, ao2_link, ao2_lock, ao2_ref, ao2_unlock, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_find_call_feature(), ast_log(), feature_exten::exten, feature_ds::feature_map, get_feature_ds(), LOG_WARNING, OBJ_KEY, and feature_exten::sname.
08912 { 08913 struct feature_ds *feature_ds; 08914 struct feature_exten *fe; 08915 08916 if (!ast_find_call_feature(data)) { 08917 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data); 08918 return -1; 08919 } 08920 08921 ast_channel_lock(chan); 08922 08923 if (!(feature_ds = get_feature_ds(chan))) { 08924 ast_channel_unlock(chan); 08925 return -1; 08926 } 08927 08928 if (!(fe = ao2_find(feature_ds->feature_map, data, OBJ_KEY))) { 08929 if (!(fe = ao2_alloc(sizeof(*fe), NULL))) { 08930 ast_channel_unlock(chan); 08931 return -1; 08932 } 08933 ast_copy_string(fe->sname, data, sizeof(fe->sname)); 08934 ao2_link(feature_ds->feature_map, fe); 08935 } 08936 08937 ast_channel_unlock(chan); 08938 08939 ao2_lock(fe); 08940 ast_copy_string(fe->exten, value, sizeof(fe->exten)); 08941 ao2_unlock(fe); 08942 ao2_ref(fe, -1); 08943 fe = NULL; 08944 08945 return 0; 08946 }
| static void features_shutdown | ( | void | ) | [static] |
Definition at line 8961 of file features.c.
References ao2_ref, ast_custom_function_unregister(), ast_devstate_prov_del(), ast_manager_unregister(), ast_unregister_application(), parkcall, parking_thread, and parkinglots.
Referenced by ast_features_init().
08962 { 08963 ast_devstate_prov_del("Park"); 08964 ast_custom_function_unregister(&featuremap_function); 08965 ast_custom_function_unregister(&feature_function); 08966 ast_manager_unregister("Bridge"); 08967 ast_manager_unregister("Park"); 08968 ast_manager_unregister("Parkinglots"); 08969 ast_manager_unregister("ParkedCalls"); 08970 ast_unregister_application(parkcall); 08971 ast_unregister_application(parkedcall); 08972 ast_unregister_application(app_bridge); 08973 08974 pthread_cancel(parking_thread); 08975 ao2_ref(parkinglots, -1); 08976 }
| static int find_channel_by_group | ( | void * | obj, | |
| void * | arg, | |||
| void * | data, | |||
| int | flags | |||
| ) | [static] |
< Potential pickup target
< Channel wanting to pickup call
< Candidate channels found.
Definition at line 7706 of file features.c.
References ao2_link, ast_can_pickup(), ast_channel_callgroup(), ast_channel_lock, ast_channel_named_callgroups(), ast_channel_named_pickupgroups(), ast_channel_pickupgroup(), ast_channel_trylock, ast_channel_unlock, and ast_namedgroups_intersect().
Referenced by ast_pickup_find_by_group().
07707 { 07708 struct ast_channel *target = obj;/*!< Potential pickup target */ 07709 struct ast_channel *chan = arg;/*!< Channel wanting to pickup call */ 07710 07711 if (chan == target) { 07712 return 0; 07713 } 07714 07715 ast_channel_lock(target); 07716 if (ast_can_pickup(target)) { 07717 /* Lock both channels. */ 07718 while (ast_channel_trylock(chan)) { 07719 ast_channel_unlock(target); 07720 sched_yield(); 07721 ast_channel_lock(target); 07722 } 07723 07724 /* 07725 * Both callgroup and namedcallgroup pickup variants are 07726 * matched independently. Checking for named group match is 07727 * done last since it's a more expensive operation. 07728 */ 07729 if ((ast_channel_pickupgroup(chan) & ast_channel_callgroup(target)) 07730 || (ast_namedgroups_intersect(ast_channel_named_pickupgroups(chan), 07731 ast_channel_named_callgroups(target)))) { 07732 struct ao2_container *candidates = data;/*!< Candidate channels found. */ 07733 07734 /* This is a candidate to pickup */ 07735 ao2_link(candidates, target); 07736 } 07737 ast_channel_unlock(chan); 07738 } 07739 ast_channel_unlock(target); 07740 07741 return 0; 07742 }
| static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static, read] |
find a call feature by name
Definition at line 3247 of file features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by ast_find_call_feature(), feature_interpret_helper(), process_applicationmap_line(), process_config(), and set_config_flags().
03248 { 03249 struct ast_call_feature *tmp; 03250 03251 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 03252 if (!strcasecmp(tmp->sname, name)) { 03253 break; 03254 } 03255 } 03256 03257 return tmp; 03258 }
| static struct feature_group* find_group | ( | const char * | name | ) | [static, read] |
Find a group by name.
| name | feature name |
| feature | group on success. | |
| NULL | on failure. |
Definition at line 3285 of file features.c.
References AST_LIST_TRAVERSE, and feature_group::gname.
Referenced by feature_interpret_helper().
03286 { 03287 struct feature_group *fg = NULL; 03288 03289 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 03290 if (!strcasecmp(fg->gname, name)) 03291 break; 03292 } 03293 03294 return fg; 03295 }
| static struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) | [static, read] |
Find parkinglot by name.
Definition at line 5268 of file features.c.
References ao2_find, ast_debug, ast_strlen_zero(), ast_parkinglot::name, and parkinglots.
Referenced by ast_masq_park_call_exten(), ast_park_call_exten(), build_parkinglot(), copy_parkinglot(), create_dynamic_parkinglot(), get_parkingtime(), manager_park(), park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().
05269 { 05270 struct ast_parkinglot *parkinglot; 05271 05272 if (ast_strlen_zero(name)) { 05273 return NULL; 05274 } 05275 05276 parkinglot = ao2_find(parkinglots, (void *) name, 0); 05277 if (parkinglot) { 05278 ast_debug(1, "Found Parking lot: %s\n", parkinglot->name); 05279 } 05280 05281 return parkinglot; 05282 }
| static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 1232 of file features.c.
References ast_channel_parkinglot(), ast_strlen_zero(), name, and pbx_builtin_getvar_helper().
Referenced by park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().
01233 { 01234 const char *name; 01235 01236 /* The channel variable overrides everything */ 01237 name = pbx_builtin_getvar_helper(chan, "PARKINGLOT"); 01238 if (!name && !ast_strlen_zero(ast_channel_parkinglot(chan))) { 01239 /* Use the channel's parking lot. */ 01240 name = ast_channel_parkinglot(chan); 01241 } 01242 return name; 01243 }
| static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 2036 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().
02037 { 02038 ast_indicate(chan, AST_CONTROL_UNHOLD); 02039 02040 return ast_autoservice_stop(chan); 02041 }
| static struct feature_ds* get_feature_ds | ( | struct ast_channel * | chan | ) | [static, read] |
Definition at line 3383 of file features.c.
References ao2_container_alloc, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_datastore_alloc, ast_datastore::data, feature_ds_destroy(), feature_exten_cmp(), feature_exten_hash(), and feature_ds::feature_map.
Referenced by builtin_feature_get_exten(), feature_write(), featuremap_write(), and get_parkingtime().
03384 { 03385 struct feature_ds *feature_ds; 03386 struct ast_datastore *ds; 03387 03388 if ((ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) { 03389 feature_ds = ds->data; 03390 return feature_ds; 03391 } 03392 03393 if (!(feature_ds = ast_calloc(1, sizeof(*feature_ds)))) { 03394 return NULL; 03395 } 03396 03397 if (!(feature_ds->feature_map = ao2_container_alloc(7, feature_exten_hash, feature_exten_cmp))) { 03398 feature_ds_destroy(feature_ds); 03399 return NULL; 03400 } 03401 03402 if (!(ds = ast_datastore_alloc(&feature_ds_info, NULL))) { 03403 feature_ds_destroy(feature_ds); 03404 return NULL; 03405 } 03406 03407 ds->data = feature_ds; 03408 03409 ast_channel_datastore_add(chan, ds); 03410 03411 return feature_ds; 03412 }
| static struct ast_exten* get_parking_exten | ( | const char * | exten_str, | |
| struct ast_channel * | chan, | |||
| const char * | context | |||
| ) | [static, read] |
Definition at line 960 of file features.c.
References ast_debug, ast_get_extension_app(), E_MATCH, 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().
00961 { 00962 struct ast_exten *exten; 00963 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 00964 const char *app_at_exten; 00965 00966 ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context); 00967 exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, 00968 E_MATCH); 00969 if (!exten) { 00970 return NULL; 00971 } 00972 00973 app_at_exten = ast_get_extension_app(exten); 00974 if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) { 00975 return NULL; 00976 } 00977 00978 return exten; 00979 }
| static unsigned int get_parkingtime | ( | struct ast_channel * | chan, | |
| struct ast_parkinglot * | parkinglot | |||
| ) | [static] |
Definition at line 8807 of file features.c.
References ast_channel_lock, ast_channel_parkinglot(), ast_channel_unlock, ast_strdupa, ast_strlen_zero(), ast_parkinglot::cfg, default_parkinglot, find_parkinglot(), get_feature_ds(), parkinglot_addref(), parkinglot_unref(), parkinglot_cfg::parkingtime, feature_ds::parkingtime, feature_ds::parkingtime_is_set, and S_OR.
Referenced by feature_read(), and park_call_full().
08808 { 08809 const char *parkinglot_name; 08810 struct feature_ds *feature_ds; 08811 unsigned int parkingtime; 08812 08813 ast_channel_lock(chan); 08814 08815 feature_ds = get_feature_ds(chan); 08816 if (feature_ds && feature_ds->parkingtime_is_set) { 08817 parkingtime = feature_ds->parkingtime; 08818 ast_channel_unlock(chan); 08819 return parkingtime; 08820 } 08821 08822 parkinglot_name = ast_strdupa(S_OR(ast_channel_parkinglot(chan), "")); 08823 08824 ast_channel_unlock(chan); 08825 08826 if (!parkinglot) { 08827 if (!ast_strlen_zero(parkinglot_name)) { 08828 parkinglot = find_parkinglot(parkinglot_name); 08829 } 08830 08831 if (!parkinglot) { 08832 parkinglot = parkinglot_addref(default_parkinglot); 08833 } 08834 } else { 08835 /* Just to balance the unref below */ 08836 parkinglot_addref(parkinglot); 08837 } 08838 08839 parkingtime = parkinglot->cfg.parkingtime; 08840 08841 parkinglot_unref(parkinglot); 08842 08843 return parkingtime; 08844 }
| 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 7089 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, ast_parkinglot::cfg, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, parkinglot_cfg::comebackcontext, parkinglot_cfg::comebackdialtime, parkinglot_cfg::comebacktoorigin, ast_cli_entry::command, ast_call_feature::default_exten, ast_parkinglot::disabled, 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.
07090 { 07091 int i; 07092 struct ast_call_feature *feature; 07093 struct ao2_iterator iter; 07094 struct ast_parkinglot *curlot; 07095 #define HFS_FORMAT "%-25s %-7s %-7s\n" 07096 07097 switch (cmd) { 07098 07099 case CLI_INIT: 07100 e->command = "features show"; 07101 e->usage = 07102 "Usage: features show\n" 07103 " Lists configured features\n"; 07104 return NULL; 07105 case CLI_GENERATE: 07106 return NULL; 07107 } 07108 07109 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 07110 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 07111 07112 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 07113 07114 ast_rwlock_rdlock(&features_lock); 07115 for (i = 0; i < FEATURES_COUNT; i++) 07116 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 07117 ast_rwlock_unlock(&features_lock); 07118 07119 ast_cli(a->fd, "\n"); 07120 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 07121 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 07122 if (AST_RWLIST_EMPTY(&feature_list)) { 07123 ast_cli(a->fd, "(none)\n"); 07124 } else { 07125 AST_RWLIST_RDLOCK(&feature_list); 07126 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 07127 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 07128 } 07129 AST_RWLIST_UNLOCK(&feature_list); 07130 } 07131 07132 ast_cli(a->fd, "\nFeature Groups:\n"); 07133 ast_cli(a->fd, "---------------\n"); 07134 if (AST_RWLIST_EMPTY(&feature_groups)) { 07135 ast_cli(a->fd, "(none)\n"); 07136 } else { 07137 struct feature_group *fg; 07138 struct feature_group_exten *fge; 07139 07140 AST_RWLIST_RDLOCK(&feature_groups); 07141 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 07142 ast_cli(a->fd, "===> Group: %s\n", fg->gname); 07143 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 07144 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten); 07145 } 07146 } 07147 AST_RWLIST_UNLOCK(&feature_groups); 07148 } 07149 07150 iter = ao2_iterator_init(parkinglots, 0); 07151 while ((curlot = ao2_iterator_next(&iter))) { 07152 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 07153 ast_cli(a->fd, "------------\n"); 07154 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->cfg.parkext); 07155 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->cfg.parking_con); 07156 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", 07157 curlot->cfg.parking_start, curlot->cfg.parking_stop); 07158 ast_cli(a->fd,"%-22s: %u ms\n", "Parkingtime", curlot->cfg.parkingtime); 07159 ast_cli(a->fd,"%-22s: %s\n", "Comeback to origin", 07160 (curlot->cfg.comebacktoorigin ? "yes" : "no")); 07161 ast_cli(a->fd,"%-22s: %s%s\n", "Comeback context", 07162 curlot->cfg.comebackcontext, (curlot->cfg.comebacktoorigin ? 07163 " (comebacktoorigin=yes, not used)" : "")); 07164 ast_cli(a->fd,"%-22s: %d\n", "Comeback dial time", 07165 curlot->cfg.comebackdialtime); 07166 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->cfg.mohclass); 07167 ast_cli(a->fd,"%-22s: %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled)); 07168 ast_cli(a->fd,"\n"); 07169 ao2_ref(curlot, -1); 07170 } 07171 ao2_iterator_destroy(&iter); 07172 07173 return CLI_SUCCESS; 07174 }
| static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7202 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
07203 { 07204 switch (cmd) { 07205 case CLI_INIT: 07206 e->command = "features reload"; 07207 e->usage = 07208 "Usage: features reload\n" 07209 " Reloads configured call features from features.conf\n"; 07210 return NULL; 07211 case CLI_GENERATE: 07212 return NULL; 07213 } 07214 ast_features_reload(); 07215 07216 return CLI_SUCCESS; 07217 }
| 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 7421 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_channel_name(), 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_parkinglot::name, parkeduser::parkingexten, parkinglots, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.
07422 { 07423 struct parkeduser *cur; 07424 int numparked = 0; 07425 struct ao2_iterator iter; 07426 struct ast_parkinglot *curlot; 07427 07428 switch (cmd) { 07429 case CLI_INIT: 07430 e->command = "parkedcalls show"; 07431 e->usage = 07432 "Usage: parkedcalls show\n" 07433 " List currently parked calls\n"; 07434 return NULL; 07435 case CLI_GENERATE: 07436 return NULL; 07437 } 07438 07439 if (a->argc > e->args) 07440 return CLI_SHOWUSAGE; 07441 07442 ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel", 07443 "Context", "Extension", "Pri", "Timeout"); 07444 07445 iter = ao2_iterator_init(parkinglots, 0); 07446 while ((curlot = ao2_iterator_next(&iter))) { 07447 int lotparked = 0; 07448 07449 /* subtract ref for iterator and for configured parking lot */ 07450 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, 07451 ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot)); 07452 07453 AST_LIST_LOCK(&curlot->parkings); 07454 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 07455 ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n", 07456 cur->parkingexten, ast_channel_name(cur->chan), cur->context, cur->exten, 07457 cur->priority, 07458 (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL))); 07459 ++lotparked; 07460 } 07461 AST_LIST_UNLOCK(&curlot->parkings); 07462 if (lotparked) { 07463 numparked += lotparked; 07464 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, 07465 ESS(lotparked), curlot->name); 07466 } 07467 07468 ao2_ref(curlot, -1); 07469 } 07470 ao2_iterator_destroy(&iter); 07471 07472 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 07473 07474 return CLI_SUCCESS; 07475 }
| static int load_config | ( | int | reload | ) | [static] |
Definition at line 7007 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_is_marked_cb(), parkinglot_markall_cb(), parkinglots, process_config(), and remove_dead_dialplan_useage().
07008 { 07009 struct ast_flags config_flags = { 07010 reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 07011 struct ast_config *cfg; 07012 struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 07013 struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 07014 07015 /* We are reloading now and have already determined if we will force the reload. */ 07016 force_reload_load = 0; 07017 07018 if (!default_parkinglot) { 07019 /* Must create the default default parking lot */ 07020 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 07021 if (!default_parkinglot) { 07022 ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n"); 07023 return -1; 07024 } 07025 ast_debug(1, "Configuration of default default parking lot done.\n"); 07026 } 07027 07028 cfg = ast_config_load2("features.conf", "features", config_flags); 07029 if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 07030 /* No sense in asking for reload trouble if nothing changed. */ 07031 ast_debug(1, "features.conf did not change.\n"); 07032 return 0; 07033 } 07034 if (cfg == CONFIG_STATUS_FILEMISSING 07035 || cfg == CONFIG_STATUS_FILEINVALID) { 07036 ast_log(LOG_WARNING, "Could not load features.conf\n"); 07037 return 0; 07038 } 07039 07040 /* Save current parking lot dialplan needs. */ 07041 if (build_dialplan_useage_map(&old_usage_map, 0)) { 07042 destroy_dialplan_usage_map(&old_usage_map); 07043 07044 /* Allow reloading later to see if conditions have improved. */ 07045 force_reload_load = 1; 07046 return -1; 07047 } 07048 07049 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, 07050 "callback to mark all parking lots"); 07051 process_config(cfg); 07052 ast_config_destroy(cfg); 07053 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, 07054 "callback to remove marked parking lots"); 07055 07056 /* Save updated parking lot dialplan needs. */ 07057 if (build_dialplan_useage_map(&new_usage_map, 1)) { 07058 /* 07059 * Yuck, if this failure caused any parking lot dialplan items 07060 * to be lost, they will likely remain lost until Asterisk is 07061 * restarted. 07062 */ 07063 destroy_dialplan_usage_map(&old_usage_map); 07064 destroy_dialplan_usage_map(&new_usage_map); 07065 return -1; 07066 } 07067 07068 /* Remove no longer needed parking lot dialplan usage. */ 07069 remove_dead_dialplan_useage(&old_usage_map, &new_usage_map); 07070 07071 destroy_dialplan_usage_map(&old_usage_map); 07072 destroy_dialplan_usage_map(&new_usage_map); 07073 07074 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL, 07075 "callback to activate all parking lots"); 07076 07077 return 0; 07078 }
| 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 4962 of file features.c.
References ast_add_extension(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_context(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_fd(), ast_channel_fd_isset(), ast_channel_fdno_set(), ast_channel_flags(), ast_channel_generatordata(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), 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_realloc, ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, callback_dialoptions(), ast_parkinglot::cfg, parkeduser::chan, parkinglot_cfg::comebackcontext, parkinglot_cfg::comebackdialtime, parkinglot_cfg::comebacktoorigin, parkeduser::context, ast_datastore::data, dial_features_info, parkeduser::exten, f, ast_frame::frametype, parkeduser::hold_method, ast_frame_subclass::integer, LOG_ERROR, LOG_NOTICE, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, parkinglot_cfg::mohclass, ast_dial_features::my_features, ast_parkinglot::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(), parkeduser::priority, registrar, S_OR, set_c_e_p(), parkeduser::start, and ast_frame::subclass.
Referenced by manage_parkinglot().
04963 { 04964 struct ast_channel *chan = pu->chan; /* shorthand */ 04965 int tms; /* timeout for this item */ 04966 int x; /* fd index in channel */ 04967 04968 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 04969 if (tms > pu->parkingtime) { 04970 /* 04971 * Call has been parked too long. 04972 * Stop entertaining the caller. 04973 */ 04974 switch (pu->hold_method) { 04975 case AST_CONTROL_HOLD: 04976 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 04977 break; 04978 case AST_CONTROL_RINGING: 04979 ast_indicate(pu->chan, -1); 04980 break; 04981 default: 04982 break; 04983 } 04984 pu->hold_method = 0; 04985 04986 /* Get chan, exten from derived kludge */ 04987 if (pu->peername[0]) { 04988 char *peername; 04989 char *dash; 04990 char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 04991 int i; 04992 04993 peername = ast_strdupa(pu->peername); 04994 dash = strrchr(peername, '-'); 04995 if (dash) { 04996 *dash = '\0'; 04997 } 04998 04999 peername_flat = ast_strdupa(peername); 05000 for (i = 0; peername_flat[i]; i++) { 05001 if (peername_flat[i] == '/') { 05002 peername_flat[i] = '_'; 05003 } 05004 } 05005 05006 if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) { 05007 ast_log(LOG_ERROR, 05008 "Parking dial context '%s' does not exist and unable to create\n", 05009 parking_con_dial); 05010 } else { 05011 char returnexten[AST_MAX_EXTENSION]; 05012 char comebackdialtime[AST_MAX_EXTENSION]; 05013 struct ast_datastore *features_datastore; 05014 struct ast_dial_features *dialfeatures; 05015 05016 if (!strncmp(peername, "Parked/", 7)) { 05017 peername += 7; 05018 } 05019 05020 ast_channel_lock(chan); 05021 features_datastore = ast_channel_datastore_find(chan, &dial_features_info, 05022 NULL); 05023 if (features_datastore && (dialfeatures = features_datastore->data)) { 05024 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 05025 05026 snprintf(returnexten, sizeof(returnexten), "%s,%u,%s", peername, 05027 pu->parkinglot->cfg.comebackdialtime, 05028 callback_dialoptions(&dialfeatures->peer_features, 05029 &dialfeatures->my_features, buf, sizeof(buf))); 05030 } else { /* Existing default */ 05031 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", 05032 ast_channel_name(chan)); 05033 snprintf(returnexten, sizeof(returnexten), "%s,%u,t", peername, 05034 pu->parkinglot->cfg.comebackdialtime); 05035 } 05036 ast_channel_unlock(chan); 05037 05038 snprintf(comebackdialtime, sizeof(comebackdialtime), "%u", 05039 pu->parkinglot->cfg.comebackdialtime); 05040 pbx_builtin_setvar_helper(chan, "COMEBACKDIALTIME", comebackdialtime); 05041 05042 pbx_builtin_setvar_helper(chan, "PARKER", peername); 05043 05044 if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL, 05045 "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) { 05046 ast_log(LOG_ERROR, 05047 "Could not create parking return dial exten: %s@%s\n", 05048 peername_flat, parking_con_dial); 05049 } 05050 } 05051 if (pu->options_specified) { 05052 /* 05053 * Park() was called with overriding return arguments, respect 05054 * those arguments. 05055 */ 05056 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 05057 } else if (pu->parkinglot->cfg.comebacktoorigin) { 05058 set_c_e_p(chan, parking_con_dial, peername_flat, 1); 05059 } else { 05060 char parkingslot[AST_MAX_EXTENSION]; 05061 05062 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 05063 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 05064 pbx_builtin_setvar_helper(chan, "PARKEDLOT", pu->parkinglot->name); 05065 set_c_e_p(chan, pu->parkinglot->cfg.comebackcontext, peername_flat, 1); 05066 } 05067 } else { 05068 /* 05069 * They've been waiting too long, send them back to where they 05070 * came. Theoretically they should have their original 05071 * extensions and such, but we copy to be on the safe side. 05072 */ 05073 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 05074 } 05075 post_manager_event("ParkedCallTimeOut", pu); 05076 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL); 05077 05078 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", 05079 ast_channel_name(pu->chan), pu->parkingnum, pu->parkinglot->name, ast_channel_context(pu->chan), 05080 ast_channel_exten(pu->chan), ast_channel_priority(pu->chan)); 05081 05082 /* Start up the PBX, or hang them up */ 05083 if (ast_pbx_start(chan)) { 05084 ast_log(LOG_WARNING, 05085 "Unable to restart the PBX for user on '%s', hanging them up...\n", 05086 ast_channel_name(pu->chan)); 05087 ast_hangup(chan); 05088 } 05089 05090 /* And take them out of the parking lot */ 05091 return 1; 05092 } 05093 05094 /* still within parking time, process descriptors */ 05095 if (pfds) { 05096 for (x = 0; x < AST_MAX_FDS; x++) { 05097 struct ast_frame *f; 05098 int y; 05099 05100 if (!ast_channel_fd_isset(chan, x)) { 05101 continue; /* nothing on this descriptor */ 05102 } 05103 05104 for (y = 0; y < nfds; y++) { 05105 if (pfds[y].fd == ast_channel_fd(chan, x)) { 05106 /* Found poll record! */ 05107 break; 05108 } 05109 } 05110 if (y == nfds) { 05111 /* Not found */ 05112 continue; 05113 } 05114 05115 if (!(pfds[y].revents & (