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 7449 of file features.c.
07449 { 07450 BRIDGE_OPT_PLAYTONE = (1 << 0), 07451 OPT_CALLEE_HANGUP = (1 << 1), 07452 OPT_CALLER_HANGUP = (1 << 2), 07453 OPT_DURATION_LIMIT = (1 << 3), 07454 OPT_DURATION_STOP = (1 << 4), 07455 OPT_CALLEE_TRANSFER = (1 << 5), 07456 OPT_CALLER_TRANSFER = (1 << 6), 07457 OPT_CALLEE_MONITOR = (1 << 7), 07458 OPT_CALLER_MONITOR = (1 << 8), 07459 OPT_CALLEE_PARK = (1 << 9), 07460 OPT_CALLER_PARK = (1 << 10), 07461 OPT_CALLEE_KILL = (1 << 11), 07462 };
anonymous enum |
Definition at line 7464 of file features.c.
07464 { 07465 OPT_ARG_DURATION_LIMIT = 0, 07466 OPT_ARG_DURATION_STOP, 07467 /* note: this entry _MUST_ be the last one in the enum */ 07468 OPT_ARG_ARRAY_SIZE, 07469 };
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 6929 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().
06930 { 06931 const char *channela = astman_get_header(m, "Channel1"); 06932 const char *channelb = astman_get_header(m, "Channel2"); 06933 const char *playtone = astman_get_header(m, "Tone"); 06934 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2]; 06935 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 06936 struct ast_bridge_thread_obj *tobj = NULL; 06937 char buf[256]; 06938 06939 /* make sure valid channels were specified */ 06940 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 06941 astman_send_error(s, m, "Missing channel parameter in request"); 06942 return 0; 06943 } 06944 06945 /* Start with chana */ 06946 chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); 06947 if (!chana) { 06948 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 06949 astman_send_error(s, m, buf); 06950 return 0; 06951 } 06952 06953 /* Answer the channels if needed */ 06954 if (chana->_state != AST_STATE_UP) 06955 ast_answer(chana); 06956 06957 /* create the placeholder channels and grab the other channels */ 06958 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 06959 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) { 06960 astman_send_error(s, m, "Unable to create temporary channel!"); 06961 chana = ast_channel_unref(chana); 06962 return 0; 06963 } 06964 06965 if (do_bridge_masquerade(chana, tmpchana)) { 06966 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela); 06967 astman_send_error(s, m, buf); 06968 ast_hangup(tmpchana); 06969 chana = ast_channel_unref(chana); 06970 return 0; 06971 } 06972 06973 chana = ast_channel_unref(chana); 06974 06975 /* now do chanb */ 06976 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); 06977 if (!chanb) { 06978 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 06979 astman_send_error(s, m, buf); 06980 ast_hangup(tmpchana); 06981 return 0; 06982 } 06983 06984 /* Answer the channels if needed */ 06985 if (chanb->_state != AST_STATE_UP) 06986 ast_answer(chanb); 06987 06988 /* create the placeholder channels and grab the other channels */ 06989 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 06990 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) { 06991 astman_send_error(s, m, "Unable to create temporary channels!"); 06992 ast_hangup(tmpchana); 06993 chanb = ast_channel_unref(chanb); 06994 return 0; 06995 } 06996 06997 if (do_bridge_masquerade(chanb, tmpchanb)) { 06998 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb); 06999 astman_send_error(s, m, buf); 07000 ast_hangup(tmpchana); 07001 ast_hangup(tmpchanb); 07002 chanb = ast_channel_unref(chanb); 07003 return 0; 07004 } 07005 07006 chanb = ast_channel_unref(chanb); 07007 07008 /* make the channels compatible, send error if we fail doing so */ 07009 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 07010 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 07011 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 07012 ast_hangup(tmpchana); 07013 ast_hangup(tmpchanb); 07014 return 0; 07015 } 07016 07017 /* setup the bridge thread object and start the bridge */ 07018 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 07019 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 07020 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 07021 ast_hangup(tmpchana); 07022 ast_hangup(tmpchanb); 07023 return 0; 07024 } 07025 07026 tobj->chan = tmpchana; 07027 tobj->peer = tmpchanb; 07028 tobj->return_to_pbx = 1; 07029 07030 if (ast_true(playtone)) { 07031 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 07032 if (ast_waitstream(tmpchanb, "") < 0) 07033 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 07034 } 07035 } 07036 07037 chans[0] = tmpchana; 07038 chans[1] = tmpchanb; 07039 07040 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans, 07041 "Response: Success\r\n" 07042 "Channel1: %s\r\n" 07043 "Channel2: %s\r\n", tmpchana->name, tmpchanb->name); 07044 07045 bridge_call_thread_launch(tobj); 07046 07047 astman_send_ack(s, m, "Launched bridge thread with success"); 07048 07049 return 0; 07050 }
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 3875 of file features.c.
References add_features_datastore(), ast_bridge_config::features_callee, and ast_bridge_config::features_caller.
Referenced by ast_bridge_call().
03876 { 03877 if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) { 03878 /* 03879 * If we don't return here, then when we do a builtin_atxfer we 03880 * will copy the disconnect flags over from the atxfer to the 03881 * callee (Party C). 03882 */ 03883 return; 03884 } 03885 03886 add_features_datastore(callee, &config->features_callee, &config->features_caller); 03887 }
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 3938 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().
03939 { 03940 /* Copy voice back and forth between the two channels. Give the peer 03941 the ability to transfer calls with '#<extension' syntax. */ 03942 struct ast_frame *f; 03943 struct ast_channel *who; 03944 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03945 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03946 char orig_channame[AST_CHANNEL_NAME]; 03947 char orig_peername[AST_CHANNEL_NAME]; 03948 int res; 03949 int diff; 03950 int hasfeatures=0; 03951 int hadfeatures=0; 03952 int autoloopflag; 03953 int sendingdtmfdigit = 0; 03954 int we_disabled_peer_cdr = 0; 03955 struct ast_option_header *aoh; 03956 struct ast_cdr *bridge_cdr = NULL; 03957 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03958 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03959 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03960 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03961 struct ast_silence_generator *silgen = NULL; 03962 const char *h_context; 03963 03964 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03965 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03966 03967 /* Clear any BLINDTRANSFER since the transfer has completed. */ 03968 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03969 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL); 03970 03971 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03972 add_features_datastores(chan, peer, config); 03973 03974 /* This is an interesting case. One example is if a ringing channel gets redirected to 03975 * an extension that picks up a parked call. This will make sure that the call taken 03976 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03977 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03978 ast_indicate(peer, AST_CONTROL_RINGING); 03979 } 03980 03981 if (monitor_ok) { 03982 const char *monitor_exec; 03983 struct ast_channel *src = NULL; 03984 if (!monitor_app) { 03985 if (!(monitor_app = pbx_findapp("Monitor"))) 03986 monitor_ok=0; 03987 } 03988 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03989 src = chan; 03990 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03991 src = peer; 03992 if (monitor_app && src) { 03993 char *tmp = ast_strdupa(monitor_exec); 03994 pbx_exec(src, monitor_app, tmp); 03995 } 03996 } 03997 03998 set_config_flags(chan, peer, config); 03999 04000 /* Answer if need be */ 04001 if (chan->_state != AST_STATE_UP) { 04002 if (ast_raw_answer(chan, 1)) { 04003 return -1; 04004 } 04005 } 04006 04007 #ifdef FOR_DEBUG 04008 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 04009 ast_channel_log("Pre-bridge CHAN Channel info", chan); 04010 ast_channel_log("Pre-bridge PEER Channel info", peer); 04011 #endif 04012 /* two channels are being marked as linked here */ 04013 ast_channel_set_linkgroup(chan,peer); 04014 04015 /* copy the userfield from the B-leg to A-leg if applicable */ 04016 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 04017 char tmp[256]; 04018 04019 ast_channel_lock(chan); 04020 if (!ast_strlen_zero(chan->cdr->userfield)) { 04021 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 04022 ast_cdr_appenduserfield(chan, tmp); 04023 } else { 04024 ast_cdr_setuserfield(chan, peer->cdr->userfield); 04025 } 04026 ast_channel_unlock(chan); 04027 /* Don't delete the CDR; just disable it. */ 04028 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04029 we_disabled_peer_cdr = 1; 04030 } 04031 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 04032 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 04033 04034 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 04035 ast_channel_lock_both(chan, peer); 04036 if (chan_cdr) { 04037 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 04038 ast_cdr_update(chan); 04039 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 04040 /* rip any forked CDR's off of the chan_cdr and attach 04041 * them to the bridge_cdr instead */ 04042 bridge_cdr->next = chan_cdr->next; 04043 chan_cdr->next = NULL; 04044 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04045 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04046 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 04047 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04048 } 04049 ast_cdr_setaccount(peer, chan->accountcode); 04050 } else { 04051 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 04052 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 04053 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 04054 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 04055 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 04056 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04057 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04058 ast_cdr_setcid(bridge_cdr, chan); 04059 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 04060 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 04061 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 04062 /* Destination information */ 04063 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 04064 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 04065 if (peer_cdr) { 04066 bridge_cdr->start = peer_cdr->start; 04067 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04068 } else { 04069 ast_cdr_start(bridge_cdr); 04070 } 04071 } 04072 ast_channel_unlock(chan); 04073 ast_channel_unlock(peer); 04074 04075 ast_debug(4,"bridge answer set, chan answer set\n"); 04076 /* peer_cdr->answer will be set when a macro runs on the peer; 04077 in that case, the bridge answer will be delayed while the 04078 macro plays on the peer channel. The peer answered the call 04079 before the macro started playing. To the phone system, 04080 this is billable time for the call, even tho the caller 04081 hears nothing but ringing while the macro does its thing. */ 04082 04083 /* Another case where the peer cdr's time will be set, is when 04084 A self-parks by pickup up phone and dialing 700, then B 04085 picks up A by dialing its parking slot; there may be more 04086 practical paths that get the same result, tho... in which 04087 case you get the previous answer time from the Park... which 04088 is before the bridge's start time, so I added in the 04089 tvcmp check to the if below */ 04090 04091 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 04092 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 04093 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 04094 if (chan_cdr) { 04095 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 04096 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 04097 } 04098 } else { 04099 ast_cdr_answer(bridge_cdr); 04100 if (chan_cdr) { 04101 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 04102 } 04103 } 04104 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 04105 if (chan_cdr) { 04106 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 04107 } 04108 if (peer_cdr) { 04109 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 04110 } 04111 } 04112 /* the DIALED flag may be set if a dialed channel is transfered 04113 * and then bridged to another channel. In order for the 04114 * bridge CDR to be written, the DIALED flag must not be 04115 * present. */ 04116 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04117 } 04118 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04119 04120 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04121 * a call is being bridged, that the humans in charge know what they're doing. If they 04122 * don't, well, what can we do about that? */ 04123 clear_dialed_interfaces(chan); 04124 clear_dialed_interfaces(peer); 04125 04126 for (;;) { 04127 struct ast_channel *other; /* used later */ 04128 04129 res = ast_channel_bridge(chan, peer, config, &f, &who); 04130 04131 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04132 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04133 /* Zombies are present time to leave! */ 04134 res = -1; 04135 if (f) { 04136 ast_frfree(f); 04137 } 04138 goto before_you_go; 04139 } 04140 04141 /* When frame is not set, we are probably involved in a situation 04142 where we've timed out. 04143 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04144 and also for DTMF_END. If we flow into the following 'if' for both, then 04145 our wait times are cut in half, as both will subtract from the 04146 feature_timer. Not good! 04147 */ 04148 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04149 /* Update feature timer for next pass */ 04150 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04151 if (res == AST_BRIDGE_RETRY) { 04152 /* The feature fully timed out but has not been updated. Skip 04153 * the potential round error from the diff calculation and 04154 * explicitly set to expired. */ 04155 config->feature_timer = -1; 04156 } else { 04157 config->feature_timer -= diff; 04158 } 04159 04160 if (hasfeatures) { 04161 if (config->feature_timer <= 0) { 04162 /* Not *really* out of time, just out of time for 04163 digits to come in for features. */ 04164 ast_debug(1, "Timed out for feature!\n"); 04165 if (!ast_strlen_zero(peer_featurecode)) { 04166 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 04167 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04168 } 04169 if (!ast_strlen_zero(chan_featurecode)) { 04170 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 04171 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04172 } 04173 if (f) 04174 ast_frfree(f); 04175 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04176 if (!hasfeatures) { 04177 /* No more digits expected - reset the timer */ 04178 config->feature_timer = 0; 04179 } 04180 hadfeatures = hasfeatures; 04181 /* Continue as we were */ 04182 continue; 04183 } else if (!f) { 04184 /* The bridge returned without a frame and there is a feature in progress. 04185 * However, we don't think the feature has quite yet timed out, so just 04186 * go back into the bridge. */ 04187 continue; 04188 } 04189 } else { 04190 if (config->feature_timer <=0) { 04191 /* We ran out of time */ 04192 config->feature_timer = 0; 04193 who = chan; 04194 if (f) 04195 ast_frfree(f); 04196 f = NULL; 04197 res = 0; 04198 } 04199 } 04200 } 04201 if (res < 0) { 04202 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04203 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 04204 } 04205 goto before_you_go; 04206 } 04207 04208 if (!f || (f->frametype == AST_FRAME_CONTROL && 04209 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04210 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04211 res = -1; 04212 break; 04213 } 04214 /* many things should be sent to the 'other' channel */ 04215 other = (who == chan) ? peer : chan; 04216 if (f->frametype == AST_FRAME_CONTROL) { 04217 switch (f->subclass.integer) { 04218 case AST_CONTROL_RINGING: 04219 case AST_CONTROL_FLASH: 04220 case -1: 04221 ast_indicate(other, f->subclass.integer); 04222 break; 04223 case AST_CONTROL_CONNECTED_LINE: 04224 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04225 break; 04226 } 04227 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04228 break; 04229 case AST_CONTROL_REDIRECTING: 04230 if (!ast_channel_redirecting_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_AOC: 04236 case AST_CONTROL_HOLD: 04237 case AST_CONTROL_UNHOLD: 04238 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04239 break; 04240 case AST_CONTROL_OPTION: 04241 aoh = f->data.ptr; 04242 /* Forward option Requests, but only ones we know are safe 04243 * These are ONLY sent by chan_iax2 and I'm not convinced that 04244 * they are useful. I haven't deleted them entirely because I 04245 * just am not sure of the ramifications of removing them. */ 04246 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04247 switch (ntohs(aoh->option)) { 04248 case AST_OPTION_TONE_VERIFY: 04249 case AST_OPTION_TDD: 04250 case AST_OPTION_RELAXDTMF: 04251 case AST_OPTION_AUDIO_MODE: 04252 case AST_OPTION_DIGIT_DETECT: 04253 case AST_OPTION_FAX_DETECT: 04254 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04255 f->datalen - sizeof(struct ast_option_header), 0); 04256 } 04257 } 04258 break; 04259 } 04260 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04261 struct ast_flags *cfg; 04262 char dtmfcode[2] = { f->subclass.integer, }; 04263 size_t featurelen; 04264 04265 if (who == chan) { 04266 featurelen = strlen(chan_featurecode); 04267 cfg = &(config->features_caller); 04268 } else { 04269 featurelen = strlen(peer_featurecode); 04270 cfg = &(config->features_callee); 04271 } 04272 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04273 * DTMF along untouched. If this is not the first digit of a multi-digit code 04274 * then we need to fall through and stream the characters if it matches */ 04275 if (featurelen == 0 04276 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04277 if (option_debug > 3) { 04278 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04279 } 04280 ast_write(other, f); 04281 sendingdtmfdigit = 1; 04282 } else { 04283 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04284 * transmitting something while we hold on to the DTMF waiting for a 04285 * feature. */ 04286 if (!silgen && ast_opt_transmit_silence) { 04287 silgen = ast_channel_start_silence_generator(other); 04288 } 04289 if (option_debug > 3) { 04290 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04291 } 04292 } 04293 } else if (f->frametype == AST_FRAME_DTMF_END) { 04294 char *featurecode; 04295 int sense; 04296 04297 hadfeatures = hasfeatures; 04298 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04299 if (who == chan) { 04300 sense = FEATURE_SENSE_CHAN; 04301 featurecode = chan_featurecode; 04302 } else { 04303 sense = FEATURE_SENSE_PEER; 04304 featurecode = peer_featurecode; 04305 } 04306 04307 if (sendingdtmfdigit == 1) { 04308 /* We let the BEGIN go through happily, so let's not bother with the END, 04309 * since we already know it's not something we bother with */ 04310 ast_write(other, f); 04311 sendingdtmfdigit = 0; 04312 } else { 04313 /*! append the event to featurecode. we rely on the string being zero-filled, and 04314 * not overflowing it. 04315 * \todo XXX how do we guarantee the latter ? 04316 */ 04317 featurecode[strlen(featurecode)] = f->subclass.integer; 04318 /* Get rid of the frame before we start doing "stuff" with the channels */ 04319 ast_frfree(f); 04320 f = NULL; 04321 if (silgen) { 04322 ast_channel_stop_silence_generator(other, silgen); 04323 silgen = NULL; 04324 } 04325 config->feature_timer = 0; 04326 res = feature_interpret(chan, peer, config, featurecode, sense); 04327 switch(res) { 04328 case AST_FEATURE_RETURN_PASSDIGITS: 04329 ast_dtmf_stream(other, who, featurecode, 0, 0); 04330 /* Fall through */ 04331 case AST_FEATURE_RETURN_SUCCESS: 04332 memset(featurecode, 0, sizeof(chan_featurecode)); 04333 break; 04334 } 04335 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04336 res = 0; 04337 } else { 04338 break; 04339 } 04340 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04341 if (hadfeatures && !hasfeatures) { 04342 /* Feature completed or timed out */ 04343 config->feature_timer = 0; 04344 } else if (hasfeatures) { 04345 if (config->timelimit) { 04346 /* No warning next time - we are waiting for feature code */ 04347 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04348 } 04349 config->feature_start_time = ast_tvnow(); 04350 config->feature_timer = featuredigittimeout; 04351 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04352 } 04353 } 04354 } 04355 if (f) 04356 ast_frfree(f); 04357 } 04358 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04359 04360 before_you_go: 04361 if (chan->sending_dtmf_digit) { 04362 ast_bridge_end_dtmf(chan, chan->sending_dtmf_digit, chan->sending_dtmf_tv, 04363 "bridge end"); 04364 } 04365 if (peer->sending_dtmf_digit) { 04366 ast_bridge_end_dtmf(peer, peer->sending_dtmf_digit, peer->sending_dtmf_tv, 04367 "bridge end"); 04368 } 04369 04370 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04371 if (silgen) { 04372 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04373 silgen = NULL; 04374 } 04375 04376 /* Wait for any dual redirect to complete. */ 04377 while (ast_test_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) { 04378 sched_yield(); 04379 } 04380 04381 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04382 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04383 if (bridge_cdr) { 04384 ast_cdr_discard(bridge_cdr); 04385 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04386 } 04387 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04388 } 04389 04390 if (config->end_bridge_callback) { 04391 config->end_bridge_callback(config->end_bridge_callback_data); 04392 } 04393 04394 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04395 * if it were, then chan belongs to a different thread now, and might have been hung up long 04396 * ago. 04397 */ 04398 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04399 /* 04400 * If the bridge was broken for a hangup that isn't real, 04401 * then don't run the h extension, because the channel isn't 04402 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04403 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04404 */ 04405 h_context = NULL; 04406 } else if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04407 h_context = NULL; 04408 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04409 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04410 h_context = chan->context; 04411 } else if (!ast_strlen_zero(chan->macrocontext) 04412 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04413 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04414 h_context = chan->macrocontext; 04415 } else { 04416 h_context = NULL; 04417 } 04418 if (h_context) { 04419 struct ast_cdr *swapper = NULL; 04420 char savelastapp[AST_MAX_EXTENSION]; 04421 char savelastdata[AST_MAX_EXTENSION]; 04422 char save_context[AST_MAX_CONTEXT]; 04423 char save_exten[AST_MAX_EXTENSION]; 04424 int save_prio; 04425 int found = 0; /* set if we find at least one match */ 04426 int spawn_error = 0; 04427 04428 /* 04429 * Make sure that the channel is marked as hungup since we are 04430 * going to run the "h" exten on it. 04431 */ 04432 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04433 04434 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04435 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04436 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04437 ast_cdr_end(bridge_cdr); 04438 } 04439 04440 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04441 dialplan code operate on it */ 04442 ast_channel_lock(chan); 04443 if (bridge_cdr) { 04444 swapper = chan->cdr; 04445 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04446 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04447 chan->cdr = bridge_cdr; 04448 } 04449 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04450 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04451 save_prio = chan->priority; 04452 if (h_context != chan->context) { 04453 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04454 } 04455 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04456 chan->priority = 1; 04457 ast_channel_unlock(chan); 04458 04459 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04460 chan->priority, 04461 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04462 &found, 1)) == 0) { 04463 chan->priority++; 04464 } 04465 if (found && spawn_error) { 04466 /* Something bad happened, or a hangup has been requested. */ 04467 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04468 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04469 } 04470 04471 /* swap it back */ 04472 ast_channel_lock(chan); 04473 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04474 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04475 chan->priority = save_prio; 04476 if (bridge_cdr) { 04477 if (chan->cdr == bridge_cdr) { 04478 chan->cdr = swapper; 04479 } else { 04480 bridge_cdr = NULL; 04481 } 04482 } 04483 /* An "h" exten has been run, so indicate that one has been run. */ 04484 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04485 ast_channel_unlock(chan); 04486 04487 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04488 if (bridge_cdr) { 04489 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04490 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04491 } 04492 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04493 } 04494 04495 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04496 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04497 /* If the channel CDR has been modified during the call, record the changes in the bridge cdr, 04498 * BUT, if we've gone through the h extension block above, the CDR got swapped so don't overwrite 04499 * what was done in the h extension. What a mess. This is why you never touch CDR code. */ 04500 if (new_chan_cdr && bridge_cdr && !h_context) { 04501 ast_cdr_copy_vars(bridge_cdr, new_chan_cdr); 04502 ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield)); 04503 bridge_cdr->amaflags = new_chan_cdr->amaflags; 04504 ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode)); 04505 if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 04506 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04507 } 04508 } 04509 04510 /* we can post the bridge CDR at this point */ 04511 if (bridge_cdr) { 04512 ast_cdr_end(bridge_cdr); 04513 ast_cdr_detach(bridge_cdr); 04514 } 04515 04516 /* do a specialized reset on the beginning channel 04517 CDR's, if they still exist, so as not to mess up 04518 issues in future bridges; 04519 04520 Here are the rules of the game: 04521 1. The chan and peer channel pointers will not change 04522 during the life of the bridge. 04523 2. But, in transfers, the channel names will change. 04524 between the time the bridge is started, and the 04525 time the channel ends. 04526 Usually, when a channel changes names, it will 04527 also change CDR pointers. 04528 3. Usually, only one of the two channels (chan or peer) 04529 will change names. 04530 4. Usually, if a channel changes names during a bridge, 04531 it is because of a transfer. Usually, in these situations, 04532 it is normal to see 2 bridges running simultaneously, and 04533 it is not unusual to see the two channels that change 04534 swapped between bridges. 04535 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04536 to attend to; if the chan or peer changed names, 04537 we have the before and after attached CDR's. 04538 */ 04539 04540 if (new_chan_cdr) { 04541 struct ast_channel *chan_ptr = NULL; 04542 04543 if (strcasecmp(orig_channame, chan->name) != 0) { 04544 /* old channel */ 04545 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04546 ast_channel_lock(chan_ptr); 04547 if (!ast_bridged_channel(chan_ptr)) { 04548 struct ast_cdr *cur; 04549 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04550 if (cur == chan_cdr) { 04551 break; 04552 } 04553 } 04554 if (cur) { 04555 ast_cdr_specialized_reset(chan_cdr, 0); 04556 } 04557 } 04558 ast_channel_unlock(chan_ptr); 04559 chan_ptr = ast_channel_unref(chan_ptr); 04560 } 04561 /* new channel */ 04562 ast_cdr_specialized_reset(new_chan_cdr, 0); 04563 } else { 04564 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04565 } 04566 } 04567 04568 { 04569 struct ast_channel *chan_ptr = NULL; 04570 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04571 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)) 04572 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04573 if (strcasecmp(orig_peername, peer->name) != 0) { 04574 /* old channel */ 04575 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04576 ast_channel_lock(chan_ptr); 04577 if (!ast_bridged_channel(chan_ptr)) { 04578 struct ast_cdr *cur; 04579 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04580 if (cur == peer_cdr) { 04581 break; 04582 } 04583 } 04584 if (cur) { 04585 ast_cdr_specialized_reset(peer_cdr, 0); 04586 } 04587 } 04588 ast_channel_unlock(chan_ptr); 04589 chan_ptr = ast_channel_unref(chan_ptr); 04590 } 04591 /* new channel */ 04592 if (new_peer_cdr) { 04593 ast_cdr_specialized_reset(new_peer_cdr, 0); 04594 } 04595 } else { 04596 if (we_disabled_peer_cdr) { 04597 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04598 } 04599 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04600 } 04601 } 04602 04603 return res; 04604 }
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 3905 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().
03906 { 03907 int dead; 03908 long duration; 03909 03910 ast_channel_lock(chan); 03911 dead = ast_test_flag(chan, AST_FLAG_ZOMBIE) 03912 || (chan->_softhangup 03913 & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)); 03914 ast_channel_unlock(chan); 03915 if (dead) { 03916 /* Channel is a zombie or a real hangup. */ 03917 return; 03918 } 03919 03920 duration = ast_tvdiff_ms(ast_tvnow(), start); 03921 ast_senddigit_end(chan, digit, duration); 03922 ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n", 03923 digit, chan->name, why, duration); 03924 }
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 7486 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().
07488 { 07489 char *stringp = ast_strdupa(parse); 07490 char *limit_str, *warning_str, *warnfreq_str; 07491 const char *var; 07492 int play_to_caller = 0, play_to_callee = 0; 07493 int delta; 07494 07495 limit_str = strsep(&stringp, ":"); 07496 warning_str = strsep(&stringp, ":"); 07497 warnfreq_str = strsep(&stringp, ":"); 07498 07499 config->timelimit = atol(limit_str); 07500 if (warning_str) 07501 config->play_warning = atol(warning_str); 07502 if (warnfreq_str) 07503 config->warning_freq = atol(warnfreq_str); 07504 07505 if (!config->timelimit) { 07506 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07507 config->timelimit = config->play_warning = config->warning_freq = 0; 07508 config->warning_sound = NULL; 07509 return -1; /* error */ 07510 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07511 int w = config->warning_freq; 07512 07513 /* 07514 * If the first warning is requested _after_ the entire call 07515 * would end, and no warning frequency is requested, then turn 07516 * off the warning. If a warning frequency is requested, reduce 07517 * the 'first warning' time by that frequency until it falls 07518 * within the call's total time limit. 07519 * 07520 * Graphically: 07521 * timelim->| delta |<-playwarning 07522 * 0__________________|_________________| 07523 * | w | | | | 07524 * 07525 * so the number of intervals to cut is 1+(delta-1)/w 07526 */ 07527 if (w == 0) { 07528 config->play_warning = 0; 07529 } else { 07530 config->play_warning -= w * ( 1 + (delta-1)/w ); 07531 if (config->play_warning < 1) 07532 config->play_warning = config->warning_freq = 0; 07533 } 07534 } 07535 07536 ast_channel_lock(chan); 07537 07538 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07539 play_to_caller = var ? ast_true(var) : 1; 07540 07541 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07542 play_to_callee = var ? ast_true(var) : 0; 07543 07544 if (!play_to_caller && !play_to_callee) 07545 play_to_caller = 1; 07546 07547 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07548 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07549 07550 /* The code looking at config wants a NULL, not just "", to decide 07551 * that the message should not be played, so we replace "" with NULL. 07552 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07553 * not found. 07554 */ 07555 07556 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07557 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07558 07559 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07560 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07561 07562 ast_channel_unlock(chan); 07563 07564 /* undo effect of S(x) in case they are both used */ 07565 calldurationlimit->tv_sec = 0; 07566 calldurationlimit->tv_usec = 0; 07567 07568 /* more efficient to do it like S(x) does since no advanced opts */ 07569 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07570 calldurationlimit->tv_sec = config->timelimit / 1000; 07571 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07572 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07573 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07574 config->timelimit = play_to_caller = play_to_callee = 07575 config->play_warning = config->warning_freq = 0; 07576 } else { 07577 ast_verb(4, "Limit Data for this call:\n"); 07578 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07579 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07580 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07581 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07582 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07583 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07584 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07585 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07586 } 07587 if (play_to_caller) 07588 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07589 if (play_to_callee) 07590 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07591 return 0; 07592 }
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 7292 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().
07293 { 07294 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07295 && (chan->_state == AST_STATE_RINGING 07296 || chan->_state == AST_STATE_RING 07297 /* 07298 * Check the down state as well because some SIP devices do not 07299 * give 180 ringing when they can just give 183 session progress 07300 * instead. Issue 14005. (Some ISDN switches as well for that 07301 * matter.) 07302 */ 07303 || chan->_state == AST_STATE_DOWN) 07304 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07305 return 1; 07306 } 07307 return 0; 07308 }
void ast_channel_log | ( | char * | title, | |
struct ast_channel * | chan | |||
) |
Definition at line 3810 of file features.c.
References ast_log(), and LOG_NOTICE.
Referenced by ast_bridge_call().
03811 { 03812 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan); 03813 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n", 03814 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority); 03815 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n", 03816 chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority); 03817 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n", 03818 chan->masq, chan->masqr, 03819 chan->_bridge, chan->uniqueid, chan->linkedid); 03820 if (chan->masqr) 03821 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n", 03822 chan->masqr->name, chan->masqr->cdr); 03823 if (chan->_bridge) 03824 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name); 03825 03826 ast_log(LOG_NOTICE, "===== done ====\n"); 03827 }
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 7368 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().
07369 { 07370 struct ast_party_connected_line connected_caller; 07371 struct ast_channel *chans[2] = { chan, target }; 07372 struct ast_datastore *ds_pickup; 07373 const char *chan_name;/*!< A masquerade changes channel names. */ 07374 const char *target_name;/*!< A masquerade changes channel names. */ 07375 int res = -1; 07376 07377 target_name = ast_strdupa(target->name); 07378 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name); 07379 07380 /* Mark the target to block any call pickup race. */ 07381 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07382 if (!ds_pickup) { 07383 ast_log(LOG_WARNING, 07384 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07385 return -1; 07386 } 07387 ast_channel_datastore_add(target, ds_pickup); 07388 07389 ast_party_connected_line_init(&connected_caller); 07390 ast_party_connected_line_copy(&connected_caller, &target->connected); 07391 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07392 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07393 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07394 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07395 } 07396 ast_party_connected_line_free(&connected_caller); 07397 07398 ast_channel_lock(chan); 07399 chan_name = ast_strdupa(chan->name); 07400 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07401 ast_channel_unlock(chan); 07402 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07403 07404 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07405 07406 if (ast_answer(chan)) { 07407 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07408 goto pickup_failed; 07409 } 07410 07411 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07412 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07413 goto pickup_failed; 07414 } 07415 07416 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07417 07418 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07419 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07420 07421 if (ast_channel_masquerade(target, chan)) { 07422 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07423 target_name); 07424 goto pickup_failed; 07425 } 07426 07427 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07428 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07429 "Channel: %s\r\n" 07430 "TargetChannel: %s\r\n", 07431 chan_name, target_name); 07432 07433 /* Do the masquerade manually to make sure that it is completed. */ 07434 ast_do_masquerade(target); 07435 res = 0; 07436 07437 pickup_failed: 07438 ast_channel_lock(target); 07439 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07440 ast_datastore_free(ds_pickup); 07441 } 07442 ast_party_connected_line_free(&connected_caller); 07443 07444 return res; 07445 }
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 3412 of file features.c.
References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03412 { 03413 03414 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03415 }
int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 8282 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().
08283 { 08284 int res; 08285 08286 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 08287 if (!parkinglots) { 08288 return -1; 08289 } 08290 08291 res = load_config(0); 08292 if (res) { 08293 return res; 08294 } 08295 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); 08296 if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) { 08297 return -1; 08298 } 08299 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); 08300 res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL); 08301 if (!res) 08302 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); 08303 if (!res) { 08304 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status); 08305 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park); 08306 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge); 08307 } 08308 08309 res |= ast_devstate_prov_add("Park", metermaidstate); 08310 #if defined(TEST_FRAMEWORK) 08311 res |= AST_TEST_REGISTER(features_test); 08312 #endif /* defined(TEST_FRAMEWORK) */ 08313 08314 ast_register_atexit(features_shutdown); 08315 08316 return res; 08317 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6833 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().
06834 { 06835 struct ast_context *con; 06836 int res; 06837 06838 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06839 06840 /* 06841 * Always destroy the parking_con_dial context to remove buildup 06842 * of recalled extensions in the context. At worst, the parked 06843 * call gets hungup attempting to run an invalid extension when 06844 * we are trying to callback the parker or the preset return 06845 * extension. This is a small window of opportunity on an 06846 * execution chain that is not expected to happen very often. 06847 */ 06848 con = ast_context_find(parking_con_dial); 06849 if (con) { 06850 ast_context_destroy(con, registrar); 06851 } 06852 06853 res = load_config(1); 06854 ast_mutex_unlock(&features_reload_lock); 06855 06856 return res; 06857 }
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 7334 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().
07335 { 07336 struct ast_channel *target;/*!< Potential pickup target */ 07337 int res = -1; 07338 ast_debug(1, "pickup attempt by %s\n", chan->name); 07339 07340 /* The found channel is already locked. */ 07341 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07342 if (target) { 07343 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name); 07344 07345 res = ast_do_pickup(chan, target); 07346 ast_channel_unlock(target); 07347 if (!res) { 07348 if (!ast_strlen_zero(pickupsound)) { 07349 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07350 } 07351 } else { 07352 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name); 07353 } 07354 target = ast_channel_unref(target); 07355 } 07356 07357 if (res < 0) { 07358 ast_debug(1, "No call pickup possible... for %s\n", chan->name); 07359 if (!ast_strlen_zero(pickupfailsound)) { 07360 ast_answer(chan); 07361 ast_stream_and_wait(chan, pickupfailsound, ""); 07362 } 07363 } 07364 07365 return res; 07366 }
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 transfered party hangs up return to PBX extension.
Definition at line 7604 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().
07605 { 07606 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2]; 07607 char *tmp_data = NULL; 07608 struct ast_flags opts = { 0, }; 07609 struct ast_bridge_config bconfig = { { 0, }, }; 07610 char *opt_args[OPT_ARG_ARRAY_SIZE]; 07611 struct timeval calldurationlimit = { 0, }; 07612 07613 AST_DECLARE_APP_ARGS(args, 07614 AST_APP_ARG(dest_chan); 07615 AST_APP_ARG(options); 07616 ); 07617 07618 if (ast_strlen_zero(data)) { 07619 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 07620 return -1; 07621 } 07622 07623 tmp_data = ast_strdupa(data); 07624 AST_STANDARD_APP_ARGS(args, tmp_data); 07625 if (!ast_strlen_zero(args.options)) 07626 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options); 07627 07628 /* avoid bridge with ourselves */ 07629 if (!strcmp(chan->name, args.dest_chan)) { 07630 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 07631 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07632 "Response: Failed\r\n" 07633 "Reason: Unable to bridge channel to itself\r\n" 07634 "Channel1: %s\r\n" 07635 "Channel2: %s\r\n", 07636 chan->name, args.dest_chan); 07637 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 07638 return 0; 07639 } 07640 07641 /* make sure we have a valid end point */ 07642 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan, 07643 strlen(args.dest_chan)))) { 07644 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n", 07645 args.dest_chan); 07646 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07647 "Response: Failed\r\n" 07648 "Reason: Channel2 does not exist\r\n" 07649 "Channel1: %s\r\n" 07650 "Channel2: %s\r\n", chan->name, args.dest_chan); 07651 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 07652 return 0; 07653 } 07654 07655 /* try to allocate a place holder where current_dest_chan will be placed */ 07656 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 07657 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) { 07658 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 07659 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07660 "Response: Failed\r\n" 07661 "Reason: Cannot create placeholder channel\r\n" 07662 "Channel1: %s\r\n" 07663 "Channel2: %s\r\n", chan->name, args.dest_chan); 07664 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 07665 ast_channel_unref(current_dest_chan); 07666 return 0; 07667 } 07668 07669 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) 07670 && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT]) 07671 && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) { 07672 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07673 "Response: Failed\r\n" 07674 "Reason: Cannot setup bridge time limit\r\n" 07675 "Channel1: %s\r\n" 07676 "Channel2: %s\r\n", chan->name, args.dest_chan); 07677 ast_hangup(final_dest_chan); 07678 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 07679 current_dest_chan = ast_channel_unref(current_dest_chan); 07680 goto done; 07681 } 07682 07683 if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) { 07684 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07685 "Response: Failed\r\n" 07686 "Reason: Cannot masquerade channels\r\n" 07687 "Channel1: %s\r\n" 07688 "Channel2: %s\r\n", chan->name, args.dest_chan); 07689 ast_hangup(final_dest_chan); 07690 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 07691 current_dest_chan = ast_channel_unref(current_dest_chan); 07692 goto done; 07693 } 07694 07695 /* answer the channel if needed */ 07696 if (final_dest_chan->_state != AST_STATE_UP) { 07697 ast_answer(final_dest_chan); 07698 } 07699 07700 chans[0] = current_dest_chan; 07701 chans[1] = final_dest_chan; 07702 07703 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 07704 /* try to make compatible, send error if we fail */ 07705 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 07706 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 07707 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07708 "Response: Failed\r\n" 07709 "Reason: Could not make channels compatible for bridge\r\n" 07710 "Channel1: %s\r\n" 07711 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 07712 07713 /* Maybe we should return this channel to the PBX? */ 07714 ast_hangup(final_dest_chan); 07715 07716 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 07717 current_dest_chan = ast_channel_unref(current_dest_chan); 07718 goto done; 07719 } 07720 07721 /* Report that the bridge will be successfull */ 07722 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07723 "Response: Success\r\n" 07724 "Channel1: %s\r\n" 07725 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 07726 07727 current_dest_chan = ast_channel_unref(current_dest_chan); 07728 07729 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 07730 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 07731 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 07732 if (ast_waitstream(final_dest_chan, "") < 0) 07733 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 07734 } 07735 } 07736 07737 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) 07738 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT); 07739 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) 07740 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT); 07741 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) 07742 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 07743 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) 07744 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 07745 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR)) 07746 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON); 07747 if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 07748 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON); 07749 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) 07750 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL); 07751 if (ast_test_flag(&opts, OPT_CALLER_PARK)) 07752 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL); 07753 07754 /* 07755 * Don't let the after-bridge code run the h-exten. We want to 07756 * continue in the dialplan. 07757 */ 07758 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 07759 ast_bridge_call(chan, final_dest_chan, &bconfig); 07760 07761 /* The bridge has ended, set BRIDGERESULT to SUCCESS. */ 07762 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 07763 07764 /* If the other channel has not been hung up, return it to the PBX */ 07765 if (!ast_check_hangup(final_dest_chan)) { 07766 if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) { 07767 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 07768 final_dest_chan->context, final_dest_chan->exten, 07769 final_dest_chan->priority, final_dest_chan->name); 07770 07771 if (ast_pbx_start(final_dest_chan)) { 07772 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 07773 ast_hangup(final_dest_chan); 07774 } else { 07775 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 07776 } 07777 } else { 07778 ast_hangup(final_dest_chan); 07779 } 07780 } else { 07781 ast_debug(1, "chan %s was hungup\n", final_dest_chan->name); 07782 ast_hangup(final_dest_chan); 07783 } 07784 done: 07785 ast_free((char *) bconfig.warning_sound); 07786 ast_free((char *) bconfig.end_sound); 07787 ast_free((char *) bconfig.start_sound); 07788 07789 return 0; 07790 }
static struct parking_dp_context* build_dialplan_useage_context | ( | struct ast_parkinglot * | lot | ) | [static, read] |
Definition at line 6278 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().
06279 { 06280 struct parking_dp_context *ctx_node; 06281 06282 ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con)); 06283 if (!ctx_node) { 06284 return NULL; 06285 } 06286 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) { 06287 destroy_dialplan_usage_context(ctx_node); 06288 return NULL; 06289 } 06290 strcpy(ctx_node->context, lot->cfg.parking_con); 06291 return ctx_node; 06292 }
static int build_dialplan_useage_map | ( | struct parking_dp_map * | usage_map, | |
int | complain | |||
) | [static] |
Definition at line 6350 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().
06351 { 06352 int status = 0; 06353 struct ao2_iterator iter; 06354 struct ast_parkinglot *curlot; 06355 06356 /* For all parking lots */ 06357 iter = ao2_iterator_init(parkinglots, 0); 06358 for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) { 06359 /* Add the parking lot to the map. */ 06360 if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) { 06361 ao2_ref(curlot, -1); 06362 status = -1; 06363 break; 06364 } 06365 } 06366 ao2_iterator_destroy(&iter); 06367 06368 return status; 06369 }
static struct parking_dp_ramp* build_dialplan_useage_ramp | ( | const char * | exten, | |
int | exclusive | |||
) | [static, read] |
Definition at line 6041 of file features.c.
References ast_calloc, parking_dp_ramp::exclusive, and parking_dp_ramp::exten.
Referenced by usage_context_add_ramp().
06042 { 06043 struct parking_dp_ramp *ramp_node; 06044 06045 ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten)); 06046 if (!ramp_node) { 06047 return NULL; 06048 } 06049 ramp_node->exclusive = exclusive; 06050 strcpy(ramp_node->exten, exten); 06051 return ramp_node; 06052 }
static struct parking_dp_spaces* build_dialplan_useage_spaces | ( | int | start, | |
int | stop | |||
) | [static, read] |
Definition at line 6122 of file features.c.
References ast_calloc, parking_dp_spaces::start, and parking_dp_spaces::stop.
Referenced by usage_context_add_spaces().
06123 { 06124 struct parking_dp_spaces *spaces_node; 06125 06126 spaces_node = ast_calloc(1, sizeof(*spaces_node)); 06127 if (!spaces_node) { 06128 return NULL; 06129 } 06130 spaces_node->start = start; 06131 spaces_node->stop = stop; 06132 return spaces_node; 06133 }
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 5643 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().
05644 { 05645 struct ast_parkinglot *parkinglot; 05646 const struct parkinglot_cfg *cfg_defaults; 05647 struct parkinglot_cfg new_cfg; 05648 int cfg_error; 05649 int oldparkinglot = 0; 05650 05651 parkinglot = find_parkinglot(pl_name); 05652 if (parkinglot) { 05653 oldparkinglot = 1; 05654 } else { 05655 parkinglot = create_parkinglot(pl_name); 05656 if (!parkinglot) { 05657 return NULL; 05658 } 05659 } 05660 if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) { 05661 cfg_defaults = &parkinglot_cfg_default_default; 05662 } else { 05663 cfg_defaults = &parkinglot_cfg_default; 05664 } 05665 new_cfg = *cfg_defaults; 05666 05667 ast_debug(1, "Building parking lot %s\n", parkinglot->name); 05668 05669 ao2_lock(parkinglot); 05670 05671 /* Do some config stuff */ 05672 cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var); 05673 if (oldparkinglot) { 05674 if (cfg_error) { 05675 /* Bad configuration read. Keep using the original config. */ 05676 ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n", 05677 parkinglot->name); 05678 cfg_error = 0; 05679 } else if (!AST_LIST_EMPTY(&parkinglot->parkings) 05680 && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) { 05681 /* Try reloading later when parking lot is empty. */ 05682 ast_log(LOG_WARNING, 05683 "Parking lot %s has parked calls. Parking lot changes discarded.\n", 05684 parkinglot->name); 05685 force_reload_load = 1; 05686 } else { 05687 /* Accept the new config */ 05688 parkinglot->cfg = new_cfg; 05689 } 05690 } else { 05691 /* Load the initial parking lot config. */ 05692 parkinglot->cfg = new_cfg; 05693 } 05694 parkinglot->the_mark = 0; 05695 05696 ao2_unlock(parkinglot); 05697 05698 if (cfg_error) { 05699 /* Only new parking lots could have config errors here. */ 05700 ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name); 05701 parkinglot_unref(parkinglot); 05702 return NULL; 05703 } 05704 05705 /* Move it into the list, if it wasn't already there */ 05706 if (!oldparkinglot) { 05707 ao2_link(parkinglots, parkinglot); 05708 } 05709 parkinglot_unref(parkinglot); 05710 05711 return parkinglot; 05712 }
static int builtin_atxfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Attended transfer.
chan | transfered user | |
peer | person transfering call | |
config | ||
code | ||
sense | feature options | |
data | Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel. |
Definition at line 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 %d 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 transfered | |
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 4629 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().
04630 { 04631 int i = 0; 04632 enum { 04633 OPT_CALLEE_REDIRECT = 't', 04634 OPT_CALLER_REDIRECT = 'T', 04635 OPT_CALLEE_AUTOMON = 'w', 04636 OPT_CALLER_AUTOMON = 'W', 04637 OPT_CALLEE_DISCONNECT = 'h', 04638 OPT_CALLER_DISCONNECT = 'H', 04639 OPT_CALLEE_PARKCALL = 'k', 04640 OPT_CALLER_PARKCALL = 'K', 04641 }; 04642 04643 memset(options, 0, len); 04644 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 04645 options[i++] = OPT_CALLER_REDIRECT; 04646 } 04647 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 04648 options[i++] = OPT_CALLER_AUTOMON; 04649 } 04650 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 04651 options[i++] = OPT_CALLER_DISCONNECT; 04652 } 04653 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 04654 options[i++] = OPT_CALLER_PARKCALL; 04655 } 04656 04657 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 04658 options[i++] = OPT_CALLEE_REDIRECT; 04659 } 04660 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 04661 options[i++] = OPT_CALLEE_AUTOMON; 04662 } 04663 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 04664 options[i++] = OPT_CALLEE_DISCONNECT; 04665 } 04666 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 04667 options[i++] = OPT_CALLEE_PARKCALL; 04668 } 04669 04670 return options; 04671 }
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 3889 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().
03890 { 03891 struct ast_datastore *di_datastore; 03892 03893 ast_channel_lock(chan); 03894 if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) { 03895 if (option_debug) { 03896 ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name); 03897 } 03898 if (!ast_channel_datastore_remove(chan, di_datastore)) { 03899 ast_datastore_free(di_datastore); 03900 } 03901 } 03902 ast_channel_unlock(chan); 03903 }
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 4994 of file features.c.
References ao2_ref, ast_debug, ast_parkinglot::cfg, create_parkinglot(), and find_parkinglot().
Referenced by create_dynamic_parkinglot().
04995 { 04996 struct ast_parkinglot *copylot; 04997 04998 if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */ 04999 ao2_ref(copylot, -1); 05000 return NULL; 05001 } 05002 05003 copylot = create_parkinglot(name); 05004 if (!copylot) { 05005 return NULL; 05006 } 05007 05008 ast_debug(1, "Building parking lot %s\n", name); 05009 05010 /* Copy the source parking lot configuration. */ 05011 copylot->cfg = parkinglot->cfg; 05012 05013 return copylot; 05014 }
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 5419 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().
05420 { 05421 struct ast_parkinglot *newlot; 05422 05423 if (ast_strlen_zero(name)) { /* No name specified */ 05424 return NULL; 05425 } 05426 05427 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 05428 if (!newlot) 05429 return NULL; 05430 05431 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 05432 newlot->cfg.is_invalid = 1;/* No config is set yet. */ 05433 AST_LIST_HEAD_INIT(&newlot->parkings); 05434 05435 return newlot; 05436 }
static void destroy_dialplan_usage_context | ( | struct parking_dp_context * | doomed | ) | [static] |
Definition at line 5997 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().
05998 { 05999 struct parking_dp_ramp *ramp; 06000 struct parking_dp_spaces *spaces; 06001 06002 while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) { 06003 ast_free(ramp); 06004 } 06005 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) { 06006 ast_free(spaces); 06007 } 06008 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) { 06009 ast_free(spaces); 06010 } 06011 ast_free(doomed); 06012 }
static void destroy_dialplan_usage_map | ( | struct parking_dp_map * | doomed | ) | [static] |
Definition at line 6022 of file features.c.
References AST_LIST_REMOVE_HEAD, and destroy_dialplan_usage_context().
Referenced by load_config().
06023 { 06024 struct parking_dp_context *item; 06025 06026 while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) { 06027 destroy_dialplan_usage_context(item); 06028 } 06029 }
static void destroy_space | ( | const char * | context, | |
int | space | |||
) | [static] |
Definition at line 6452 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().
06453 { 06454 char exten[AST_MAX_EXTENSION]; 06455 06456 /* Destroy priorities of the parking space that we registered. */ 06457 snprintf(exten, sizeof(exten), "%d", space); 06458 remove_exten_if_exist(context, exten, PRIORITY_HINT); 06459 remove_exten_if_exist(context, exten, 1); 06460 }
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 6305 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().
06306 { 06307 struct parking_dp_context *cur_ctx; 06308 struct parking_dp_context *new_ctx; 06309 int cmp; 06310 06311 AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) { 06312 cmp = strcmp(lot->cfg.parking_con, cur_ctx->context); 06313 if (cmp > 0) { 06314 /* The parking lot context goes after this node. */ 06315 continue; 06316 } 06317 if (cmp == 0) { 06318 /* This is the node we will add parking lot spaces to the map. */ 06319 return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain); 06320 } 06321 /* The new parking lot context goes before this node. */ 06322 new_ctx = build_dialplan_useage_context(lot); 06323 if (!new_ctx) { 06324 return -1; 06325 } 06326 AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node); 06327 return 0; 06328 } 06329 AST_LIST_TRAVERSE_SAFE_END; 06330 06331 /* New parking lot context goes on the end. */ 06332 new_ctx = build_dialplan_useage_context(lot); 06333 if (!new_ctx) { 06334 return -1; 06335 } 06336 AST_LIST_INSERT_TAIL(usage_map, new_ctx, node); 06337 return 0; 06338 }
static int dialplan_usage_add_parkinglot_data | ( | struct parking_dp_context * | ctx_node, | |
struct ast_parkinglot * | lot, | |||
int | complain | |||
) | [static] |
Definition at line 6251 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().
06252 { 06253 if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext, 06254 lot->cfg.parkext_exclusive, lot, complain)) { 06255 return -1; 06256 } 06257 if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start, 06258 lot->cfg.parking_stop, lot, complain)) { 06259 return -1; 06260 } 06261 if (lot->cfg.parkaddhints 06262 && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start, 06263 lot->cfg.parking_stop, lot, 0)) { 06264 return -1; 06265 } 06266 return 0; 06267 }
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 6887 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().
06888 { 06889 const char *context; 06890 const char *exten; 06891 int priority; 06892 06893 ast_moh_stop(chan); 06894 ast_channel_lock_both(chan, tmpchan); 06895 context = ast_strdupa(chan->context); 06896 exten = ast_strdupa(chan->exten); 06897 priority = chan->priority; 06898 ast_setstate(tmpchan, chan->_state); 06899 tmpchan->readformat = chan->readformat; 06900 tmpchan->writeformat = chan->writeformat; 06901 ast_channel_unlock(chan); 06902 ast_channel_unlock(tmpchan); 06903 06904 /* Masquerade setup and execution must be done without any channel locks held */ 06905 if (ast_channel_masquerade(tmpchan, chan)) { 06906 return -1; 06907 } 06908 ast_do_masquerade(tmpchan); 06909 06910 /* when returning from bridge, the channel will continue at the next priority */ 06911 ast_explicit_goto(tmpchan, context, exten, priority + 1); 06912 06913 return 0; 06914 }
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 4944 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().
04945 { 04946 struct pollfd *pfds = NULL, *new_pfds = NULL; 04947 int nfds = 0, new_nfds = 0; 04948 04949 for (;;) { 04950 struct ao2_iterator iter; 04951 struct ast_parkinglot *curlot; 04952 int ms = -1; /* poll2 timeout, uninitialized */ 04953 04954 iter = ao2_iterator_init(parkinglots, 0); 04955 while ((curlot = ao2_iterator_next(&iter))) { 04956 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms); 04957 ao2_ref(curlot, -1); 04958 } 04959 ao2_iterator_destroy(&iter); 04960 04961 /* Recycle */ 04962 ast_free(pfds); 04963 pfds = new_pfds; 04964 nfds = new_nfds; 04965 new_pfds = NULL; 04966 new_nfds = 0; 04967 04968 /* Wait for something to happen */ 04969 ast_poll(pfds, nfds, ms); 04970 pthread_testcancel(); 04971 } 04972 /* If this WERE reached, we'd need to free(pfds) */ 04973 return NULL; /* Never reached */ 04974 }
static int feature_check | ( | struct ast_channel * | chan, | |
struct ast_flags * | features, | |||
char * | code | |||
) | [static] |
Check if a feature exists.
Definition at line 3418 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().
03418 { 03419 char *chan_dynamic_features; 03420 ast_channel_lock(chan); 03421 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03422 ast_channel_unlock(chan); 03423 03424 return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL); 03425 }
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_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 res = pbx_exec(work, app, feature->app_args); 03214 03215 if (!ast_strlen_zero(feature->moh_class)) 03216 ast_moh_stop(idle); 03217 03218 ast_autoservice_stop(idle); 03219 03220 if (res) { 03221 return AST_FEATURE_RETURN_SUCCESSBREAK; 03222 } 03223 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 03224 }
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 3381 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().
03381 { 03382 03383 char dynamic_features_buf[128]; 03384 const char *peer_dynamic_features, *chan_dynamic_features; 03385 struct ast_flags features; 03386 struct ast_call_feature feature; 03387 if (sense == FEATURE_SENSE_CHAN) { 03388 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 03389 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 03390 } 03391 else { 03392 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 03393 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 03394 } 03395 03396 ast_channel_lock(peer); 03397 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 03398 ast_channel_unlock(peer); 03399 03400 ast_channel_lock(chan); 03401 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03402 ast_channel_unlock(chan); 03403 03404 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,"")); 03405 03406 ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf); 03407 03408 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature); 03409 }
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 3264 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().
03267 { 03268 int x; 03269 struct feature_group *fg = NULL; 03270 struct feature_group_exten *fge; 03271 struct ast_call_feature *tmpfeature; 03272 char *tmp, *tok; 03273 int res = AST_FEATURE_RETURN_PASSDIGITS; 03274 int feature_detected = 0; 03275 03276 if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) { 03277 return -1; /* can not run feature operation */ 03278 } 03279 03280 ast_rwlock_rdlock(&features_lock); 03281 for (x = 0; x < FEATURES_COUNT; x++) { 03282 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 03283 !ast_strlen_zero(builtin_features[x].exten)) { 03284 /* Feature is up for consideration */ 03285 if (!strcmp(builtin_features[x].exten, code)) { 03286 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 03287 if (operation == FEATURE_INTERPRET_CHECK) { 03288 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03289 } else if (operation == FEATURE_INTERPRET_DO) { 03290 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 03291 } 03292 if (feature) { 03293 memcpy(feature, &builtin_features[x], sizeof(*feature)); 03294 } 03295 feature_detected = 1; 03296 break; 03297 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 03298 if (res == AST_FEATURE_RETURN_PASSDIGITS) { 03299 res = AST_FEATURE_RETURN_STOREDIGITS; 03300 } 03301 } 03302 } 03303 } 03304 ast_rwlock_unlock(&features_lock); 03305 03306 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 03307 return res; 03308 } 03309 03310 tmp = dynamic_features_buf; 03311 03312 while ((tok = strsep(&tmp, "#"))) { 03313 AST_RWLIST_RDLOCK(&feature_groups); 03314 03315 fg = find_group(tok); 03316 03317 if (fg) { 03318 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03319 if (!strcmp(fge->exten, code)) { 03320 if (operation) { 03321 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 03322 } 03323 if (feature) { 03324 memcpy(feature, fge->feature, sizeof(*feature)); 03325 } 03326 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03327 AST_RWLIST_UNLOCK(&feature_groups); 03328 break; 03329 } 03330 res = AST_FEATURE_RETURN_PASSDIGITS; 03331 } else if (!strncmp(fge->exten, code, strlen(code))) { 03332 res = AST_FEATURE_RETURN_STOREDIGITS; 03333 } 03334 } 03335 if (fge) { 03336 break; 03337 } 03338 } 03339 03340 AST_RWLIST_UNLOCK(&feature_groups); 03341 03342 AST_RWLIST_RDLOCK(&feature_list); 03343 03344 if (!(tmpfeature = find_dynamic_feature(tok))) { 03345 AST_RWLIST_UNLOCK(&feature_list); 03346 continue; 03347 } 03348 03349 /* Feature is up for consideration */ 03350 if (!strcmp(tmpfeature->exten, code)) { 03351 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 03352 if (operation == FEATURE_INTERPRET_CHECK) { 03353 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03354 } else if (operation == FEATURE_INTERPRET_DO) { 03355 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 03356 } 03357 if (feature) { 03358 memcpy(feature, tmpfeature, sizeof(*feature)); 03359 } 03360 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03361 AST_RWLIST_UNLOCK(&feature_list); 03362 break; 03363 } 03364 res = AST_FEATURE_RETURN_PASSDIGITS; 03365 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 03366 res = AST_FEATURE_RETURN_STOREDIGITS; 03367 03368 AST_RWLIST_UNLOCK(&feature_list); 03369 } 03370 03371 return res; 03372 }
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 3522 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().
03526 { 03527 int state = 0; 03528 int cause = 0; 03529 int to; 03530 int caller_hungup; 03531 int transferee_hungup; 03532 struct ast_channel *chan; 03533 struct ast_channel *monitor_chans[3]; 03534 struct ast_channel *active_channel; 03535 int res; 03536 int ready = 0; 03537 struct timeval started; 03538 int x, len = 0; 03539 char *disconnect_code = NULL, *dialed_code = NULL; 03540 struct ast_frame *f; 03541 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; 03542 03543 caller_hungup = ast_check_hangup(caller); 03544 03545 if (!(chan = ast_request(type, format, requestor, data, &cause))) { 03546 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 03547 switch (cause) { 03548 case AST_CAUSE_BUSY: 03549 state = AST_CONTROL_BUSY; 03550 break; 03551 case AST_CAUSE_CONGESTION: 03552 state = AST_CONTROL_CONGESTION; 03553 break; 03554 default: 03555 state = 0; 03556 break; 03557 } 03558 goto done; 03559 } 03560 03561 ast_string_field_set(chan, language, language); 03562 ast_channel_inherit_variables(caller, chan); 03563 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name); 03564 03565 ast_channel_lock(chan); 03566 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller); 03567 ast_channel_unlock(chan); 03568 03569 if (ast_call(chan, data, timeout)) { 03570 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 03571 switch (chan->hangupcause) { 03572 case AST_CAUSE_BUSY: 03573 state = AST_CONTROL_BUSY; 03574 break; 03575 case AST_CAUSE_CONGESTION: 03576 state = AST_CONTROL_CONGESTION; 03577 break; 03578 default: 03579 state = 0; 03580 break; 03581 } 03582 goto done; 03583 } 03584 03585 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 03586 ast_rwlock_rdlock(&features_lock); 03587 for (x = 0; x < FEATURES_COUNT; x++) { 03588 if (strcasecmp(builtin_features[x].sname, "disconnect")) 03589 continue; 03590 03591 disconnect_code = builtin_features[x].exten; 03592 len = strlen(disconnect_code) + 1; 03593 dialed_code = ast_alloca(len); 03594 memset(dialed_code, 0, len); 03595 break; 03596 } 03597 ast_rwlock_unlock(&features_lock); 03598 x = 0; 03599 started = ast_tvnow(); 03600 to = timeout; 03601 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); 03602 03603 ast_poll_channel_add(caller, chan); 03604 03605 transferee_hungup = 0; 03606 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) { 03607 int num_chans = 0; 03608 03609 monitor_chans[num_chans++] = transferee; 03610 monitor_chans[num_chans++] = chan; 03611 if (!caller_hungup) { 03612 if (ast_check_hangup(caller)) { 03613 caller_hungup = 1; 03614 03615 #if defined(ATXFER_NULL_TECH) 03616 /* Change caller's name to ensure that it will remain unique. */ 03617 set_new_chan_name(caller); 03618 03619 /* 03620 * Get rid of caller's physical technology so it is free for 03621 * other calls. 03622 */ 03623 set_kill_chan_tech(caller); 03624 #endif /* defined(ATXFER_NULL_TECH) */ 03625 } else { 03626 /* caller is not hungup so monitor it. */ 03627 monitor_chans[num_chans++] = caller; 03628 } 03629 } 03630 03631 /* see if the timeout has been violated */ 03632 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 03633 state = AST_CONTROL_UNHOLD; 03634 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name); 03635 break; /*doh! timeout*/ 03636 } 03637 03638 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to); 03639 if (!active_channel) 03640 continue; 03641 03642 f = NULL; 03643 if (transferee == active_channel) { 03644 struct ast_frame *dup_f; 03645 03646 f = ast_read(transferee); 03647 if (f == NULL) { /*doh! where'd he go?*/ 03648 transferee_hungup = 1; 03649 state = 0; 03650 break; 03651 } 03652 if (ast_is_deferrable_frame(f)) { 03653 dup_f = ast_frisolate(f); 03654 if (dup_f) { 03655 if (dup_f == f) { 03656 f = NULL; 03657 } 03658 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); 03659 } 03660 } 03661 } else if (chan == active_channel) { 03662 if (!ast_strlen_zero(chan->call_forward)) { 03663 state = 0; 03664 ast_autoservice_start(transferee); 03665 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state); 03666 ast_autoservice_stop(transferee); 03667 if (!chan) { 03668 break; 03669 } 03670 continue; 03671 } 03672 f = ast_read(chan); 03673 if (f == NULL) { /*doh! where'd he go?*/ 03674 switch (chan->hangupcause) { 03675 case AST_CAUSE_BUSY: 03676 state = AST_CONTROL_BUSY; 03677 break; 03678 case AST_CAUSE_CONGESTION: 03679 state = AST_CONTROL_CONGESTION; 03680 break; 03681 default: 03682 state = 0; 03683 break; 03684 } 03685 break; 03686 } 03687 03688 if (f->frametype == AST_FRAME_CONTROL) { 03689 if (f->subclass.integer == AST_CONTROL_RINGING) { 03690 ast_verb(3, "%s is ringing\n", chan->name); 03691 ast_indicate(caller, AST_CONTROL_RINGING); 03692 } else if (f->subclass.integer == AST_CONTROL_BUSY) { 03693 state = f->subclass.integer; 03694 ast_verb(3, "%s is busy\n", chan->name); 03695 ast_indicate(caller, AST_CONTROL_BUSY); 03696 ast_frfree(f); 03697 break; 03698 } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) { 03699 ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", chan->name, chan->exten); 03700 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) { 03701 state = f->subclass.integer; 03702 ast_verb(3, "%s is congested\n", chan->name); 03703 ast_indicate(caller, AST_CONTROL_CONGESTION); 03704 ast_frfree(f); 03705 break; 03706 } else if (f->subclass.integer == AST_CONTROL_ANSWER) { 03707 /* This is what we are hoping for */ 03708 state = f->subclass.integer; 03709 ast_frfree(f); 03710 ready=1; 03711 break; 03712 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) { 03713 if (caller_hungup) { 03714 struct ast_party_connected_line connected; 03715 03716 /* Just save it for the transfer. */ 03717 ast_party_connected_line_set_init(&connected, &caller->connected); 03718 res = ast_connected_line_parse_data(f->data.ptr, f->datalen, 03719 &connected); 03720 if (!res) { 03721 ast_channel_set_connected_line(caller, &connected, NULL); 03722 } 03723 ast_party_connected_line_free(&connected); 03724 } else { 03725 ast_autoservice_start(transferee); 03726 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { 03727 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, 03728 f->data.ptr, f->datalen); 03729 } 03730 ast_autoservice_stop(transferee); 03731 } 03732 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) { 03733 if (!caller_hungup) { 03734 ast_autoservice_start(transferee); 03735 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { 03736 ast_indicate_data(caller, AST_CONTROL_REDIRECTING, 03737 f->data.ptr, f->datalen); 03738 } 03739 ast_autoservice_stop(transferee); 03740 } 03741 } else if (f->subclass.integer != -1 03742 && f->subclass.integer != AST_CONTROL_PROGRESS 03743 && f->subclass.integer != AST_CONTROL_PROCEEDING) { 03744 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer); 03745 } 03746 /* else who cares */ 03747 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03748 ast_write(caller, f); 03749 } 03750 } else if (caller == active_channel) { 03751 f = ast_read(caller); 03752 if (f) { 03753 if (f->frametype == AST_FRAME_DTMF) { 03754 dialed_code[x++] = f->subclass.integer; 03755 dialed_code[x] = '\0'; 03756 if (strlen(dialed_code) == len) { 03757 x = 0; 03758 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 03759 x = 0; 03760 dialed_code[x] = '\0'; 03761 } 03762 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 03763 /* Caller Canceled the call */ 03764 state = AST_CONTROL_UNHOLD; 03765 ast_frfree(f); 03766 break; 03767 } 03768 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03769 ast_write(chan, f); 03770 } 03771 } 03772 } 03773 if (f) 03774 ast_frfree(f); 03775 } /* end while */ 03776 03777 ast_poll_channel_del(caller, chan); 03778 03779 /* 03780 * We need to free all the deferred frames, but we only need to 03781 * queue the deferred frames if no hangup was received. 03782 */ 03783 ast_channel_lock(transferee); 03784 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee)); 03785 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { 03786 if (!transferee_hungup) { 03787 ast_queue_frame_head(transferee, f); 03788 } 03789 ast_frfree(f); 03790 } 03791 ast_channel_unlock(transferee); 03792 03793 done: 03794 ast_indicate(caller, -1); 03795 if (chan && (ready || chan->_state == AST_STATE_UP)) { 03796 state = AST_CONTROL_ANSWER; 03797 } else if (chan) { 03798 ast_hangup(chan); 03799 chan = NULL; 03800 } 03801 03802 if (outstate) 03803 *outstate = state; 03804 03805 return chan; 03806 }
static void features_shutdown | ( | void | ) | [static] |
Definition at line 8267 of file features.c.
References ao2_ref, ast_devstate_prov_del(), ast_manager_unregister(), ast_unregister_application(), parkcall, parking_thread, and parkinglots.
Referenced by ast_features_init().
08268 { 08269 ast_devstate_prov_del("Park"); 08270 ast_manager_unregister("Bridge"); 08271 ast_manager_unregister("Park"); 08272 ast_manager_unregister("Parkinglots"); 08273 ast_manager_unregister("ParkedCalls"); 08274 ast_unregister_application(parkcall); 08275 ast_unregister_application(parkedcall); 08276 ast_unregister_application(app_bridge); 08277 08278 pthread_cancel(parking_thread); 08279 ao2_ref(parkinglots, -1); 08280 }
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 7310 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().
07311 { 07312 struct ast_channel *target = obj;/*!< Potential pickup target */ 07313 struct ast_channel *chan = data;/*!< Channel wanting to pickup call */ 07314 07315 ast_channel_lock(target); 07316 if (chan != target && (chan->pickupgroup & target->callgroup) 07317 && ast_can_pickup(target)) { 07318 /* Return with the channel still locked on purpose */ 07319 return CMP_MATCH | CMP_STOP; 07320 } 07321 ast_channel_unlock(target); 07322 07323 return 0; 07324 }
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 4977 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().
04978 { 04979 struct ast_parkinglot *parkinglot; 04980 04981 if (ast_strlen_zero(name)) { 04982 return NULL; 04983 } 04984 04985 parkinglot = ao2_find(parkinglots, (void *) name, 0); 04986 if (parkinglot) { 04987 ast_debug(1, "Found Parking lot: %s\n", parkinglot->name); 04988 } 04989 04990 return parkinglot; 04991 }
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 6753 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.
06754 { 06755 int i; 06756 struct ast_call_feature *feature; 06757 struct ao2_iterator iter; 06758 struct ast_parkinglot *curlot; 06759 #define HFS_FORMAT "%-25s %-7s %-7s\n" 06760 06761 switch (cmd) { 06762 06763 case CLI_INIT: 06764 e->command = "features show"; 06765 e->usage = 06766 "Usage: features show\n" 06767 " Lists configured features\n"; 06768 return NULL; 06769 case CLI_GENERATE: 06770 return NULL; 06771 } 06772 06773 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 06774 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06775 06776 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 06777 06778 ast_rwlock_rdlock(&features_lock); 06779 for (i = 0; i < FEATURES_COUNT; i++) 06780 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 06781 ast_rwlock_unlock(&features_lock); 06782 06783 ast_cli(a->fd, "\n"); 06784 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 06785 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06786 if (AST_RWLIST_EMPTY(&feature_list)) { 06787 ast_cli(a->fd, "(none)\n"); 06788 } else { 06789 AST_RWLIST_RDLOCK(&feature_list); 06790 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 06791 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 06792 } 06793 AST_RWLIST_UNLOCK(&feature_list); 06794 } 06795 06796 ast_cli(a->fd, "\nFeature Groups:\n"); 06797 ast_cli(a->fd, "---------------\n"); 06798 if (AST_RWLIST_EMPTY(&feature_groups)) { 06799 ast_cli(a->fd, "(none)\n"); 06800 } else { 06801 struct feature_group *fg; 06802 struct feature_group_exten *fge; 06803 06804 AST_RWLIST_RDLOCK(&feature_groups); 06805 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 06806 ast_cli(a->fd, "===> Group: %s\n", fg->gname); 06807 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 06808 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten); 06809 } 06810 } 06811 AST_RWLIST_UNLOCK(&feature_groups); 06812 } 06813 06814 iter = ao2_iterator_init(parkinglots, 0); 06815 while ((curlot = ao2_iterator_next(&iter))) { 06816 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 06817 ast_cli(a->fd, "------------\n"); 06818 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->cfg.parkext); 06819 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->cfg.parking_con); 06820 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", 06821 curlot->cfg.parking_start, curlot->cfg.parking_stop); 06822 ast_cli(a->fd,"%-22s: %d ms\n", "Parkingtime", curlot->cfg.parkingtime); 06823 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->cfg.mohclass); 06824 ast_cli(a->fd,"%-22s: %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled)); 06825 ast_cli(a->fd,"\n"); 06826 ao2_ref(curlot, -1); 06827 } 06828 ao2_iterator_destroy(&iter); 06829 06830 return CLI_SUCCESS; 06831 }
static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6859 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
06860 { 06861 switch (cmd) { 06862 case CLI_INIT: 06863 e->command = "features reload"; 06864 e->usage = 06865 "Usage: features reload\n" 06866 " Reloads configured call features from features.conf\n"; 06867 return NULL; 06868 case CLI_GENERATE: 06869 return NULL; 06870 } 06871 ast_features_reload(); 06872 06873 return CLI_SUCCESS; 06874 }
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 7063 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.
07064 { 07065 struct parkeduser *cur; 07066 int numparked = 0; 07067 struct ao2_iterator iter; 07068 struct ast_parkinglot *curlot; 07069 07070 switch (cmd) { 07071 case CLI_INIT: 07072 e->command = "parkedcalls show"; 07073 e->usage = 07074 "Usage: parkedcalls show\n" 07075 " List currently parked calls\n"; 07076 return NULL; 07077 case CLI_GENERATE: 07078 return NULL; 07079 } 07080 07081 if (a->argc > e->args) 07082 return CLI_SHOWUSAGE; 07083 07084 ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel", 07085 "Context", "Extension", "Pri", "Timeout"); 07086 07087 iter = ao2_iterator_init(parkinglots, 0); 07088 while ((curlot = ao2_iterator_next(&iter))) { 07089 int lotparked = 0; 07090 07091 /* subtract ref for iterator and for configured parking lot */ 07092 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, 07093 ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot)); 07094 07095 AST_LIST_LOCK(&curlot->parkings); 07096 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 07097 ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n", 07098 cur->parkingexten, cur->chan->name, cur->context, cur->exten, 07099 cur->priority, 07100 (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL))); 07101 ++lotparked; 07102 } 07103 AST_LIST_UNLOCK(&curlot->parkings); 07104 if (lotparked) { 07105 numparked += lotparked; 07106 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, 07107 ESS(lotparked), curlot->name); 07108 } 07109 07110 ao2_ref(curlot, -1); 07111 } 07112 ao2_iterator_destroy(&iter); 07113 07114 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 07115 07116 return CLI_SUCCESS; 07117 }
static int load_config | ( | int | reload | ) | [static] |
Definition at line 6671 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().
06672 { 06673 struct ast_flags config_flags = { 06674 reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06675 struct ast_config *cfg; 06676 struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06677 struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06678 06679 /* We are reloading now and have already determined if we will force the reload. */ 06680 force_reload_load = 0; 06681 06682 if (!default_parkinglot) { 06683 /* Must create the default default parking lot */ 06684 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 06685 if (!default_parkinglot) { 06686 ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n"); 06687 return -1; 06688 } 06689 ast_debug(1, "Configuration of default default parking lot done.\n"); 06690 } 06691 06692 cfg = ast_config_load2("features.conf", "features", config_flags); 06693 if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06694 /* No sense in asking for reload trouble if nothing changed. */ 06695 ast_debug(1, "features.conf did not change.\n"); 06696 return 0; 06697 } 06698 if (cfg == CONFIG_STATUS_FILEMISSING 06699 || cfg == CONFIG_STATUS_FILEINVALID) { 06700 ast_log(LOG_WARNING, "Could not load features.conf\n"); 06701 return 0; 06702 } 06703 06704 /* Save current parking lot dialplan needs. */ 06705 if (build_dialplan_useage_map(&old_usage_map, 0)) { 06706 destroy_dialplan_usage_map(&old_usage_map); 06707 06708 /* Allow reloading later to see if conditions have improved. */ 06709 force_reload_load = 1; 06710 return -1; 06711 } 06712 06713 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, 06714 "callback to mark all parking lots"); 06715 process_config(cfg); 06716 ast_config_destroy(cfg); 06717 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, 06718 "callback to remove marked parking lots"); 06719 06720 /* Save updated parking lot dialplan needs. */ 06721 if (build_dialplan_useage_map(&new_usage_map, 1)) { 06722 /* 06723 * Yuck, if this failure caused any parking lot dialplan items 06724 * to be lost, they will likely remain lost until Asterisk is 06725 * restarted. 06726 */ 06727 destroy_dialplan_usage_map(&old_usage_map); 06728 destroy_dialplan_usage_map(&new_usage_map); 06729 return -1; 06730 } 06731 06732 /* Remove no longer needed parking lot dialplan usage. */ 06733 remove_dead_dialplan_useage(&old_usage_map, &new_usage_map); 06734 06735 destroy_dialplan_usage_map(&old_usage_map); 06736 destroy_dialplan_usage_map(&new_usage_map); 06737 06738 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL, 06739 "callback to activate all parking lots"); 06740 06741 return 0; 06742 }
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 4681 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().
04682 { 04683 struct ast_channel *chan = pu->chan; /* shorthand */ 04684 int tms; /* timeout for this item */ 04685 int x; /* fd index in channel */ 04686 04687 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 04688 if (tms > pu->parkingtime) { 04689 /* 04690 * Call has been parked too long. 04691 * Stop entertaining the caller. 04692 */ 04693 switch (pu->hold_method) { 04694 case AST_CONTROL_HOLD: 04695 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 04696 break; 04697 case AST_CONTROL_RINGING: 04698 ast_indicate(pu->chan, -1); 04699 break; 04700 default: 04701 break; 04702 } 04703 pu->hold_method = 0; 04704 04705 /* Get chan, exten from derived kludge */ 04706 if (pu->peername[0]) { 04707 char *peername; 04708 char *dash; 04709 char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 04710 int i; 04711 04712 peername = ast_strdupa(pu->peername); 04713 dash = strrchr(peername, '-'); 04714 if (dash) { 04715 *dash = '\0'; 04716 } 04717 04718 peername_flat = ast_strdupa(peername); 04719 for (i = 0; peername_flat[i]; i++) { 04720 if (peername_flat[i] == '/') { 04721 peername_flat[i] = '_'; 04722 } 04723 } 04724 04725 if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) { 04726 ast_log(LOG_ERROR, 04727 "Parking dial context '%s' does not exist and unable to create\n", 04728 parking_con_dial); 04729 } else { 04730 char returnexten[AST_MAX_EXTENSION]; 04731 struct ast_datastore *features_datastore; 04732 struct ast_dial_features *dialfeatures; 04733 04734 if (!strncmp(peername, "Parked/", 7)) { 04735 peername += 7; 04736 } 04737 04738 ast_channel_lock(chan); 04739 features_datastore = ast_channel_datastore_find(chan, &dial_features_info, 04740 NULL); 04741 if (features_datastore && (dialfeatures = features_datastore->data)) { 04742 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 04743 04744 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, 04745 callback_dialoptions(&dialfeatures->peer_features, 04746 &dialfeatures->my_features, buf, sizeof(buf))); 04747 } else { /* Existing default */ 04748 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", 04749 chan->name); 04750 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername); 04751 } 04752 ast_channel_unlock(chan); 04753 04754 if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL, 04755 "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) { 04756 ast_log(LOG_ERROR, 04757 "Could not create parking return dial exten: %s@%s\n", 04758 peername_flat, parking_con_dial); 04759 } 04760 } 04761 if (pu->options_specified) { 04762 /* 04763 * Park() was called with overriding return arguments, respect 04764 * those arguments. 04765 */ 04766 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04767 } else if (comebacktoorigin) { 04768 set_c_e_p(chan, parking_con_dial, peername_flat, 1); 04769 } else { 04770 char parkingslot[AST_MAX_EXTENSION]; 04771 04772 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 04773 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 04774 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 04775 } 04776 } else { 04777 /* 04778 * They've been waiting too long, send them back to where they 04779 * came. Theoretically they should have their original 04780 * extensions and such, but we copy to be on the safe side. 04781 */ 04782 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04783 } 04784 post_manager_event("ParkedCallTimeOut", pu); 04785 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL); 04786 04787 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", 04788 pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, 04789 pu->chan->exten, pu->chan->priority); 04790 04791 /* Start up the PBX, or hang them up */ 04792 if (ast_pbx_start(chan)) { 04793 ast_log(LOG_WARNING, 04794 "Unable to restart the PBX for user on '%s', hanging them up...\n", 04795 pu->chan->name); 04796 ast_hangup(chan); 04797 } 04798 04799 /* And take them out of the parking lot */ 04800 return 1; 04801 } 04802 04803 /* still within parking time, process descriptors */ 04804 if (pfds) { 04805 for (x = 0; x < AST_MAX_FDS; x++) { 04806 struct ast_frame *f; 04807 int y; 04808 04809 if (chan->fds[x] == -1) { 04810 continue; /* nothing on this descriptor */ 04811 } 04812 04813 for (y = 0; y < nfds; y++) { 04814 if (pfds[y].fd == chan->fds[x]) { 04815 /* Found poll record! */ 04816 break; 04817 } 04818 } 04819 if (y == nfds) { 04820 /* Not found */ 04821 continue; 04822 } 04823 04824 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) { 04825 /* Next x */ 04826 continue; 04827 } 04828 04829 if (pfds[y].revents & POLLPRI) { 04830 ast_set_flag(chan, AST_FLAG_EXCEPTION); 04831 } else { 04832 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 04833 } 04834 chan->fdno = x; 04835 04836 /* See if they need servicing */ 04837 f = ast_read(pu->chan); 04838 /* Hangup? */ 04839 if (!f || (f->frametype == AST_FRAME_CONTROL 04840 && f->subclass.integer == AST_CONTROL_HANGUP)) { 04841 if (f) { 04842 ast_frfree(f); 04843 } 04844 post_manager_event("ParkedCallGiveUp", pu); 04845 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", 04846 NULL); 04847 04848 /* There's a problem, hang them up */ 04849 ast_verb(2, "%s got tired of being parked\n", chan->name); 04850 ast_hangup(chan); 04851 04852 /* And take them out of the parking lot */ 04853 return 1; 04854 } else { 04855 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 04856 ast_frfree(f); 04857 if (pu->hold_method == AST_CONTROL_HOLD 04858 && pu->moh_trys < 3 04859 && !chan->generatordata) { 04860 ast_debug(1, 04861 "MOH on parked call stopped by outside source. Restarting on channel %s.\n", 04862 chan->name); 04863 ast_indicate_data(chan, AST_CONTROL_HOLD, 04864 S_OR(pu->parkinglot->cfg.mohclass, NULL), 04865 (!ast_strlen_zero(pu->parkinglot->cfg.mohclass) 04866 ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0)); 04867 pu->moh_trys++; 04868 } 04869 break; 04870 } 04871 } /* End for */ 04872 } 04873 04874 /* mark fds for next round */ 04875 for (x = 0; x < AST_MAX_FDS; x++) { 04876 if (chan->fds[x] > -1) { 04877 void *tmp = ast_realloc(*new_pfds, 04878 (*new_nfds + 1) * sizeof(struct pollfd)); 04879 04880 if (!tmp) { 04881 continue; 04882 } 04883 *new_pfds = tmp; 04884 (*new_pfds)[*new_nfds].fd = chan->fds[x]; 04885 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI; 04886 (*new_pfds)[*new_nfds].revents = 0; 04887 (*new_nfds)++; 04888 } 04889 } 04890 /* Keep track of our shortest wait */ 04891 if (tms < *ms || *ms < 0) { 04892 *ms = tms; 04893 } 04894 04895 /* Stay in the parking lot. */ 04896 return 0; 04897 }
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 4900 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().
04901 { 04902 struct parkeduser *pu; 04903 struct ast_context *con; 04904 04905 /* Lock parkings list */ 04906 AST_LIST_LOCK(&curlot->parkings); 04907 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 04908 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 04909 continue; 04910 } 04911 if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) { 04912 /* Parking is complete for this call so remove it from the parking lot. */ 04913 con = ast_context_find(pu->parkinglot->cfg.parking_con); 04914 if (con) { 04915 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 04916 ast_log(LOG_WARNING, 04917 "Whoa, failed to remove the parking extension %s@%s!\n", 04918 pu->parkingexten, pu->parkinglot->cfg.parking_con); 04919 } 04920 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, 04921 AST_DEVICE_NOT_INUSE); 04922 } else { 04923 ast_log(LOG_WARNING, 04924 "Whoa, parking lot '%s' context '%s' does not exist.\n", 04925 pu->parkinglot->name, pu->parkinglot->cfg.parking_con); 04926 } 04927 AST_LIST_REMOVE_CURRENT(list); 04928 parkinglot_unref(pu->parkinglot); 04929 ast_free(pu); 04930 } 04931 } 04932 AST_LIST_TRAVERSE_SAFE_END; 04933 AST_LIST_UNLOCK(&curlot->parkings); 04934 }
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 7199 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().
07200 { 07201 const char *channel = astman_get_header(m, "Channel"); 07202 const char *channel2 = astman_get_header(m, "Channel2"); 07203 const char *timeout = astman_get_header(m, "Timeout"); 07204 const char *parkinglotname = astman_get_header(m, "Parkinglot"); 07205 char buf[BUFSIZ]; 07206 int res = 0; 07207 struct ast_channel *ch1, *ch2; 07208 struct ast_park_call_args args = { 07209 /* 07210 * Don't say anything to ch2 since AMI is a third party parking 07211 * a call and we will likely crash if we do. 07212 * 07213 * XXX When the AMI action was originally implemented, the 07214 * parking space was announced to ch2. Unfortunately, grabbing 07215 * the ch2 lock and holding it while the announcement is played 07216 * was not really a good thing to do to begin with since it 07217 * could hold up the system. Also holding the lock is no longer 07218 * possible with a masquerade. 07219 * 07220 * Restoring the announcement to ch2 is not easily doable for 07221 * the following reasons: 07222 * 07223 * 1) The AMI manager is not the thread processing ch2. 07224 * 07225 * 2) ch2 could be the same as ch1, bridged to ch1, or some 07226 * random uninvolved channel. 07227 */ 07228 .flags = AST_PARK_OPT_SILENCE, 07229 }; 07230 07231 if (ast_strlen_zero(channel)) { 07232 astman_send_error(s, m, "Channel not specified"); 07233 return 0; 07234 } 07235 07236 if (ast_strlen_zero(channel2)) { 07237 astman_send_error(s, m, "Channel2 not specified"); 07238 return 0; 07239 } 07240 07241 if (!ast_strlen_zero(timeout)) { 07242 if (sscanf(timeout, "%30d", &args.timeout) != 1) { 07243 astman_send_error(s, m, "Invalid timeout value."); 07244 return 0; 07245 } 07246 } 07247 07248 if (!(ch1 = ast_channel_get_by_name(channel))) { 07249 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 07250 astman_send_error(s, m, buf); 07251 return 0; 07252 } 07253 07254 if (!(ch2 = ast_channel_get_by_name(channel2))) { 07255 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 07256 astman_send_error(s, m, buf); 07257 ast_channel_unref(ch1); 07258 return 0; 07259 } 07260 07261 if (!ast_strlen_zero(parkinglotname)) { 07262 args.parkinglot = find_parkinglot(parkinglotname); 07263 } 07264 07265 res = masq_park_call(ch1, ch2, &args); 07266 if (!res) { 07267 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 07268 astman_send_ack(s, m, "Park successful"); 07269 } else { 07270 astman_send_error(s, m, "Park failure"); 07271 } 07272 07273 if (args.parkinglot) { 07274 parkinglot_unref(args.parkinglot); 07275 } 07276 ch1 = ast_channel_unref(ch1); 07277 ch2 = ast_channel_unref(ch2); 07278 07279 return 0; 07280 }
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 7133 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().
07134 { 07135 struct parkeduser *cur; 07136 const char *id = astman_get_header(m, "ActionID"); 07137 char idText[256] = ""; 07138 struct ao2_iterator iter; 07139 struct ast_parkinglot *curlot; 07140 int numparked = 0; 07141 07142 if (!ast_strlen_zero(id)) 07143 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 07144 07145 astman_send_ack(s, m, "Parked calls will follow"); 07146 07147 iter = ao2_iterator_init(parkinglots, 0); 07148 while ((curlot = ao2_iterator_next(&iter))) { 07149 AST_LIST_LOCK(&curlot->parkings); 07150 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 07151 astman_append(s, "Event: ParkedCall\r\n" 07152 "Parkinglot: %s\r\n" 07153 "Exten: %d\r\n" 07154 "Channel: %s\r\n" 07155 "From: %s\r\n" 07156 "Timeout: %ld\r\n" 07157 "CallerIDNum: %s\r\n" 07158 "CallerIDName: %s\r\n" 07159 "ConnectedLineNum: %s\r\n" 07160 "ConnectedLineName: %s\r\n" 07161 "%s" 07162 "\r\n", 07163 curlot->name, 07164 cur->parkingnum, cur->chan->name, cur->peername, 07165 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 07166 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""), /* XXX in other places it is <unknown> */ 07167 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""), 07168 S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""), /* XXX in other places it is <unknown> */ 07169 S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""), 07170 idText); 07171 ++numparked; 07172 } 07173 AST_LIST_UNLOCK(&curlot->parkings); 07174 ao2_ref(curlot, -1); 07175 } 07176 ao2_iterator_destroy(&iter); 07177 07178 astman_append(s, 07179 "Event: ParkedCallsComplete\r\n" 07180 "Total: %d\r\n" 07181 "%s" 07182 "\r\n", 07183 numparked, idText); 07184 07185 return RESULT_SUCCESS; 07186 }
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 5444 of file features.c.
References ast_add_extension(), AST_MAX_EXTENSION, PRIORITY_HINT, and registrar.
Referenced by parkinglot_activate().
05445 { 05446 int numext; 05447 char device[AST_MAX_EXTENSION]; 05448 char exten[10]; 05449 05450 for (numext = start; numext <= stop; numext++) { 05451 snprintf(exten, sizeof(exten), "%d", numext); 05452 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 05453 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 05454 } 05455 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Park a call.
Definition at line 5023 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().
05024 { 05025 struct ast_park_call_args args = { 0, }; 05026 struct ast_flags flags = { 0 }; 05027 char orig_exten[AST_MAX_EXTENSION]; 05028 int orig_priority; 05029 int res; 05030 const char *pl_name; 05031 char *parse; 05032 struct park_app_args app_args; 05033 05034 /* 05035 * Cache the original channel name because we are going to 05036 * masquerade the channel. Prefer the BLINDTRANSFER channel 05037 * name over this channel name. BLINDTRANSFER could be set if 05038 * the parking access extension did not get detected and we are 05039 * executing the Park application from the dialplan. 05040 * 05041 * The orig_chan_name is used to return the call to the 05042 * originator on parking timeout. 05043 */ 05044 args.orig_chan_name = ast_strdupa(S_OR( 05045 pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name)); 05046 05047 /* Answer if call is not up */ 05048 if (chan->_state != AST_STATE_UP) { 05049 if (ast_answer(chan)) { 05050 return -1; 05051 } 05052 05053 /* Sleep to allow VoIP streams to settle down */ 05054 if (ast_safe_sleep(chan, 1000)) { 05055 return -1; 05056 } 05057 } 05058 05059 /* Process the dialplan application options. */ 05060 parse = ast_strdupa(data); 05061 AST_STANDARD_APP_ARGS(app_args, parse); 05062 05063 if (!ast_strlen_zero(app_args.timeout)) { 05064 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) { 05065 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 05066 args.timeout = 0; 05067 } 05068 } 05069 if (!ast_strlen_zero(app_args.return_con)) { 05070 args.return_con = app_args.return_con; 05071 } 05072 if (!ast_strlen_zero(app_args.return_ext)) { 05073 args.return_ext = app_args.return_ext; 05074 } 05075 if (!ast_strlen_zero(app_args.return_pri)) { 05076 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) { 05077 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 05078 args.return_pri = 0; 05079 } 05080 } 05081 05082 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 05083 args.flags = flags.flags; 05084 05085 /* 05086 * Setup the exten/priority to be s/1 since we don't know where 05087 * this call should return. 05088 */ 05089 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 05090 orig_priority = chan->priority; 05091 strcpy(chan->exten, "s"); 05092 chan->priority = 1; 05093 05094 /* Park the call */ 05095 if (!ast_strlen_zero(app_args.pl_name)) { 05096 pl_name = app_args.pl_name; 05097 } else { 05098 pl_name = findparkinglotname(chan); 05099 } 05100 if (ast_strlen_zero(pl_name)) { 05101 /* Parking lot is not specified, so use the default parking lot. */ 05102 args.parkinglot = parkinglot_addref(default_parkinglot); 05103 } else { 05104 args.parkinglot = find_parkinglot(pl_name); 05105 if (!args.parkinglot && parkeddynamic) { 05106 args.parkinglot = create_dynamic_parkinglot(pl_name, chan); 05107 } 05108 } 05109 if (args.parkinglot) { 05110 res = masq_park_call(chan, chan, &args); 05111 parkinglot_unref(args.parkinglot); 05112 } else { 05113 /* Parking failed because the parking lot does not exist. */ 05114 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { 05115 ast_stream_and_wait(chan, "pbx-parkingfailed", ""); 05116 } 05117 res = -1; 05118 } 05119 if (res) { 05120 /* Park failed, try to continue in the dialplan. */ 05121 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 05122 chan->priority = orig_priority; 05123 res = 0; 05124 } else { 05125 /* Park succeeded. */ 05126 res = -1; 05127 } 05128 05129 return res; 05130 }
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 5133 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().
05134 { 05135 int res; 05136 struct ast_channel *peer = NULL; 05137 struct parkeduser *pu; 05138 struct ast_context *con; 05139 char *parse; 05140 const char *pl_name; 05141 int park = 0; 05142 struct ast_bridge_config config; 05143 struct ast_parkinglot *parkinglot; 05144 AST_DECLARE_APP_ARGS(app_args, 05145 AST_APP_ARG(pl_space); /*!< Parking lot space to retrieve if present. */ 05146 AST_APP_ARG(pl_name); /*!< Parking lot name to use if present. */ 05147 AST_APP_ARG(dummy); /*!< Place to put any remaining args string. */ 05148 ); 05149 05150 parse = ast_strdupa(data); 05151 AST_STANDARD_APP_ARGS(app_args, parse); 05152 05153 if (!ast_strlen_zero(app_args.pl_space)) { 05154 if (sscanf(app_args.pl_space, "%30u", &park) != 1) { 05155 ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n", 05156 app_args.pl_space); 05157 park = -1; 05158 } 05159 } 05160 05161 if (!ast_strlen_zero(app_args.pl_name)) { 05162 pl_name = app_args.pl_name; 05163 } else { 05164 pl_name = findparkinglotname(chan); 05165 } 05166 if (ast_strlen_zero(pl_name)) { 05167 /* Parking lot is not specified, so use the default parking lot. */ 05168 parkinglot = parkinglot_addref(default_parkinglot); 05169 } else { 05170 parkinglot = find_parkinglot(pl_name); 05171 if (!parkinglot) { 05172 /* It helps to answer the channel if not already up. :) */ 05173 if (chan->_state != AST_STATE_UP) { 05174 ast_answer(chan); 05175 } 05176 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05177 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", 05178 "pbx-invalidpark", chan->name); 05179 } 05180 ast_log(LOG_WARNING, 05181 "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n", 05182 chan->name, pl_name); 05183 return -1; 05184 } 05185 } 05186 05187 AST_LIST_LOCK(&parkinglot->parkings); 05188 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 05189 if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park) 05190 && !pu->notquiteyet && !pu->chan->pbx) { 05191 /* The parking space has a call and can be picked up now. */ 05192 AST_LIST_REMOVE_CURRENT(list); 05193 break; 05194 } 05195 } 05196 AST_LIST_TRAVERSE_SAFE_END; 05197 if (pu) { 05198 /* Found a parked call to pickup. */ 05199 peer = pu->chan; 05200 con = ast_context_find(parkinglot->cfg.parking_con); 05201 if (con) { 05202 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 05203 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 05204 } else { 05205 notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE); 05206 } 05207 } else { 05208 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 05209 } 05210 05211 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan); 05212 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall", 05213 "Exten: %s\r\n" 05214 "Channel: %s\r\n" 05215 "Parkinglot: %s\r\n" 05216 "From: %s\r\n" 05217 "CallerIDNum: %s\r\n" 05218 "CallerIDName: %s\r\n" 05219 "ConnectedLineNum: %s\r\n" 05220 "ConnectedLineName: %s\r\n" 05221 "Uniqueid: %s\r\n", 05222 pu->parkingexten, pu->chan->name, pu->parkinglot->name, chan->name, 05223 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 05224 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 05225 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 05226 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 05227 pu->chan->uniqueid 05228 ); 05229 05230 /* Stop entertaining the caller. */ 05231 switch (pu->hold_method) { 05232 case AST_CONTROL_HOLD: 05233 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 05234 break; 05235 case AST_CONTROL_RINGING: 05236 ast_indicate(pu->chan, -1); 05237 break; 05238 default: 05239 break; 05240 } 05241 pu->hold_method = 0; 05242 05243 parkinglot_unref(pu->parkinglot); 05244 ast_free(pu); 05245 } 05246 AST_LIST_UNLOCK(&parkinglot->parkings); 05247 05248 if (peer) { 05249 /* Update connected line between retrieving call and parked call. */ 05250 struct ast_party_connected_line connected; 05251 05252 ast_party_connected_line_init(&connected); 05253 05254 /* Send our caller-id to peer. */ 05255 ast_channel_lock(chan); 05256 ast_connected_line_copy_from_caller(&connected, &chan->caller); 05257 ast_channel_unlock(chan); 05258 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05259 if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) { 05260 ast_channel_update_connected_line(peer, &connected, NULL); 05261 } 05262 05263 /* 05264 * Get caller-id from peer. 05265 * 05266 * Update the retrieving call before it is answered if possible 05267 * for best results. Some phones do not support updating the 05268 * connected line information after connection. 05269 */ 05270 ast_channel_lock(peer); 05271 ast_connected_line_copy_from_caller(&connected, &peer->caller); 05272 ast_channel_unlock(peer); 05273 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05274 if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) { 05275 ast_channel_update_connected_line(chan, &connected, NULL); 05276 } 05277 05278 ast_party_connected_line_free(&connected); 05279 } 05280 05281 /* JK02: it helps to answer the channel if not already up */ 05282 if (chan->_state != AST_STATE_UP) { 05283 ast_answer(chan); 05284 } 05285 05286 if (peer) { 05287 struct ast_datastore *features_datastore; 05288 struct ast_dial_features *dialfeatures; 05289 05290 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 05291 if (!ast_strlen_zero(courtesytone)) { 05292 static const char msg[] = "courtesy tone"; 05293 05294 switch (parkedplay) { 05295 case 0:/* Courtesy tone to pickup chan */ 05296 res = play_message_to_chans(chan, peer, -1, msg, courtesytone); 05297 break; 05298 case 1:/* Courtesy tone to parked chan */ 05299 res = play_message_to_chans(chan, peer, 1, msg, courtesytone); 05300 break; 05301 case 2:/* Courtesy tone to both chans */ 05302 res = play_message_to_chans(chan, peer, 0, msg, courtesytone); 05303 break; 05304 default: 05305 res = 0; 05306 break; 05307 } 05308 if (res) { 05309 ast_hangup(peer); 05310 parkinglot_unref(parkinglot); 05311 return -1; 05312 } 05313 } 05314 05315 res = ast_channel_make_compatible(chan, peer); 05316 if (res < 0) { 05317 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 05318 ast_hangup(peer); 05319 parkinglot_unref(parkinglot); 05320 return -1; 05321 } 05322 /* This runs sorta backwards, since we give the incoming channel control, as if it 05323 were the person called. */ 05324 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park); 05325 05326 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 05327 ast_cdr_setdestchan(chan->cdr, peer->name); 05328 memset(&config, 0, sizeof(struct ast_bridge_config)); 05329 05330 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 05331 ast_channel_lock(peer); 05332 features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL); 05333 if (features_datastore && (dialfeatures = features_datastore->data)) { 05334 ast_copy_flags(&config.features_callee, &dialfeatures->my_features, 05335 AST_FLAGS_ALL); 05336 } 05337 ast_channel_unlock(peer); 05338 05339 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05340 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 05341 } 05342 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05343 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 05344 } 05345 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05346 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 05347 } 05348 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05349 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 05350 } 05351 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05352 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 05353 } 05354 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05355 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 05356 } 05357 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05358 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 05359 } 05360 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05361 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 05362 } 05363 05364 res = ast_bridge_call(chan, peer, &config); 05365 05366 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 05367 ast_cdr_setdestchan(chan->cdr, peer->name); 05368 05369 /* Simulate the PBX hanging up */ 05370 ast_hangup(peer); 05371 } else { 05372 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05373 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", 05374 chan->name); 05375 } 05376 ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n", 05377 chan->name, park); 05378 res = -1; 05379 } 05380 05381 parkinglot_unref(parkinglot); 05382 return res; 05383 }
static int parkinglot_activate | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 5594 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().
05595 { 05596 int disabled = 0; 05597 char app_data[5 + AST_MAX_CONTEXT]; 05598 05599 /* Create Park option list. Must match with struct park_app_args options. */ 05600 if (parkinglot->cfg.parkext_exclusive) { 05601 /* Specify the parking lot this parking extension parks calls. */ 05602 snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name); 05603 } else { 05604 /* The dialplan must specify which parking lot to use. */ 05605 app_data[0] = '\0'; 05606 } 05607 05608 /* Create context */ 05609 if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) { 05610 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", 05611 parkinglot->cfg.parking_con); 05612 disabled = 1; 05613 05614 /* Add a parking extension into the context */ 05615 } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext, 05616 1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) { 05617 ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n", 05618 parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con); 05619 disabled = 1; 05620 } else { 05621 /* Add parking hints */ 05622 if (parkinglot->cfg.parkaddhints) { 05623 park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start, 05624 parkinglot->cfg.parking_stop); 05625 } 05626 05627 /* 05628 * XXX Not sure why we should need to notify the metermaids for 05629 * this exten. It was originally done for the default parking 05630 * lot entry exten only but should be done for all entry extens 05631 * if we do it for one. 05632 */ 05633 /* Notify metermaids about parking lot entry exten state. */ 05634 notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con, 05635 AST_DEVICE_INUSE); 05636 } 05637 05638 parkinglot->disabled = disabled; 05639 return disabled ? -1 : 0; 05640 }
static int parkinglot_activate_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6643 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().
06644 { 06645 struct ast_parkinglot *parkinglot = obj; 06646 06647 if (parkinglot->the_mark) { 06648 /* 06649 * Don't activate a parking lot that still bears the_mark since 06650 * it is effectively deleted. 06651 */ 06652 return 0; 06653 } 06654 06655 if (parkinglot_activate(parkinglot)) { 06656 /* 06657 * The parking lot failed to activate. Allow reloading later to 06658 * see if that fixes it. 06659 */ 06660 force_reload_load = 1; 06661 ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name); 06662 } else { 06663 ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n", 06664 parkinglot->name, parkinglot->cfg.parking_start, 06665 parkinglot->cfg.parking_stop); 06666 } 06667 06668 return 0; 06669 }
static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static, read] |
Definition at line 5395 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 5506 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().
05507 { 05508 int error = 0; 05509 05510 while (var) { 05511 if (!strcasecmp(var->name, "context")) { 05512 ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con)); 05513 } else if (!strcasecmp(var->name, "parkext")) { 05514 ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext)); 05515 } else if (!strcasecmp(var->name, "parkext_exclusive")) { 05516 cfg->parkext_exclusive = ast_true(var->value); 05517 } else if (!strcasecmp(var->name, "parkinghints")) { 05518 cfg->parkaddhints = ast_true(var->value); 05519 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 05520 ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass)); 05521 } else if (!strcasecmp(var->name, "parkingtime")) { 05522 int parkingtime = 0; 05523 05524 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) { 05525 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 05526 error = -1; 05527 } else { 05528 cfg->parkingtime = parkingtime * 1000; 05529 } 05530 } else if (!strcasecmp(var->name, "parkpos")) { 05531 int start = 0; 05532 int end = 0; 05533 05534 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 05535 ast_log(LOG_WARNING, 05536 "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n", 05537 var->lineno, var->file); 05538 error = -1; 05539 } else if (end < start || start <= 0 || end <= 0) { 05540 ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n", 05541 var->lineno, var->file); 05542 error = -1; 05543 } else { 05544 cfg->parking_start = start; 05545 cfg->parking_stop = end; 05546 } 05547 } else if (!strcasecmp(var->name, "findslot")) { 05548 cfg->parkfindnext = (!strcasecmp(var->value, "next")); 05549 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 05550 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var); 05551 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 05552 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var); 05553 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 05554 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var); 05555 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 05556 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var); 05557 } 05558 var = var->next; 05559 } 05560 05561 /* Check for configuration errors */ 05562 if (ast_strlen_zero(cfg->parking_con)) { 05563 ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name); 05564 error = -1; 05565 } 05566 if (ast_strlen_zero(cfg->parkext)) { 05567 ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name); 05568 error = -1; 05569 } 05570 if (!cfg->parking_start) { 05571 ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name); 05572 error = -1; 05573 } 05574 if (error) { 05575 cfg->is_invalid = 1; 05576 } 05577 05578 return error; 05579 }
static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 5405 of file features.c.
References ast_assert, AST_LIST_EMPTY, AST_LIST_HEAD_DESTROY, and ast_parkinglot::parkings.
Referenced by create_parkinglot().
05406 { 05407 struct ast_parkinglot *doomed = obj; 05408 05409 /* 05410 * No need to destroy parked calls here because any parked call 05411 * holds a parking lot reference. Therefore the parkings list 05412 * must be empty. 05413 */ 05414 ast_assert(AST_LIST_EMPTY(&doomed->parkings)); 05415 AST_LIST_HEAD_DESTROY(&doomed->parkings); 05416 }
static void parkinglot_feature_flag_cfg | ( | const char * | pl_name, | |
int * | param, | |||
struct ast_variable * | var | |||
) | [static] |
Definition at line 5483 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().
05484 { 05485 ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value); 05486 if (!strcasecmp(var->value, "both")) { 05487 *param = AST_FEATURE_FLAG_BYBOTH; 05488 } else if (!strcasecmp(var->value, "caller")) { 05489 *param = AST_FEATURE_FLAG_BYCALLER; 05490 } else if (!strcasecmp(var->value, "callee")) { 05491 *param = AST_FEATURE_FLAG_BYCALLEE; 05492 } 05493 }
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 6623 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().
06624 { 06625 struct ast_parkinglot *parkinglot = obj; 06626 06627 if (parkinglot->the_mark) { 06628 if (AST_LIST_EMPTY(&parkinglot->parkings)) { 06629 /* This parking lot can actually be deleted. */ 06630 return CMP_MATCH; 06631 } 06632 /* Try reloading later when parking lot is empty. */ 06633 ast_log(LOG_WARNING, 06634 "Parking lot %s has parked calls. Could not remove.\n", 06635 parkinglot->name); 06636 parkinglot->disabled = 1; 06637 force_reload_load = 1; 06638 } 06639 06640 return 0; 06641 }
static int parkinglot_markall_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6615 of file features.c.
References ast_parkinglot::the_mark.
Referenced by load_config().
06616 { 06617 struct ast_parkinglot *parkinglot = obj; 06618 06619 parkinglot->the_mark = 1; 06620 return 0; 06621 }
static void parkinglot_unref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Unreference parkinglot object.
Definition at line 5388 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 3832 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
03833 { 03834 struct ast_cdr *cdr_orig = cdr; 03835 while (cdr) { 03836 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 03837 return cdr; 03838 cdr = cdr->next; 03839 } 03840 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 03841 }
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 4607 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().
04608 { 04609 manager_event(EVENT_FLAG_CALL, s, 04610 "Exten: %s\r\n" 04611 "Channel: %s\r\n" 04612 "Parkinglot: %s\r\n" 04613 "CallerIDNum: %s\r\n" 04614 "CallerIDName: %s\r\n" 04615 "ConnectedLineNum: %s\r\n" 04616 "ConnectedLineName: %s\r\n" 04617 "UniqueID: %s\r\n", 04618 pu->parkingexten, 04619 pu->chan->name, 04620 pu->parkinglot->name, 04621 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 04622 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 04623 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 04624 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 04625 pu->chan->uniqueid 04626 ); 04627 }
static void process_applicationmap_line | ( | struct ast_variable * | var | ) | [static] |
Definition at line 5722 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().
05723 { 05724 char *tmp_val = ast_strdupa(var->value); 05725 char *activateon, *new_syn; 05726 struct ast_call_feature *feature; 05727 AST_DECLARE_APP_ARGS(args, 05728 AST_APP_ARG(exten); 05729 AST_APP_ARG(activatedby); 05730 AST_APP_ARG(app); 05731 AST_APP_ARG(app_args); 05732 AST_APP_ARG(moh_class); 05733 ); 05734 05735 AST_STANDARD_APP_ARGS(args, tmp_val); 05736 if ((new_syn = strchr(args.app, '('))) { 05737 /* New syntax */ 05738 args.moh_class = args.app_args; 05739 args.app_args = new_syn; 05740 *args.app_args++ = '\0'; 05741 if (args.app_args[strlen(args.app_args) - 1] == ')') { 05742 args.app_args[strlen(args.app_args) - 1] = '\0'; 05743 } 05744 } 05745 05746 activateon = strsep(&args.activatedby, "/"); 05747 05748 /*! \todo XXX var_name or app_args ? */ 05749 if (ast_strlen_zero(args.app) 05750 || ast_strlen_zero(args.exten) 05751 || ast_strlen_zero(activateon) 05752 || ast_strlen_zero(var->name)) { 05753 ast_log(LOG_NOTICE, 05754 "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 05755 args.app, args.exten, activateon, var->name); 05756 return; 05757 } 05758 05759 AST_RWLIST_RDLOCK(&feature_list); 05760 if (find_dynamic_feature(var->name)) { 05761 AST_RWLIST_UNLOCK(&feature_list); 05762 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", 05763 var->name); 05764 return; 05765 } 05766 AST_RWLIST_UNLOCK(&feature_list); 05767 05768 if (!(feature = ast_calloc(1, sizeof(*feature)))) { 05769 return; 05770 } 05771 05772 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 05773 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN); 05774 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN); 05775 05776 if (args.app_args) { 05777 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN); 05778 } 05779 05780 if (args.moh_class) { 05781 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN); 05782 } 05783 05784 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten)); 05785 feature->operation = feature_exec_app; 05786 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 05787 05788 /* Allow caller and callee to be specified for backwards compatability */ 05789 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) { 05790 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 05791 } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) { 05792 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 05793 } else { 05794 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 05795 " must be 'self', or 'peer'\n", var->name); 05796 ast_free(feature); 05797 return; 05798 } 05799 05800 if (ast_strlen_zero(args.activatedby)) { 05801 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05802 } else if (!strcasecmp(args.activatedby, "caller")) { 05803 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 05804 } else if (!strcasecmp(args.activatedby, "callee")) { 05805 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 05806 } else if (!strcasecmp(args.activatedby, "both")) { 05807 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05808 } else { 05809 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 05810 " must be 'caller', or 'callee', or 'both'\n", var->name); 05811 ast_free(feature); 05812 return; 05813 } 05814 05815 ast_register_feature(feature); 05816 05817 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", 05818 var->name, args.app, args.app_args, args.exten); 05819 }
static int process_config | ( | struct ast_config * | cfg | ) | [static] |
Definition at line 5821 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().
05822 { 05823 int i; 05824 struct ast_variable *var = NULL; 05825 struct feature_group *fg = NULL; 05826 char *ctg; 05827 static const char * const categories[] = { 05828 /* Categories in features.conf that are not 05829 * to be parsed as group categories 05830 */ 05831 "general", 05832 "featuremap", 05833 "applicationmap" 05834 }; 05835 05836 /* Set general features global defaults. */ 05837 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05838 05839 /* Set global call pickup defaults. */ 05840 strcpy(pickup_ext, "*8"); 05841 pickupsound[0] = '\0'; 05842 pickupfailsound[0] = '\0'; 05843 05844 /* Set global call transfer defaults. */ 05845 strcpy(xfersound, "beep"); 05846 strcpy(xferfailsound, "beeperr"); 05847 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05848 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05849 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05850 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 05851 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05852 05853 /* Set global call parking defaults. */ 05854 comebacktoorigin = 1; 05855 courtesytone[0] = '\0'; 05856 parkedplay = 0; 05857 adsipark = 0; 05858 parkeddynamic = 0; 05859 05860 var = ast_variable_browse(cfg, "general"); 05861 build_parkinglot(DEFAULT_PARKINGLOT, var); 05862 for (; var; var = var->next) { 05863 if (!strcasecmp(var->name, "parkeddynamic")) { 05864 parkeddynamic = ast_true(var->value); 05865 } else if (!strcasecmp(var->name, "adsipark")) { 05866 adsipark = ast_true(var->value); 05867 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 05868 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 05869 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 05870 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05871 } else { 05872 transferdigittimeout = transferdigittimeout * 1000; 05873 } 05874 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 05875 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 05876 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 05877 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05878 } 05879 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 05880 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 05881 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 05882 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05883 } else { 05884 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 05885 } 05886 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 05887 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 05888 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 05889 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05890 } else { 05891 atxferloopdelay *= 1000; 05892 } 05893 } else if (!strcasecmp(var->name, "atxferdropcall")) { 05894 atxferdropcall = ast_true(var->value); 05895 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 05896 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) { 05897 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 05898 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05899 } 05900 } else if (!strcasecmp(var->name, "courtesytone")) { 05901 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 05902 } else if (!strcasecmp(var->name, "parkedplay")) { 05903 if (!strcasecmp(var->value, "both")) { 05904 parkedplay = 2; 05905 } else if (!strcasecmp(var->value, "parked")) { 05906 parkedplay = 1; 05907 } else { 05908 parkedplay = 0; 05909 } 05910 } else if (!strcasecmp(var->name, "xfersound")) { 05911 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 05912 } else if (!strcasecmp(var->name, "xferfailsound")) { 05913 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 05914 } else if (!strcasecmp(var->name, "pickupexten")) { 05915 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 05916 } else if (!strcasecmp(var->name, "pickupsound")) { 05917 ast_copy_string(pickupsound, var->value, sizeof(pickupsound)); 05918 } else if (!strcasecmp(var->name, "pickupfailsound")) { 05919 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound)); 05920 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 05921 comebacktoorigin = ast_true(var->value); 05922 } 05923 } 05924 05925 unmap_features(); 05926 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 05927 if (remap_feature(var->name, var->value)) { 05928 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 05929 } 05930 } 05931 05932 /* Map a key combination to an application */ 05933 ast_unregister_features(); 05934 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 05935 process_applicationmap_line(var); 05936 } 05937 05938 ast_unregister_groups(); 05939 AST_RWLIST_WRLOCK(&feature_groups); 05940 05941 ctg = NULL; 05942 while ((ctg = ast_category_browse(cfg, ctg))) { 05943 /* Is this a parkinglot definition ? */ 05944 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 05945 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 05946 if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) { 05947 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 05948 } else { 05949 ast_debug(1, "Configured parking context %s\n", ctg); 05950 } 05951 continue; 05952 } 05953 05954 /* No, check if it's a group */ 05955 for (i = 0; i < ARRAY_LEN(categories); i++) { 05956 if (!strcasecmp(categories[i], ctg)) { 05957 break; 05958 } 05959 } 05960 if (i < ARRAY_LEN(categories)) { 05961 continue; 05962 } 05963 05964 if (!(fg = register_group(ctg))) { 05965 continue; 05966 } 05967 05968 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 05969 struct ast_call_feature *feature; 05970 05971 AST_RWLIST_RDLOCK(&feature_list); 05972 if (!(feature = find_dynamic_feature(var->name)) && 05973 !(feature = ast_find_call_feature(var->name))) { 05974 AST_RWLIST_UNLOCK(&feature_list); 05975 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 05976 continue; 05977 } 05978 AST_RWLIST_UNLOCK(&feature_list); 05979 05980 register_group_feature(fg, var->value, feature); 05981 } 05982 } 05983 05984 AST_RWLIST_UNLOCK(&feature_groups); 05985 05986 return 0; 05987 }
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 3236 of file features.c.
References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, FEATURES_COUNT, and features_lock.
Referenced by process_config().
03237 { 03238 int x, res = -1; 03239 03240 ast_rwlock_wrlock(&features_lock); 03241 for (x = 0; x < FEATURES_COUNT; x++) { 03242 if (strcasecmp(builtin_features[x].sname, name)) 03243 continue; 03244 03245 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 03246 res = 0; 03247 break; 03248 } 03249 ast_rwlock_unlock(&features_lock); 03250 03251 return res; 03252 }
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 6548 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().
06549 { 06550 remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens); 06551 remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space); 06552 #if 0 06553 /* I don't think we should destroy hints if the parking space still exists. */ 06554 remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint); 06555 #endif 06556 }
static void remove_dead_dialplan_useage | ( | struct parking_dp_map * | old_map, | |
struct parking_dp_map * | new_map | |||
) | [static] |
Definition at line 6571 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().
06572 { 06573 struct parking_dp_context *old_ctx; 06574 struct parking_dp_context *new_ctx; 06575 struct ast_context *con; 06576 int cmp; 06577 06578 old_ctx = AST_LIST_FIRST(old_map); 06579 new_ctx = AST_LIST_FIRST(new_map); 06580 06581 while (new_ctx) { 06582 if (!old_ctx) { 06583 /* No old contexts left, so no dead stuff can remain. */ 06584 return; 06585 } 06586 cmp = strcmp(old_ctx->context, new_ctx->context); 06587 if (cmp < 0) { 06588 /* New map does not have old map context. */ 06589 con = ast_context_find(old_ctx->context); 06590 if (con) { 06591 ast_context_destroy(con, registrar); 06592 } 06593 old_ctx = AST_LIST_NEXT(old_ctx, node); 06594 continue; 06595 } 06596 if (cmp == 0) { 06597 /* Old and new map have this context. */ 06598 remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx); 06599 old_ctx = AST_LIST_NEXT(old_ctx, node); 06600 } else { 06601 /* Old map does not have new map context. */ 06602 } 06603 new_ctx = AST_LIST_NEXT(new_ctx, node); 06604 } 06605 06606 /* Any old contexts left must be dead. */ 06607 for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) { 06608 con = ast_context_find(old_ctx->context); 06609 if (con) { 06610 ast_context_destroy(con, registrar); 06611 } 06612 } 06613 }
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 6407 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().
06408 { 06409 struct parking_dp_ramp *old_ramp; 06410 struct parking_dp_ramp *new_ramp; 06411 int cmp; 06412 06413 old_ramp = AST_LIST_FIRST(old_ramps); 06414 new_ramp = AST_LIST_FIRST(new_ramps); 06415 06416 while (new_ramp) { 06417 if (!old_ramp) { 06418 /* No old ramps left, so no dead ramps can remain. */ 06419 return; 06420 } 06421 cmp = strcmp(old_ramp->exten, new_ramp->exten); 06422 if (cmp < 0) { 06423 /* New map does not have old ramp. */ 06424 remove_exten_if_exist(context, old_ramp->exten, 1); 06425 old_ramp = AST_LIST_NEXT(old_ramp, node); 06426 continue; 06427 } 06428 if (cmp == 0) { 06429 /* Old and new map have this ramp. */ 06430 old_ramp = AST_LIST_NEXT(old_ramp, node); 06431 } else { 06432 /* Old map does not have new ramp. */ 06433 } 06434 new_ramp = AST_LIST_NEXT(new_ramp, node); 06435 } 06436 06437 /* Any old ramps left must be dead. */ 06438 for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) { 06439 remove_exten_if_exist(context, old_ramp->exten, 1); 06440 } 06441 }
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 6477 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().
06480 { 06481 struct parking_dp_spaces *old_range; 06482 struct parking_dp_spaces *new_range; 06483 int space;/*!< Current position in the current old range. */ 06484 int stop; 06485 06486 old_range = AST_LIST_FIRST(old_spaces); 06487 new_range = AST_LIST_FIRST(new_spaces); 06488 space = -1; 06489 06490 while (old_range) { 06491 if (space < old_range->start) { 06492 space = old_range->start; 06493 } 06494 if (new_range) { 06495 if (space < new_range->start) { 06496 /* Current position in old range starts before new range. */ 06497 if (old_range->stop < new_range->start) { 06498 /* Old range ends before new range. */ 06499 stop = old_range->stop; 06500 old_range = AST_LIST_NEXT(old_range, node); 06501 } else { 06502 /* Tail of old range overlaps new range. */ 06503 stop = new_range->start - 1; 06504 } 06505 } else if (/* new_range->start <= space && */ space <= new_range->stop) { 06506 /* Current position in old range overlaps new range. */ 06507 if (old_range->stop <= new_range->stop) { 06508 /* Old range ends at or before new range. */ 06509 old_range = AST_LIST_NEXT(old_range, node); 06510 } else { 06511 /* Old range extends beyond end of new range. */ 06512 space = new_range->stop + 1; 06513 new_range = AST_LIST_NEXT(new_range, node); 06514 } 06515 continue; 06516 } else /* if (new_range->stop < space) */ { 06517 /* Current position in old range starts after new range. */ 06518 new_range = AST_LIST_NEXT(new_range, node); 06519 continue; 06520 } 06521 } else { 06522 /* No more new ranges. All remaining old spaces are dead. */ 06523 stop = old_range->stop; 06524 old_range = AST_LIST_NEXT(old_range, node); 06525 } 06526 06527 /* Destroy dead parking spaces. */ 06528 for (; space <= stop; ++space) { 06529 destroy_space(context, space); 06530 } 06531 } 06532 }
static void remove_exten_if_exist | ( | const char * | context, | |
const char * | exten, | |||
int | priority | |||
) | [static] |
Definition at line 6381 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().
06382 { 06383 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 06384 06385 if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL, 06386 E_MATCH)) { 06387 ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n", 06388 context, exten, priority); 06389 ast_context_remove_extension(context, exten, priority, registrar); 06390 } 06391 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 3843 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().
03844 { 03845 const char *feature; 03846 03847 if (ast_strlen_zero(features)) { 03848 return; 03849 } 03850 03851 for (feature = features; *feature; feature++) { 03852 switch (*feature) { 03853 case 'T' : 03854 case 't' : 03855 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 03856 break; 03857 case 'K' : 03858 case 'k' : 03859 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 03860 break; 03861 case 'H' : 03862 case 'h' : 03863 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 03864 break; 03865 case 'W' : 03866 case 'w' : 03867 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 03868 break; 03869 default : 03870 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 03871 } 03872 } 03873 }
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 3427 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().
03428 { 03429 int x; 03430 03431 ast_clear_flag(config, AST_FLAGS_ALL); 03432 03433 ast_rwlock_rdlock(&features_lock); 03434 for (x = 0; x < FEATURES_COUNT; x++) { 03435 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 03436 continue; 03437 03438 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 03439 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03440 03441 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 03442 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03443 } 03444 ast_rwlock_unlock(&features_lock); 03445 03446 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 03447 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 03448 03449 if (dynamic_features) { 03450 char *tmp = ast_strdupa(dynamic_features); 03451 char *tok; 03452 struct ast_call_feature *feature; 03453 03454 /* while we have a feature */ 03455 while ((tok = strsep(&tmp, "#"))) { 03456 struct feature_group *fg; 03457 03458 AST_RWLIST_RDLOCK(&feature_groups); 03459 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 03460 struct feature_group_exten *fge; 03461 03462 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03463 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) { 03464 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03465 } 03466 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) { 03467 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03468 } 03469 } 03470 } 03471 AST_RWLIST_UNLOCK(&feature_groups); 03472 03473 AST_RWLIST_RDLOCK(&feature_list); 03474 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 03475 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) { 03476 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03477 } 03478 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) { 03479 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03480 } 03481 } 03482 AST_RWLIST_UNLOCK(&feature_list); 03483 } 03484 } 03485 } 03486 }
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 3226 of file features.c.
References ast_rwlock_unlock, ast_rwlock_wrlock, FEATURES_COUNT, and features_lock.
Referenced by process_config().
03227 { 03228 int x; 03229 03230 ast_rwlock_wrlock(&features_lock); 03231 for (x = 0; x < FEATURES_COUNT; x++) 03232 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 03233 ast_rwlock_unlock(&features_lock); 03234 }
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 6067 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().
06068 { 06069 struct parking_dp_ramp *cur_ramp; 06070 struct parking_dp_ramp *new_ramp; 06071 int cmp; 06072 06073 /* Make sure that exclusive is only 0 or 1 */ 06074 if (exclusive) { 06075 exclusive = 1; 06076 } 06077 06078 AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) { 06079 cmp = strcmp(exten, cur_ramp->exten); 06080 if (cmp > 0) { 06081 /* The parking lot ramp goes after this node. */ 06082 continue; 06083 } 06084 if (cmp == 0) { 06085 /* The ramp is already in the map. */ 06086 if (complain && (cur_ramp->exclusive || exclusive)) { 06087 ast_log(LOG_WARNING, 06088 "Parking lot '%s' parkext %s@%s used by another parking lot.\n", 06089 lot->name, exten, lot->cfg.parking_con); 06090 } 06091 return 0; 06092 } 06093 /* The new parking lot ramp goes before this node. */ 06094 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 06095 if (!new_ramp) { 06096 return -1; 06097 } 06098 AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node); 06099 return 0; 06100 } 06101 AST_LIST_TRAVERSE_SAFE_END; 06102 06103 /* New parking lot access ramp goes on the end. */ 06104 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 06105 if (!new_ramp) { 06106 return -1; 06107 } 06108 AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node); 06109 return 0; 06110 }
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 6148 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().
06149 { 06150 struct parking_dp_spaces *cur_node; 06151 struct parking_dp_spaces *expand_node; 06152 struct parking_dp_spaces *new_node; 06153 06154 expand_node = NULL; 06155 AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) { 06156 /* NOTE: stop + 1 to combine immediately adjacent nodes into one. */ 06157 if (expand_node) { 06158 /* The previous node is expanding to possibly eat following nodes. */ 06159 if (expand_node->stop + 1 < cur_node->start) { 06160 /* Current node is completely after expanding node. */ 06161 return 0; 06162 } 06163 06164 if (complain 06165 && ((cur_node->start <= start && start <= cur_node->stop) 06166 || (cur_node->start <= stop && stop <= cur_node->stop) 06167 || (start < cur_node->start && cur_node->stop < stop))) { 06168 /* Only complain once per range add. */ 06169 complain = 0; 06170 ast_log(LOG_WARNING, 06171 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06172 lot->name, start, stop, lot->cfg.parking_con); 06173 } 06174 06175 /* Current node is eaten by the expanding node. */ 06176 if (expand_node->stop < cur_node->stop) { 06177 expand_node->stop = cur_node->stop; 06178 } 06179 AST_LIST_REMOVE_CURRENT(node); 06180 ast_free(cur_node); 06181 continue; 06182 } 06183 06184 if (cur_node->stop + 1 < start) { 06185 /* New range is completely after current node. */ 06186 continue; 06187 } 06188 if (stop + 1 < cur_node->start) { 06189 /* New range is completely before current node. */ 06190 new_node = build_dialplan_useage_spaces(start, stop); 06191 if (!new_node) { 06192 return -1; 06193 } 06194 AST_LIST_INSERT_BEFORE_CURRENT(new_node, node); 06195 return 0; 06196 } 06197 06198 if (complain 06199 && ((cur_node->start <= start && start <= cur_node->stop) 06200 || (cur_node->start <= stop && stop <= cur_node->stop) 06201 || (start < cur_node->start && cur_node->stop < stop))) { 06202 /* Only complain once per range add. */ 06203 complain = 0; 06204 ast_log(LOG_WARNING, 06205 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06206 lot->name, start, stop, lot->cfg.parking_con); 06207 } 06208 06209 /* Current node range overlaps or is immediately adjacent to new range. */ 06210 if (start < cur_node->start) { 06211 /* Expand the current node in the front. */ 06212 cur_node->start = start; 06213 } 06214 if (stop <= cur_node->stop) { 06215 /* Current node is not expanding in the rear. */ 06216 return 0; 06217 } 06218 cur_node->stop = stop; 06219 expand_node = cur_node; 06220 } 06221 AST_LIST_TRAVERSE_SAFE_END; 06222 06223 if (expand_node) { 06224 /* 06225 * The previous node expanded and either ate all following nodes 06226 * or it was the last node. 06227 */ 06228 return 0; 06229 } 06230 06231 /* New range goes on the end. */ 06232 new_node = build_dialplan_useage_spaces(start, stop); 06233 if (!new_node) { 06234 return -1; 06235 } 06236 AST_LIST_INSERT_TAIL(space_map, new_node, node); 06237 return 0; 06238 }
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 7447 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 7484 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 7119 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 5020 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 5468 of file features.c.
struct parkinglot_cfg parkinglot_cfg_default_default [static] |
Default configuration for default parking lot.
Definition at line 5458 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 7288 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(), 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().