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 char | parkingretalertinfo [256] |
static char | parkingretcidname [256] |
static char | parkingretdahdiring [3] |
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 2977 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 7495 of file features.c.
07495 { 07496 BRIDGE_OPT_PLAYTONE = (1 << 0), 07497 OPT_CALLEE_HANGUP = (1 << 1), 07498 OPT_CALLER_HANGUP = (1 << 2), 07499 OPT_DURATION_LIMIT = (1 << 3), 07500 OPT_DURATION_STOP = (1 << 4), 07501 OPT_CALLEE_TRANSFER = (1 << 5), 07502 OPT_CALLER_TRANSFER = (1 << 6), 07503 OPT_CALLEE_MONITOR = (1 << 7), 07504 OPT_CALLER_MONITOR = (1 << 8), 07505 OPT_CALLEE_PARK = (1 << 9), 07506 OPT_CALLER_PARK = (1 << 10), 07507 OPT_CALLEE_KILL = (1 << 11), 07508 };
anonymous enum |
Definition at line 7510 of file features.c.
07510 { 07511 OPT_ARG_DURATION_LIMIT = 0, 07512 OPT_ARG_DURATION_STOP, 07513 /* note: this entry _MUST_ be the last one in the enum */ 07514 OPT_ARG_ARRAY_SIZE, 07515 };
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 1125 of file features.c.
01125 { 01126 /*! Provide ringing to the parked caller instead of music on hold */ 01127 AST_PARK_OPT_RINGING = (1 << 0), 01128 /*! Randomly choose a parking spot for the caller instead of choosing 01129 * the first one that is available. */ 01130 AST_PARK_OPT_RANDOMIZE = (1 << 1), 01131 /*! Do not announce the parking number */ 01132 AST_PARK_OPT_SILENCE = (1 << 2), 01133 };
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 6975 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().
06976 { 06977 const char *channela = astman_get_header(m, "Channel1"); 06978 const char *channelb = astman_get_header(m, "Channel2"); 06979 const char *playtone = astman_get_header(m, "Tone"); 06980 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2]; 06981 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 06982 struct ast_bridge_thread_obj *tobj = NULL; 06983 char buf[256]; 06984 06985 /* make sure valid channels were specified */ 06986 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 06987 astman_send_error(s, m, "Missing channel parameter in request"); 06988 return 0; 06989 } 06990 06991 /* Start with chana */ 06992 chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); 06993 if (!chana) { 06994 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 06995 astman_send_error(s, m, buf); 06996 return 0; 06997 } 06998 06999 /* Answer the channels if needed */ 07000 if (chana->_state != AST_STATE_UP) 07001 ast_answer(chana); 07002 07003 /* create the placeholder channels and grab the other channels */ 07004 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 07005 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) { 07006 astman_send_error(s, m, "Unable to create temporary channel!"); 07007 chana = ast_channel_unref(chana); 07008 return 0; 07009 } 07010 07011 if (do_bridge_masquerade(chana, tmpchana)) { 07012 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela); 07013 astman_send_error(s, m, buf); 07014 ast_hangup(tmpchana); 07015 chana = ast_channel_unref(chana); 07016 return 0; 07017 } 07018 07019 chana = ast_channel_unref(chana); 07020 07021 /* now do chanb */ 07022 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); 07023 if (!chanb) { 07024 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 07025 astman_send_error(s, m, buf); 07026 ast_hangup(tmpchana); 07027 return 0; 07028 } 07029 07030 /* Answer the channels if needed */ 07031 if (chanb->_state != AST_STATE_UP) 07032 ast_answer(chanb); 07033 07034 /* create the placeholder channels and grab the other channels */ 07035 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 07036 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) { 07037 astman_send_error(s, m, "Unable to create temporary channels!"); 07038 ast_hangup(tmpchana); 07039 chanb = ast_channel_unref(chanb); 07040 return 0; 07041 } 07042 07043 if (do_bridge_masquerade(chanb, tmpchanb)) { 07044 snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb); 07045 astman_send_error(s, m, buf); 07046 ast_hangup(tmpchana); 07047 ast_hangup(tmpchanb); 07048 chanb = ast_channel_unref(chanb); 07049 return 0; 07050 } 07051 07052 chanb = ast_channel_unref(chanb); 07053 07054 /* make the channels compatible, send error if we fail doing so */ 07055 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 07056 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 07057 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 07058 ast_hangup(tmpchana); 07059 ast_hangup(tmpchanb); 07060 return 0; 07061 } 07062 07063 /* setup the bridge thread object and start the bridge */ 07064 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 07065 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 07066 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 07067 ast_hangup(tmpchana); 07068 ast_hangup(tmpchanb); 07069 return 0; 07070 } 07071 07072 tobj->chan = tmpchana; 07073 tobj->peer = tmpchanb; 07074 tobj->return_to_pbx = 1; 07075 07076 if (ast_true(playtone)) { 07077 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 07078 if (ast_waitstream(tmpchanb, "") < 0) 07079 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 07080 } 07081 } 07082 07083 chans[0] = tmpchana; 07084 chans[1] = tmpchanb; 07085 07086 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans, 07087 "Response: Success\r\n" 07088 "Channel1: %s\r\n" 07089 "Channel2: %s\r\n", tmpchana->name, tmpchanb->name); 07090 07091 bridge_call_thread_launch(tobj); 07092 07093 astman_send_ack(s, m, "Launched bridge thread with success"); 07094 07095 return 0; 07096 }
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 768 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().
00769 { 00770 struct ast_datastore *datastore; 00771 struct ast_dial_features *dialfeatures; 00772 00773 ast_channel_lock(chan); 00774 datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL); 00775 ast_channel_unlock(chan); 00776 if (datastore) { 00777 /* Already exists. */ 00778 return 1; 00779 } 00780 00781 /* Create a new datastore with specified feature flags. */ 00782 datastore = ast_datastore_alloc(&dial_features_info, NULL); 00783 if (!datastore) { 00784 ast_log(LOG_WARNING, "Unable to create channel features datastore.\n"); 00785 return 0; 00786 } 00787 dialfeatures = ast_calloc(1, sizeof(*dialfeatures)); 00788 if (!dialfeatures) { 00789 ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n"); 00790 ast_datastore_free(datastore); 00791 return 0; 00792 } 00793 ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL); 00794 ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL); 00795 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 00796 datastore->data = dialfeatures; 00797 ast_channel_lock(chan); 00798 ast_channel_datastore_add(chan, datastore); 00799 ast_channel_unlock(chan); 00800 return 0; 00801 }
static void add_features_datastores | ( | struct ast_channel * | caller, | |
struct ast_channel * | callee, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 3897 of file features.c.
References add_features_datastore(), ast_bridge_config::features_callee, and ast_bridge_config::features_caller.
Referenced by ast_bridge_call().
03898 { 03899 if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) { 03900 /* 03901 * If we don't return here, then when we do a builtin_atxfer we 03902 * will copy the disconnect flags over from the atxfer to the 03903 * callee (Party C). 03904 */ 03905 return; 03906 } 03907 03908 add_features_datastore(callee, &config->features_callee, &config->features_caller); 03909 }
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 1063 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
01064 { 01065 int res; 01066 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 01067 char tmp[256]; 01068 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 01069 01070 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 01071 message[0] = tmp; 01072 res = ast_adsi_load_session(chan, NULL, 0, 1); 01073 if (res == -1) 01074 return res; 01075 return ast_adsi_print(chan, message, justify, 1); 01076 }
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 3960 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().
03961 { 03962 /* Copy voice back and forth between the two channels. Give the peer 03963 the ability to transfer calls with '#<extension' syntax. */ 03964 struct ast_frame *f; 03965 struct ast_channel *who; 03966 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03967 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03968 char orig_channame[AST_CHANNEL_NAME]; 03969 char orig_peername[AST_CHANNEL_NAME]; 03970 int res; 03971 int diff; 03972 int hasfeatures=0; 03973 int hadfeatures=0; 03974 int autoloopflag; 03975 int sendingdtmfdigit = 0; 03976 int we_disabled_peer_cdr = 0; 03977 struct ast_option_header *aoh; 03978 struct ast_cdr *bridge_cdr = NULL; 03979 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03980 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03981 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03982 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03983 struct ast_silence_generator *silgen = NULL; 03984 const char *h_context; 03985 03986 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03987 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03988 03989 /* Clear any BLINDTRANSFER since the transfer has completed. */ 03990 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03991 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL); 03992 03993 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03994 add_features_datastores(chan, peer, config); 03995 03996 /* This is an interesting case. One example is if a ringing channel gets redirected to 03997 * an extension that picks up a parked call. This will make sure that the call taken 03998 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03999 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 04000 ast_indicate(peer, AST_CONTROL_RINGING); 04001 } 04002 04003 if (monitor_ok) { 04004 const char *monitor_exec; 04005 struct ast_channel *src = NULL; 04006 if (!monitor_app) { 04007 if (!(monitor_app = pbx_findapp("Monitor"))) 04008 monitor_ok=0; 04009 } 04010 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 04011 src = chan; 04012 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 04013 src = peer; 04014 if (monitor_app && src) { 04015 char *tmp = ast_strdupa(monitor_exec); 04016 pbx_exec(src, monitor_app, tmp); 04017 } 04018 } 04019 04020 set_config_flags(chan, peer, config); 04021 04022 /* Answer if need be */ 04023 if (chan->_state != AST_STATE_UP) { 04024 if (ast_raw_answer(chan, 1)) { 04025 return -1; 04026 } 04027 } 04028 04029 #ifdef FOR_DEBUG 04030 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 04031 ast_channel_log("Pre-bridge CHAN Channel info", chan); 04032 ast_channel_log("Pre-bridge PEER Channel info", peer); 04033 #endif 04034 /* two channels are being marked as linked here */ 04035 ast_channel_set_linkgroup(chan,peer); 04036 04037 /* copy the userfield from the B-leg to A-leg if applicable */ 04038 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 04039 char tmp[256]; 04040 04041 ast_channel_lock(chan); 04042 if (!ast_strlen_zero(chan->cdr->userfield)) { 04043 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 04044 ast_cdr_appenduserfield(chan, tmp); 04045 } else { 04046 ast_cdr_setuserfield(chan, peer->cdr->userfield); 04047 } 04048 ast_channel_unlock(chan); 04049 /* Don't delete the CDR; just disable it. */ 04050 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04051 we_disabled_peer_cdr = 1; 04052 } 04053 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 04054 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 04055 04056 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 04057 ast_channel_lock_both(chan, peer); 04058 if (chan_cdr) { 04059 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 04060 ast_cdr_update(chan); 04061 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 04062 /* rip any forked CDR's off of the chan_cdr and attach 04063 * them to the bridge_cdr instead */ 04064 bridge_cdr->next = chan_cdr->next; 04065 chan_cdr->next = NULL; 04066 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04067 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04068 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 04069 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04070 } 04071 ast_cdr_setaccount(peer, chan->accountcode); 04072 } else { 04073 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 04074 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 04075 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 04076 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 04077 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 04078 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04079 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04080 ast_cdr_setcid(bridge_cdr, chan); 04081 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 04082 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 04083 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 04084 /* Destination information */ 04085 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 04086 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 04087 if (peer_cdr) { 04088 bridge_cdr->start = peer_cdr->start; 04089 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04090 } else { 04091 ast_cdr_start(bridge_cdr); 04092 } 04093 } 04094 ast_channel_unlock(chan); 04095 ast_channel_unlock(peer); 04096 04097 ast_debug(4,"bridge answer set, chan answer set\n"); 04098 /* peer_cdr->answer will be set when a macro runs on the peer; 04099 in that case, the bridge answer will be delayed while the 04100 macro plays on the peer channel. The peer answered the call 04101 before the macro started playing. To the phone system, 04102 this is billable time for the call, even tho the caller 04103 hears nothing but ringing while the macro does its thing. */ 04104 04105 /* Another case where the peer cdr's time will be set, is when 04106 A self-parks by pickup up phone and dialing 700, then B 04107 picks up A by dialing its parking slot; there may be more 04108 practical paths that get the same result, tho... in which 04109 case you get the previous answer time from the Park... which 04110 is before the bridge's start time, so I added in the 04111 tvcmp check to the if below */ 04112 04113 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 04114 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 04115 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 04116 if (chan_cdr) { 04117 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 04118 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 04119 } 04120 } else { 04121 ast_cdr_answer(bridge_cdr); 04122 if (chan_cdr) { 04123 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 04124 } 04125 } 04126 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 04127 if (chan_cdr) { 04128 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 04129 } 04130 if (peer_cdr) { 04131 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 04132 } 04133 } 04134 /* the DIALED flag may be set if a dialed channel is transferred 04135 * and then bridged to another channel. In order for the 04136 * bridge CDR to be written, the DIALED flag must not be 04137 * present. */ 04138 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04139 } 04140 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04141 04142 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04143 * a call is being bridged, that the humans in charge know what they're doing. If they 04144 * don't, well, what can we do about that? */ 04145 clear_dialed_interfaces(chan); 04146 clear_dialed_interfaces(peer); 04147 04148 for (;;) { 04149 struct ast_channel *other; /* used later */ 04150 04151 res = ast_channel_bridge(chan, peer, config, &f, &who); 04152 04153 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04154 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04155 /* Zombies are present time to leave! */ 04156 res = -1; 04157 if (f) { 04158 ast_frfree(f); 04159 } 04160 goto before_you_go; 04161 } 04162 04163 /* When frame is not set, we are probably involved in a situation 04164 where we've timed out. 04165 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04166 and also for DTMF_END. If we flow into the following 'if' for both, then 04167 our wait times are cut in half, as both will subtract from the 04168 feature_timer. Not good! 04169 */ 04170 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04171 /* Update feature timer for next pass */ 04172 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04173 if (res == AST_BRIDGE_RETRY) { 04174 /* The feature fully timed out but has not been updated. Skip 04175 * the potential round error from the diff calculation and 04176 * explicitly set to expired. */ 04177 config->feature_timer = -1; 04178 } else { 04179 config->feature_timer -= diff; 04180 } 04181 04182 if (hasfeatures) { 04183 if (config->feature_timer <= 0) { 04184 /* Not *really* out of time, just out of time for 04185 digits to come in for features. */ 04186 ast_debug(1, "Timed out for feature!\n"); 04187 if (!ast_strlen_zero(peer_featurecode)) { 04188 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 04189 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04190 } 04191 if (!ast_strlen_zero(chan_featurecode)) { 04192 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 04193 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04194 } 04195 if (f) 04196 ast_frfree(f); 04197 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04198 if (!hasfeatures) { 04199 /* No more digits expected - reset the timer */ 04200 config->feature_timer = 0; 04201 } 04202 hadfeatures = hasfeatures; 04203 /* Continue as we were */ 04204 continue; 04205 } else if (!f) { 04206 /* The bridge returned without a frame and there is a feature in progress. 04207 * However, we don't think the feature has quite yet timed out, so just 04208 * go back into the bridge. */ 04209 continue; 04210 } 04211 } else { 04212 if (config->feature_timer <=0) { 04213 /* We ran out of time */ 04214 config->feature_timer = 0; 04215 who = chan; 04216 if (f) 04217 ast_frfree(f); 04218 f = NULL; 04219 res = 0; 04220 } 04221 } 04222 } 04223 if (res < 0) { 04224 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04225 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 04226 } 04227 goto before_you_go; 04228 } 04229 04230 if (!f || (f->frametype == AST_FRAME_CONTROL && 04231 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04232 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04233 res = -1; 04234 break; 04235 } 04236 /* many things should be sent to the 'other' channel */ 04237 other = (who == chan) ? peer : chan; 04238 if (f->frametype == AST_FRAME_CONTROL) { 04239 switch (f->subclass.integer) { 04240 case AST_CONTROL_RINGING: 04241 case AST_CONTROL_FLASH: 04242 case -1: 04243 ast_indicate(other, f->subclass.integer); 04244 break; 04245 case AST_CONTROL_CONNECTED_LINE: 04246 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04247 break; 04248 } 04249 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04250 break; 04251 case AST_CONTROL_REDIRECTING: 04252 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04253 break; 04254 } 04255 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04256 break; 04257 case AST_CONTROL_AOC: 04258 case AST_CONTROL_HOLD: 04259 case AST_CONTROL_UNHOLD: 04260 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04261 break; 04262 case AST_CONTROL_OPTION: 04263 aoh = f->data.ptr; 04264 /* Forward option Requests, but only ones we know are safe 04265 * These are ONLY sent by chan_iax2 and I'm not convinced that 04266 * they are useful. I haven't deleted them entirely because I 04267 * just am not sure of the ramifications of removing them. */ 04268 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04269 switch (ntohs(aoh->option)) { 04270 case AST_OPTION_TONE_VERIFY: 04271 case AST_OPTION_TDD: 04272 case AST_OPTION_RELAXDTMF: 04273 case AST_OPTION_AUDIO_MODE: 04274 case AST_OPTION_DIGIT_DETECT: 04275 case AST_OPTION_FAX_DETECT: 04276 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04277 f->datalen - sizeof(struct ast_option_header), 0); 04278 } 04279 } 04280 break; 04281 } 04282 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04283 struct ast_flags *cfg; 04284 char dtmfcode[2] = { f->subclass.integer, }; 04285 size_t featurelen; 04286 04287 if (who == chan) { 04288 featurelen = strlen(chan_featurecode); 04289 cfg = &(config->features_caller); 04290 } else { 04291 featurelen = strlen(peer_featurecode); 04292 cfg = &(config->features_callee); 04293 } 04294 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04295 * DTMF along untouched. If this is not the first digit of a multi-digit code 04296 * then we need to fall through and stream the characters if it matches */ 04297 if (featurelen == 0 04298 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04299 if (option_debug > 3) { 04300 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04301 } 04302 ast_write(other, f); 04303 sendingdtmfdigit = 1; 04304 } else { 04305 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04306 * transmitting something while we hold on to the DTMF waiting for a 04307 * feature. */ 04308 if (!silgen && ast_opt_transmit_silence) { 04309 silgen = ast_channel_start_silence_generator(other); 04310 } 04311 if (option_debug > 3) { 04312 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04313 } 04314 } 04315 } else if (f->frametype == AST_FRAME_DTMF_END) { 04316 char *featurecode; 04317 int sense; 04318 04319 hadfeatures = hasfeatures; 04320 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04321 if (who == chan) { 04322 sense = FEATURE_SENSE_CHAN; 04323 featurecode = chan_featurecode; 04324 } else { 04325 sense = FEATURE_SENSE_PEER; 04326 featurecode = peer_featurecode; 04327 } 04328 04329 if (sendingdtmfdigit == 1) { 04330 /* We let the BEGIN go through happily, so let's not bother with the END, 04331 * since we already know it's not something we bother with */ 04332 ast_write(other, f); 04333 sendingdtmfdigit = 0; 04334 } else { 04335 /*! append the event to featurecode. we rely on the string being zero-filled, and 04336 * not overflowing it. 04337 * \todo XXX how do we guarantee the latter ? 04338 */ 04339 featurecode[strlen(featurecode)] = f->subclass.integer; 04340 /* Get rid of the frame before we start doing "stuff" with the channels */ 04341 ast_frfree(f); 04342 f = NULL; 04343 if (silgen) { 04344 ast_channel_stop_silence_generator(other, silgen); 04345 silgen = NULL; 04346 } 04347 config->feature_timer = 0; 04348 res = feature_interpret(chan, peer, config, featurecode, sense); 04349 switch(res) { 04350 case AST_FEATURE_RETURN_PASSDIGITS: 04351 ast_dtmf_stream(other, who, featurecode, 0, 0); 04352 /* Fall through */ 04353 case AST_FEATURE_RETURN_SUCCESS: 04354 memset(featurecode, 0, sizeof(chan_featurecode)); 04355 break; 04356 } 04357 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04358 res = 0; 04359 } else { 04360 break; 04361 } 04362 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04363 if (hadfeatures && !hasfeatures) { 04364 /* Feature completed or timed out */ 04365 config->feature_timer = 0; 04366 } else if (hasfeatures) { 04367 if (config->timelimit) { 04368 /* No warning next time - we are waiting for feature code */ 04369 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04370 } 04371 config->feature_start_time = ast_tvnow(); 04372 config->feature_timer = featuredigittimeout; 04373 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04374 } 04375 } 04376 } 04377 if (f) 04378 ast_frfree(f); 04379 } 04380 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04381 04382 before_you_go: 04383 if (chan->sending_dtmf_digit) { 04384 ast_bridge_end_dtmf(chan, chan->sending_dtmf_digit, chan->sending_dtmf_tv, 04385 "bridge end"); 04386 } 04387 if (peer->sending_dtmf_digit) { 04388 ast_bridge_end_dtmf(peer, peer->sending_dtmf_digit, peer->sending_dtmf_tv, 04389 "bridge end"); 04390 } 04391 04392 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04393 if (silgen) { 04394 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04395 silgen = NULL; 04396 } 04397 04398 /* Wait for any dual redirect to complete. */ 04399 while (ast_test_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) { 04400 sched_yield(); 04401 } 04402 04403 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04404 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04405 if (bridge_cdr) { 04406 ast_cdr_discard(bridge_cdr); 04407 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04408 } 04409 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04410 } 04411 04412 if (config->end_bridge_callback) { 04413 config->end_bridge_callback(config->end_bridge_callback_data); 04414 } 04415 04416 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04417 * if it were, then chan belongs to a different thread now, and might have been hung up long 04418 * ago. 04419 */ 04420 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04421 /* 04422 * If the bridge was broken for a hangup that isn't real, 04423 * then don't run the h extension, because the channel isn't 04424 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04425 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04426 */ 04427 h_context = NULL; 04428 } else if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04429 h_context = NULL; 04430 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04431 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04432 h_context = chan->context; 04433 } else if (!ast_strlen_zero(chan->macrocontext) 04434 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04435 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04436 h_context = chan->macrocontext; 04437 } else { 04438 h_context = NULL; 04439 } 04440 if (h_context) { 04441 struct ast_cdr *swapper = NULL; 04442 char savelastapp[AST_MAX_EXTENSION]; 04443 char savelastdata[AST_MAX_EXTENSION]; 04444 char save_context[AST_MAX_CONTEXT]; 04445 char save_exten[AST_MAX_EXTENSION]; 04446 int save_prio; 04447 int found = 0; /* set if we find at least one match */ 04448 int spawn_error = 0; 04449 04450 /* 04451 * Make sure that the channel is marked as hungup since we are 04452 * going to run the "h" exten on it. 04453 */ 04454 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04455 04456 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04457 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04458 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04459 ast_cdr_end(bridge_cdr); 04460 } 04461 04462 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04463 dialplan code operate on it */ 04464 ast_channel_lock(chan); 04465 if (bridge_cdr) { 04466 swapper = chan->cdr; 04467 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04468 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04469 chan->cdr = bridge_cdr; 04470 } 04471 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04472 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04473 save_prio = chan->priority; 04474 if (h_context != chan->context) { 04475 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04476 } 04477 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04478 chan->priority = 1; 04479 ast_channel_unlock(chan); 04480 04481 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04482 chan->priority, 04483 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04484 &found, 1)) == 0) { 04485 chan->priority++; 04486 } 04487 if (found && spawn_error) { 04488 /* Something bad happened, or a hangup has been requested. */ 04489 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04490 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04491 } 04492 04493 /* swap it back */ 04494 ast_channel_lock(chan); 04495 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04496 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04497 chan->priority = save_prio; 04498 if (bridge_cdr) { 04499 if (chan->cdr == bridge_cdr) { 04500 chan->cdr = swapper; 04501 } else { 04502 bridge_cdr = NULL; 04503 } 04504 } 04505 /* An "h" exten has been run, so indicate that one has been run. */ 04506 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04507 ast_channel_unlock(chan); 04508 04509 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04510 if (bridge_cdr) { 04511 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04512 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04513 } 04514 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04515 } 04516 04517 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04518 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04519 /* If the channel CDR has been modified during the call, record the changes in the bridge cdr, 04520 * BUT, if we've gone through the h extension block above, the CDR got swapped so don't overwrite 04521 * what was done in the h extension. What a mess. This is why you never touch CDR code. */ 04522 if (new_chan_cdr && bridge_cdr && !h_context) { 04523 ast_cdr_copy_vars(bridge_cdr, new_chan_cdr); 04524 ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield)); 04525 bridge_cdr->amaflags = new_chan_cdr->amaflags; 04526 ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode)); 04527 if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 04528 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04529 } 04530 } 04531 04532 /* we can post the bridge CDR at this point */ 04533 if (bridge_cdr) { 04534 ast_cdr_end(bridge_cdr); 04535 ast_cdr_detach(bridge_cdr); 04536 } 04537 04538 /* do a specialized reset on the beginning channel 04539 CDR's, if they still exist, so as not to mess up 04540 issues in future bridges; 04541 04542 Here are the rules of the game: 04543 1. The chan and peer channel pointers will not change 04544 during the life of the bridge. 04545 2. But, in transfers, the channel names will change. 04546 between the time the bridge is started, and the 04547 time the channel ends. 04548 Usually, when a channel changes names, it will 04549 also change CDR pointers. 04550 3. Usually, only one of the two channels (chan or peer) 04551 will change names. 04552 4. Usually, if a channel changes names during a bridge, 04553 it is because of a transfer. Usually, in these situations, 04554 it is normal to see 2 bridges running simultaneously, and 04555 it is not unusual to see the two channels that change 04556 swapped between bridges. 04557 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04558 to attend to; if the chan or peer changed names, 04559 we have the before and after attached CDR's. 04560 */ 04561 04562 if (new_chan_cdr) { 04563 struct ast_channel *chan_ptr = NULL; 04564 04565 if (strcasecmp(orig_channame, chan->name) != 0) { 04566 /* old channel */ 04567 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04568 ast_channel_lock(chan_ptr); 04569 if (!ast_bridged_channel(chan_ptr)) { 04570 struct ast_cdr *cur; 04571 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04572 if (cur == chan_cdr) { 04573 break; 04574 } 04575 } 04576 if (cur) { 04577 ast_cdr_specialized_reset(chan_cdr, 0); 04578 } 04579 } 04580 ast_channel_unlock(chan_ptr); 04581 chan_ptr = ast_channel_unref(chan_ptr); 04582 } 04583 /* new channel */ 04584 ast_cdr_specialized_reset(new_chan_cdr, 0); 04585 } else { 04586 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04587 } 04588 } 04589 04590 { 04591 struct ast_channel *chan_ptr = NULL; 04592 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04593 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)) 04594 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04595 if (strcasecmp(orig_peername, peer->name) != 0) { 04596 /* old channel */ 04597 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04598 ast_channel_lock(chan_ptr); 04599 if (!ast_bridged_channel(chan_ptr)) { 04600 struct ast_cdr *cur; 04601 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04602 if (cur == peer_cdr) { 04603 break; 04604 } 04605 } 04606 if (cur) { 04607 ast_cdr_specialized_reset(peer_cdr, 0); 04608 } 04609 } 04610 ast_channel_unlock(chan_ptr); 04611 chan_ptr = ast_channel_unref(chan_ptr); 04612 } 04613 /* new channel */ 04614 if (new_peer_cdr) { 04615 ast_cdr_specialized_reset(new_peer_cdr, 0); 04616 } 04617 } else { 04618 if (we_disabled_peer_cdr) { 04619 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04620 } 04621 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04622 } 04623 } 04624 04625 return res; 04626 }
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 3927 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().
03928 { 03929 int dead; 03930 long duration; 03931 03932 ast_channel_lock(chan); 03933 dead = ast_test_flag(chan, AST_FLAG_ZOMBIE) 03934 || (chan->_softhangup 03935 & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)); 03936 ast_channel_unlock(chan); 03937 if (dead) { 03938 /* Channel is a zombie or a real hangup. */ 03939 return; 03940 } 03941 03942 duration = ast_tvdiff_ms(ast_tvnow(), start); 03943 ast_senddigit_end(chan, digit, duration); 03944 ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n", 03945 digit, chan->name, why, duration); 03946 }
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 7532 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().
07534 { 07535 char *stringp = ast_strdupa(parse); 07536 char *limit_str, *warning_str, *warnfreq_str; 07537 const char *var; 07538 int play_to_caller = 0, play_to_callee = 0; 07539 int delta; 07540 07541 limit_str = strsep(&stringp, ":"); 07542 warning_str = strsep(&stringp, ":"); 07543 warnfreq_str = strsep(&stringp, ":"); 07544 07545 config->timelimit = atol(limit_str); 07546 if (warning_str) 07547 config->play_warning = atol(warning_str); 07548 if (warnfreq_str) 07549 config->warning_freq = atol(warnfreq_str); 07550 07551 if (!config->timelimit) { 07552 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07553 config->timelimit = config->play_warning = config->warning_freq = 0; 07554 config->warning_sound = NULL; 07555 return -1; /* error */ 07556 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07557 int w = config->warning_freq; 07558 07559 /* 07560 * If the first warning is requested _after_ the entire call 07561 * would end, and no warning frequency is requested, then turn 07562 * off the warning. If a warning frequency is requested, reduce 07563 * the 'first warning' time by that frequency until it falls 07564 * within the call's total time limit. 07565 * 07566 * Graphically: 07567 * timelim->| delta |<-playwarning 07568 * 0__________________|_________________| 07569 * | w | | | | 07570 * 07571 * so the number of intervals to cut is 1+(delta-1)/w 07572 */ 07573 if (w == 0) { 07574 config->play_warning = 0; 07575 } else { 07576 config->play_warning -= w * ( 1 + (delta-1)/w ); 07577 if (config->play_warning < 1) 07578 config->play_warning = config->warning_freq = 0; 07579 } 07580 } 07581 07582 ast_channel_lock(chan); 07583 07584 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07585 play_to_caller = var ? ast_true(var) : 1; 07586 07587 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07588 play_to_callee = var ? ast_true(var) : 0; 07589 07590 if (!play_to_caller && !play_to_callee) 07591 play_to_caller = 1; 07592 07593 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07594 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07595 07596 /* The code looking at config wants a NULL, not just "", to decide 07597 * that the message should not be played, so we replace "" with NULL. 07598 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07599 * not found. 07600 */ 07601 07602 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07603 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07604 07605 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07606 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07607 07608 ast_channel_unlock(chan); 07609 07610 /* undo effect of S(x) in case they are both used */ 07611 calldurationlimit->tv_sec = 0; 07612 calldurationlimit->tv_usec = 0; 07613 07614 /* more efficient to do it like S(x) does since no advanced opts */ 07615 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07616 calldurationlimit->tv_sec = config->timelimit / 1000; 07617 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07618 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07619 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07620 config->timelimit = play_to_caller = play_to_callee = 07621 config->play_warning = config->warning_freq = 0; 07622 } else { 07623 ast_verb(4, "Limit Data for this call:\n"); 07624 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07625 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07626 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07627 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07628 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07629 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07630 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07631 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07632 } 07633 if (play_to_caller) 07634 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07635 if (play_to_callee) 07636 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07637 return 0; 07638 }
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 7338 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().
07339 { 07340 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07341 && (chan->_state == AST_STATE_RINGING 07342 || chan->_state == AST_STATE_RING 07343 /* 07344 * Check the down state as well because some SIP devices do not 07345 * give 180 ringing when they can just give 183 session progress 07346 * instead. Issue 14005. (Some ISDN switches as well for that 07347 * matter.) 07348 */ 07349 || chan->_state == AST_STATE_DOWN) 07350 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07351 return 1; 07352 } 07353 return 0; 07354 }
void ast_channel_log | ( | char * | title, | |
struct ast_channel * | chan | |||
) |
Definition at line 3832 of file features.c.
References ast_log(), and LOG_NOTICE.
Referenced by ast_bridge_call().
03833 { 03834 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan); 03835 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n", 03836 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority); 03837 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n", 03838 chan->accountcode, chan->dialcontext, (unsigned)chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority); 03839 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n", 03840 chan->masq, chan->masqr, 03841 chan->_bridge, chan->uniqueid, chan->linkedid); 03842 if (chan->masqr) 03843 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n", 03844 chan->masqr->name, chan->masqr->cdr); 03845 if (chan->_bridge) 03846 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name); 03847 03848 ast_log(LOG_NOTICE, "===== done ====\n"); 03849 }
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 7414 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().
07415 { 07416 struct ast_party_connected_line connected_caller; 07417 struct ast_channel *chans[2] = { chan, target }; 07418 struct ast_datastore *ds_pickup; 07419 const char *chan_name;/*!< A masquerade changes channel names. */ 07420 const char *target_name;/*!< A masquerade changes channel names. */ 07421 int res = -1; 07422 07423 target_name = ast_strdupa(target->name); 07424 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name); 07425 07426 /* Mark the target to block any call pickup race. */ 07427 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07428 if (!ds_pickup) { 07429 ast_log(LOG_WARNING, 07430 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07431 return -1; 07432 } 07433 ast_channel_datastore_add(target, ds_pickup); 07434 07435 ast_party_connected_line_init(&connected_caller); 07436 ast_party_connected_line_copy(&connected_caller, &target->connected); 07437 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07438 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07439 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07440 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07441 } 07442 ast_party_connected_line_free(&connected_caller); 07443 07444 ast_channel_lock(chan); 07445 chan_name = ast_strdupa(chan->name); 07446 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07447 ast_channel_unlock(chan); 07448 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07449 07450 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07451 07452 if (ast_answer(chan)) { 07453 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07454 goto pickup_failed; 07455 } 07456 07457 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07458 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07459 goto pickup_failed; 07460 } 07461 07462 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07463 07464 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07465 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07466 07467 if (ast_channel_masquerade(target, chan)) { 07468 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07469 target_name); 07470 goto pickup_failed; 07471 } 07472 07473 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07474 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07475 "Channel: %s\r\n" 07476 "TargetChannel: %s\r\n", 07477 chan_name, target_name); 07478 07479 /* Do the masquerade manually to make sure that it is completed. */ 07480 ast_do_masquerade(target); 07481 res = 0; 07482 07483 pickup_failed: 07484 ast_channel_lock(target); 07485 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07486 ast_datastore_free(ds_pickup); 07487 } 07488 ast_party_connected_line_free(&connected_caller); 07489 07490 return res; 07491 }
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 3434 of file features.c.
References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03434 { 03435 03436 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03437 }
int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 8336 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().
08337 { 08338 int res; 08339 08340 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 08341 if (!parkinglots) { 08342 return -1; 08343 } 08344 08345 res = load_config(0); 08346 if (res) { 08347 return res; 08348 } 08349 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); 08350 if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) { 08351 return -1; 08352 } 08353 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); 08354 res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL); 08355 if (!res) 08356 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); 08357 if (!res) { 08358 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status); 08359 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park); 08360 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge); 08361 } 08362 08363 res |= ast_devstate_prov_add("Park", metermaidstate); 08364 #if defined(TEST_FRAMEWORK) 08365 res |= AST_TEST_REGISTER(features_test); 08366 #endif /* defined(TEST_FRAMEWORK) */ 08367 08368 ast_register_atexit(features_shutdown); 08369 08370 return res; 08371 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6879 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().
06880 { 06881 struct ast_context *con; 06882 int res; 06883 06884 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06885 06886 /* 06887 * Always destroy the parking_con_dial context to remove buildup 06888 * of recalled extensions in the context. At worst, the parked 06889 * call gets hungup attempting to run an invalid extension when 06890 * we are trying to callback the parker or the preset return 06891 * extension. This is a small window of opportunity on an 06892 * execution chain that is not expected to happen very often. 06893 */ 06894 con = ast_context_find(parking_con_dial); 06895 if (con) { 06896 ast_context_destroy(con, registrar); 06897 } 06898 06899 res = load_config(1); 06900 ast_mutex_unlock(&features_reload_lock); 06901 06902 return res; 06903 }
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 3160 of file features.c.
References FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), handle_request_info(), and process_config().
03161 { 03162 int x; 03163 for (x = 0; x < FEATURES_COUNT; x++) { 03164 if (!strcasecmp(name, builtin_features[x].sname)) 03165 return &builtin_features[x]; 03166 } 03167 return NULL; 03168 }
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 1857 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().
01858 { 01859 struct ast_park_call_args args = { 01860 .timeout = timeout, 01861 .extout = extout, 01862 }; 01863 01864 if (peer) { 01865 args.orig_chan_name = ast_strdupa(peer->name); 01866 } 01867 return masq_park_call(rchan, peer, &args); 01868 }
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 1803 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().
01804 { 01805 int res; 01806 char *parse; 01807 const char *app_data; 01808 struct ast_exten *exten; 01809 struct park_app_args app_args; 01810 struct ast_park_call_args args = { 01811 .timeout = timeout, 01812 .extout = extout, 01813 }; 01814 01815 if (parker) { 01816 args.orig_chan_name = ast_strdupa(parker->name); 01817 } 01818 if (!park_exten || !park_context) { 01819 return masq_park_call(park_me, parker, &args); 01820 } 01821 01822 /* 01823 * Determiine if the specified park extension has an exclusive 01824 * parking lot to use. 01825 */ 01826 if (parker && parker != park_me) { 01827 ast_autoservice_start(park_me); 01828 } 01829 exten = get_parking_exten(park_exten, parker, park_context); 01830 if (exten) { 01831 app_data = ast_get_extension_app_data(exten); 01832 if (!app_data) { 01833 app_data = ""; 01834 } 01835 parse = ast_strdupa(app_data); 01836 AST_STANDARD_APP_ARGS(app_args, parse); 01837 01838 if (!ast_strlen_zero(app_args.pl_name)) { 01839 /* Find the specified exclusive parking lot */ 01840 args.parkinglot = find_parkinglot(app_args.pl_name); 01841 if (!args.parkinglot && parkeddynamic) { 01842 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01843 } 01844 } 01845 } 01846 if (parker && parker != park_me) { 01847 ast_autoservice_stop(park_me); 01848 } 01849 01850 res = masq_park_call(park_me, parker, &args); 01851 if (args.parkinglot) { 01852 parkinglot_unref(args.parkinglot); 01853 } 01854 return res; 01855 }
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 1706 of file features.c.
References park_call_full(), and ast_park_call_args::timeout.
01707 { 01708 struct ast_park_call_args args = { 01709 .timeout = timeout, 01710 .extout = extout, 01711 }; 01712 01713 return park_call_full(park_me, parker, &args); 01714 }
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 1655 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().
01656 { 01657 int res; 01658 char *parse; 01659 const char *app_data; 01660 struct ast_exten *exten; 01661 struct park_app_args app_args; 01662 struct ast_park_call_args args = { 01663 .timeout = timeout, 01664 .extout = extout, 01665 }; 01666 01667 if (!park_exten || !park_context) { 01668 return park_call_full(park_me, parker, &args); 01669 } 01670 01671 /* 01672 * Determiine if the specified park extension has an exclusive 01673 * parking lot to use. 01674 */ 01675 if (parker && parker != park_me) { 01676 ast_autoservice_start(park_me); 01677 } 01678 exten = get_parking_exten(park_exten, parker, park_context); 01679 if (exten) { 01680 app_data = ast_get_extension_app_data(exten); 01681 if (!app_data) { 01682 app_data = ""; 01683 } 01684 parse = ast_strdupa(app_data); 01685 AST_STANDARD_APP_ARGS(app_args, parse); 01686 01687 if (!ast_strlen_zero(app_args.pl_name)) { 01688 /* Find the specified exclusive parking lot */ 01689 args.parkinglot = find_parkinglot(app_args.pl_name); 01690 if (!args.parkinglot && parkeddynamic) { 01691 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01692 } 01693 } 01694 } 01695 if (parker && parker != park_me) { 01696 ast_autoservice_stop(park_me); 01697 } 01698 01699 res = park_call_full(park_me, parker, &args); 01700 if (args.parkinglot) { 01701 parkinglot_unref(args.parkinglot); 01702 } 01703 return res; 01704 }
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 844 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().
00845 { 00846 return get_parking_exten(exten_str, chan, context) ? 1 : 0; 00847 }
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 7380 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().
07381 { 07382 struct ast_channel *target;/*!< Potential pickup target */ 07383 int res = -1; 07384 ast_debug(1, "pickup attempt by %s\n", chan->name); 07385 07386 /* The found channel is already locked. */ 07387 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07388 if (target) { 07389 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name); 07390 07391 res = ast_do_pickup(chan, target); 07392 ast_channel_unlock(target); 07393 if (!res) { 07394 if (!ast_strlen_zero(pickupsound)) { 07395 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07396 } 07397 } else { 07398 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name); 07399 } 07400 target = ast_channel_unref(target); 07401 } 07402 07403 if (res < 0) { 07404 ast_debug(1, "No call pickup possible... for %s\n", chan->name); 07405 if (!ast_strlen_zero(pickupfailsound)) { 07406 ast_answer(chan); 07407 ast_stream_and_wait(chan, pickupfailsound, ""); 07408 } 07409 } 07410 07411 return res; 07412 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 849 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().
00850 { 00851 return pickup_ext; 00852 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 3150 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
03151 { 03152 ast_rwlock_rdlock(&features_lock); 03153 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_list
register new feature into feature_set
Definition at line 2994 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().
02995 { 02996 if (!feature) { 02997 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02998 return; 02999 } 03000 03001 AST_RWLIST_WRLOCK(&feature_list); 03002 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 03003 AST_RWLIST_UNLOCK(&feature_list); 03004 03005 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 03006 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 3155 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
03156 { 03157 ast_rwlock_unlock(&features_lock); 03158 }
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 3074 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
03075 { 03076 if (!feature) { 03077 return; 03078 } 03079 03080 AST_RWLIST_WRLOCK(&feature_list); 03081 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 03082 AST_RWLIST_UNLOCK(&feature_list); 03083 03084 ast_free(feature); 03085 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 3088 of file features.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
Referenced by process_config().
03089 { 03090 struct ast_call_feature *feature; 03091 03092 AST_RWLIST_WRLOCK(&feature_list); 03093 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 03094 ast_free(feature); 03095 } 03096 AST_RWLIST_UNLOCK(&feature_list); 03097 }
static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 3114 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().
03115 { 03116 struct feature_group *fg; 03117 struct feature_group_exten *fge; 03118 03119 AST_RWLIST_WRLOCK(&feature_groups); 03120 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 03121 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 03122 ast_string_field_free_memory(fge); 03123 ast_free(fge); 03124 } 03125 03126 ast_string_field_free_memory(fg); 03127 ast_free(fg); 03128 } 03129 AST_RWLIST_UNLOCK(&feature_groups); 03130 }
static void atxfer_fail_cleanup | ( | struct ast_channel * | transferee, | |
struct ast_channel * | transferer, | |||
struct ast_party_connected_line * | connected_line | |||
) | [static] |
Definition at line 2490 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().
02491 { 02492 finishup(transferee); 02493 02494 /* 02495 * Restore party B connected line info about party A. 02496 * 02497 * Party B was the caller to party C and is the last known mode 02498 * for party B. 02499 */ 02500 if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) { 02501 ast_channel_update_connected_line(transferer, connected_line, NULL); 02502 } 02503 ast_party_connected_line_free(connected_line); 02504 }
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 987 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().
00988 { 00989 struct ast_bridge_thread_obj *tobj = data; 00990 00991 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00992 if (set_chan_app_data(tobj->chan, tobj->peer->name)) { 00993 tobj->chan->data = "(Empty)"; 00994 } 00995 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00996 if (set_chan_app_data(tobj->peer, tobj->chan->name)) { 00997 tobj->peer->data = "(Empty)"; 00998 } 00999 01000 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 01001 01002 if (tobj->return_to_pbx) { 01003 if (!ast_check_hangup(tobj->peer)) { 01004 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 01005 if (ast_pbx_start(tobj->peer)) { 01006 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 01007 ast_hangup(tobj->peer); 01008 } 01009 } else { 01010 ast_hangup(tobj->peer); 01011 } 01012 if (!ast_check_hangup(tobj->chan)) { 01013 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 01014 if (ast_pbx_start(tobj->chan)) { 01015 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 01016 ast_hangup(tobj->chan); 01017 } 01018 } else { 01019 ast_hangup(tobj->chan); 01020 } 01021 } else { 01022 ast_hangup(tobj->chan); 01023 ast_hangup(tobj->peer); 01024 } 01025 01026 ast_free(tobj); 01027 01028 return NULL; 01029 }
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 1037 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().
01038 { 01039 pthread_t thread; 01040 pthread_attr_t attr; 01041 struct sched_param sched; 01042 01043 pthread_attr_init(&attr); 01044 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 01045 if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) { 01046 ast_hangup(data->chan); 01047 ast_hangup(data->peer); 01048 ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n"); 01049 } 01050 pthread_attr_destroy(&attr); 01051 memset(&sched, 0, sizeof(sched)); 01052 pthread_setschedparam(thread, SCHED_RR, &sched); 01053 }
static int bridge_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Bridge channels.
chan | ||
data | channel to bridge with. |
Split data, check we aren't bridging with ourself, check valid channel, answer call if not already, check compatible channels, setup bridge config now bridge call, if transferred party hangs up return to PBX extension.
Definition at line 7650 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().
07651 { 07652 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2]; 07653 char *tmp_data = NULL; 07654 struct ast_flags opts = { 0, }; 07655 struct ast_bridge_config bconfig = { { 0, }, }; 07656 char *opt_args[OPT_ARG_ARRAY_SIZE]; 07657 struct timeval calldurationlimit = { 0, }; 07658 07659 AST_DECLARE_APP_ARGS(args, 07660 AST_APP_ARG(dest_chan); 07661 AST_APP_ARG(options); 07662 ); 07663 07664 if (ast_strlen_zero(data)) { 07665 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 07666 return -1; 07667 } 07668 07669 tmp_data = ast_strdupa(data); 07670 AST_STANDARD_APP_ARGS(args, tmp_data); 07671 if (!ast_strlen_zero(args.options)) 07672 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options); 07673 07674 /* avoid bridge with ourselves */ 07675 if (!strcmp(chan->name, args.dest_chan)) { 07676 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 07677 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07678 "Response: Failed\r\n" 07679 "Reason: Unable to bridge channel to itself\r\n" 07680 "Channel1: %s\r\n" 07681 "Channel2: %s\r\n", 07682 chan->name, args.dest_chan); 07683 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 07684 return 0; 07685 } 07686 07687 /* make sure we have a valid end point */ 07688 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan, 07689 strlen(args.dest_chan)))) { 07690 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n", 07691 args.dest_chan); 07692 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07693 "Response: Failed\r\n" 07694 "Reason: Channel2 does not exist\r\n" 07695 "Channel1: %s\r\n" 07696 "Channel2: %s\r\n", chan->name, args.dest_chan); 07697 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 07698 return 0; 07699 } 07700 07701 /* try to allocate a place holder where current_dest_chan will be placed */ 07702 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 07703 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) { 07704 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 07705 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07706 "Response: Failed\r\n" 07707 "Reason: Cannot create placeholder channel\r\n" 07708 "Channel1: %s\r\n" 07709 "Channel2: %s\r\n", chan->name, args.dest_chan); 07710 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 07711 ast_channel_unref(current_dest_chan); 07712 return 0; 07713 } 07714 07715 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) 07716 && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT]) 07717 && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) { 07718 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07719 "Response: Failed\r\n" 07720 "Reason: Cannot setup bridge time limit\r\n" 07721 "Channel1: %s\r\n" 07722 "Channel2: %s\r\n", chan->name, args.dest_chan); 07723 ast_hangup(final_dest_chan); 07724 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 07725 current_dest_chan = ast_channel_unref(current_dest_chan); 07726 goto done; 07727 } 07728 07729 if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) { 07730 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07731 "Response: Failed\r\n" 07732 "Reason: Cannot masquerade channels\r\n" 07733 "Channel1: %s\r\n" 07734 "Channel2: %s\r\n", chan->name, args.dest_chan); 07735 ast_hangup(final_dest_chan); 07736 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE"); 07737 current_dest_chan = ast_channel_unref(current_dest_chan); 07738 goto done; 07739 } 07740 07741 /* answer the channel if needed */ 07742 if (final_dest_chan->_state != AST_STATE_UP) { 07743 ast_answer(final_dest_chan); 07744 } 07745 07746 chans[0] = current_dest_chan; 07747 chans[1] = final_dest_chan; 07748 07749 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 07750 /* try to make compatible, send error if we fail */ 07751 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 07752 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 07753 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07754 "Response: Failed\r\n" 07755 "Reason: Could not make channels compatible for bridge\r\n" 07756 "Channel1: %s\r\n" 07757 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 07758 07759 /* Maybe we should return this channel to the PBX? */ 07760 ast_hangup(final_dest_chan); 07761 07762 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 07763 current_dest_chan = ast_channel_unref(current_dest_chan); 07764 goto done; 07765 } 07766 07767 /* Report that the bridge will be successfull */ 07768 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07769 "Response: Success\r\n" 07770 "Channel1: %s\r\n" 07771 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 07772 07773 current_dest_chan = ast_channel_unref(current_dest_chan); 07774 07775 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 07776 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 07777 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 07778 if (ast_waitstream(final_dest_chan, "") < 0) 07779 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 07780 } 07781 } 07782 07783 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) 07784 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT); 07785 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) 07786 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT); 07787 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) 07788 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 07789 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) 07790 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 07791 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR)) 07792 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON); 07793 if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 07794 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON); 07795 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) 07796 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL); 07797 if (ast_test_flag(&opts, OPT_CALLER_PARK)) 07798 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL); 07799 07800 /* 07801 * Don't let the after-bridge code run the h-exten. We want to 07802 * continue in the dialplan. 07803 */ 07804 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 07805 ast_bridge_call(chan, final_dest_chan, &bconfig); 07806 07807 /* The bridge has ended, set BRIDGERESULT to SUCCESS. */ 07808 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 07809 07810 /* If the other channel has not been hung up, return it to the PBX */ 07811 if (!ast_check_hangup(final_dest_chan)) { 07812 if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) { 07813 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 07814 final_dest_chan->context, final_dest_chan->exten, 07815 final_dest_chan->priority, final_dest_chan->name); 07816 07817 if (ast_pbx_start(final_dest_chan)) { 07818 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 07819 ast_hangup(final_dest_chan); 07820 } else { 07821 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 07822 } 07823 } else { 07824 ast_hangup(final_dest_chan); 07825 } 07826 } else { 07827 ast_debug(1, "chan %s was hungup\n", final_dest_chan->name); 07828 ast_hangup(final_dest_chan); 07829 } 07830 done: 07831 ast_free((char *) bconfig.warning_sound); 07832 ast_free((char *) bconfig.end_sound); 07833 ast_free((char *) bconfig.start_sound); 07834 07835 return 0; 07836 }
static struct parking_dp_context* build_dialplan_useage_context | ( | struct ast_parkinglot * | lot | ) | [static, read] |
Definition at line 6324 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().
06325 { 06326 struct parking_dp_context *ctx_node; 06327 06328 ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con)); 06329 if (!ctx_node) { 06330 return NULL; 06331 } 06332 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) { 06333 destroy_dialplan_usage_context(ctx_node); 06334 return NULL; 06335 } 06336 strcpy(ctx_node->context, lot->cfg.parking_con); 06337 return ctx_node; 06338 }
static int build_dialplan_useage_map | ( | struct parking_dp_map * | usage_map, | |
int | complain | |||
) | [static] |
Definition at line 6396 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().
06397 { 06398 int status = 0; 06399 struct ao2_iterator iter; 06400 struct ast_parkinglot *curlot; 06401 06402 /* For all parking lots */ 06403 iter = ao2_iterator_init(parkinglots, 0); 06404 for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) { 06405 /* Add the parking lot to the map. */ 06406 if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) { 06407 ao2_ref(curlot, -1); 06408 status = -1; 06409 break; 06410 } 06411 } 06412 ao2_iterator_destroy(&iter); 06413 06414 return status; 06415 }
static struct parking_dp_ramp* build_dialplan_useage_ramp | ( | const char * | exten, | |
int | exclusive | |||
) | [static, read] |
Definition at line 6087 of file features.c.
References ast_calloc, parking_dp_ramp::exclusive, and parking_dp_ramp::exten.
Referenced by usage_context_add_ramp().
06088 { 06089 struct parking_dp_ramp *ramp_node; 06090 06091 ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten)); 06092 if (!ramp_node) { 06093 return NULL; 06094 } 06095 ramp_node->exclusive = exclusive; 06096 strcpy(ramp_node->exten, exten); 06097 return ramp_node; 06098 }
static struct parking_dp_spaces* build_dialplan_useage_spaces | ( | int | start, | |
int | stop | |||
) | [static, read] |
Definition at line 6168 of file features.c.
References ast_calloc, parking_dp_spaces::start, and parking_dp_spaces::stop.
Referenced by usage_context_add_spaces().
06169 { 06170 struct parking_dp_spaces *spaces_node; 06171 06172 spaces_node = ast_calloc(1, sizeof(*spaces_node)); 06173 if (!spaces_node) { 06174 return NULL; 06175 } 06176 spaces_node->start = start; 06177 spaces_node->stop = stop; 06178 return spaces_node; 06179 }
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 5689 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().
05690 { 05691 struct ast_parkinglot *parkinglot; 05692 const struct parkinglot_cfg *cfg_defaults; 05693 struct parkinglot_cfg new_cfg; 05694 int cfg_error; 05695 int oldparkinglot = 0; 05696 05697 parkinglot = find_parkinglot(pl_name); 05698 if (parkinglot) { 05699 oldparkinglot = 1; 05700 } else { 05701 parkinglot = create_parkinglot(pl_name); 05702 if (!parkinglot) { 05703 return NULL; 05704 } 05705 } 05706 if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) { 05707 cfg_defaults = &parkinglot_cfg_default_default; 05708 } else { 05709 cfg_defaults = &parkinglot_cfg_default; 05710 } 05711 new_cfg = *cfg_defaults; 05712 05713 ast_debug(1, "Building parking lot %s\n", parkinglot->name); 05714 05715 ao2_lock(parkinglot); 05716 05717 /* Do some config stuff */ 05718 cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var); 05719 if (oldparkinglot) { 05720 if (cfg_error) { 05721 /* Bad configuration read. Keep using the original config. */ 05722 ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n", 05723 parkinglot->name); 05724 cfg_error = 0; 05725 } else if (!AST_LIST_EMPTY(&parkinglot->parkings) 05726 && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) { 05727 /* Try reloading later when parking lot is empty. */ 05728 ast_log(LOG_WARNING, 05729 "Parking lot %s has parked calls. Parking lot changes discarded.\n", 05730 parkinglot->name); 05731 force_reload_load = 1; 05732 } else { 05733 /* Accept the new config */ 05734 parkinglot->cfg = new_cfg; 05735 } 05736 } else { 05737 /* Load the initial parking lot config. */ 05738 parkinglot->cfg = new_cfg; 05739 } 05740 parkinglot->the_mark = 0; 05741 05742 ao2_unlock(parkinglot); 05743 05744 if (cfg_error) { 05745 /* Only new parking lots could have config errors here. */ 05746 ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name); 05747 parkinglot_unref(parkinglot); 05748 return NULL; 05749 } 05750 05751 /* Move it into the list, if it wasn't already there */ 05752 if (!oldparkinglot) { 05753 ao2_link(parkinglots, parkinglot); 05754 } 05755 parkinglot_unref(parkinglot); 05756 05757 return parkinglot; 05758 }
static int builtin_atxfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Attended transfer.
chan | transferred user | |
peer | person transfering call | |
config | ||
code | ||
sense | feature options | |
data | Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel. |
Definition at line 2521 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.
02522 { 02523 struct ast_channel *transferer;/* Party B */ 02524 struct ast_channel *transferee;/* Party A */ 02525 struct ast_exten *park_exten; 02526 const char *chan1_attended_sound; 02527 const char *chan2_attended_sound; 02528 const char *transferer_real_context; 02529 char xferto[256] = ""; 02530 int res; 02531 int outstate=0; 02532 struct ast_channel *newchan; 02533 struct ast_channel *xferchan; 02534 struct ast_bridge_thread_obj *tobj; 02535 struct ast_bridge_config bconfig; 02536 int l; 02537 struct ast_party_connected_line connected_line; 02538 struct ast_datastore *features_datastore; 02539 struct ast_dial_features *dialfeatures; 02540 char *transferer_tech; 02541 char *transferer_name; 02542 char *transferer_name_orig; 02543 char *dash; 02544 02545 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 02546 set_peers(&transferer, &transferee, peer, chan, sense); 02547 transferer_real_context = real_ctx(transferer, transferee); 02548 02549 /* Start autoservice on transferee while we talk to the transferer */ 02550 ast_autoservice_start(transferee); 02551 ast_indicate(transferee, AST_CONTROL_HOLD); 02552 02553 /* Transfer */ 02554 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02555 if (res < 0) { 02556 finishup(transferee); 02557 return -1; 02558 } 02559 if (res > 0) { /* If they've typed a digit already, handle it */ 02560 xferto[0] = (char) res; 02561 } 02562 02563 /* this is specific of atxfer */ 02564 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02565 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02566 finishup(transferee); 02567 return -1; 02568 } 02569 l = strlen(xferto); 02570 if (res == 0) { 02571 if (l) { 02572 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02573 xferto, transferer_real_context); 02574 } else { 02575 /* Does anyone care about this case? */ 02576 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n"); 02577 } 02578 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02579 finishup(transferee); 02580 return AST_FEATURE_RETURN_SUCCESS; 02581 } 02582 02583 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02584 if (park_exten) { 02585 /* We are transfering the transferee to a parking lot. */ 02586 return xfer_park_call_helper(transferee, transferer, park_exten); 02587 } 02588 02589 /* 02590 * Append context to dialed transfer number. 02591 * 02592 * NOTE: The local channel needs the /n flag so party C will use 02593 * the feature flags set by the dialplan when calling that 02594 * party. 02595 */ 02596 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); 02597 02598 /* If we are performing an attended transfer and we have two channels involved then 02599 copy sound file information to play upon attended transfer completion */ 02600 chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02601 chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02602 if (!ast_strlen_zero(chan1_attended_sound)) { 02603 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 02604 } 02605 if (!ast_strlen_zero(chan2_attended_sound)) { 02606 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 02607 } 02608 02609 /* Extract redial transferer information from the channel name. */ 02610 transferer_name_orig = ast_strdupa(transferer->name); 02611 transferer_name = ast_strdupa(transferer_name_orig); 02612 transferer_tech = strsep(&transferer_name, "/"); 02613 dash = strrchr(transferer_name, '-'); 02614 if (dash) { 02615 /* Trim off channel name sequence/serial number. */ 02616 *dash = '\0'; 02617 } 02618 02619 /* Stop autoservice so we can monitor all parties involved in the transfer. */ 02620 if (ast_autoservice_stop(transferee) < 0) { 02621 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02622 return -1; 02623 } 02624 02625 /* Save connected line info for party B about party A in case transfer fails. */ 02626 ast_party_connected_line_init(&connected_line); 02627 ast_channel_lock(transferer); 02628 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02629 ast_channel_unlock(transferer); 02630 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02631 02632 /* Dial party C */ 02633 newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer, 02634 transferee, "Local", ast_best_codec(transferer->nativeformats), xferto, 02635 atxfernoanswertimeout, &outstate, transferer->language); 02636 ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate); 02637 02638 if (!ast_check_hangup(transferer)) { 02639 int hangup_dont = 0; 02640 02641 /* Transferer (party B) is up */ 02642 ast_debug(1, "Actually doing an attended transfer.\n"); 02643 02644 /* Start autoservice on transferee while the transferer deals with party C. */ 02645 ast_autoservice_start(transferee); 02646 02647 ast_indicate(transferer, -1); 02648 if (!newchan) { 02649 /* any reason besides user requested cancel and busy triggers the failed sound */ 02650 switch (outstate) { 02651 case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */ 02652 case AST_CONTROL_BUSY: 02653 case AST_CONTROL_CONGESTION: 02654 if (ast_stream_and_wait(transferer, xfersound, "")) { 02655 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02656 } 02657 break; 02658 default: 02659 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02660 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02661 } 02662 break; 02663 } 02664 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02665 return AST_FEATURE_RETURN_SUCCESS; 02666 } 02667 02668 if (check_compat(transferer, newchan)) { 02669 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02670 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02671 } 02672 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02673 return AST_FEATURE_RETURN_SUCCESS; 02674 } 02675 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 02676 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 02677 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 02678 02679 /* 02680 * ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we 02681 * don't want that to happen here because the transferer is in 02682 * another bridge already. 02683 */ 02684 if (ast_test_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT)) { 02685 hangup_dont = 1; 02686 } 02687 02688 /* 02689 * Don't let the after-bridge code run the h-exten. It is the 02690 * wrong bridge to run the h-exten after. 02691 */ 02692 ast_set_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT); 02693 02694 /* 02695 * Let party B and C talk as long as they want while party A 02696 * languishes in autoservice listening to MOH. 02697 */ 02698 ast_bridge_call(transferer, newchan, &bconfig); 02699 02700 if (hangup_dont) { 02701 /* Restore the AST_FLAG_BRIDGE_HANGUP_DONT flag */ 02702 ast_set_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT); 02703 } 02704 02705 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 02706 ast_hangup(newchan); 02707 if (ast_stream_and_wait(transferer, xfersound, "")) { 02708 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02709 } 02710 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02711 return AST_FEATURE_RETURN_SUCCESS; 02712 } 02713 02714 /* Transferer (party B) is confirmed hung up at this point. */ 02715 if (check_compat(transferee, newchan)) { 02716 finishup(transferee); 02717 ast_party_connected_line_free(&connected_line); 02718 return -1; 02719 } 02720 02721 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02722 if ((ast_autoservice_stop(transferee) < 0) 02723 || (ast_waitfordigit(transferee, 100) < 0) 02724 || (ast_waitfordigit(newchan, 100) < 0) 02725 || ast_check_hangup(transferee) 02726 || ast_check_hangup(newchan)) { 02727 ast_hangup(newchan); 02728 ast_party_connected_line_free(&connected_line); 02729 return -1; 02730 } 02731 } else if (!ast_check_hangup(transferee)) { 02732 /* Transferer (party B) has hung up at this point. Doing blonde transfer. */ 02733 ast_debug(1, "Actually doing a blonde transfer.\n"); 02734 02735 if (!newchan && !atxferdropcall) { 02736 /* Party C is not available, try to call party B back. */ 02737 unsigned int tries = 0; 02738 02739 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 02740 ast_log(LOG_WARNING, 02741 "Transferer channel name: '%s' cannot be used for callback.\n", 02742 transferer_name_orig); 02743 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02744 ast_party_connected_line_free(&connected_line); 02745 return -1; 02746 } 02747 02748 tries = 0; 02749 for (;;) { 02750 /* Try to get party B back. */ 02751 ast_debug(1, "We're trying to callback %s/%s\n", 02752 transferer_tech, transferer_name); 02753 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02754 transferee, transferee, transferer_tech, 02755 ast_best_codec(transferee->nativeformats), transferer_name, 02756 atxfernoanswertimeout, &outstate, transferer->language); 02757 ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n", 02758 !!newchan, outstate); 02759 if (newchan) { 02760 /* 02761 * We have recalled party B (newchan). We need to give this 02762 * call leg the same feature flags as the original party B call 02763 * leg. 02764 */ 02765 ast_channel_lock(transferer); 02766 features_datastore = ast_channel_datastore_find(transferer, 02767 &dial_features_info, NULL); 02768 if (features_datastore && (dialfeatures = features_datastore->data)) { 02769 struct ast_flags my_features = { 0 }; 02770 struct ast_flags peer_features = { 0 }; 02771 02772 ast_copy_flags(&my_features, &dialfeatures->my_features, 02773 AST_FLAGS_ALL); 02774 ast_copy_flags(&peer_features, &dialfeatures->peer_features, 02775 AST_FLAGS_ALL); 02776 ast_channel_unlock(transferer); 02777 add_features_datastore(newchan, &my_features, &peer_features); 02778 } else { 02779 ast_channel_unlock(transferer); 02780 } 02781 break; 02782 } 02783 if (ast_check_hangup(transferee)) { 02784 break; 02785 } 02786 02787 ++tries; 02788 if (atxfercallbackretries <= tries) { 02789 /* No more callback tries remaining. */ 02790 break; 02791 } 02792 02793 if (atxferloopdelay) { 02794 /* Transfer failed, sleeping */ 02795 ast_debug(1, "Sleeping for %u ms before retrying atxfer.\n", 02796 atxferloopdelay); 02797 ast_safe_sleep(transferee, atxferloopdelay); 02798 if (ast_check_hangup(transferee)) { 02799 ast_party_connected_line_free(&connected_line); 02800 return -1; 02801 } 02802 } 02803 02804 /* Retry dialing party C. */ 02805 ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto); 02806 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02807 transferer, transferee, "Local", 02808 ast_best_codec(transferee->nativeformats), xferto, 02809 atxfernoanswertimeout, &outstate, transferer->language); 02810 ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n", 02811 !!newchan, outstate); 02812 if (newchan || ast_check_hangup(transferee)) { 02813 break; 02814 } 02815 } 02816 } 02817 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02818 if (!newchan) { 02819 /* No party C or could not callback party B. */ 02820 ast_party_connected_line_free(&connected_line); 02821 return -1; 02822 } 02823 02824 /* newchan is up, we should prepare transferee and bridge them */ 02825 if (ast_check_hangup(newchan)) { 02826 ast_hangup(newchan); 02827 ast_party_connected_line_free(&connected_line); 02828 return -1; 02829 } 02830 if (check_compat(transferee, newchan)) { 02831 ast_party_connected_line_free(&connected_line); 02832 return -1; 02833 } 02834 } else { 02835 /* 02836 * Both the transferer and transferee have hungup. If newchan 02837 * is up, hang it up as it has no one to talk to. 02838 */ 02839 ast_debug(1, "Everyone is hungup.\n"); 02840 if (newchan) { 02841 ast_hangup(newchan); 02842 } 02843 ast_party_connected_line_free(&connected_line); 02844 return -1; 02845 } 02846 02847 /* Initiate the channel transfer of party A to party C (or recalled party B). */ 02848 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan); 02849 02850 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name); 02851 if (!xferchan) { 02852 ast_hangup(newchan); 02853 ast_party_connected_line_free(&connected_line); 02854 return -1; 02855 } 02856 02857 /* Give party A a momentary ringback tone during transfer. */ 02858 xferchan->visible_indication = AST_CONTROL_RINGING; 02859 02860 /* Make formats okay */ 02861 xferchan->readformat = transferee->readformat; 02862 xferchan->writeformat = transferee->writeformat; 02863 02864 if (ast_channel_masquerade(xferchan, transferee)) { 02865 ast_hangup(xferchan); 02866 ast_hangup(newchan); 02867 ast_party_connected_line_free(&connected_line); 02868 return -1; 02869 } 02870 02871 dash = strrchr(xferto, '@'); 02872 if (dash) { 02873 /* Trim off the context. */ 02874 *dash = '\0'; 02875 } 02876 ast_explicit_goto(xferchan, transferer_real_context, xferto, 1); 02877 xferchan->_state = AST_STATE_UP; 02878 ast_clear_flag(xferchan, AST_FLAGS_ALL); 02879 02880 /* Do the masquerade manually to make sure that is is completed. */ 02881 ast_do_masquerade(xferchan); 02882 02883 newchan->_state = AST_STATE_UP; 02884 ast_clear_flag(newchan, AST_FLAGS_ALL); 02885 tobj = ast_calloc(1, sizeof(*tobj)); 02886 if (!tobj) { 02887 ast_hangup(xferchan); 02888 ast_hangup(newchan); 02889 ast_party_connected_line_free(&connected_line); 02890 return -1; 02891 } 02892 02893 tobj->chan = newchan; 02894 tobj->peer = xferchan; 02895 tobj->bconfig = *config; 02896 02897 ast_channel_lock(newchan); 02898 features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL); 02899 if (features_datastore && (dialfeatures = features_datastore->data)) { 02900 ast_copy_flags(&tobj->bconfig.features_callee, &dialfeatures->my_features, 02901 AST_FLAGS_ALL); 02902 } 02903 ast_channel_unlock(newchan); 02904 02905 ast_channel_lock(xferchan); 02906 features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL); 02907 if (features_datastore && (dialfeatures = features_datastore->data)) { 02908 ast_copy_flags(&tobj->bconfig.features_caller, &dialfeatures->my_features, 02909 AST_FLAGS_ALL); 02910 } 02911 ast_channel_unlock(xferchan); 02912 02913 if (tobj->bconfig.end_bridge_callback_data_fixup) { 02914 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 02915 } 02916 02917 /* 02918 * xferchan is transferee, and newchan is the transfer target 02919 * So...in a transfer, who is the caller and who is the callee? 02920 * 02921 * When the call is originally made, it is clear who is caller and callee. 02922 * When a transfer occurs, it is my humble opinion that the transferee becomes 02923 * the caller, and the transfer target is the callee. 02924 * 02925 * The problem is that these macros were set with the intention of the original 02926 * caller and callee taking those roles. A transfer can totally mess things up, 02927 * to be technical. What sucks even more is that you can't effectively change 02928 * the macros in the dialplan during the call from the transferer to the transfer 02929 * target because the transferee is stuck with whatever role he originally had. 02930 * 02931 * I think the answer here is just to make sure that it is well documented that 02932 * during a transfer, the transferee is the "caller" and the transfer target 02933 * is the "callee." 02934 * 02935 * This means that if party B calls party A, and party B transfers party A to 02936 * party C, then A has switched roles for the call. Now party A will have the 02937 * caller macro called on his channel instead of the callee macro. 02938 * 02939 * Luckily, the method by which the party B to party C bridge is 02940 * launched above ensures that the transferee is the "chan" on 02941 * the bridge and the transfer target is the "peer," so my idea 02942 * for the roles post-transfer does not require extensive code 02943 * changes. 02944 */ 02945 02946 /* Transfer party C connected line to party A */ 02947 ast_channel_lock(transferer); 02948 /* 02949 * Due to a limitation regarding when callerID is set on a Local channel, 02950 * we use the transferer's connected line information here. 02951 */ 02952 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02953 ast_channel_unlock(transferer); 02954 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02955 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { 02956 ast_channel_update_connected_line(xferchan, &connected_line, NULL); 02957 } 02958 02959 /* Transfer party A connected line to party C */ 02960 ast_channel_lock(xferchan); 02961 ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller); 02962 ast_channel_unlock(xferchan); 02963 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02964 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { 02965 ast_channel_update_connected_line(newchan, &connected_line, NULL); 02966 } 02967 02968 if (ast_stream_and_wait(newchan, xfersound, "")) 02969 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02970 bridge_call_thread_launch(tobj); 02971 02972 ast_party_connected_line_free(&connected_line); 02973 return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */ 02974 }
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 2200 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.
02201 { 02202 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02203 int x = 0; 02204 size_t len; 02205 struct ast_channel *caller_chan, *callee_chan; 02206 const char *mixmonitor_spy_type = "MixMonitor"; 02207 const char *touch_format; 02208 const char *touch_monitor; 02209 int count = 0; 02210 02211 if (!mixmonitor_ok) { 02212 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02213 return -1; 02214 } 02215 02216 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 02217 mixmonitor_ok = 0; 02218 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02219 return -1; 02220 } 02221 02222 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02223 02224 if (!ast_strlen_zero(courtesytone)) { 02225 if (ast_autoservice_start(callee_chan)) 02226 return -1; 02227 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END); 02228 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 02229 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02230 ast_autoservice_stop(callee_chan); 02231 return -1; 02232 } 02233 if (ast_autoservice_stop(callee_chan)) 02234 return -1; 02235 } 02236 02237 ast_channel_lock(callee_chan); 02238 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02239 ast_channel_unlock(callee_chan); 02240 02241 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 02242 if (count > 0) { 02243 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 02244 02245 /* Make sure they are running */ 02246 ast_channel_lock(callee_chan); 02247 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02248 ast_channel_unlock(callee_chan); 02249 if (count > 0) { 02250 if (!stopmixmonitor_ok) { 02251 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02252 return -1; 02253 } 02254 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 02255 stopmixmonitor_ok = 0; 02256 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02257 return -1; 02258 } else { 02259 pbx_exec(callee_chan, stopmixmonitor_app, ""); 02260 return AST_FEATURE_RETURN_SUCCESS; 02261 } 02262 } 02263 02264 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 02265 } 02266 02267 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 02268 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 02269 02270 if (!touch_format) 02271 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 02272 02273 if (!touch_monitor) 02274 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 02275 02276 if (touch_monitor) { 02277 len = strlen(touch_monitor) + 50; 02278 args = ast_alloca(len); 02279 touch_filename = ast_alloca(len); 02280 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 02281 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 02282 } else { 02283 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 02284 caller_chan->caller.id.number.str, caller_chan->name)); 02285 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 02286 callee_chan->caller.id.number.str, callee_chan->name)); 02287 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02288 args = ast_alloca(len); 02289 touch_filename = ast_alloca(len); 02290 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 02291 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 02292 } 02293 02294 for( x = 0; x < strlen(args); x++) { 02295 if (args[x] == '/') 02296 args[x] = '-'; 02297 } 02298 02299 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 02300 02301 pbx_exec(callee_chan, mixmonitor_app, args); 02302 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02303 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02304 return AST_FEATURE_RETURN_SUCCESS; 02305 }
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 2098 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, EVENT_FLAG_USER, ast_party_caller::id, LOG_ERROR, manager_event, 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.
02099 { 02100 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02101 int x = 0; 02102 size_t len; 02103 struct ast_channel *caller_chan, *callee_chan; 02104 const char *automon_message_start = NULL; 02105 const char *automon_message_stop = NULL; 02106 const char *touch_format = NULL; 02107 const char *touch_monitor = NULL; 02108 const char *touch_monitor_prefix = NULL; 02109 02110 if (!monitor_ok) { 02111 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02112 return -1; 02113 } 02114 02115 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 02116 monitor_ok = 0; 02117 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02118 return -1; 02119 } 02120 02121 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02122 02123 /* Find extra messages */ 02124 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 02125 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 02126 02127 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 02128 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 02129 return -1; 02130 } 02131 } 02132 02133 if (callee_chan->monitor) { 02134 manager_event(EVENT_FLAG_USER, "UserEvent", 02135 "UserEvent: StopRec\r\n" 02136 "Uniqueid: %s\r\n", 02137 caller_chan->uniqueid); 02138 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 02139 if (!ast_strlen_zero(automon_message_stop)) { 02140 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 02141 } 02142 callee_chan->monitor->stop(callee_chan, 1); 02143 return AST_FEATURE_RETURN_SUCCESS; 02144 } 02145 02146 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 02147 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 02148 touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 02149 02150 if (!touch_format) 02151 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 02152 02153 if (!touch_monitor) 02154 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 02155 02156 if (!touch_monitor_prefix) 02157 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 02158 02159 if (touch_monitor) { 02160 len = strlen(touch_monitor) + 50; 02161 args = ast_alloca(len); 02162 touch_filename = ast_alloca(len); 02163 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 02164 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02165 } else { 02166 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 02167 caller_chan->caller.id.number.str, caller_chan->name)); 02168 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 02169 callee_chan->caller.id.number.str, callee_chan->name)); 02170 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02171 args = ast_alloca(len); 02172 touch_filename = ast_alloca(len); 02173 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 02174 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02175 } 02176 02177 for(x = 0; x < strlen(args); x++) { 02178 if (args[x] == '/') 02179 args[x] = '-'; 02180 } 02181 02182 manager_event(EVENT_FLAG_USER, "UserEvent", 02183 "UserEvent: Rec\r\n" 02184 "Uniqueid: %s\r\n" 02185 "FileName: %s\r\n", 02186 caller_chan->uniqueid, touch_filename); 02187 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 02188 02189 pbx_exec(callee_chan, monitor_app, args); 02190 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02191 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02192 02193 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 02194 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 02195 } 02196 02197 return AST_FEATURE_RETURN_SUCCESS; 02198 }
static int builtin_blindtransfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Blind transfer user to another extension.
chan | channel to be transferred | |
peer | channel initiated blind transfer | |
config | ||
code | ||
data | ||
sense | feature options |
Place chan on hold, check if transferred to parkinglot extension, otherwise check extension exists and transfer caller.
AST_FEATURE_RETURN_SUCCESS. | ||
-1 | on failure. |
Definition at line 2350 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().
02351 { 02352 struct ast_channel *transferer; 02353 struct ast_channel *transferee; 02354 struct ast_exten *park_exten; 02355 const char *transferer_real_context; 02356 char xferto[256] = ""; 02357 int res; 02358 02359 ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 02360 set_peers(&transferer, &transferee, peer, chan, sense); 02361 transferer_real_context = real_ctx(transferer, transferee); 02362 02363 /* Start autoservice on transferee while we talk to the transferer */ 02364 ast_autoservice_start(transferee); 02365 ast_indicate(transferee, AST_CONTROL_HOLD); 02366 02367 /* Transfer */ 02368 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02369 if (res < 0) { 02370 finishup(transferee); 02371 return -1; /* error ? */ 02372 } 02373 if (res > 0) { /* If they've typed a digit already, handle it */ 02374 xferto[0] = (char) res; 02375 } 02376 02377 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02378 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02379 finishup(transferee); 02380 return -1; 02381 } 02382 if (res == 0) { 02383 if (xferto[0]) { 02384 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02385 xferto, transferer_real_context); 02386 } else { 02387 /* Does anyone care about this case? */ 02388 ast_log(LOG_WARNING, "No digits dialed.\n"); 02389 } 02390 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02391 finishup(transferee); 02392 return AST_FEATURE_RETURN_SUCCESS; 02393 } 02394 02395 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02396 if (park_exten) { 02397 /* We are transfering the transferee to a parking lot. */ 02398 return xfer_park_call_helper(transferee, transferer, park_exten); 02399 } 02400 02401 /* Do blind transfer. */ 02402 ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n", 02403 transferee->name, xferto, transferer_real_context); 02404 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee); 02405 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 02406 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 02407 finishup(transferee); 02408 ast_channel_lock(transferer); 02409 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 02410 transferer->cdr = ast_cdr_alloc(); 02411 if (transferer->cdr) { 02412 ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */ 02413 ast_cdr_start(transferer->cdr); 02414 } 02415 } 02416 ast_channel_unlock(transferer); 02417 if (transferer->cdr) { 02418 struct ast_cdr *swap = transferer->cdr; 02419 02420 ast_debug(1, 02421 "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 02422 transferer->name, transferee->name, transferer->cdr->lastapp, 02423 transferer->cdr->lastdata, transferer->cdr->channel, 02424 transferer->cdr->dstchannel); 02425 ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 02426 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, 02427 transferee->cdr->dstchannel); 02428 ast_debug(1, "transferer_real_context=%s; xferto=%s\n", 02429 transferer_real_context, xferto); 02430 /* swap cdrs-- it will save us some time & work */ 02431 transferer->cdr = transferee->cdr; 02432 transferee->cdr = swap; 02433 } 02434 if (!transferee->pbx) { 02435 /* Doh! Use our handy async_goto functions */ 02436 ast_debug(1, "About to ast_async_goto %s.\n", transferee->name); 02437 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) { 02438 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 02439 } 02440 02441 /* The transferee is masqueraded and the original bridged channels can be hungup. */ 02442 res = -1; 02443 } else { 02444 /* Set the transferee's new extension, since it exists, using transferer context */ 02445 ast_debug(1, "About to explicit goto %s, it has a PBX.\n", transferee->name); 02446 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 02447 set_c_e_p(transferee, transferer_real_context, xferto, 0); 02448 02449 /* 02450 * Break the bridge. The transferee needs to resume executing 02451 * dialplan at the xferto location. 02452 */ 02453 res = AST_FEATURE_RETURN_SUCCESSBREAK; 02454 } 02455 check_goto_on_transfer(transferer); 02456 return res; 02457 }
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 2307 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
02308 { 02309 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 02310 return AST_FEATURE_RETURN_HANGUP; 02311 }
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 1976 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().
01977 { 01978 struct ast_channel *parker; 01979 struct ast_channel *parkee; 01980 struct ast_park_call_args args = { 0, }; 01981 01982 /* 01983 * We used to set chan's exten and priority to "s" and 1 here, 01984 * but this generates (in some cases) an invalid extension, and 01985 * if "s" exists, could errantly cause execution of extensions 01986 * you don't expect. It makes more sense to let nature take its 01987 * course when chan finishes, and let the pbx do its thing and 01988 * hang up when the park is over. 01989 */ 01990 01991 /* Answer if call is not up */ 01992 if (chan->_state != AST_STATE_UP) { 01993 /* 01994 * XXX Why are we doing this? Both of the channels should be up 01995 * since you cannot do DTMF features unless you are bridged. 01996 */ 01997 if (ast_answer(chan)) { 01998 return -1; 01999 } 02000 02001 /* Sleep to allow VoIP streams to settle down */ 02002 if (ast_safe_sleep(chan, 1000)) { 02003 return -1; 02004 } 02005 } 02006 02007 /* one direction used to call park_call.... */ 02008 set_peers(&parker, &parkee, peer, chan, sense); 02009 return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1; 02010 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 4651 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().
04652 { 04653 int i = 0; 04654 enum { 04655 OPT_CALLEE_REDIRECT = 't', 04656 OPT_CALLER_REDIRECT = 'T', 04657 OPT_CALLEE_AUTOMON = 'w', 04658 OPT_CALLER_AUTOMON = 'W', 04659 OPT_CALLEE_DISCONNECT = 'h', 04660 OPT_CALLER_DISCONNECT = 'H', 04661 OPT_CALLEE_PARKCALL = 'k', 04662 OPT_CALLER_PARKCALL = 'K', 04663 }; 04664 04665 memset(options, 0, len); 04666 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 04667 options[i++] = OPT_CALLER_REDIRECT; 04668 } 04669 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 04670 options[i++] = OPT_CALLER_AUTOMON; 04671 } 04672 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 04673 options[i++] = OPT_CALLER_DISCONNECT; 04674 } 04675 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 04676 options[i++] = OPT_CALLER_PARKCALL; 04677 } 04678 04679 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 04680 options[i++] = OPT_CALLEE_REDIRECT; 04681 } 04682 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 04683 options[i++] = OPT_CALLEE_AUTOMON; 04684 } 04685 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 04686 options[i++] = OPT_CALLEE_DISCONNECT; 04687 } 04688 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 04689 options[i++] = OPT_CALLEE_PARKCALL; 04690 } 04691 04692 return options; 04693 }
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 2466 of file features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING.
Referenced by builtin_atxfer().
02467 { 02468 if (ast_channel_make_compatible(c, newchan) < 0) { 02469 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 02470 c->name, newchan->name); 02471 ast_hangup(newchan); 02472 return -1; 02473 } 02474 return 0; 02475 }
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 896 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().
00897 { 00898 struct ast_channel *xferchan; 00899 const char *val; 00900 char *goto_on_transfer; 00901 char *x; 00902 00903 ast_channel_lock(chan); 00904 val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00905 if (ast_strlen_zero(val)) { 00906 ast_channel_unlock(chan); 00907 return; 00908 } 00909 goto_on_transfer = ast_strdupa(val); 00910 ast_channel_unlock(chan); 00911 00912 ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, chan->name); 00913 00914 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, 00915 "%s", chan->name); 00916 if (!xferchan) { 00917 return; 00918 } 00919 00920 /* Make formats okay */ 00921 xferchan->readformat = chan->readformat; 00922 xferchan->writeformat = chan->writeformat; 00923 00924 if (ast_channel_masquerade(xferchan, chan)) { 00925 /* Failed to setup masquerade. */ 00926 ast_hangup(xferchan); 00927 return; 00928 } 00929 00930 for (x = goto_on_transfer; *x; ++x) { 00931 if (*x == '^') { 00932 *x = ','; 00933 } 00934 } 00935 ast_parseable_goto(xferchan, goto_on_transfer); 00936 xferchan->_state = AST_STATE_UP; 00937 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00938 ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL); 00939 00940 ast_do_masquerade(xferchan); 00941 if (ast_pbx_start(xferchan)) { 00942 /* Failed to start PBX. */ 00943 ast_hangup(xferchan); 00944 } 00945 }
static void clear_dialed_interfaces | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 3911 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().
03912 { 03913 struct ast_datastore *di_datastore; 03914 03915 ast_channel_lock(chan); 03916 if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) { 03917 if (option_debug) { 03918 ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name); 03919 } 03920 if (!ast_channel_datastore_remove(chan, di_datastore)) { 03921 ast_datastore_free(di_datastore); 03922 } 03923 } 03924 ast_channel_unlock(chan); 03925 }
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 5034 of file features.c.
References ao2_ref, ast_debug, ast_parkinglot::cfg, create_parkinglot(), and find_parkinglot().
Referenced by create_dynamic_parkinglot().
05035 { 05036 struct ast_parkinglot *copylot; 05037 05038 if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */ 05039 ao2_ref(copylot, -1); 05040 return NULL; 05041 } 05042 05043 copylot = create_parkinglot(name); 05044 if (!copylot) { 05045 return NULL; 05046 } 05047 05048 ast_debug(1, "Building parking lot %s\n", name); 05049 05050 /* Copy the source parking lot configuration. */ 05051 copylot->cfg = parkinglot->cfg; 05052 05053 return copylot; 05054 }
static struct ast_parkinglot* create_dynamic_parkinglot | ( | const char * | name, | |
struct ast_channel * | chan | |||
) | [static, read] |
Definition at line 1165 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().
01166 { 01167 const char *dyn_context; 01168 const char *dyn_exten; 01169 const char *dyn_range; 01170 const char *template_name; 01171 struct ast_parkinglot *template_parkinglot = NULL; 01172 struct ast_parkinglot *parkinglot; 01173 int dyn_start; 01174 int dyn_end; 01175 01176 ast_channel_lock(chan); 01177 template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), "")); 01178 dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), "")); 01179 dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), "")); 01180 dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), "")); 01181 ast_channel_unlock(chan); 01182 01183 if (!ast_strlen_zero(template_name)) { 01184 template_parkinglot = find_parkinglot(template_name); 01185 if (!template_parkinglot) { 01186 ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n", 01187 template_name); 01188 } else if (template_parkinglot->cfg.is_invalid) { 01189 ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n", 01190 template_name); 01191 parkinglot_unref(template_parkinglot); 01192 template_parkinglot = NULL; 01193 } 01194 } 01195 if (!template_parkinglot) { 01196 template_parkinglot = parkinglot_addref(default_parkinglot); 01197 ast_debug(1, "Using default parking lot for template\n"); 01198 } 01199 01200 parkinglot = copy_parkinglot(name, template_parkinglot); 01201 if (!parkinglot) { 01202 ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n"); 01203 } else { 01204 /* Configure the dynamic parking lot. */ 01205 if (!ast_strlen_zero(dyn_context)) { 01206 ast_copy_string(parkinglot->cfg.parking_con, dyn_context, 01207 sizeof(parkinglot->cfg.parking_con)); 01208 } 01209 if (!ast_strlen_zero(dyn_exten)) { 01210 ast_copy_string(parkinglot->cfg.parkext, dyn_exten, 01211 sizeof(parkinglot->cfg.parkext)); 01212 } 01213 if (!ast_strlen_zero(dyn_range)) { 01214 if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) { 01215 ast_log(LOG_WARNING, 01216 "Format for parking positions is a-b, where a and b are numbers\n"); 01217 } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) { 01218 ast_log(LOG_WARNING, 01219 "Format for parking positions is a-b, where a <= b\n"); 01220 } else { 01221 parkinglot->cfg.parking_start = dyn_start; 01222 parkinglot->cfg.parking_stop = dyn_end; 01223 } 01224 } 01225 01226 /* 01227 * Sanity check for dynamic parking lot configuration. 01228 * 01229 * XXX It may be desirable to instead check if the dynamic 01230 * parking lot overlaps any existing lots like what is done for 01231 * a reload. 01232 */ 01233 if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) { 01234 if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext) 01235 && parkinglot->cfg.parkext_exclusive) { 01236 ast_log(LOG_WARNING, 01237 "Parking lot '%s' conflicts with template parking lot '%s'!\n" 01238 "Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n", 01239 parkinglot->name, template_parkinglot->name); 01240 } 01241 if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start 01242 && parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop) 01243 || (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop 01244 && parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop) 01245 || (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start 01246 && template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) { 01247 ast_log(LOG_WARNING, 01248 "Parking lot '%s' parking spaces overlap template parking lot '%s'!\n" 01249 "Change PARKINGDYNPOS.\n", 01250 parkinglot->name, template_parkinglot->name); 01251 } 01252 } 01253 01254 parkinglot_activate(parkinglot); 01255 ao2_link(parkinglots, parkinglot); 01256 } 01257 parkinglot_unref(template_parkinglot); 01258 01259 return parkinglot; 01260 }
static struct ast_parkinglot * create_parkinglot | ( | const char * | name | ) | [static, read] |
Allocate parking lot structure.
Definition at line 5459 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().
05460 { 05461 struct ast_parkinglot *newlot; 05462 05463 if (ast_strlen_zero(name)) { /* No name specified */ 05464 return NULL; 05465 } 05466 05467 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 05468 if (!newlot) 05469 return NULL; 05470 05471 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 05472 newlot->cfg.is_invalid = 1;/* No config is set yet. */ 05473 AST_LIST_HEAD_INIT(&newlot->parkings); 05474 05475 return newlot; 05476 }
static void destroy_dialplan_usage_context | ( | struct parking_dp_context * | doomed | ) | [static] |
Definition at line 6043 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().
06044 { 06045 struct parking_dp_ramp *ramp; 06046 struct parking_dp_spaces *spaces; 06047 06048 while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) { 06049 ast_free(ramp); 06050 } 06051 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) { 06052 ast_free(spaces); 06053 } 06054 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) { 06055 ast_free(spaces); 06056 } 06057 ast_free(doomed); 06058 }
static void destroy_dialplan_usage_map | ( | struct parking_dp_map * | doomed | ) | [static] |
Definition at line 6068 of file features.c.
References AST_LIST_REMOVE_HEAD, and destroy_dialplan_usage_context().
Referenced by load_config().
06069 { 06070 struct parking_dp_context *item; 06071 06072 while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) { 06073 destroy_dialplan_usage_context(item); 06074 } 06075 }
static void destroy_space | ( | const char * | context, | |
int | space | |||
) | [static] |
Definition at line 6498 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().
06499 { 06500 char exten[AST_MAX_EXTENSION]; 06501 06502 /* Destroy priorities of the parking space that we registered. */ 06503 snprintf(exten, sizeof(exten), "%d", space); 06504 remove_exten_if_exist(context, exten, PRIORITY_HINT); 06505 remove_exten_if_exist(context, exten, 1); 06506 }
static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 744 of file features.c.
References ast_free.
00745 { 00746 struct ast_dial_features *df = data; 00747 if (df) { 00748 ast_free(df); 00749 } 00750 }
static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 731 of file features.c.
References ast_calloc.
00732 { 00733 struct ast_dial_features *df = data, *df_copy; 00734 00735 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00736 return NULL; 00737 } 00738 00739 memcpy(df_copy, df, sizeof(*df)); 00740 00741 return df_copy; 00742 }
static int dialplan_usage_add_parkinglot | ( | struct parking_dp_map * | usage_map, | |
struct ast_parkinglot * | lot, | |||
int | complain | |||
) | [static] |
Definition at line 6351 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().
06352 { 06353 struct parking_dp_context *cur_ctx; 06354 struct parking_dp_context *new_ctx; 06355 int cmp; 06356 06357 AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) { 06358 cmp = strcmp(lot->cfg.parking_con, cur_ctx->context); 06359 if (cmp > 0) { 06360 /* The parking lot context goes after this node. */ 06361 continue; 06362 } 06363 if (cmp == 0) { 06364 /* This is the node we will add parking lot spaces to the map. */ 06365 return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain); 06366 } 06367 /* The new parking lot context goes before this node. */ 06368 new_ctx = build_dialplan_useage_context(lot); 06369 if (!new_ctx) { 06370 return -1; 06371 } 06372 AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node); 06373 return 0; 06374 } 06375 AST_LIST_TRAVERSE_SAFE_END; 06376 06377 /* New parking lot context goes on the end. */ 06378 new_ctx = build_dialplan_useage_context(lot); 06379 if (!new_ctx) { 06380 return -1; 06381 } 06382 AST_LIST_INSERT_TAIL(usage_map, new_ctx, node); 06383 return 0; 06384 }
static int dialplan_usage_add_parkinglot_data | ( | struct parking_dp_context * | ctx_node, | |
struct ast_parkinglot * | lot, | |||
int | complain | |||
) | [static] |
Definition at line 6297 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().
06298 { 06299 if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext, 06300 lot->cfg.parkext_exclusive, lot, complain)) { 06301 return -1; 06302 } 06303 if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start, 06304 lot->cfg.parking_stop, lot, complain)) { 06305 return -1; 06306 } 06307 if (lot->cfg.parkaddhints 06308 && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start, 06309 lot->cfg.parking_stop, lot, 0)) { 06310 return -1; 06311 } 06312 return 0; 06313 }
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 6933 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().
06934 { 06935 const char *context; 06936 const char *exten; 06937 int priority; 06938 06939 ast_moh_stop(chan); 06940 ast_channel_lock_both(chan, tmpchan); 06941 context = ast_strdupa(chan->context); 06942 exten = ast_strdupa(chan->exten); 06943 priority = chan->priority; 06944 ast_setstate(tmpchan, chan->_state); 06945 tmpchan->readformat = chan->readformat; 06946 tmpchan->writeformat = chan->writeformat; 06947 ast_channel_unlock(chan); 06948 ast_channel_unlock(tmpchan); 06949 06950 /* Masquerade setup and execution must be done without any channel locks held */ 06951 if (ast_channel_masquerade(tmpchan, chan)) { 06952 return -1; 06953 } 06954 ast_do_masquerade(tmpchan); 06955 06956 /* when returning from bridge, the channel will continue at the next priority */ 06957 ast_explicit_goto(tmpchan, context, exten, priority + 1); 06958 06959 return 0; 06960 }
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 4984 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().
04985 { 04986 struct pollfd *pfds = NULL, *new_pfds = NULL; 04987 int nfds = 0, new_nfds = 0; 04988 04989 for (;;) { 04990 struct ao2_iterator iter; 04991 struct ast_parkinglot *curlot; 04992 int ms = -1; /* poll2 timeout, uninitialized */ 04993 04994 iter = ao2_iterator_init(parkinglots, 0); 04995 while ((curlot = ao2_iterator_next(&iter))) { 04996 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms); 04997 ao2_ref(curlot, -1); 04998 } 04999 ao2_iterator_destroy(&iter); 05000 05001 /* Recycle */ 05002 ast_free(pfds); 05003 pfds = new_pfds; 05004 nfds = new_nfds; 05005 new_pfds = NULL; 05006 new_nfds = 0; 05007 05008 /* Wait for something to happen */ 05009 ast_poll(pfds, nfds, ms); 05010 pthread_testcancel(); 05011 } 05012 /* If this WERE reached, we'd need to free(pfds) */ 05013 return NULL; /* Never reached */ 05014 }
static int feature_check | ( | struct ast_channel * | chan, | |
struct ast_flags * | features, | |||
char * | code | |||
) | [static] |
Check if a feature exists.
Definition at line 3440 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().
03440 { 03441 char *chan_dynamic_features; 03442 ast_channel_lock(chan); 03443 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03444 ast_channel_unlock(chan); 03445 03446 return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL); 03447 }
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 3179 of file features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_app_exec_macro(), ast_app_exec_sub(), ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, AST_FRAME_DTMF_END, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), and ast_call_feature::sname.
Referenced by process_applicationmap_line().
03180 { 03181 struct ast_app *app; 03182 struct ast_call_feature *feature = data; 03183 struct ast_channel *work, *idle; 03184 int res; 03185 03186 if (!feature) { /* shouldn't ever happen! */ 03187 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 03188 return -1; 03189 } 03190 03191 if (sense == FEATURE_SENSE_CHAN) { 03192 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 03193 return AST_FEATURE_RETURN_KEEPTRYING; 03194 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03195 work = chan; 03196 idle = peer; 03197 } else { 03198 work = peer; 03199 idle = chan; 03200 } 03201 } else { 03202 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 03203 return AST_FEATURE_RETURN_KEEPTRYING; 03204 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03205 work = peer; 03206 idle = chan; 03207 } else { 03208 work = chan; 03209 idle = peer; 03210 } 03211 } 03212 03213 if (!(app = pbx_findapp(feature->app))) { 03214 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 03215 return -2; 03216 } 03217 03218 ast_autoservice_start(idle); 03219 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END); 03220 03221 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name); 03222 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name); 03223 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname); 03224 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname); 03225 03226 if (!ast_strlen_zero(feature->moh_class)) 03227 ast_moh_start(idle, feature->moh_class, NULL); 03228 03229 if (!strcasecmp("Gosub", feature->app)) { 03230 res = ast_app_exec_sub(NULL, work, feature->app_args, 0); 03231 } else if (!strcasecmp("Macro", feature->app)) { 03232 res = ast_app_exec_macro(NULL, work, feature->app_args); 03233 } else { 03234 res = pbx_exec(work, app, feature->app_args); 03235 } 03236 03237 if (!ast_strlen_zero(feature->moh_class)) 03238 ast_moh_stop(idle); 03239 03240 ast_autoservice_stop(idle); 03241 03242 if (res) { 03243 return AST_FEATURE_RETURN_SUCCESSBREAK; 03244 } 03245 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 03246 }
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 3403 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().
03403 { 03404 03405 char dynamic_features_buf[128]; 03406 const char *peer_dynamic_features, *chan_dynamic_features; 03407 struct ast_flags features; 03408 struct ast_call_feature feature; 03409 if (sense == FEATURE_SENSE_CHAN) { 03410 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 03411 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 03412 } 03413 else { 03414 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 03415 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 03416 } 03417 03418 ast_channel_lock(peer); 03419 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 03420 ast_channel_unlock(peer); 03421 03422 ast_channel_lock(chan); 03423 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03424 ast_channel_unlock(chan); 03425 03426 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,"")); 03427 03428 ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%u, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf); 03429 03430 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature); 03431 }
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 3286 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().
03289 { 03290 int x; 03291 struct feature_group *fg = NULL; 03292 struct feature_group_exten *fge; 03293 struct ast_call_feature *tmpfeature; 03294 char *tmp, *tok; 03295 int res = AST_FEATURE_RETURN_PASSDIGITS; 03296 int feature_detected = 0; 03297 03298 if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) { 03299 return -1; /* can not run feature operation */ 03300 } 03301 03302 ast_rwlock_rdlock(&features_lock); 03303 for (x = 0; x < FEATURES_COUNT; x++) { 03304 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 03305 !ast_strlen_zero(builtin_features[x].exten)) { 03306 /* Feature is up for consideration */ 03307 if (!strcmp(builtin_features[x].exten, code)) { 03308 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 03309 if (operation == FEATURE_INTERPRET_CHECK) { 03310 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03311 } else if (operation == FEATURE_INTERPRET_DO) { 03312 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 03313 } 03314 if (feature) { 03315 memcpy(feature, &builtin_features[x], sizeof(*feature)); 03316 } 03317 feature_detected = 1; 03318 break; 03319 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 03320 if (res == AST_FEATURE_RETURN_PASSDIGITS) { 03321 res = AST_FEATURE_RETURN_STOREDIGITS; 03322 } 03323 } 03324 } 03325 } 03326 ast_rwlock_unlock(&features_lock); 03327 03328 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 03329 return res; 03330 } 03331 03332 tmp = dynamic_features_buf; 03333 03334 while ((tok = strsep(&tmp, "#"))) { 03335 AST_RWLIST_RDLOCK(&feature_groups); 03336 03337 fg = find_group(tok); 03338 03339 if (fg) { 03340 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03341 if (!strcmp(fge->exten, code)) { 03342 if (operation) { 03343 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 03344 } 03345 if (feature) { 03346 memcpy(feature, fge->feature, sizeof(*feature)); 03347 } 03348 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03349 AST_RWLIST_UNLOCK(&feature_groups); 03350 break; 03351 } 03352 res = AST_FEATURE_RETURN_PASSDIGITS; 03353 } else if (!strncmp(fge->exten, code, strlen(code))) { 03354 res = AST_FEATURE_RETURN_STOREDIGITS; 03355 } 03356 } 03357 if (fge) { 03358 break; 03359 } 03360 } 03361 03362 AST_RWLIST_UNLOCK(&feature_groups); 03363 03364 AST_RWLIST_RDLOCK(&feature_list); 03365 03366 if (!(tmpfeature = find_dynamic_feature(tok))) { 03367 AST_RWLIST_UNLOCK(&feature_list); 03368 continue; 03369 } 03370 03371 /* Feature is up for consideration */ 03372 if (!strcmp(tmpfeature->exten, code)) { 03373 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 03374 if (operation == FEATURE_INTERPRET_CHECK) { 03375 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03376 } else if (operation == FEATURE_INTERPRET_DO) { 03377 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 03378 } 03379 if (feature) { 03380 memcpy(feature, tmpfeature, sizeof(*feature)); 03381 } 03382 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03383 AST_RWLIST_UNLOCK(&feature_list); 03384 break; 03385 } 03386 res = AST_FEATURE_RETURN_PASSDIGITS; 03387 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 03388 res = AST_FEATURE_RETURN_STOREDIGITS; 03389 03390 AST_RWLIST_UNLOCK(&feature_list); 03391 } 03392 03393 return res; 03394 }
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 3544 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().
03548 { 03549 int state = 0; 03550 int cause = 0; 03551 int to; 03552 int caller_hungup; 03553 int transferee_hungup; 03554 struct ast_channel *chan; 03555 struct ast_channel *monitor_chans[3]; 03556 struct ast_channel *active_channel; 03557 int res; 03558 int ready = 0; 03559 struct timeval started; 03560 int x, len = 0; 03561 char *disconnect_code = NULL, *dialed_code = NULL; 03562 struct ast_frame *f; 03563 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; 03564 03565 caller_hungup = ast_check_hangup(caller); 03566 03567 if (!(chan = ast_request(type, format, requestor, data, &cause))) { 03568 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 03569 switch (cause) { 03570 case AST_CAUSE_BUSY: 03571 state = AST_CONTROL_BUSY; 03572 break; 03573 case AST_CAUSE_CONGESTION: 03574 state = AST_CONTROL_CONGESTION; 03575 break; 03576 default: 03577 state = 0; 03578 break; 03579 } 03580 goto done; 03581 } 03582 03583 ast_string_field_set(chan, language, language); 03584 ast_channel_inherit_variables(caller, chan); 03585 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name); 03586 03587 ast_channel_lock(chan); 03588 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller); 03589 ast_channel_unlock(chan); 03590 03591 if (ast_call(chan, data, timeout)) { 03592 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 03593 switch (chan->hangupcause) { 03594 case AST_CAUSE_BUSY: 03595 state = AST_CONTROL_BUSY; 03596 break; 03597 case AST_CAUSE_CONGESTION: 03598 state = AST_CONTROL_CONGESTION; 03599 break; 03600 default: 03601 state = 0; 03602 break; 03603 } 03604 goto done; 03605 } 03606 03607 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 03608 ast_rwlock_rdlock(&features_lock); 03609 for (x = 0; x < FEATURES_COUNT; x++) { 03610 if (strcasecmp(builtin_features[x].sname, "disconnect")) 03611 continue; 03612 03613 disconnect_code = builtin_features[x].exten; 03614 len = strlen(disconnect_code) + 1; 03615 dialed_code = ast_alloca(len); 03616 memset(dialed_code, 0, len); 03617 break; 03618 } 03619 ast_rwlock_unlock(&features_lock); 03620 x = 0; 03621 started = ast_tvnow(); 03622 to = timeout; 03623 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); 03624 03625 ast_poll_channel_add(caller, chan); 03626 03627 transferee_hungup = 0; 03628 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) { 03629 int num_chans = 0; 03630 03631 monitor_chans[num_chans++] = transferee; 03632 monitor_chans[num_chans++] = chan; 03633 if (!caller_hungup) { 03634 if (ast_check_hangup(caller)) { 03635 caller_hungup = 1; 03636 03637 #if defined(ATXFER_NULL_TECH) 03638 /* Change caller's name to ensure that it will remain unique. */ 03639 set_new_chan_name(caller); 03640 03641 /* 03642 * Get rid of caller's physical technology so it is free for 03643 * other calls. 03644 */ 03645 set_kill_chan_tech(caller); 03646 #endif /* defined(ATXFER_NULL_TECH) */ 03647 } else { 03648 /* caller is not hungup so monitor it. */ 03649 monitor_chans[num_chans++] = caller; 03650 } 03651 } 03652 03653 /* see if the timeout has been violated */ 03654 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 03655 state = AST_CONTROL_UNHOLD; 03656 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name); 03657 break; /*doh! timeout*/ 03658 } 03659 03660 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to); 03661 if (!active_channel) 03662 continue; 03663 03664 f = NULL; 03665 if (transferee == active_channel) { 03666 struct ast_frame *dup_f; 03667 03668 f = ast_read(transferee); 03669 if (f == NULL) { /*doh! where'd he go?*/ 03670 transferee_hungup = 1; 03671 state = 0; 03672 break; 03673 } 03674 if (ast_is_deferrable_frame(f)) { 03675 dup_f = ast_frisolate(f); 03676 if (dup_f) { 03677 if (dup_f == f) { 03678 f = NULL; 03679 } 03680 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); 03681 } 03682 } 03683 } else if (chan == active_channel) { 03684 if (!ast_strlen_zero(chan->call_forward)) { 03685 state = 0; 03686 ast_autoservice_start(transferee); 03687 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state); 03688 ast_autoservice_stop(transferee); 03689 if (!chan) { 03690 break; 03691 } 03692 continue; 03693 } 03694 f = ast_read(chan); 03695 if (f == NULL) { /*doh! where'd he go?*/ 03696 switch (chan->hangupcause) { 03697 case AST_CAUSE_BUSY: 03698 state = AST_CONTROL_BUSY; 03699 break; 03700 case AST_CAUSE_CONGESTION: 03701 state = AST_CONTROL_CONGESTION; 03702 break; 03703 default: 03704 state = 0; 03705 break; 03706 } 03707 break; 03708 } 03709 03710 if (f->frametype == AST_FRAME_CONTROL) { 03711 if (f->subclass.integer == AST_CONTROL_RINGING) { 03712 ast_verb(3, "%s is ringing\n", chan->name); 03713 ast_indicate(caller, AST_CONTROL_RINGING); 03714 } else if (f->subclass.integer == AST_CONTROL_BUSY) { 03715 state = f->subclass.integer; 03716 ast_verb(3, "%s is busy\n", chan->name); 03717 ast_indicate(caller, AST_CONTROL_BUSY); 03718 ast_frfree(f); 03719 break; 03720 } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) { 03721 ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", chan->name, chan->exten); 03722 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) { 03723 state = f->subclass.integer; 03724 ast_verb(3, "%s is congested\n", chan->name); 03725 ast_indicate(caller, AST_CONTROL_CONGESTION); 03726 ast_frfree(f); 03727 break; 03728 } else if (f->subclass.integer == AST_CONTROL_ANSWER) { 03729 /* This is what we are hoping for */ 03730 state = f->subclass.integer; 03731 ast_frfree(f); 03732 ready=1; 03733 break; 03734 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) { 03735 if (caller_hungup) { 03736 struct ast_party_connected_line connected; 03737 03738 /* Just save it for the transfer. */ 03739 ast_party_connected_line_set_init(&connected, &caller->connected); 03740 res = ast_connected_line_parse_data(f->data.ptr, f->datalen, 03741 &connected); 03742 if (!res) { 03743 ast_channel_set_connected_line(caller, &connected, NULL); 03744 } 03745 ast_party_connected_line_free(&connected); 03746 } else { 03747 ast_autoservice_start(transferee); 03748 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { 03749 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, 03750 f->data.ptr, f->datalen); 03751 } 03752 ast_autoservice_stop(transferee); 03753 } 03754 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) { 03755 if (!caller_hungup) { 03756 ast_autoservice_start(transferee); 03757 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { 03758 ast_indicate_data(caller, AST_CONTROL_REDIRECTING, 03759 f->data.ptr, f->datalen); 03760 } 03761 ast_autoservice_stop(transferee); 03762 } 03763 } else if (f->subclass.integer != -1 03764 && f->subclass.integer != AST_CONTROL_PROGRESS 03765 && f->subclass.integer != AST_CONTROL_PROCEEDING) { 03766 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer); 03767 } 03768 /* else who cares */ 03769 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03770 ast_write(caller, f); 03771 } 03772 } else if (caller == active_channel) { 03773 f = ast_read(caller); 03774 if (f) { 03775 if (f->frametype == AST_FRAME_DTMF) { 03776 dialed_code[x++] = f->subclass.integer; 03777 dialed_code[x] = '\0'; 03778 if (strlen(dialed_code) == len) { 03779 x = 0; 03780 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 03781 x = 0; 03782 dialed_code[x] = '\0'; 03783 } 03784 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 03785 /* Caller Canceled the call */ 03786 state = AST_CONTROL_UNHOLD; 03787 ast_frfree(f); 03788 break; 03789 } 03790 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03791 ast_write(chan, f); 03792 } 03793 } 03794 } 03795 if (f) 03796 ast_frfree(f); 03797 } /* end while */ 03798 03799 ast_poll_channel_del(caller, chan); 03800 03801 /* 03802 * We need to free all the deferred frames, but we only need to 03803 * queue the deferred frames if no hangup was received. 03804 */ 03805 ast_channel_lock(transferee); 03806 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee)); 03807 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { 03808 if (!transferee_hungup) { 03809 ast_queue_frame_head(transferee, f); 03810 } 03811 ast_frfree(f); 03812 } 03813 ast_channel_unlock(transferee); 03814 03815 done: 03816 ast_indicate(caller, -1); 03817 if (chan && (ready || chan->_state == AST_STATE_UP)) { 03818 state = AST_CONTROL_ANSWER; 03819 } else if (chan) { 03820 ast_hangup(chan); 03821 chan = NULL; 03822 } 03823 03824 if (outstate) 03825 *outstate = state; 03826 03827 return chan; 03828 }
static void features_shutdown | ( | void | ) | [static] |
Definition at line 8314 of file features.c.
References ao2_ref, ARRAY_LEN, ast_cli_unregister_multiple(), ast_context_destroy(), ast_devstate_prov_del(), ast_manager_unregister(), AST_TEST_UNREGISTER, ast_unregister_application(), parkcall, parking_thread, parkinglots, and registrar.
Referenced by ast_features_init().
08315 { 08316 ast_cli_unregister_multiple(cli_features, ARRAY_LEN(cli_features)); 08317 ast_devstate_prov_del("Park"); 08318 ast_manager_unregister("Bridge"); 08319 ast_manager_unregister("Park"); 08320 ast_manager_unregister("Parkinglots"); 08321 ast_manager_unregister("ParkedCalls"); 08322 ast_unregister_application(parkcall); 08323 ast_unregister_application(parkedcall); 08324 ast_unregister_application(app_bridge); 08325 #if defined(TEST_FRAMEWORK) 08326 AST_TEST_UNREGISTER(features_test); 08327 #endif /* defined(TEST_FRAMEWORK) */ 08328 08329 pthread_cancel(parking_thread); 08330 pthread_kill(parking_thread, SIGURG); 08331 pthread_join(parking_thread, NULL); 08332 ast_context_destroy(NULL, registrar); 08333 ao2_ref(parkinglots, -1); 08334 }
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 7356 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().
07357 { 07358 struct ast_channel *target = obj;/*!< Potential pickup target */ 07359 struct ast_channel *chan = data;/*!< Channel wanting to pickup call */ 07360 07361 ast_channel_lock(target); 07362 if (chan != target && (chan->pickupgroup & target->callgroup) 07363 && ast_can_pickup(target)) { 07364 /* Return with the channel still locked on purpose */ 07365 return CMP_MATCH | CMP_STOP; 07366 } 07367 ast_channel_unlock(target); 07368 07369 return 0; 07370 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static, read] |
find a call feature by name
Definition at line 3100 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().
03101 { 03102 struct ast_call_feature *tmp; 03103 03104 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 03105 if (!strcasecmp(tmp->sname, name)) { 03106 break; 03107 } 03108 } 03109 03110 return tmp; 03111 }
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 3138 of file features.c.
References AST_LIST_TRAVERSE, and feature_group::gname.
Referenced by feature_interpret_helper().
03139 { 03140 struct feature_group *fg = NULL; 03141 03142 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 03143 if (!strcasecmp(fg->gname, name)) 03144 break; 03145 } 03146 03147 return fg; 03148 }
static struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) | [static, read] |
Find parkinglot by name.
Definition at line 5017 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().
05018 { 05019 struct ast_parkinglot *parkinglot; 05020 05021 if (ast_strlen_zero(name)) { 05022 return NULL; 05023 } 05024 05025 parkinglot = ao2_find(parkinglots, (void *) name, 0); 05026 if (parkinglot) { 05027 ast_debug(1, "Found Parking lot: %s\n", parkinglot->name); 05028 } 05029 05030 return parkinglot; 05031 }
static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 1082 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().
01083 { 01084 const char *name; 01085 01086 /* The channel variable overrides everything */ 01087 name = pbx_builtin_getvar_helper(chan, "PARKINGLOT"); 01088 if (!name && !ast_strlen_zero(chan->parkinglot)) { 01089 /* Use the channel's parking lot. */ 01090 name = chan->parkinglot; 01091 } 01092 return name; 01093 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1870 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().
01871 { 01872 ast_indicate(chan, AST_CONTROL_UNHOLD); 01873 01874 return ast_autoservice_stop(chan); 01875 }
static struct ast_exten* get_parking_exten | ( | const char * | exten_str, | |
struct ast_channel * | chan, | |||
const char * | context | |||
) | [static, read] |
Definition at line 823 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().
00824 { 00825 struct ast_exten *exten; 00826 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 00827 const char *app_at_exten; 00828 00829 ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context); 00830 exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, 00831 E_MATCH); 00832 if (!exten) { 00833 return NULL; 00834 } 00835 00836 app_at_exten = ast_get_extension_app(exten); 00837 if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) { 00838 return NULL; 00839 } 00840 00841 return exten; 00842 }
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 6799 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.
06800 { 06801 int i; 06802 struct ast_call_feature *feature; 06803 struct ao2_iterator iter; 06804 struct ast_parkinglot *curlot; 06805 #define HFS_FORMAT "%-25s %-7s %-7s\n" 06806 06807 switch (cmd) { 06808 06809 case CLI_INIT: 06810 e->command = "features show"; 06811 e->usage = 06812 "Usage: features show\n" 06813 " Lists configured features\n"; 06814 return NULL; 06815 case CLI_GENERATE: 06816 return NULL; 06817 } 06818 06819 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 06820 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06821 06822 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 06823 06824 ast_rwlock_rdlock(&features_lock); 06825 for (i = 0; i < FEATURES_COUNT; i++) 06826 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 06827 ast_rwlock_unlock(&features_lock); 06828 06829 ast_cli(a->fd, "\n"); 06830 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 06831 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06832 if (AST_RWLIST_EMPTY(&feature_list)) { 06833 ast_cli(a->fd, "(none)\n"); 06834 } else { 06835 AST_RWLIST_RDLOCK(&feature_list); 06836 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 06837 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 06838 } 06839 AST_RWLIST_UNLOCK(&feature_list); 06840 } 06841 06842 ast_cli(a->fd, "\nFeature Groups:\n"); 06843 ast_cli(a->fd, "---------------\n"); 06844 if (AST_RWLIST_EMPTY(&feature_groups)) { 06845 ast_cli(a->fd, "(none)\n"); 06846 } else { 06847 struct feature_group *fg; 06848 struct feature_group_exten *fge; 06849 06850 AST_RWLIST_RDLOCK(&feature_groups); 06851 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 06852 ast_cli(a->fd, "===> Group: %s\n", fg->gname); 06853 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 06854 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten); 06855 } 06856 } 06857 AST_RWLIST_UNLOCK(&feature_groups); 06858 } 06859 06860 iter = ao2_iterator_init(parkinglots, 0); 06861 while ((curlot = ao2_iterator_next(&iter))) { 06862 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 06863 ast_cli(a->fd, "------------\n"); 06864 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->cfg.parkext); 06865 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->cfg.parking_con); 06866 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", 06867 curlot->cfg.parking_start, curlot->cfg.parking_stop); 06868 ast_cli(a->fd,"%-22s: %d ms\n", "Parkingtime", curlot->cfg.parkingtime); 06869 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->cfg.mohclass); 06870 ast_cli(a->fd,"%-22s: %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled)); 06871 ast_cli(a->fd,"\n"); 06872 ao2_ref(curlot, -1); 06873 } 06874 ao2_iterator_destroy(&iter); 06875 06876 return CLI_SUCCESS; 06877 }
static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6905 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
06906 { 06907 switch (cmd) { 06908 case CLI_INIT: 06909 e->command = "features reload"; 06910 e->usage = 06911 "Usage: features reload\n" 06912 " Reloads configured call features from features.conf\n"; 06913 return NULL; 06914 case CLI_GENERATE: 06915 return NULL; 06916 } 06917 ast_features_reload(); 06918 06919 return CLI_SUCCESS; 06920 }
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 7109 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.
07110 { 07111 struct parkeduser *cur; 07112 int numparked = 0; 07113 struct ao2_iterator iter; 07114 struct ast_parkinglot *curlot; 07115 07116 switch (cmd) { 07117 case CLI_INIT: 07118 e->command = "parkedcalls show"; 07119 e->usage = 07120 "Usage: parkedcalls show\n" 07121 " List currently parked calls\n"; 07122 return NULL; 07123 case CLI_GENERATE: 07124 return NULL; 07125 } 07126 07127 if (a->argc > e->args) 07128 return CLI_SHOWUSAGE; 07129 07130 ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel", 07131 "Context", "Extension", "Pri", "Timeout"); 07132 07133 iter = ao2_iterator_init(parkinglots, 0); 07134 while ((curlot = ao2_iterator_next(&iter))) { 07135 int lotparked = 0; 07136 07137 /* subtract ref for iterator and for configured parking lot */ 07138 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, 07139 ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot)); 07140 07141 AST_LIST_LOCK(&curlot->parkings); 07142 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 07143 ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n", 07144 cur->parkingexten, cur->chan->name, cur->context, cur->exten, 07145 cur->priority, 07146 (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL))); 07147 ++lotparked; 07148 } 07149 AST_LIST_UNLOCK(&curlot->parkings); 07150 if (lotparked) { 07151 numparked += lotparked; 07152 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, 07153 ESS(lotparked), curlot->name); 07154 } 07155 07156 ao2_ref(curlot, -1); 07157 } 07158 ao2_iterator_destroy(&iter); 07159 07160 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 07161 07162 return CLI_SUCCESS; 07163 }
static int load_config | ( | int | reload | ) | [static] |
Definition at line 6717 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().
06718 { 06719 struct ast_flags config_flags = { 06720 reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06721 struct ast_config *cfg; 06722 struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06723 struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06724 06725 /* We are reloading now and have already determined if we will force the reload. */ 06726 force_reload_load = 0; 06727 06728 if (!default_parkinglot) { 06729 /* Must create the default default parking lot */ 06730 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 06731 if (!default_parkinglot) { 06732 ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n"); 06733 return -1; 06734 } 06735 ast_debug(1, "Configuration of default default parking lot done.\n"); 06736 } 06737 06738 cfg = ast_config_load2("features.conf", "features", config_flags); 06739 if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06740 /* No sense in asking for reload trouble if nothing changed. */ 06741 ast_debug(1, "features.conf did not change.\n"); 06742 return 0; 06743 } 06744 if (cfg == CONFIG_STATUS_FILEMISSING 06745 || cfg == CONFIG_STATUS_FILEINVALID) { 06746 ast_log(LOG_WARNING, "Could not load features.conf\n"); 06747 return 0; 06748 } 06749 06750 /* Save current parking lot dialplan needs. */ 06751 if (build_dialplan_useage_map(&old_usage_map, 0)) { 06752 destroy_dialplan_usage_map(&old_usage_map); 06753 06754 /* Allow reloading later to see if conditions have improved. */ 06755 force_reload_load = 1; 06756 return -1; 06757 } 06758 06759 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, 06760 "callback to mark all parking lots"); 06761 process_config(cfg); 06762 ast_config_destroy(cfg); 06763 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, 06764 "callback to remove marked parking lots"); 06765 06766 /* Save updated parking lot dialplan needs. */ 06767 if (build_dialplan_useage_map(&new_usage_map, 1)) { 06768 /* 06769 * Yuck, if this failure caused any parking lot dialplan items 06770 * to be lost, they will likely remain lost until Asterisk is 06771 * restarted. 06772 */ 06773 destroy_dialplan_usage_map(&old_usage_map); 06774 destroy_dialplan_usage_map(&new_usage_map); 06775 return -1; 06776 } 06777 06778 /* Remove no longer needed parking lot dialplan usage. */ 06779 remove_dead_dialplan_useage(&old_usage_map, &new_usage_map); 06780 06781 destroy_dialplan_usage_map(&old_usage_map); 06782 destroy_dialplan_usage_map(&new_usage_map); 06783 06784 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL, 06785 "callback to activate all parking lots"); 06786 06787 return 0; 06788 }
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 4703 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, parkingretalertinfo, parkingretcidname, parkingretdahdiring, 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, strdup, and ast_frame::subclass.
Referenced by manage_parkinglot().
04704 { 04705 struct ast_channel *chan = pu->chan; /* shorthand */ 04706 int tms; /* timeout for this item */ 04707 int x; /* fd index in channel */ 04708 04709 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 04710 if (tms > pu->parkingtime) { 04711 /* 04712 * Call has been parked too long. 04713 * Stop entertaining the caller. 04714 */ 04715 switch (pu->hold_method) { 04716 case AST_CONTROL_HOLD: 04717 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 04718 break; 04719 case AST_CONTROL_RINGING: 04720 ast_indicate(pu->chan, -1); 04721 break; 04722 default: 04723 break; 04724 } 04725 pu->hold_method = 0; 04726 04727 /* Get chan, exten from derived kludge */ 04728 if (pu->peername[0]) { 04729 char *peername; 04730 char *dash; 04731 char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 04732 int i; 04733 04734 peername = ast_strdupa(pu->peername); 04735 dash = strrchr(peername, '-'); 04736 if (dash) { 04737 *dash = '\0'; 04738 } 04739 04740 peername_flat = ast_strdupa(peername); 04741 for (i = 0; peername_flat[i]; i++) { 04742 if (peername_flat[i] == '/') { 04743 peername_flat[i] = '_'; 04744 } 04745 } 04746 04747 if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) { 04748 ast_log(LOG_ERROR, 04749 "Parking dial context '%s' does not exist and unable to create\n", 04750 parking_con_dial); 04751 } else { 04752 char returnexten[AST_MAX_EXTENSION]; 04753 struct ast_datastore *features_datastore; 04754 struct ast_dial_features *dialfeatures; 04755 04756 if (!strncmp(peername, "Parked/", 7)) { 04757 peername += 7; 04758 } 04759 /* If dahdi channel, add a ring cadence DAHDI/NNr3 (if parkingretdahdiring defined) */ 04760 if (!ast_strlen_zero(parkingretdahdiring) && !strncasecmp(peername, "dahdi", 5)) 04761 strncat(peername, parkingretdahdiring, 2); 04762 04763 ast_channel_lock(chan); 04764 features_datastore = ast_channel_datastore_find(chan, &dial_features_info, 04765 NULL); 04766 if (features_datastore && (dialfeatures = features_datastore->data)) { 04767 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 04768 04769 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, 04770 callback_dialoptions(&dialfeatures->peer_features, 04771 &dialfeatures->my_features, buf, sizeof(buf))); 04772 } else { /* Existing default */ 04773 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", 04774 chan->name); 04775 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername); 04776 } 04777 ast_channel_unlock(chan); 04778 04779 04780 int parkdialprio = 1; 04781 char parkciddata[512]; 04782 char parkalertinfodata[512]; 04783 /* alter CALLERID(name) and add AlertInfo header if requested */ 04784 if (!ast_strlen_zero(parkingretcidname)) { 04785 snprintf(parkciddata, sizeof(parkciddata), "CALLERID(name)=%s", parkingretcidname); 04786 if (ast_add_extension(parking_con_dial, 1, peername_flat, parkdialprio++, NULL, NULL, "Set", strdup(parkciddata), ast_free_ptr, registrar)) 04787 ast_log(LOG_ERROR, "Could not create parking return dial exten: %s@%s\n", peername_flat, parking_con_dial); 04788 } 04789 if (!ast_strlen_zero(parkingretalertinfo)) { 04790 snprintf(parkalertinfodata, sizeof(parkalertinfodata), "Alert-Info: %s", parkingretalertinfo); 04791 if (ast_add_extension(parking_con_dial, 1, peername_flat, parkdialprio++, NULL, NULL, "SIPAddHeader", strdup(parkalertinfodata), ast_free_ptr, registrar)) 04792 ast_log(LOG_ERROR, "Could not create parking return dial exten: %s@%s\n", peername_flat, parking_con_dial); 04793 } 04794 if (ast_add_extension(parking_con_dial, 1, peername_flat, parkdialprio, NULL, NULL, 04795 "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) { 04796 ast_log(LOG_ERROR, 04797 "Could not create parking return dial exten: %s@%s\n", 04798 peername_flat, parking_con_dial); 04799 } 04800 } 04801 if (pu->options_specified) { 04802 /* 04803 * Park() was called with overriding return arguments, respect 04804 * those arguments. 04805 */ 04806 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04807 } else if (comebacktoorigin) { 04808 set_c_e_p(chan, parking_con_dial, peername_flat, 1); 04809 } else { 04810 char parkingslot[AST_MAX_EXTENSION]; 04811 04812 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 04813 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 04814 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 04815 } 04816 } else { 04817 /* 04818 * They've been waiting too long, send them back to where they 04819 * came. Theoretically they should have their original 04820 * extensions and such, but we copy to be on the safe side. 04821 */ 04822 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04823 } 04824 post_manager_event("ParkedCallTimeOut", pu); 04825 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL); 04826 04827 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", 04828 pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, 04829 pu->chan->exten, pu->chan->priority); 04830 04831 /* Start up the PBX, or hang them up */ 04832 if (ast_pbx_start(chan)) { 04833 ast_log(LOG_WARNING, 04834 "Unable to restart the PBX for user on '%s', hanging them up...\n", 04835 pu->chan->name); 04836 ast_hangup(chan); 04837 } 04838 04839 /* And take them out of the parking lot */ 04840 return 1; 04841 } 04842 04843 /* still within parking time, process descriptors */ 04844 if (pfds) { 04845 for (x = 0; x < AST_MAX_FDS; x++) { 04846 struct ast_frame *f; 04847 int y; 04848 04849 if (chan->fds[x] == -1) { 04850 continue; /* nothing on this descriptor */ 04851 } 04852 04853 for (y = 0; y < nfds; y++) { 04854 if (pfds[y].fd == chan->fds[x]) { 04855 /* Found poll record! */ 04856 break; 04857 } 04858 } 04859 if (y == nfds) { 04860 /* Not found */ 04861 continue; 04862 } 04863 04864 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) { 04865 /* Next x */ 04866 continue; 04867 } 04868 04869 if (pfds[y].revents & POLLPRI) { 04870 ast_set_flag(chan, AST_FLAG_EXCEPTION); 04871 } else { 04872 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 04873 } 04874 chan->fdno = x; 04875 04876 /* See if they need servicing */ 04877 f = ast_read(pu->chan); 04878 /* Hangup? */ 04879 if (!f || (f->frametype == AST_FRAME_CONTROL 04880 && f->subclass.integer == AST_CONTROL_HANGUP)) { 04881 if (f) { 04882 ast_frfree(f); 04883 } 04884 post_manager_event("ParkedCallGiveUp", pu); 04885 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", 04886 NULL); 04887 04888 /* There's a problem, hang them up */ 04889 ast_verb(2, "%s got tired of being parked\n", chan->name); 04890 ast_hangup(chan); 04891 04892 /* And take them out of the parking lot */ 04893 return 1; 04894 } else { 04895 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 04896 ast_frfree(f); 04897 if (pu->hold_method == AST_CONTROL_HOLD 04898 && pu->moh_trys < 3 04899 && !chan->generatordata) { 04900 ast_debug(1, 04901 "MOH on parked call stopped by outside source. Restarting on channel %s.\n", 04902 chan->name); 04903 ast_indicate_data(chan, AST_CONTROL_HOLD, 04904 S_OR(pu->parkinglot->cfg.mohclass, NULL), 04905 (!ast_strlen_zero(pu->parkinglot->cfg.mohclass) 04906 ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0)); 04907 pu->moh_trys++; 04908 } 04909 break; 04910 } 04911 } /* End for */ 04912 } 04913 04914 /* mark fds for next round */ 04915 for (x = 0; x < AST_MAX_FDS; x++) { 04916 if (chan->fds[x] > -1) { 04917 void *tmp = ast_realloc(*new_pfds, 04918 (*new_nfds + 1) * sizeof(struct pollfd)); 04919 04920 if (!tmp) { 04921 continue; 04922 } 04923 *new_pfds = tmp; 04924 (*new_pfds)[*new_nfds].fd = chan->fds[x]; 04925 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI; 04926 (*new_pfds)[*new_nfds].revents = 0; 04927 (*new_nfds)++; 04928 } 04929 } 04930 /* Keep track of our shortest wait */ 04931 if (tms < *ms || *ms < 0) { 04932 *ms = tms; 04933 } 04934 04935 /* Stay in the parking lot. */ 04936 return 0; 04937 }
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 4940 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().
04941 { 04942 struct parkeduser *pu; 04943 struct ast_context *con; 04944 04945 /* Lock parkings list */ 04946 AST_LIST_LOCK(&curlot->parkings); 04947 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 04948 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 04949 continue; 04950 } 04951 if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) { 04952 /* Parking is complete for this call so remove it from the parking lot. */ 04953 con = ast_context_find(pu->parkinglot->cfg.parking_con); 04954 if (con) { 04955 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 04956 ast_log(LOG_WARNING, 04957 "Whoa, failed to remove the parking extension %s@%s!\n", 04958 pu->parkingexten, pu->parkinglot->cfg.parking_con); 04959 } 04960 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, 04961 AST_DEVICE_NOT_INUSE); 04962 } else { 04963 ast_log(LOG_WARNING, 04964 "Whoa, parking lot '%s' context '%s' does not exist.\n", 04965 pu->parkinglot->name, pu->parkinglot->cfg.parking_con); 04966 } 04967 AST_LIST_REMOVE_CURRENT(list); 04968 parkinglot_unref(pu->parkinglot); 04969 ast_free(pu); 04970 } 04971 } 04972 AST_LIST_TRAVERSE_SAFE_END; 04973 AST_LIST_UNLOCK(&curlot->parkings); 04974 }
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 7245 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().
07246 { 07247 const char *channel = astman_get_header(m, "Channel"); 07248 const char *channel2 = astman_get_header(m, "Channel2"); 07249 const char *timeout = astman_get_header(m, "Timeout"); 07250 const char *parkinglotname = astman_get_header(m, "Parkinglot"); 07251 char buf[BUFSIZ]; 07252 int res = 0; 07253 struct ast_channel *ch1, *ch2; 07254 struct ast_park_call_args args = { 07255 /* 07256 * Don't say anything to ch2 since AMI is a third party parking 07257 * a call and we will likely crash if we do. 07258 * 07259 * XXX When the AMI action was originally implemented, the 07260 * parking space was announced to ch2. Unfortunately, grabbing 07261 * the ch2 lock and holding it while the announcement is played 07262 * was not really a good thing to do to begin with since it 07263 * could hold up the system. Also holding the lock is no longer 07264 * possible with a masquerade. 07265 * 07266 * Restoring the announcement to ch2 is not easily doable for 07267 * the following reasons: 07268 * 07269 * 1) The AMI manager is not the thread processing ch2. 07270 * 07271 * 2) ch2 could be the same as ch1, bridged to ch1, or some 07272 * random uninvolved channel. 07273 */ 07274 .flags = AST_PARK_OPT_SILENCE, 07275 }; 07276 07277 if (ast_strlen_zero(channel)) { 07278 astman_send_error(s, m, "Channel not specified"); 07279 return 0; 07280 } 07281 07282 if (ast_strlen_zero(channel2)) { 07283 astman_send_error(s, m, "Channel2 not specified"); 07284 return 0; 07285 } 07286 07287 if (!ast_strlen_zero(timeout)) { 07288 if (sscanf(timeout, "%30d", &args.timeout) != 1) { 07289 astman_send_error(s, m, "Invalid timeout value."); 07290 return 0; 07291 } 07292 } 07293 07294 if (!(ch1 = ast_channel_get_by_name(channel))) { 07295 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 07296 astman_send_error(s, m, buf); 07297 return 0; 07298 } 07299 07300 if (!(ch2 = ast_channel_get_by_name(channel2))) { 07301 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 07302 astman_send_error(s, m, buf); 07303 ast_channel_unref(ch1); 07304 return 0; 07305 } 07306 07307 if (!ast_strlen_zero(parkinglotname)) { 07308 args.parkinglot = find_parkinglot(parkinglotname); 07309 } 07310 07311 res = masq_park_call(ch1, ch2, &args); 07312 if (!res) { 07313 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 07314 astman_send_ack(s, m, "Park successful"); 07315 } else { 07316 astman_send_error(s, m, "Park failure"); 07317 } 07318 07319 if (args.parkinglot) { 07320 parkinglot_unref(args.parkinglot); 07321 } 07322 ch1 = ast_channel_unref(ch1); 07323 ch2 = ast_channel_unref(ch2); 07324 07325 return 0; 07326 }
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 7179 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().
07180 { 07181 struct parkeduser *cur; 07182 const char *id = astman_get_header(m, "ActionID"); 07183 char idText[256] = ""; 07184 struct ao2_iterator iter; 07185 struct ast_parkinglot *curlot; 07186 int numparked = 0; 07187 07188 if (!ast_strlen_zero(id)) 07189 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 07190 07191 astman_send_ack(s, m, "Parked calls will follow"); 07192 07193 iter = ao2_iterator_init(parkinglots, 0); 07194 while ((curlot = ao2_iterator_next(&iter))) { 07195 AST_LIST_LOCK(&curlot->parkings); 07196 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 07197 astman_append(s, "Event: ParkedCall\r\n" 07198 "Parkinglot: %s\r\n" 07199 "Exten: %d\r\n" 07200 "Channel: %s\r\n" 07201 "From: %s\r\n" 07202 "Timeout: %ld\r\n" 07203 "CallerIDNum: %s\r\n" 07204 "CallerIDName: %s\r\n" 07205 "ConnectedLineNum: %s\r\n" 07206 "ConnectedLineName: %s\r\n" 07207 "%s" 07208 "\r\n", 07209 curlot->name, 07210 cur->parkingnum, cur->chan->name, cur->peername, 07211 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 07212 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""), /* XXX in other places it is <unknown> */ 07213 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""), 07214 S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""), /* XXX in other places it is <unknown> */ 07215 S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""), 07216 idText); 07217 ++numparked; 07218 } 07219 AST_LIST_UNLOCK(&curlot->parkings); 07220 ao2_ref(curlot, -1); 07221 } 07222 ao2_iterator_destroy(&iter); 07223 07224 astman_append(s, 07225 "Event: ParkedCallsComplete\r\n" 07226 "Total: %d\r\n" 07227 "%s" 07228 "\r\n", 07229 numparked, idText); 07230 07231 return RESULT_SUCCESS; 07232 }
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 1726 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().
01727 { 01728 struct ast_channel *chan; 01729 01730 /* Make a new, channel that we'll use to masquerade in the real one */ 01731 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, 01732 rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s", rchan->name); 01733 if (!chan) { 01734 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 01735 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01736 if (peer == rchan) { 01737 /* Only have one channel to worry about. */ 01738 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01739 } else if (peer) { 01740 /* Have two different channels to worry about. */ 01741 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01742 } 01743 } 01744 return -1; 01745 } 01746 01747 args->pu = park_space_reserve(rchan, peer, args); 01748 if (!args->pu) { 01749 ast_hangup(chan); 01750 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01751 if (peer == rchan) { 01752 /* Only have one channel to worry about. */ 01753 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01754 } else if (peer) { 01755 /* Have two different channels to worry about. */ 01756 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01757 } 01758 } 01759 return -1; 01760 } 01761 01762 /* Make formats okay */ 01763 chan->readformat = rchan->readformat; 01764 chan->writeformat = rchan->writeformat; 01765 01766 if (ast_channel_masquerade(chan, rchan)) { 01767 park_space_abort(args->pu); 01768 args->pu = NULL; 01769 ast_hangup(chan); 01770 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01771 if (peer == rchan) { 01772 /* Only have one channel to worry about. */ 01773 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01774 } else if (peer) { 01775 /* Have two different channels to worry about. */ 01776 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01777 } 01778 } 01779 return -1; 01780 } 01781 01782 /* Setup the extensions and such */ 01783 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 01784 01785 /* Setup the macro extension and such */ 01786 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext)); 01787 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten)); 01788 chan->macropriority = rchan->macropriority; 01789 01790 /* Manually do the masquerade to make sure it is complete. */ 01791 ast_do_masquerade(chan); 01792 01793 if (peer == rchan) { 01794 peer = chan; 01795 } 01796 01797 /* parking space reserved, return code check unnecessary */ 01798 park_call_full(chan, peer, args); 01799 01800 return 0; 01801 }
static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 1105 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().
01106 { 01107 char *context; 01108 char *exten; 01109 01110 context = ast_strdupa(data); 01111 01112 exten = strsep(&context, "@"); 01113 if (!context) 01114 return AST_DEVICE_INVALID; 01115 01116 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 01117 01118 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 01119 return AST_DEVICE_NOT_INUSE; 01120 01121 return AST_DEVICE_INUSE; 01122 }
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 1096 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().
01097 { 01098 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 01099 exten, context, ast_devstate2str(state)); 01100 01101 ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "park:%s@%s", exten, context); 01102 }
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 5484 of file features.c.
References ast_add_extension(), AST_MAX_EXTENSION, PRIORITY_HINT, and registrar.
Referenced by parkinglot_activate().
05485 { 05486 int numext; 05487 char device[AST_MAX_EXTENSION]; 05488 char exten[10]; 05489 05490 for (numext = start; numext <= stop; numext++) { 05491 snprintf(exten, sizeof(exten), "%d", numext); 05492 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 05493 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 05494 } 05495 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Park a call.
Definition at line 5063 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().
05064 { 05065 struct ast_park_call_args args = { 0, }; 05066 struct ast_flags flags = { 0 }; 05067 char orig_exten[AST_MAX_EXTENSION]; 05068 int orig_priority; 05069 int res; 05070 const char *pl_name; 05071 char *parse; 05072 struct park_app_args app_args; 05073 05074 /* 05075 * Cache the original channel name because we are going to 05076 * masquerade the channel. Prefer the BLINDTRANSFER channel 05077 * name over this channel name. BLINDTRANSFER could be set if 05078 * the parking access extension did not get detected and we are 05079 * executing the Park application from the dialplan. 05080 * 05081 * The orig_chan_name is used to return the call to the 05082 * originator on parking timeout. 05083 */ 05084 args.orig_chan_name = ast_strdupa(S_OR( 05085 pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name)); 05086 05087 /* Answer if call is not up */ 05088 if (chan->_state != AST_STATE_UP) { 05089 if (ast_answer(chan)) { 05090 return -1; 05091 } 05092 05093 /* Sleep to allow VoIP streams to settle down */ 05094 if (ast_safe_sleep(chan, 1000)) { 05095 return -1; 05096 } 05097 } 05098 05099 /* Process the dialplan application options. */ 05100 parse = ast_strdupa(data); 05101 AST_STANDARD_APP_ARGS(app_args, parse); 05102 05103 if (!ast_strlen_zero(app_args.timeout)) { 05104 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) { 05105 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 05106 args.timeout = 0; 05107 } 05108 } 05109 if (!ast_strlen_zero(app_args.return_con)) { 05110 args.return_con = app_args.return_con; 05111 } 05112 if (!ast_strlen_zero(app_args.return_ext)) { 05113 args.return_ext = app_args.return_ext; 05114 } 05115 if (!ast_strlen_zero(app_args.return_pri)) { 05116 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) { 05117 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 05118 args.return_pri = 0; 05119 } 05120 } 05121 05122 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 05123 args.flags = flags.flags; 05124 05125 /* 05126 * Setup the exten/priority to be s/1 since we don't know where 05127 * this call should return. 05128 */ 05129 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 05130 orig_priority = chan->priority; 05131 strcpy(chan->exten, "s"); 05132 chan->priority = 1; 05133 05134 /* Park the call */ 05135 if (!ast_strlen_zero(app_args.pl_name)) { 05136 pl_name = app_args.pl_name; 05137 } else { 05138 pl_name = findparkinglotname(chan); 05139 } 05140 if (ast_strlen_zero(pl_name)) { 05141 /* Parking lot is not specified, so use the default parking lot. */ 05142 args.parkinglot = parkinglot_addref(default_parkinglot); 05143 } else { 05144 args.parkinglot = find_parkinglot(pl_name); 05145 if (!args.parkinglot && parkeddynamic) { 05146 args.parkinglot = create_dynamic_parkinglot(pl_name, chan); 05147 } 05148 } 05149 if (args.parkinglot) { 05150 res = masq_park_call(chan, chan, &args); 05151 parkinglot_unref(args.parkinglot); 05152 } else { 05153 /* Parking failed because the parking lot does not exist. */ 05154 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { 05155 ast_stream_and_wait(chan, "pbx-parkingfailed", ""); 05156 } 05157 res = -1; 05158 } 05159 if (res) { 05160 /* Park failed, try to continue in the dialplan. */ 05161 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 05162 chan->priority = orig_priority; 05163 res = 0; 05164 } else { 05165 /* Park succeeded. */ 05166 res = -1; 05167 } 05168 05169 return res; 05170 }
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 1470 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(), pbx_builtin_setvar_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().
01471 { 01472 struct parkeduser *pu = args->pu; 01473 const char *event_from; /*!< Channel name that is parking the call. */ 01474 char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT]; 01475 01476 if (pu == NULL) { 01477 args->pu = pu = park_space_reserve(chan, peer, args); 01478 if (pu == NULL) { 01479 return -1; 01480 } 01481 } 01482 01483 chan->appl = "Parked Call"; 01484 chan->data = NULL; 01485 01486 pu->chan = chan; 01487 01488 /* Put the parked channel on hold if we have two different channels */ 01489 if (chan != peer) { 01490 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 01491 pu->hold_method = AST_CONTROL_RINGING; 01492 ast_indicate(chan, AST_CONTROL_RINGING); 01493 } else { 01494 pu->hold_method = AST_CONTROL_HOLD; 01495 ast_indicate_data(chan, AST_CONTROL_HOLD, 01496 S_OR(pu->parkinglot->cfg.mohclass, NULL), 01497 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0); 01498 } 01499 } 01500 01501 pu->start = ast_tvnow(); 01502 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->cfg.parkingtime; 01503 if (args->extout) 01504 *(args->extout) = pu->parkingnum; 01505 01506 if (peer) { 01507 event_from = S_OR(args->orig_chan_name, peer->name); 01508 01509 /* 01510 * This is so ugly that it hurts, but implementing 01511 * get_base_channel() on local channels could have ugly side 01512 * effects. We could have 01513 * transferer<->local,1<->local,2<->parking and we need the 01514 * callback name to be that of transferer. Since local,1/2 have 01515 * the same name we can be tricky and just grab the bridged 01516 * channel from the other side of the local. 01517 */ 01518 if (!strcasecmp(peer->tech->type, "Local")) { 01519 struct ast_channel *tmpchan, *base_peer; 01520 char other_side[AST_CHANNEL_NAME]; 01521 char *c; 01522 01523 ast_copy_string(other_side, event_from, sizeof(other_side)); 01524 if ((c = strrchr(other_side, ';'))) { 01525 *++c = '1'; 01526 } 01527 if ((tmpchan = ast_channel_get_by_name(other_side))) { 01528 ast_channel_lock(tmpchan); 01529 if ((base_peer = ast_bridged_channel(tmpchan))) { 01530 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 01531 } 01532 ast_channel_unlock(tmpchan); 01533 tmpchan = ast_channel_unref(tmpchan); 01534 } 01535 } else { 01536 ast_copy_string(pu->peername, event_from, sizeof(pu->peername)); 01537 } 01538 } else { 01539 event_from = S_OR(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name); 01540 } 01541 01542 /* 01543 * Remember what had been dialed, so that if the parking 01544 * expires, we try to come back to the same place 01545 */ 01546 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri); 01547 01548 /* 01549 * If extension has options specified, they override all other 01550 * possibilities such as the returntoorigin flag and transferred 01551 * context. Information on extension options is lost here, so 01552 * we set a flag 01553 */ 01554 ast_copy_string(pu->context, 01555 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 01556 sizeof(pu->context)); 01557 ast_copy_string(pu->exten, 01558 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 01559 sizeof(pu->exten)); 01560 pu->priority = args->return_pri ? args->return_pri : 01561 (chan->macropriority ? chan->macropriority : chan->priority); 01562 01563 /* Mark channel as parked */ 01564 pbx_builtin_setvar_helper(pu->chan, "PARKED_CALL", "1"); 01565 01566 /* 01567 * If parking a channel directly, don't quite yet get parking 01568 * running on it. All parking lot entries are put into the 01569 * parking lot with notquiteyet on. 01570 */ 01571 if (peer != chan) { 01572 pu->notquiteyet = 0; 01573 } 01574 01575 /* Wake up the (presumably select()ing) thread */ 01576 pthread_kill(parking_thread, SIGURG); 01577 ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", 01578 chan->name, pu->parkingnum, pu->parkinglot->name, 01579 pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000)); 01580 01581 ast_cel_report_event(chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer); 01582 01583 ast_manager_event(chan, EVENT_FLAG_CALL, "ParkedCall", 01584 "Exten: %s\r\n" 01585 "Channel: %s\r\n" 01586 "Parkinglot: %s\r\n" 01587 "From: %s\r\n" 01588 "Timeout: %ld\r\n" 01589 "CallerIDNum: %s\r\n" 01590 "CallerIDName: %s\r\n" 01591 "ConnectedLineNum: %s\r\n" 01592 "ConnectedLineName: %s\r\n" 01593 "Uniqueid: %s\r\n", 01594 pu->parkingexten, chan->name, pu->parkinglot->name, event_from, 01595 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 01596 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<unknown>"), 01597 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>"), 01598 S_COR(chan->connected.id.number.valid, chan->connected.id.number.str, "<unknown>"), 01599 S_COR(chan->connected.id.name.valid, chan->connected.id.name.str, "<unknown>"), 01600 chan->uniqueid 01601 ); 01602 ast_debug(4, "peer->name: %s\n", peer ? peer->name : "-No peer-"); 01603 ast_debug(4, "args->orig_chan_name: %s\n", args->orig_chan_name ? args->orig_chan_name : "-none-"); 01604 ast_debug(4, "pu->peername: %s\n", pu->peername); 01605 ast_debug(4, "AMI ParkedCall Channel: %s\n", chan->name); 01606 ast_debug(4, "AMI ParkedCall From: %s\n", event_from); 01607 01608 if (peer && adsipark && ast_adsi_available(peer)) { 01609 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 01610 ast_adsi_unload_session(peer); 01611 } 01612 01613 snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten, 01614 pu->parkinglot->name); 01615 if (ast_add_extension(pu->parkinglot->cfg.parking_con, 1, pu->parkingexten, 1, 01616 NULL, NULL, parkedcall, ast_strdup(app_data), ast_free_ptr, registrar)) { 01617 ast_log(LOG_ERROR, "Could not create parked call exten: %s@%s\n", 01618 pu->parkingexten, pu->parkinglot->cfg.parking_con); 01619 } else { 01620 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE); 01621 } 01622 01623 AST_LIST_UNLOCK(&pu->parkinglot->parkings); 01624 01625 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 01626 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) 01627 && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) { 01628 /* 01629 * If a channel is masqueraded into peer while playing back the 01630 * parking space number do not continue playing it back. This 01631 * is the case if an attended transfer occurs. 01632 */ 01633 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01634 /* Tell the peer channel the number of the parking space */ 01635 ast_say_digits(peer, pu->parkingnum, "", peer->language); 01636 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01637 } 01638 if (peer == chan) { /* pu->notquiteyet = 1 */ 01639 /* Wake up parking thread if we're really done */ 01640 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 01641 pu->hold_method = AST_CONTROL_RINGING; 01642 ast_indicate(chan, AST_CONTROL_RINGING); 01643 } else { 01644 pu->hold_method = AST_CONTROL_HOLD; 01645 ast_indicate_data(chan, AST_CONTROL_HOLD, 01646 S_OR(pu->parkinglot->cfg.mohclass, NULL), 01647 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0); 01648 } 01649 pu->notquiteyet = 0; 01650 pthread_kill(parking_thread, SIGURG); 01651 } 01652 return 0; 01653 }
static void park_space_abort | ( | struct parkeduser * | pu | ) | [static] |
Definition at line 1272 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().
01273 { 01274 struct ast_parkinglot *parkinglot; 01275 01276 parkinglot = pu->parkinglot; 01277 01278 /* Put back the parking space just allocated. */ 01279 --parkinglot->next_parking_space; 01280 01281 AST_LIST_REMOVE(&parkinglot->parkings, pu, list); 01282 01283 AST_LIST_UNLOCK(&parkinglot->parkings); 01284 parkinglot_unref(parkinglot); 01285 ast_free(pu); 01286 }
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 1299 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().
01300 { 01301 struct parkeduser *pu; 01302 int i; 01303 int parking_space = -1; 01304 const char *parkinglotname; 01305 const char *parkingexten; 01306 struct parkeduser *cur; 01307 struct ast_parkinglot *parkinglot = NULL; 01308 01309 if (args->parkinglot) { 01310 parkinglot = parkinglot_addref(args->parkinglot); 01311 parkinglotname = parkinglot->name; 01312 } else { 01313 if (parker) { 01314 parkinglotname = findparkinglotname(parker); 01315 } else { /* parker was NULL, check park_me (ParkAndAnnounce / res_agi) */ 01316 parkinglotname = findparkinglotname(park_me); 01317 } 01318 if (!ast_strlen_zero(parkinglotname)) { 01319 parkinglot = find_parkinglot(parkinglotname); 01320 } else { 01321 /* Parking lot is not specified, so use the default parking lot. */ 01322 ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n"); 01323 parkinglot = parkinglot_addref(default_parkinglot); 01324 } 01325 } 01326 01327 /* Dynamically create parkinglot */ 01328 if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) { 01329 parkinglot = create_dynamic_parkinglot(parkinglotname, park_me); 01330 } 01331 01332 if (!parkinglot) { 01333 ast_log(LOG_WARNING, "Parking lot not available to park %s.\n", park_me->name); 01334 return NULL; 01335 } 01336 01337 ast_debug(1, "Parking lot: %s\n", parkinglot->name); 01338 if (parkinglot->disabled || parkinglot->cfg.is_invalid) { 01339 ast_log(LOG_WARNING, "Parking lot %s is not in a useable state.\n", 01340 parkinglot->name); 01341 parkinglot_unref(parkinglot); 01342 return NULL; 01343 } 01344 01345 /* Allocate memory for parking data */ 01346 if (!(pu = ast_calloc(1, sizeof(*pu)))) { 01347 parkinglot_unref(parkinglot); 01348 return NULL; 01349 } 01350 01351 /* Lock parking list */ 01352 AST_LIST_LOCK(&parkinglot->parkings); 01353 01354 /* Check for channel variable PARKINGEXTEN */ 01355 parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(park_me, "PARKINGEXTEN"), "")); 01356 if (!ast_strlen_zero(parkingexten)) { 01357 /*! 01358 * \note The API forces us to specify a numeric parking slot, even 01359 * though the architecture would tend to support non-numeric extensions 01360 * (as are possible with SIP, for example). Hence, we enforce that 01361 * limitation here. If extout was not numeric, we could permit 01362 * arbitrary non-numeric extensions. 01363 */ 01364 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space <= 0) { 01365 ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", 01366 parkingexten); 01367 AST_LIST_UNLOCK(&parkinglot->parkings); 01368 parkinglot_unref(parkinglot); 01369 ast_free(pu); 01370 return NULL; 01371 } 01372 01373 if (parking_space < parkinglot->cfg.parking_start 01374 || parkinglot->cfg.parking_stop < parking_space) { 01375 /* 01376 * Cannot allow park because parking lots are not setup for 01377 * spaces outside of the lot. (Things like dialplan hints don't 01378 * exist for outside lot space.) 01379 */ 01380 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is not in %s (%d-%d).\n", 01381 parking_space, parkinglot->name, parkinglot->cfg.parking_start, 01382 parkinglot->cfg.parking_stop); 01383 AST_LIST_UNLOCK(&parkinglot->parkings); 01384 parkinglot_unref(parkinglot); 01385 ast_free(pu); 01386 return NULL; 01387 } 01388 01389 /* Check if requested parking space is in use. */ 01390 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 01391 if (cur->parkingnum == parking_space) { 01392 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is already in use in %s\n", 01393 parking_space, parkinglot->name); 01394 AST_LIST_UNLOCK(&parkinglot->parkings); 01395 parkinglot_unref(parkinglot); 01396 ast_free(pu); 01397 return NULL; 01398 } 01399 } 01400 } else { 01401 /* PARKINGEXTEN is empty, so find a usable extension in the lot to park the call */ 01402 int start; /* The first slot we look in the parkinglot. It can be randomized. */ 01403 int start_checked = 0; /* flag raised once the first slot is checked */ 01404 01405 /* If using randomize mode, set start to random position on parking range */ 01406 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) { 01407 start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1); 01408 start += parkinglot->cfg.parking_start; 01409 } else if (parkinglot->cfg.parkfindnext 01410 && parkinglot->cfg.parking_start <= parkinglot->next_parking_space 01411 && parkinglot->next_parking_space <= parkinglot->cfg.parking_stop) { 01412 /* Start looking with the next parking space in the lot. */ 01413 start = parkinglot->next_parking_space; 01414 } else { 01415 /* Otherwise, just set it to the start position. */ 01416 start = parkinglot->cfg.parking_start; 01417 } 01418 01419 /* free parking extension linear search: O(n^2) */ 01420 for (i = start; ; i++) { 01421 /* If we are past the end, wrap around to the first parking slot*/ 01422 if (i == parkinglot->cfg.parking_stop + 1) { 01423 i = parkinglot->cfg.parking_start; 01424 } 01425 01426 if (i == start) { 01427 /* At this point, if start_checked, we've exhausted all the possible slots. */ 01428 if (start_checked) { 01429 break; 01430 } else { 01431 start_checked = 1; 01432 } 01433 } 01434 01435 /* Search the list of parked calls already in use for i. If we find it, it's in use. */ 01436 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 01437 if (cur->parkingnum == i) { 01438 break; 01439 } 01440 } 01441 if (!cur) { 01442 /* We found a parking space. */ 01443 parking_space = i; 01444 break; 01445 } 01446 } 01447 if (parking_space == -1) { 01448 /* We did not find a parking space. Lot is full. */ 01449 ast_log(LOG_WARNING, "No more parking spaces in %s\n", parkinglot->name); 01450 AST_LIST_UNLOCK(&parkinglot->parkings); 01451 parkinglot_unref(parkinglot); 01452 ast_free(pu); 01453 return NULL; 01454 } 01455 } 01456 01457 /* Prepare for next parking space search. */ 01458 parkinglot->next_parking_space = parking_space + 1; 01459 01460 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 01461 pu->notquiteyet = 1; 01462 pu->parkingnum = parking_space; 01463 pu->parkinglot = parkinglot; 01464 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list); 01465 01466 return pu; 01467 }
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 5173 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().
05174 { 05175 int res; 05176 struct ast_channel *peer = NULL; 05177 struct parkeduser *pu; 05178 struct ast_context *con; 05179 char *parse; 05180 const char *pl_name; 05181 unsigned int park = 0; 05182 struct ast_bridge_config config; 05183 struct ast_parkinglot *parkinglot; 05184 AST_DECLARE_APP_ARGS(app_args, 05185 AST_APP_ARG(pl_space); /*!< Parking lot space to retrieve if present. */ 05186 AST_APP_ARG(pl_name); /*!< Parking lot name to use if present. */ 05187 AST_APP_ARG(dummy); /*!< Place to put any remaining args string. */ 05188 ); 05189 05190 parse = ast_strdupa(data); 05191 AST_STANDARD_APP_ARGS(app_args, parse); 05192 05193 if (!ast_strlen_zero(app_args.pl_space)) { 05194 if (sscanf(app_args.pl_space, "%30u", &park) != 1) { 05195 ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n", 05196 app_args.pl_space); 05197 park = -1; 05198 } 05199 } 05200 05201 if (!ast_strlen_zero(app_args.pl_name)) { 05202 pl_name = app_args.pl_name; 05203 } else { 05204 pl_name = findparkinglotname(chan); 05205 } 05206 if (ast_strlen_zero(pl_name)) { 05207 /* Parking lot is not specified, so use the default parking lot. */ 05208 parkinglot = parkinglot_addref(default_parkinglot); 05209 } else { 05210 parkinglot = find_parkinglot(pl_name); 05211 if (!parkinglot) { 05212 /* It helps to answer the channel if not already up. :) */ 05213 if (chan->_state != AST_STATE_UP) { 05214 ast_answer(chan); 05215 } 05216 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05217 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", 05218 "pbx-invalidpark", chan->name); 05219 } 05220 ast_log(LOG_WARNING, 05221 "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n", 05222 chan->name, pl_name); 05223 return -1; 05224 } 05225 } 05226 05227 AST_LIST_LOCK(&parkinglot->parkings); 05228 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 05229 if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park) 05230 && !pu->notquiteyet && !pu->chan->pbx) { 05231 /* The parking space has a call and can be picked up now. */ 05232 AST_LIST_REMOVE_CURRENT(list); 05233 break; 05234 } 05235 } 05236 AST_LIST_TRAVERSE_SAFE_END; 05237 if (pu) { 05238 /* Found a parked call to pickup. */ 05239 peer = pu->chan; 05240 con = ast_context_find(parkinglot->cfg.parking_con); 05241 if (con) { 05242 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 05243 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 05244 } else { 05245 notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE); 05246 } 05247 } else { 05248 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 05249 } 05250 05251 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan); 05252 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall", 05253 "Exten: %s\r\n" 05254 "Channel: %s\r\n" 05255 "Parkinglot: %s\r\n" 05256 "From: %s\r\n" 05257 "CallerIDNum: %s\r\n" 05258 "CallerIDName: %s\r\n" 05259 "ConnectedLineNum: %s\r\n" 05260 "ConnectedLineName: %s\r\n" 05261 "Uniqueid: %s\r\n", 05262 pu->parkingexten, pu->chan->name, pu->parkinglot->name, chan->name, 05263 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 05264 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 05265 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 05266 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 05267 pu->chan->uniqueid 05268 ); 05269 05270 /* Stop entertaining the caller. */ 05271 switch (pu->hold_method) { 05272 case AST_CONTROL_HOLD: 05273 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 05274 break; 05275 case AST_CONTROL_RINGING: 05276 ast_indicate(pu->chan, -1); 05277 break; 05278 default: 05279 break; 05280 } 05281 pu->hold_method = 0; 05282 05283 parkinglot_unref(pu->parkinglot); 05284 ast_free(pu); 05285 } 05286 AST_LIST_UNLOCK(&parkinglot->parkings); 05287 05288 if (peer) { 05289 /* Update connected line between retrieving call and parked call. */ 05290 struct ast_party_connected_line connected; 05291 05292 ast_party_connected_line_init(&connected); 05293 05294 /* Send our caller-id to peer. */ 05295 ast_channel_lock(chan); 05296 ast_connected_line_copy_from_caller(&connected, &chan->caller); 05297 ast_channel_unlock(chan); 05298 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05299 if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) { 05300 ast_channel_update_connected_line(peer, &connected, NULL); 05301 } 05302 05303 /* 05304 * Get caller-id from peer. 05305 * 05306 * Update the retrieving call before it is answered if possible 05307 * for best results. Some phones do not support updating the 05308 * connected line information after connection. 05309 */ 05310 ast_channel_lock(peer); 05311 ast_connected_line_copy_from_caller(&connected, &peer->caller); 05312 ast_channel_unlock(peer); 05313 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05314 if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) { 05315 ast_channel_update_connected_line(chan, &connected, NULL); 05316 } 05317 05318 ast_party_connected_line_free(&connected); 05319 } 05320 05321 /* JK02: it helps to answer the channel if not already up */ 05322 if (chan->_state != AST_STATE_UP) { 05323 ast_answer(chan); 05324 } 05325 05326 if (peer) { 05327 struct ast_datastore *features_datastore; 05328 struct ast_dial_features *dialfeatures; 05329 05330 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 05331 if (!ast_strlen_zero(courtesytone)) { 05332 static const char msg[] = "courtesy tone"; 05333 05334 switch (parkedplay) { 05335 case 0:/* Courtesy tone to pickup chan */ 05336 res = play_message_to_chans(chan, peer, -1, msg, courtesytone); 05337 break; 05338 case 1:/* Courtesy tone to parked chan */ 05339 res = play_message_to_chans(chan, peer, 1, msg, courtesytone); 05340 break; 05341 case 2:/* Courtesy tone to both chans */ 05342 res = play_message_to_chans(chan, peer, 0, msg, courtesytone); 05343 break; 05344 default: 05345 res = 0; 05346 break; 05347 } 05348 if (res) { 05349 ast_hangup(peer); 05350 parkinglot_unref(parkinglot); 05351 return -1; 05352 } 05353 } 05354 05355 res = ast_channel_make_compatible(chan, peer); 05356 if (res < 0) { 05357 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 05358 ast_hangup(peer); 05359 parkinglot_unref(parkinglot); 05360 return -1; 05361 } 05362 /* This runs sorta backwards, since we give the incoming channel control, as if it 05363 were the person called. */ 05364 ast_verb(3, "Channel %s connected to parked call %u\n", chan->name, park); 05365 05366 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 05367 ast_cdr_setdestchan(chan->cdr, peer->name); 05368 memset(&config, 0, sizeof(struct ast_bridge_config)); 05369 05370 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 05371 ast_channel_lock(peer); 05372 features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL); 05373 if (features_datastore && (dialfeatures = features_datastore->data)) { 05374 ast_copy_flags(&config.features_callee, &dialfeatures->my_features, 05375 AST_FLAGS_ALL); 05376 } 05377 ast_channel_unlock(peer); 05378 05379 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05380 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 05381 } 05382 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05383 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 05384 } 05385 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05386 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 05387 } 05388 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05389 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 05390 } 05391 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05392 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 05393 } 05394 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05395 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 05396 } 05397 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05398 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 05399 } 05400 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05401 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 05402 } 05403 05404 res = ast_bridge_call(chan, peer, &config); 05405 05406 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 05407 ast_cdr_setdestchan(chan->cdr, peer->name); 05408 05409 /* Simulate the PBX hanging up */ 05410 ast_hangup(peer); 05411 } else { 05412 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05413 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", 05414 chan->name); 05415 } 05416 ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %u\n", 05417 chan->name, park); 05418 res = -1; 05419 } 05420 05421 parkinglot_unref(parkinglot); 05422 return res; 05423 }
static int parkinglot_activate | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 5640 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().
05641 { 05642 int disabled = 0; 05643 char app_data[5 + AST_MAX_CONTEXT]; 05644 05645 /* Create Park option list. Must match with struct park_app_args options. */ 05646 if (parkinglot->cfg.parkext_exclusive) { 05647 /* Specify the parking lot this parking extension parks calls. */ 05648 snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name); 05649 } else { 05650 /* The dialplan must specify which parking lot to use. */ 05651 app_data[0] = '\0'; 05652 } 05653 05654 /* Create context */ 05655 if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) { 05656 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", 05657 parkinglot->cfg.parking_con); 05658 disabled = 1; 05659 05660 /* Add a parking extension into the context */ 05661 } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext, 05662 1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) { 05663 ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n", 05664 parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con); 05665 disabled = 1; 05666 } else { 05667 /* Add parking hints */ 05668 if (parkinglot->cfg.parkaddhints) { 05669 park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start, 05670 parkinglot->cfg.parking_stop); 05671 } 05672 05673 /* 05674 * XXX Not sure why we should need to notify the metermaids for 05675 * this exten. It was originally done for the default parking 05676 * lot entry exten only but should be done for all entry extens 05677 * if we do it for one. 05678 */ 05679 /* Notify metermaids about parking lot entry exten state. */ 05680 notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con, 05681 AST_DEVICE_INUSE); 05682 } 05683 05684 parkinglot->disabled = disabled; 05685 return disabled ? -1 : 0; 05686 }
static int parkinglot_activate_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6689 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().
06690 { 06691 struct ast_parkinglot *parkinglot = obj; 06692 06693 if (parkinglot->the_mark) { 06694 /* 06695 * Don't activate a parking lot that still bears the_mark since 06696 * it is effectively deleted. 06697 */ 06698 return 0; 06699 } 06700 06701 if (parkinglot_activate(parkinglot)) { 06702 /* 06703 * The parking lot failed to activate. Allow reloading later to 06704 * see if that fixes it. 06705 */ 06706 force_reload_load = 1; 06707 ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name); 06708 } else { 06709 ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n", 06710 parkinglot->name, parkinglot->cfg.parking_start, 06711 parkinglot->cfg.parking_stop); 06712 } 06713 06714 return 0; 06715 }
static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static, read] |
Definition at line 5435 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 869 of file features.c.
References CMP_MATCH, CMP_STOP, and ast_parkinglot::name.
Referenced by ast_features_init().
00870 { 00871 struct ast_parkinglot *parkinglot = obj; 00872 struct ast_parkinglot *parkinglot2 = arg; 00873 00874 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0; 00875 }
static int parkinglot_config_read | ( | const char * | pl_name, | |
struct parkinglot_cfg * | cfg, | |||
struct ast_variable * | var | |||
) | [static] |
Definition at line 5546 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(), parkingretalertinfo, parkingretcidname, parkingretdahdiring, parkinglot_cfg::parkingtime, and ast_variable::value.
Referenced by build_parkinglot().
05547 { 05548 int error = 0; 05549 05550 while (var) { 05551 if (!strcasecmp(var->name, "context")) { 05552 ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con)); 05553 } else if (!strcasecmp(var->name, "parkext")) { 05554 ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext)); 05555 } else if (!strcasecmp(var->name, "parkext_exclusive")) { 05556 cfg->parkext_exclusive = ast_true(var->value); 05557 } else if (!strcasecmp(var->name, "parkinghints")) { 05558 cfg->parkaddhints = ast_true(var->value); 05559 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 05560 ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass)); 05561 } else if (!strcasecmp(var->name, "parkingtime")) { 05562 int parkingtime = 0; 05563 05564 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) { 05565 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 05566 error = -1; 05567 } else { 05568 cfg->parkingtime = parkingtime * 1000; 05569 } 05570 } else if (!strcasecmp(var->name, "parkpos")) { 05571 int start = 0; 05572 int end = 0; 05573 05574 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 05575 ast_log(LOG_WARNING, 05576 "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n", 05577 var->lineno, var->file); 05578 error = -1; 05579 } else if (end < start || start <= 0 || end <= 0) { 05580 ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n", 05581 var->lineno, var->file); 05582 error = -1; 05583 } else { 05584 cfg->parking_start = start; 05585 cfg->parking_stop = end; 05586 } 05587 } else if (!strcasecmp(var->name, "findslot")) { 05588 cfg->parkfindnext = (!strcasecmp(var->value, "next")); 05589 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 05590 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var); 05591 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 05592 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var); 05593 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 05594 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var); 05595 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 05596 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var); 05597 } else if (!strcasecmp(var->name, "parkingretcidname")) { 05598 ast_copy_string(parkingretcidname, var->value, sizeof(parkingretcidname)); 05599 } else if (!strcasecmp(var->name, "parkingretdahdiring")) { 05600 ast_copy_string(parkingretdahdiring, var->value, sizeof(parkingretdahdiring)); 05601 } else if (!strcasecmp(var->name, "parkingretalertinfo")) { 05602 ast_copy_string(parkingretalertinfo, var->value, sizeof(parkingretalertinfo)); 05603 } 05604 var = var->next; 05605 } 05606 05607 /* Check for configuration errors */ 05608 if (ast_strlen_zero(cfg->parking_con)) { 05609 ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name); 05610 error = -1; 05611 } 05612 if (ast_strlen_zero(cfg->parkext)) { 05613 ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name); 05614 error = -1; 05615 } 05616 if (!cfg->parking_start) { 05617 ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name); 05618 error = -1; 05619 } 05620 if (error) { 05621 cfg->is_invalid = 1; 05622 } 05623 05624 return error; 05625 }
static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 5445 of file features.c.
References ast_assert, AST_LIST_EMPTY, AST_LIST_HEAD_DESTROY, and ast_parkinglot::parkings.
Referenced by create_parkinglot().
05446 { 05447 struct ast_parkinglot *doomed = obj; 05448 05449 /* 05450 * No need to destroy parked calls here because any parked call 05451 * holds a parking lot reference. Therefore the parkings list 05452 * must be empty. 05453 */ 05454 ast_assert(AST_LIST_EMPTY(&doomed->parkings)); 05455 AST_LIST_HEAD_DESTROY(&doomed->parkings); 05456 }
static void parkinglot_feature_flag_cfg | ( | const char * | pl_name, | |
int * | param, | |||
struct ast_variable * | var | |||
) | [static] |
Definition at line 5523 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().
05524 { 05525 ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value); 05526 if (!strcasecmp(var->value, "both")) { 05527 *param = AST_FEATURE_FLAG_BYBOTH; 05528 } else if (!strcasecmp(var->value, "caller")) { 05529 *param = AST_FEATURE_FLAG_BYCALLER; 05530 } else if (!strcasecmp(var->value, "callee")) { 05531 *param = AST_FEATURE_FLAG_BYCALLEE; 05532 } 05533 }
static int parkinglot_hash_cb | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 862 of file features.c.
References ast_str_case_hash(), and ast_parkinglot::name.
Referenced by ast_features_init().
00863 { 00864 const struct ast_parkinglot *parkinglot = obj; 00865 00866 return ast_str_case_hash(parkinglot->name); 00867 }
static int parkinglot_is_marked_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6669 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().
06670 { 06671 struct ast_parkinglot *parkinglot = obj; 06672 06673 if (parkinglot->the_mark) { 06674 if (AST_LIST_EMPTY(&parkinglot->parkings)) { 06675 /* This parking lot can actually be deleted. */ 06676 return CMP_MATCH; 06677 } 06678 /* Try reloading later when parking lot is empty. */ 06679 ast_log(LOG_WARNING, 06680 "Parking lot %s has parked calls. Could not remove.\n", 06681 parkinglot->name); 06682 parkinglot->disabled = 1; 06683 force_reload_load = 1; 06684 } 06685 06686 return 0; 06687 }
static int parkinglot_markall_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6661 of file features.c.
References ast_parkinglot::the_mark.
Referenced by load_config().
06662 { 06663 struct ast_parkinglot *parkinglot = obj; 06664 06665 parkinglot->the_mark = 1; 06666 return 0; 06667 }
static void parkinglot_unref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Unreference parkinglot object.
Definition at line 5428 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 3854 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
03855 { 03856 struct ast_cdr *cdr_orig = cdr; 03857 while (cdr) { 03858 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 03859 return cdr; 03860 cdr = cdr->next; 03861 } 03862 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 03863 }
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 2078 of file features.c.
References play_message_to_chans().
Referenced by builtin_automonitor().
02079 { 02080 return play_message_to_chans(caller_chan, callee_chan, 0, "automon message", 02081 audiofile); 02082 }
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 2024 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().
02025 { 02026 /* Put other channel in autoservice. */ 02027 if (ast_autoservice_start(other)) { 02028 return -1; 02029 } 02030 ast_autoservice_ignore(other, AST_FRAME_DTMF_BEGIN); 02031 ast_autoservice_ignore(other, AST_FRAME_DTMF_END); 02032 if (ast_stream_and_wait(play_to, audiofile, "")) { 02033 ast_log(LOG_WARNING, "Failed to play %s '%s'!\n", msg, audiofile); 02034 ast_autoservice_stop(other); 02035 return -1; 02036 } 02037 if (ast_autoservice_stop(other)) { 02038 return -1; 02039 } 02040 return 0; 02041 }
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 2059 of file features.c.
References play_message_on_chan().
Referenced by parked_call_exec(), and play_message_in_bridged_call().
02060 { 02061 /* First play the file to the left channel if requested. */ 02062 if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) { 02063 return -1; 02064 } 02065 02066 /* Then play the file to the right channel if requested. */ 02067 if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) { 02068 return -1; 02069 } 02070 02071 return 0; 02072 }
static void post_manager_event | ( | const char * | s, | |
struct parkeduser * | pu | |||
) | [static] |
Output parking event to manager.
Definition at line 4629 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().
04630 { 04631 manager_event(EVENT_FLAG_CALL, s, 04632 "Exten: %s\r\n" 04633 "Channel: %s\r\n" 04634 "Parkinglot: %s\r\n" 04635 "CallerIDNum: %s\r\n" 04636 "CallerIDName: %s\r\n" 04637 "ConnectedLineNum: %s\r\n" 04638 "ConnectedLineName: %s\r\n" 04639 "UniqueID: %s\r\n", 04640 pu->parkingexten, 04641 pu->chan->name, 04642 pu->parkinglot->name, 04643 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 04644 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 04645 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 04646 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 04647 pu->chan->uniqueid 04648 ); 04649 }
static void process_applicationmap_line | ( | struct ast_variable * | var | ) | [static] |
Definition at line 5768 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().
05769 { 05770 char *tmp_val = ast_strdupa(var->value); 05771 char *activateon, *new_syn; 05772 struct ast_call_feature *feature; 05773 AST_DECLARE_APP_ARGS(args, 05774 AST_APP_ARG(exten); 05775 AST_APP_ARG(activatedby); 05776 AST_APP_ARG(app); 05777 AST_APP_ARG(app_args); 05778 AST_APP_ARG(moh_class); 05779 ); 05780 05781 AST_STANDARD_APP_ARGS(args, tmp_val); 05782 05783 activateon = strsep(&args.activatedby, "/"); 05784 05785 if (ast_strlen_zero(args.app) 05786 || ast_strlen_zero(args.exten) 05787 || ast_strlen_zero(activateon) 05788 || ast_strlen_zero(var->name)) { 05789 ast_log(LOG_NOTICE, 05790 "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 05791 args.app, args.exten, activateon, var->name); 05792 return; 05793 } 05794 05795 if ((new_syn = strchr(args.app, '('))) { 05796 /* New syntax */ 05797 args.moh_class = args.app_args; 05798 args.app_args = new_syn; 05799 *args.app_args++ = '\0'; 05800 if (args.app_args[strlen(args.app_args) - 1] == ')') { 05801 args.app_args[strlen(args.app_args) - 1] = '\0'; 05802 } 05803 } 05804 05805 AST_RWLIST_RDLOCK(&feature_list); 05806 if (find_dynamic_feature(var->name)) { 05807 AST_RWLIST_UNLOCK(&feature_list); 05808 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", 05809 var->name); 05810 return; 05811 } 05812 AST_RWLIST_UNLOCK(&feature_list); 05813 05814 if (!(feature = ast_calloc(1, sizeof(*feature)))) { 05815 return; 05816 } 05817 05818 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 05819 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN); 05820 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN); 05821 05822 if (args.app_args) { 05823 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN); 05824 } 05825 05826 if (args.moh_class) { 05827 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN); 05828 } 05829 05830 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten)); 05831 feature->operation = feature_exec_app; 05832 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 05833 05834 /* Allow caller and callee to be specified for backwards compatability */ 05835 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) { 05836 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 05837 } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) { 05838 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 05839 } else { 05840 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 05841 " must be 'self', or 'peer'\n", var->name); 05842 ast_free(feature); 05843 return; 05844 } 05845 05846 if (ast_strlen_zero(args.activatedby)) { 05847 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05848 } else if (!strcasecmp(args.activatedby, "caller")) { 05849 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 05850 } else if (!strcasecmp(args.activatedby, "callee")) { 05851 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 05852 } else if (!strcasecmp(args.activatedby, "both")) { 05853 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05854 } else { 05855 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 05856 " must be 'caller', or 'callee', or 'both'\n", var->name); 05857 ast_free(feature); 05858 return; 05859 } 05860 05861 ast_register_feature(feature); 05862 05863 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", 05864 var->name, args.app, args.app_args, args.exten); 05865 }
static int process_config | ( | struct ast_config * | cfg | ) | [static] |
Definition at line 5867 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().
05868 { 05869 int i; 05870 struct ast_variable *var = NULL; 05871 struct feature_group *fg = NULL; 05872 char *ctg; 05873 static const char * const categories[] = { 05874 /* Categories in features.conf that are not 05875 * to be parsed as group categories 05876 */ 05877 "general", 05878 "featuremap", 05879 "applicationmap" 05880 }; 05881 05882 /* Set general features global defaults. */ 05883 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05884 05885 /* Set global call pickup defaults. */ 05886 strcpy(pickup_ext, "*8"); 05887 pickupsound[0] = '\0'; 05888 pickupfailsound[0] = '\0'; 05889 05890 /* Set global call transfer defaults. */ 05891 strcpy(xfersound, "beep"); 05892 strcpy(xferfailsound, "beeperr"); 05893 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05894 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05895 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05896 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 05897 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05898 05899 /* Set global call parking defaults. */ 05900 comebacktoorigin = 1; 05901 courtesytone[0] = '\0'; 05902 parkedplay = 0; 05903 adsipark = 0; 05904 parkeddynamic = 0; 05905 05906 var = ast_variable_browse(cfg, "general"); 05907 build_parkinglot(DEFAULT_PARKINGLOT, var); 05908 for (; var; var = var->next) { 05909 if (!strcasecmp(var->name, "parkeddynamic")) { 05910 parkeddynamic = ast_true(var->value); 05911 } else if (!strcasecmp(var->name, "adsipark")) { 05912 adsipark = ast_true(var->value); 05913 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 05914 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 05915 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 05916 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05917 } else { 05918 transferdigittimeout = transferdigittimeout * 1000; 05919 } 05920 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 05921 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 05922 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 05923 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05924 } 05925 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 05926 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 05927 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 05928 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05929 } else { 05930 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 05931 } 05932 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 05933 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 05934 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 05935 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05936 } else { 05937 atxferloopdelay *= 1000; 05938 } 05939 } else if (!strcasecmp(var->name, "atxferdropcall")) { 05940 atxferdropcall = ast_true(var->value); 05941 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 05942 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) { 05943 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 05944 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05945 } 05946 } else if (!strcasecmp(var->name, "courtesytone")) { 05947 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 05948 } else if (!strcasecmp(var->name, "parkedplay")) { 05949 if (!strcasecmp(var->value, "both")) { 05950 parkedplay = 2; 05951 } else if (!strcasecmp(var->value, "parked")) { 05952 parkedplay = 1; 05953 } else { 05954 parkedplay = 0; 05955 } 05956 } else if (!strcasecmp(var->name, "xfersound")) { 05957 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 05958 } else if (!strcasecmp(var->name, "xferfailsound")) { 05959 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 05960 } else if (!strcasecmp(var->name, "pickupexten")) { 05961 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 05962 } else if (!strcasecmp(var->name, "pickupsound")) { 05963 ast_copy_string(pickupsound, var->value, sizeof(pickupsound)); 05964 } else if (!strcasecmp(var->name, "pickupfailsound")) { 05965 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound)); 05966 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 05967 comebacktoorigin = ast_true(var->value); 05968 } 05969 } 05970 05971 unmap_features(); 05972 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 05973 if (remap_feature(var->name, var->value)) { 05974 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 05975 } 05976 } 05977 05978 /* Map a key combination to an application */ 05979 ast_unregister_features(); 05980 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 05981 process_applicationmap_line(var); 05982 } 05983 05984 ast_unregister_groups(); 05985 AST_RWLIST_WRLOCK(&feature_groups); 05986 05987 ctg = NULL; 05988 while ((ctg = ast_category_browse(cfg, ctg))) { 05989 /* Is this a parkinglot definition ? */ 05990 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 05991 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 05992 if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) { 05993 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 05994 } else { 05995 ast_debug(1, "Configured parking context %s\n", ctg); 05996 } 05997 continue; 05998 } 05999 06000 /* No, check if it's a group */ 06001 for (i = 0; i < ARRAY_LEN(categories); i++) { 06002 if (!strcasecmp(categories[i], ctg)) { 06003 break; 06004 } 06005 } 06006 if (i < ARRAY_LEN(categories)) { 06007 continue; 06008 } 06009 06010 if (!(fg = register_group(ctg))) { 06011 continue; 06012 } 06013 06014 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 06015 struct ast_call_feature *feature; 06016 06017 AST_RWLIST_RDLOCK(&feature_list); 06018 if (!(feature = find_dynamic_feature(var->name)) && 06019 !(feature = ast_find_call_feature(var->name))) { 06020 AST_RWLIST_UNLOCK(&feature_list); 06021 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 06022 continue; 06023 } 06024 AST_RWLIST_UNLOCK(&feature_list); 06025 06026 register_group_feature(fg, var->value, feature); 06027 } 06028 } 06029 06030 AST_RWLIST_UNLOCK(&feature_groups); 06031 06032 return 0; 06033 }
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 2321 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().
02322 { 02323 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 02324 if (ast_strlen_zero(s)) { 02325 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 02326 } 02327 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 02328 s = transferer->macrocontext; 02329 } 02330 if (ast_strlen_zero(s)) { 02331 s = transferer->context; 02332 } 02333 return s; 02334 }
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 3015 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().
03016 { 03017 struct feature_group *fg; 03018 03019 if (!fgname) { 03020 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 03021 return NULL; 03022 } 03023 03024 if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) { 03025 return NULL; 03026 } 03027 03028 ast_string_field_set(fg, gname, fgname); 03029 03030 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 03031 03032 ast_verb(2, "Registered group '%s'\n", fg->gname); 03033 03034 return fg; 03035 }
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 3046 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().
03047 { 03048 struct feature_group_exten *fge; 03049 03050 if (!fg) { 03051 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 03052 return; 03053 } 03054 03055 if (!feature) { 03056 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 03057 return; 03058 } 03059 03060 if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) { 03061 return; 03062 } 03063 03064 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 03065 03066 fge->feature = feature; 03067 03068 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 03069 03070 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 03071 feature->sname, fg->gname, fge->exten); 03072 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 3258 of file features.c.
References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, FEATURES_COUNT, and features_lock.
Referenced by process_config().
03259 { 03260 int x, res = -1; 03261 03262 ast_rwlock_wrlock(&features_lock); 03263 for (x = 0; x < FEATURES_COUNT; x++) { 03264 if (strcasecmp(builtin_features[x].sname, name)) 03265 continue; 03266 03267 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 03268 res = 0; 03269 break; 03270 } 03271 ast_rwlock_unlock(&features_lock); 03272 03273 return res; 03274 }
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 6594 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().
06595 { 06596 remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens); 06597 remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space); 06598 #if 0 06599 /* I don't think we should destroy hints if the parking space still exists. */ 06600 remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint); 06601 #endif 06602 }
static void remove_dead_dialplan_useage | ( | struct parking_dp_map * | old_map, | |
struct parking_dp_map * | new_map | |||
) | [static] |
Definition at line 6617 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().
06618 { 06619 struct parking_dp_context *old_ctx; 06620 struct parking_dp_context *new_ctx; 06621 struct ast_context *con; 06622 int cmp; 06623 06624 old_ctx = AST_LIST_FIRST(old_map); 06625 new_ctx = AST_LIST_FIRST(new_map); 06626 06627 while (new_ctx) { 06628 if (!old_ctx) { 06629 /* No old contexts left, so no dead stuff can remain. */ 06630 return; 06631 } 06632 cmp = strcmp(old_ctx->context, new_ctx->context); 06633 if (cmp < 0) { 06634 /* New map does not have old map context. */ 06635 con = ast_context_find(old_ctx->context); 06636 if (con) { 06637 ast_context_destroy(con, registrar); 06638 } 06639 old_ctx = AST_LIST_NEXT(old_ctx, node); 06640 continue; 06641 } 06642 if (cmp == 0) { 06643 /* Old and new map have this context. */ 06644 remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx); 06645 old_ctx = AST_LIST_NEXT(old_ctx, node); 06646 } else { 06647 /* Old map does not have new map context. */ 06648 } 06649 new_ctx = AST_LIST_NEXT(new_ctx, node); 06650 } 06651 06652 /* Any old contexts left must be dead. */ 06653 for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) { 06654 con = ast_context_find(old_ctx->context); 06655 if (con) { 06656 ast_context_destroy(con, registrar); 06657 } 06658 } 06659 }
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 6453 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().
06454 { 06455 struct parking_dp_ramp *old_ramp; 06456 struct parking_dp_ramp *new_ramp; 06457 int cmp; 06458 06459 old_ramp = AST_LIST_FIRST(old_ramps); 06460 new_ramp = AST_LIST_FIRST(new_ramps); 06461 06462 while (new_ramp) { 06463 if (!old_ramp) { 06464 /* No old ramps left, so no dead ramps can remain. */ 06465 return; 06466 } 06467 cmp = strcmp(old_ramp->exten, new_ramp->exten); 06468 if (cmp < 0) { 06469 /* New map does not have old ramp. */ 06470 remove_exten_if_exist(context, old_ramp->exten, 1); 06471 old_ramp = AST_LIST_NEXT(old_ramp, node); 06472 continue; 06473 } 06474 if (cmp == 0) { 06475 /* Old and new map have this ramp. */ 06476 old_ramp = AST_LIST_NEXT(old_ramp, node); 06477 } else { 06478 /* Old map does not have new ramp. */ 06479 } 06480 new_ramp = AST_LIST_NEXT(new_ramp, node); 06481 } 06482 06483 /* Any old ramps left must be dead. */ 06484 for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) { 06485 remove_exten_if_exist(context, old_ramp->exten, 1); 06486 } 06487 }
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 6523 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().
06526 { 06527 struct parking_dp_spaces *old_range; 06528 struct parking_dp_spaces *new_range; 06529 int space;/*!< Current position in the current old range. */ 06530 int stop; 06531 06532 old_range = AST_LIST_FIRST(old_spaces); 06533 new_range = AST_LIST_FIRST(new_spaces); 06534 space = -1; 06535 06536 while (old_range) { 06537 if (space < old_range->start) { 06538 space = old_range->start; 06539 } 06540 if (new_range) { 06541 if (space < new_range->start) { 06542 /* Current position in old range starts before new range. */ 06543 if (old_range->stop < new_range->start) { 06544 /* Old range ends before new range. */ 06545 stop = old_range->stop; 06546 old_range = AST_LIST_NEXT(old_range, node); 06547 } else { 06548 /* Tail of old range overlaps new range. */ 06549 stop = new_range->start - 1; 06550 } 06551 } else if (/* new_range->start <= space && */ space <= new_range->stop) { 06552 /* Current position in old range overlaps new range. */ 06553 if (old_range->stop <= new_range->stop) { 06554 /* Old range ends at or before new range. */ 06555 old_range = AST_LIST_NEXT(old_range, node); 06556 } else { 06557 /* Old range extends beyond end of new range. */ 06558 space = new_range->stop + 1; 06559 new_range = AST_LIST_NEXT(new_range, node); 06560 } 06561 continue; 06562 } else /* if (new_range->stop < space) */ { 06563 /* Current position in old range starts after new range. */ 06564 new_range = AST_LIST_NEXT(new_range, node); 06565 continue; 06566 } 06567 } else { 06568 /* No more new ranges. All remaining old spaces are dead. */ 06569 stop = old_range->stop; 06570 old_range = AST_LIST_NEXT(old_range, node); 06571 } 06572 06573 /* Destroy dead parking spaces. */ 06574 for (; space <= stop; ++space) { 06575 destroy_space(context, space); 06576 } 06577 } 06578 }
static void remove_exten_if_exist | ( | const char * | context, | |
const char * | exten, | |||
int | priority | |||
) | [static] |
Definition at line 6427 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().
06428 { 06429 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 06430 06431 if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL, 06432 E_MATCH)) { 06433 ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n", 06434 context, exten, priority); 06435 ast_context_remove_extension(context, exten, priority, registrar); 06436 } 06437 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 3865 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().
03866 { 03867 const char *feature; 03868 03869 if (ast_strlen_zero(features)) { 03870 return; 03871 } 03872 03873 for (feature = features; *feature; feature++) { 03874 switch (*feature) { 03875 case 'T' : 03876 case 't' : 03877 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 03878 break; 03879 case 'K' : 03880 case 'k' : 03881 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 03882 break; 03883 case 'H' : 03884 case 'h' : 03885 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 03886 break; 03887 case 'W' : 03888 case 'w' : 03889 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 03890 break; 03891 default : 03892 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 03893 } 03894 } 03895 }
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 881 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().
00882 { 00883 ast_copy_string(chan->context, context, sizeof(chan->context)); 00884 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00885 chan->priority = pri; 00886 }
static int set_chan_app_data | ( | struct ast_channel * | chan, | |
const char * | src_app_data | |||
) | [static] |
Definition at line 957 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().
00958 { 00959 struct ast_datastore *datastore; 00960 char *dst_app_data; 00961 00962 datastore = ast_datastore_alloc(&channel_app_data_datastore, NULL); 00963 if (!datastore) { 00964 return -1; 00965 } 00966 00967 dst_app_data = ast_malloc(strlen(src_app_data) + 1); 00968 if (!dst_app_data) { 00969 ast_datastore_free(datastore); 00970 return -1; 00971 } 00972 00973 chan->data = strcpy(dst_app_data, src_app_data); 00974 datastore->data = dst_app_data; 00975 ast_channel_datastore_add(chan, datastore); 00976 return 0; 00977 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 3449 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().
03450 { 03451 int x; 03452 03453 ast_clear_flag(config, AST_FLAGS_ALL); 03454 03455 ast_rwlock_rdlock(&features_lock); 03456 for (x = 0; x < FEATURES_COUNT; x++) { 03457 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 03458 continue; 03459 03460 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 03461 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03462 03463 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 03464 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03465 } 03466 ast_rwlock_unlock(&features_lock); 03467 03468 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 03469 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 03470 03471 if (dynamic_features) { 03472 char *tmp = ast_strdupa(dynamic_features); 03473 char *tok; 03474 struct ast_call_feature *feature; 03475 03476 /* while we have a feature */ 03477 while ((tok = strsep(&tmp, "#"))) { 03478 struct feature_group *fg; 03479 03480 AST_RWLIST_RDLOCK(&feature_groups); 03481 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 03482 struct feature_group_exten *fge; 03483 03484 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03485 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) { 03486 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03487 } 03488 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) { 03489 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03490 } 03491 } 03492 } 03493 AST_RWLIST_UNLOCK(&feature_groups); 03494 03495 AST_RWLIST_RDLOCK(&feature_list); 03496 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 03497 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) { 03498 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03499 } 03500 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) { 03501 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03502 } 03503 } 03504 AST_RWLIST_UNLOCK(&feature_list); 03505 } 03506 } 03507 } 03508 }
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 1951 of file features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
01953 { 01954 if (sense == FEATURE_SENSE_PEER) { 01955 *caller = peer; 01956 *callee = chan; 01957 } else { 01958 *callee = peer; 01959 *caller = chan; 01960 } 01961 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 3248 of file features.c.
References ast_rwlock_unlock, ast_rwlock_wrlock, FEATURES_COUNT, and features_lock.
Referenced by process_config().
03249 { 03250 int x; 03251 03252 ast_rwlock_wrlock(&features_lock); 03253 for (x = 0; x < FEATURES_COUNT; x++) 03254 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 03255 ast_rwlock_unlock(&features_lock); 03256 }
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 6113 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().
06114 { 06115 struct parking_dp_ramp *cur_ramp; 06116 struct parking_dp_ramp *new_ramp; 06117 int cmp; 06118 06119 /* Make sure that exclusive is only 0 or 1 */ 06120 if (exclusive) { 06121 exclusive = 1; 06122 } 06123 06124 AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) { 06125 cmp = strcmp(exten, cur_ramp->exten); 06126 if (cmp > 0) { 06127 /* The parking lot ramp goes after this node. */ 06128 continue; 06129 } 06130 if (cmp == 0) { 06131 /* The ramp is already in the map. */ 06132 if (complain && (cur_ramp->exclusive || exclusive)) { 06133 ast_log(LOG_WARNING, 06134 "Parking lot '%s' parkext %s@%s used by another parking lot.\n", 06135 lot->name, exten, lot->cfg.parking_con); 06136 } 06137 return 0; 06138 } 06139 /* The new parking lot ramp goes before this node. */ 06140 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 06141 if (!new_ramp) { 06142 return -1; 06143 } 06144 AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node); 06145 return 0; 06146 } 06147 AST_LIST_TRAVERSE_SAFE_END; 06148 06149 /* New parking lot access ramp goes on the end. */ 06150 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 06151 if (!new_ramp) { 06152 return -1; 06153 } 06154 AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node); 06155 return 0; 06156 }
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 6194 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().
06195 { 06196 struct parking_dp_spaces *cur_node; 06197 struct parking_dp_spaces *expand_node; 06198 struct parking_dp_spaces *new_node; 06199 06200 expand_node = NULL; 06201 AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) { 06202 /* NOTE: stop + 1 to combine immediately adjacent nodes into one. */ 06203 if (expand_node) { 06204 /* The previous node is expanding to possibly eat following nodes. */ 06205 if (expand_node->stop + 1 < cur_node->start) { 06206 /* Current node is completely after expanding node. */ 06207 return 0; 06208 } 06209 06210 if (complain 06211 && ((cur_node->start <= start && start <= cur_node->stop) 06212 || (cur_node->start <= stop && stop <= cur_node->stop) 06213 || (start < cur_node->start && cur_node->stop < stop))) { 06214 /* Only complain once per range add. */ 06215 complain = 0; 06216 ast_log(LOG_WARNING, 06217 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06218 lot->name, start, stop, lot->cfg.parking_con); 06219 } 06220 06221 /* Current node is eaten by the expanding node. */ 06222 if (expand_node->stop < cur_node->stop) { 06223 expand_node->stop = cur_node->stop; 06224 } 06225 AST_LIST_REMOVE_CURRENT(node); 06226 ast_free(cur_node); 06227 continue; 06228 } 06229 06230 if (cur_node->stop + 1 < start) { 06231 /* New range is completely after current node. */ 06232 continue; 06233 } 06234 if (stop + 1 < cur_node->start) { 06235 /* New range is completely before current node. */ 06236 new_node = build_dialplan_useage_spaces(start, stop); 06237 if (!new_node) { 06238 return -1; 06239 } 06240 AST_LIST_INSERT_BEFORE_CURRENT(new_node, node); 06241 return 0; 06242 } 06243 06244 if (complain 06245 && ((cur_node->start <= start && start <= cur_node->stop) 06246 || (cur_node->start <= stop && stop <= cur_node->stop) 06247 || (start < cur_node->start && cur_node->stop < stop))) { 06248 /* Only complain once per range add. */ 06249 complain = 0; 06250 ast_log(LOG_WARNING, 06251 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06252 lot->name, start, stop, lot->cfg.parking_con); 06253 } 06254 06255 /* Current node range overlaps or is immediately adjacent to new range. */ 06256 if (start < cur_node->start) { 06257 /* Expand the current node in the front. */ 06258 cur_node->start = start; 06259 } 06260 if (stop <= cur_node->stop) { 06261 /* Current node is not expanding in the rear. */ 06262 return 0; 06263 } 06264 cur_node->stop = stop; 06265 expand_node = cur_node; 06266 } 06267 AST_LIST_TRAVERSE_SAFE_END; 06268 06269 if (expand_node) { 06270 /* 06271 * The previous node expanded and either ate all following nodes 06272 * or it was the last node. 06273 */ 06274 return 0; 06275 } 06276 06277 /* New range goes on the end. */ 06278 new_node = build_dialplan_useage_spaces(start, stop); 06279 if (!new_node) { 06280 return -1; 06281 } 06282 AST_LIST_INSERT_TAIL(space_map, new_node, node); 06283 return 0; 06284 }
static int xfer_park_call_helper | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
struct ast_exten * | park_exten | |||
) | [static] |
Definition at line 1891 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().
01892 { 01893 char *parse; 01894 const char *app_data; 01895 const char *pl_name; 01896 struct ast_park_call_args args = { 0, }; 01897 struct park_app_args app_args; 01898 int res; 01899 01900 app_data = ast_get_extension_app_data(park_exten); 01901 if (!app_data) { 01902 app_data = ""; 01903 } 01904 parse = ast_strdupa(app_data); 01905 AST_STANDARD_APP_ARGS(app_args, parse); 01906 01907 /* Find the parking lot */ 01908 if (!ast_strlen_zero(app_args.pl_name)) { 01909 pl_name = app_args.pl_name; 01910 } else { 01911 pl_name = findparkinglotname(parker); 01912 } 01913 if (ast_strlen_zero(pl_name)) { 01914 /* Parking lot is not specified, so use the default parking lot. */ 01915 args.parkinglot = parkinglot_addref(default_parkinglot); 01916 } else { 01917 args.parkinglot = find_parkinglot(pl_name); 01918 if (!args.parkinglot && parkeddynamic) { 01919 args.parkinglot = create_dynamic_parkinglot(pl_name, park_me); 01920 } 01921 } 01922 01923 if (args.parkinglot) { 01924 /* Park the call */ 01925 res = finishup(park_me); 01926 if (res) { 01927 /* park_me hungup on us. */ 01928 parkinglot_unref(args.parkinglot); 01929 return -1; 01930 } 01931 res = masq_park_call(park_me, parker, &args); 01932 parkinglot_unref(args.parkinglot); 01933 } else { 01934 /* Parking failed because parking lot does not exist. */ 01935 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { 01936 ast_stream_and_wait(parker, "pbx-parkingfailed", ""); 01937 } 01938 finishup(park_me); 01939 res = -1; 01940 } 01941 01942 return res ? AST_FEATURE_RETURN_SUCCESS : -1; 01943 }
int adsipark [static] |
Definition at line 612 of file features.c.
Referenced by park_call_full(), and process_config().
char* app_bridge = "Bridge" [static] |
Definition at line 7493 of file features.c.
unsigned int atxfercallbackretries [static] |
Definition at line 621 of file features.c.
Referenced by builtin_atxfer(), and process_config().
unsigned int atxferdropcall [static] |
Definition at line 619 of file features.c.
Referenced by builtin_atxfer(), and process_config().
unsigned int atxferloopdelay [static] |
Definition at line 620 of file features.c.
Referenced by builtin_atxfer(), and process_config().
int atxfernoanswertimeout [static] |
Definition at line 618 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 7530 of file features.c.
Referenced by bridge_exec().
struct ast_call_feature builtin_features[] [static] |
Definition at line 2981 of file features.c.
struct ast_datastore_info channel_app_data_datastore [static] |
{ .type = "Channel appdata datastore", .destroy = ast_free_ptr, }
Definition at line 952 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 7165 of file features.c.
int comebacktoorigin = 1 [static] |
Definition at line 616 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 752 of file features.c.
Referenced by add_features_datastore(), builtin_atxfer(), manage_parked_call(), and parked_call_exec().
int featuredigittimeout [static] |
Definition at line 615 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 2979 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 610 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 642 of file features.c.
Referenced by builtin_automixmonitor().
int mixmonitor_ok = 1 [static] |
Definition at line 643 of file features.c.
Referenced by builtin_automixmonitor().
struct ast_app* monitor_app = NULL [static] |
Definition at line 639 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 640 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 5060 of file features.c.
Referenced by park_call_exec().
const char* parkcall = "Park" [static] |
Definition at line 637 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 607 of file features.c.
Referenced by ast_features_reload(), and manage_parked_call().
pthread_t parking_thread [static] |
Definition at line 648 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 5508 of file features.c.
struct parkinglot_cfg parkinglot_cfg_default_default [static] |
Default configuration for default parking lot.
Definition at line 5498 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().
char parkingretalertinfo[256] [static] |
Distinctive ring if chantech = SIP (adds a SIP AlertInfo header)
Definition at line 597 of file features.c.
Referenced by manage_parked_call(), and parkinglot_config_read().
char parkingretcidname[256] [static] |
Callerid name of returned parked call
Definition at line 595 of file features.c.
Referenced by manage_parked_call(), and parkinglot_config_read().
char parkingretdahdiring[3] [static] |
Distinctive ring if chantech = DAHDI
Definition at line 596 of file features.c.
Referenced by manage_parked_call(), and parkinglot_config_read().
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 7334 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 623 of file features.c.
Referenced by ast_features_reload(), features_shutdown(), manage_parked_call(), park_add_hints(), park_call_full(), parkinglot_activate(), remove_dead_dialplan_useage(), and remove_exten_if_exist().
struct ast_app* stopmixmonitor_app = NULL [static] |
Definition at line 645 of file features.c.
Referenced by builtin_automixmonitor().
int stopmixmonitor_ok = 1 [static] |
Definition at line 646 of file features.c.
Referenced by builtin_automixmonitor().
int transferdigittimeout [static] |
Definition at line 614 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().