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