#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"
#include "asterisk/astobj2.h"
#include "asterisk/cel.h"
#include "asterisk/test.h"

Go to the source code of this file.
Data Structures | |
| struct | ast_bridge_thread_obj |
| struct | ast_dial_features |
| struct | ast_park_call_args |
| struct | ast_parkinglot |
| Structure for parking lots which are put in a container. More... | |
| struct | ast_parkinglot::parkinglot_parklist |
| struct | feature_group |
| struct | feature_group_exten |
| struct | feature_groups |
| struct | feature_list |
| struct | park_app_args |
| struct | parkeduser |
| Description of one parked call, added to a list while active, then removed. The list belongs to a parkinglot. More... | |
| struct | parking_dp_context |
| struct | parking_dp_map |
| struct | parking_dp_ramp |
| struct | parking_dp_ramp_map |
| struct | parking_dp_space_map |
| struct | parking_dp_spaces |
| struct | parkinglot_cfg |
Defines | |
| #define | AST_MAX_WATCHERS 256 |
| #define | DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
| #define | DEFAULT_ATXFER_DROP_CALL 0 |
| #define | DEFAULT_ATXFER_LOOP_DELAY 10000 |
| #define | DEFAULT_COMEBACK_CONTEXT "parkedcallstimeout" |
| #define | DEFAULT_COMEBACK_DIAL_TIME 30 |
| #define | DEFAULT_COMEBACK_TO_ORIGIN 1 |
| #define | DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
| #define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
| #define | DEFAULT_PARK_EXTENSION "700" |
| #define | DEFAULT_PARK_TIME 45000 |
| #define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
| #define | FEATURES_COUNT ARRAY_LEN(builtin_features) |
| #define | HFS_FORMAT "%-25s %-7s %-7s\n" |
| #define | MAX_DIAL_FEATURE_OPTIONS 30 |
Enumerations | |
| enum | { BRIDGE_OPT_PLAYTONE = (1 << 0), OPT_CALLEE_HANGUP = (1 << 1), OPT_CALLER_HANGUP = (1 << 2), OPT_DURATION_LIMIT = (1 << 3), OPT_DURATION_STOP = (1 << 4), OPT_CALLEE_TRANSFER = (1 << 5), OPT_CALLER_TRANSFER = (1 << 6), OPT_CALLEE_MONITOR = (1 << 7), OPT_CALLER_MONITOR = (1 << 8), OPT_CALLEE_PARK = (1 << 9), OPT_CALLER_PARK = (1 << 10), OPT_CALLEE_KILL = (1 << 11) } |
| 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 void | __fini_feature_groups (void) |
| static void | __fini_feature_list (void) |
| static void | __init_feature_groups (void) |
| static void | __init_feature_list (void) |
| static int | action_bridge (struct mansession *s, const struct message *m) |
| Bridge channels together. | |
| static void | add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config) |
| static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
| Announce call parking by ADSI. | |
| int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
| bridge the call and set CDR | |
| int | ast_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit) |
| parse L option and read associated channel variables to set warning, warning frequency, and timelimit | |
| int | ast_can_pickup (struct ast_channel *chan) |
| Test if a channel can be picked up. | |
| void | ast_channel_log (char *title, struct ast_channel *chan) |
| int | ast_do_pickup (struct ast_channel *chan, struct ast_channel *target) |
| Pickup a call target. | |
| int | ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) |
| detect a feature before bridging | |
| int | ast_features_init (void) |
| int | ast_features_reload (void) |
| Reload call features from features.conf. | |
| struct ast_call_feature * | ast_find_call_feature (const char *name) |
| look for a call feature entry by its sname | |
| int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
| Park a call via a masqueraded channel. | |
| int | ast_masq_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout) |
| Park a call via a masqueraded channel. | |
| int | ast_park_call (struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout) |
| Park a call and read back parked location. | |
| int | ast_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout) |
| Park a call and read back parked location. | |
| int | ast_parking_ext_valid (const char *exten_str, struct ast_channel *chan, const char *context) |
| Determine if parking extension exists in a given context. | |
| int | ast_pickup_call (struct ast_channel *chan) |
| Pickup a call. | |
| const char * | ast_pickup_ext (void) |
| Determine system call pickup extension. | |
| 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 (void *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 void | 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, struct ast_format_cap *cap, const char *addr, int timeout, int *outstate, const char *language) |
| static int | find_channel_by_group (void *obj, void *arg, void *data, int flags) |
| static struct ast_call_feature * | find_dynamic_feature (const char *name) |
| find a call feature by name | |
| static struct feature_group * | find_group (const char *name) |
| Find a group by name. | |
| static struct ast_parkinglot * | find_parkinglot (const char *name) |
| Find parkinglot by name. | |
| static const char * | findparkinglotname (struct ast_channel *chan) |
| Find parking lot name from channel. | |
| static int | finishup (struct ast_channel *chan) |
| static struct ast_exten * | get_parking_exten (const char *exten_str, struct ast_channel *chan, const char *context) |
| static char * | handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI command to list configured features. | |
| static char * | handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI command to list parked calls. | |
| static int | load_config (int reload) |
| static int | manage_parked_call (struct parkeduser *pu, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms) |
| static void | manage_parkinglot (struct ast_parkinglot *curlot, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms) |
| Run management on parkinglots, called once per parkinglot. | |
| static int | manager_park (struct mansession *s, const struct message *m) |
| Create manager event for parked calls. | |
| static int | manager_parking_status (struct mansession *s, const struct message *m) |
| Dump parking lot status. | |
| static int | masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args) |
| Park call via masqueraded channel and announce parking spot on peer channel. | |
| static enum ast_device_state | metermaidstate (const char *data) |
| metermaids callback from devicestate.c | |
| static void | notify_metermaids (const char *exten, char *context, enum ast_device_state state) |
| Notify metermaids that we've changed an extension. | |
| static void | park_add_hints (const char *context, int start, int stop) |
| Add parking hints for all defined parking spaces. | |
| static int | park_call_exec (struct ast_channel *chan, const char *data) |
| Park a call. | |
| static int | park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) |
| static void | park_space_abort (struct parkeduser *pu) |
| static struct parkeduser * | park_space_reserve (struct ast_channel *park_me, struct ast_channel *parker, struct ast_park_call_args *args) |
| static int | parked_call_exec (struct ast_channel *chan, const char *data) |
| Pickup parked call. | |
| static int | parkinglot_activate (struct ast_parkinglot *parkinglot) |
| static int | parkinglot_activate_cb (void *obj, void *arg, int flags) |
| static struct ast_parkinglot * | parkinglot_addref (struct ast_parkinglot *parkinglot) |
| static int | parkinglot_cmp_cb (void *obj, void *arg, int flags) |
| static int | parkinglot_config_read (const char *pl_name, struct parkinglot_cfg *cfg, struct ast_variable *var) |
| static void | parkinglot_destroy (void *obj) |
| Destroy a parking lot. | |
| static void | parkinglot_feature_flag_cfg (const char *pl_name, int *param, struct ast_variable *var) |
| static int | parkinglot_hash_cb (const void *obj, const int flags) |
| static int | parkinglot_is_marked_cb (void *obj, void *arg, int flags) |
| static int | parkinglot_markall_cb (void *obj, void *arg, int flags) |
| static void | parkinglot_unref (struct ast_parkinglot *parkinglot) |
| Unreference parkinglot object. | |
| static struct ast_cdr * | pick_unlocked_cdr (struct ast_cdr *cdr) |
| return the first unlocked cdr in a possible chain | |
| static int | play_message_in_bridged_call (struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile) |
| Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages. | |
| static int | play_message_on_chan (struct ast_channel *play_to, struct ast_channel *other, const char *msg, const char *audiofile) |
| static int | play_message_to_chans (struct ast_channel *left, struct ast_channel *right, int which, const char *msg, const char *audiofile) |
| static void | post_manager_event (const char *s, struct parkeduser *pu) |
| Output parking event to manager. | |
| static void | process_applicationmap_line (struct ast_variable *var) |
| static int | process_config (struct ast_config *cfg) |
| static const char * | real_ctx (struct ast_channel *transferer, struct ast_channel *transferee) |
| Find the context for the transfer. | |
| static struct feature_group * | register_group (const char *fgname) |
| Add new feature group. | |
| static void | register_group_feature (struct feature_group *fg, const char *exten, struct ast_call_feature *feature) |
| Add feature to group. | |
| static int | remap_feature (const char *name, const char *value) |
| static void | remove_dead_context_usage (const char *context, struct parking_dp_context *old_ctx, struct parking_dp_context *new_ctx) |
| static void | remove_dead_dialplan_useage (struct parking_dp_map *old_map, struct parking_dp_map *new_map) |
| static void | remove_dead_ramp_usage (const char *context, struct parking_dp_ramp_map *old_ramps, struct parking_dp_ramp_map *new_ramps) |
| static void | remove_dead_spaces_usage (const char *context, struct parking_dp_space_map *old_spaces, struct parking_dp_space_map *new_spaces, void(*destroy_space)(const char *context, int space)) |
| static void | remove_exten_if_exist (const char *context, const char *exten, int priority) |
| static void | set_bridge_features_on_config (struct ast_bridge_config *config, const char *features) |
| static void | set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri) |
| store context, extension and priority | |
| static void | set_config_flags (struct ast_channel *chan, struct ast_bridge_config *config) |
| static void | set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense) |
| set caller and callee according to the direction | |
| static void | unmap_features (void) |
| static int | usage_context_add_ramp (struct parking_dp_ramp_map *ramp_map, const char *exten, int exclusive, struct ast_parkinglot *lot, int complain) |
| static int | usage_context_add_spaces (struct parking_dp_space_map *space_map, int start, int stop, struct ast_parkinglot *lot, int complain) |
| static int | xfer_park_call_helper (struct ast_channel *park_me, struct ast_channel *parker, struct ast_exten *park_exten) |
Variables | |
| static int | adsipark |
| static char * | app_bridge = "Bridge" |
| static unsigned int | atxfercallbackretries |
| static unsigned int | atxferdropcall |
| static unsigned int | atxferloopdelay |
| static int | atxfernoanswertimeout |
| static struct ast_app_option | bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ '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_cli_entry | cli_features [] |
| static char | courtesytone [256] |
| static struct ast_parkinglot * | default_parkinglot |
| Default parking lot. | |
| static struct ast_datastore_info | dial_features_info |
| static int | featuredigittimeout |
| static ast_rwlock_t | features_lock = { {0} , NULL, 1 } |
| static ast_mutex_t | features_reload_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } |
| static int | force_reload_load |
| static struct ast_app * | mixmonitor_app = NULL |
| static int | mixmonitor_ok = 1 |
| static struct ast_app * | monitor_app = NULL |
| static int | monitor_ok = 1 |
| static struct ast_app_option | park_call_options [128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } |
| static const char * | parkcall = "Park" |
| static const char * | parkedcall = "ParkedCall" |
| static int | parkeddynamic = 0 |
| static int | parkedplay = 0 |
| static char | parking_con_dial [] = "park-dial" |
| Context for parking dialback to parker. | |
| static pthread_t | parking_thread |
| static struct parkinglot_cfg | parkinglot_cfg_default |
| static struct parkinglot_cfg | parkinglot_cfg_default_default |
| static struct ao2_container * | parkinglots |
| The configured parking lots container. Always at least one - the default parking lot. | |
| static struct ast_datastore_info | pickup_active |
| static char | pickup_ext [AST_MAX_EXTENSION] |
| static char | pickupfailsound [256] |
| static char | pickupsound [256] |
| static char * | registrar = "features" |
| static struct ast_app * | stopmixmonitor_app = NULL |
| static int | stopmixmonitor_ok = 1 |
| static int | transferdigittimeout |
| static char | xferfailsound [256] |
| static char | xfersound [256] |
Definition in file features.c.
| #define AST_MAX_WATCHERS 256 |
Definition at line 395 of file features.c.
| #define DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
| #define DEFAULT_ATXFER_DROP_CALL 0 |
| #define DEFAULT_ATXFER_LOOP_DELAY 10000 |
| #define DEFAULT_COMEBACK_CONTEXT "parkedcallstimeout" |
Definition at line 391 of file features.c.
| #define DEFAULT_COMEBACK_DIAL_TIME 30 |
| #define DEFAULT_COMEBACK_TO_ORIGIN 1 |
Definition at line 392 of file features.c.
| #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
| #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
| #define DEFAULT_PARK_EXTENSION "700" |
Definition at line 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 2836 of file features.c.
Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
| #define HFS_FORMAT "%-25s %-7s %-7s\n" |
Referenced by handle_feature_show().
| #define MAX_DIAL_FEATURE_OPTIONS 30 |
| anonymous enum |
Definition at line 7353 of file features.c.
07353 { 07354 BRIDGE_OPT_PLAYTONE = (1 << 0), 07355 OPT_CALLEE_HANGUP = (1 << 1), 07356 OPT_CALLER_HANGUP = (1 << 2), 07357 OPT_DURATION_LIMIT = (1 << 3), 07358 OPT_DURATION_STOP = (1 << 4), 07359 OPT_CALLEE_TRANSFER = (1 << 5), 07360 OPT_CALLER_TRANSFER = (1 << 6), 07361 OPT_CALLEE_MONITOR = (1 << 7), 07362 OPT_CALLER_MONITOR = (1 << 8), 07363 OPT_CALLEE_PARK = (1 << 9), 07364 OPT_CALLER_PARK = (1 << 10), 07365 OPT_CALLEE_KILL = (1 << 11), 07366 };
| anonymous enum |
Definition at line 7368 of file features.c.
07368 { 07369 OPT_ARG_DURATION_LIMIT = 0, 07370 OPT_ARG_DURATION_STOP, 07371 /* note: this entry _MUST_ be the last one in the enum */ 07372 OPT_ARG_ARRAY_SIZE, 07373 };
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 1043 of file features.c.
01043 { 01044 /*! Provide ringing to the parked caller instead of music on hold */ 01045 AST_PARK_OPT_RINGING = (1 << 0), 01046 /*! Randomly choose a parking spot for the caller instead of choosing 01047 * the first one that is available. */ 01048 AST_PARK_OPT_RANDOMIZE = (1 << 1), 01049 /*! Do not announce the parking number */ 01050 AST_PARK_OPT_SILENCE = (1 << 2), 01051 };
| enum feature_interpret_op |
Definition at line 416 of file features.c.
00416 { 00417 FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */ 00418 FEATURE_INTERPRET_DO, /* Used by feature_interpret */ 00419 FEATURE_INTERPRET_CHECK, /* Used by feature_check */ 00420 } feature_interpret_op;
| static void __fini_feature_groups | ( | void | ) | [static] |
| static void __fini_feature_list | ( | void | ) | [static] |
| static void __init_feature_groups | ( | void | ) | [static] |
| static void __init_feature_list | ( | void | ) | [static] |
| static int action_bridge | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Bridge channels together.
| s | ||
| m | Make sure valid channels were specified, send errors if any of the channels could not be found/locked, answer channels if needed, create the placeholder channels and grab the other channels make the channels compatible, send error if we fail doing so setup the bridge thread object and start the bridge. |
| 0 | on success or on incorrect use. | |
| 1 | on failure to bridge channels. |
Definition at line 6843 of file features.c.
References ast_channel::_state, ast_answer(), ast_calloc, ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_language(), ast_channel_linkedid(), ast_channel_make_compatible(), ast_channel_name(), ast_channel_unref, ast_hangup(), ast_log(), ast_manager_event_multichan, AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), bridge_call_thread_launch(), ast_bridge_thread_obj::chan, do_bridge_masquerade(), errno, EVENT_FLAG_CALL, LOG_WARNING, ast_bridge_thread_obj::peer, playtone(), ast_bridge_thread_obj::return_to_pbx, and xfersound.
Referenced by ast_features_init().
06844 { 06845 const char *channela = astman_get_header(m, "Channel1"); 06846 const char *channelb = astman_get_header(m, "Channel2"); 06847 const char *playtone = astman_get_header(m, "Tone"); 06848 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2]; 06849 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 06850 struct ast_bridge_thread_obj *tobj = NULL; 06851 06852 /* make sure valid channels were specified */ 06853 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 06854 astman_send_error(s, m, "Missing channel parameter in request"); 06855 return 0; 06856 } 06857 06858 /* Start with chana */ 06859 chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); 06860 06861 /* send errors if any of the channels could not be found/locked */ 06862 if (!chana) { 06863 char buf[256]; 06864 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 06865 astman_send_error(s, m, buf); 06866 return 0; 06867 } 06868 06869 /* Answer the channels if needed */ 06870 if (chana->_state != AST_STATE_UP) 06871 ast_answer(chana); 06872 06873 /* create the placeholder channels and grab the other channels */ 06874 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 06875 NULL, NULL, ast_channel_linkedid(chana), 0, "Bridge/%s", ast_channel_name(chana)))) { 06876 astman_send_error(s, m, "Unable to create temporary channel!"); 06877 chana = ast_channel_unref(chana); 06878 return 1; 06879 } 06880 06881 do_bridge_masquerade(chana, tmpchana); 06882 06883 chana = ast_channel_unref(chana); 06884 06885 /* now do chanb */ 06886 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); 06887 /* send errors if any of the channels could not be found/locked */ 06888 if (!chanb) { 06889 char buf[256]; 06890 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 06891 ast_hangup(tmpchana); 06892 astman_send_error(s, m, buf); 06893 return 0; 06894 } 06895 06896 /* Answer the channels if needed */ 06897 if (chanb->_state != AST_STATE_UP) 06898 ast_answer(chanb); 06899 06900 /* create the placeholder channels and grab the other channels */ 06901 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 06902 NULL, NULL, ast_channel_linkedid(chanb), 0, "Bridge/%s", ast_channel_name(chanb)))) { 06903 astman_send_error(s, m, "Unable to create temporary channels!"); 06904 ast_hangup(tmpchana); 06905 chanb = ast_channel_unref(chanb); 06906 return 1; 06907 } 06908 06909 do_bridge_masquerade(chanb, tmpchanb); 06910 06911 chanb = ast_channel_unref(chanb); 06912 06913 /* make the channels compatible, send error if we fail doing so */ 06914 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 06915 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb)); 06916 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 06917 ast_hangup(tmpchana); 06918 ast_hangup(tmpchanb); 06919 return 1; 06920 } 06921 06922 /* setup the bridge thread object and start the bridge */ 06923 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 06924 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb), strerror(errno)); 06925 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 06926 ast_hangup(tmpchana); 06927 ast_hangup(tmpchanb); 06928 return 1; 06929 } 06930 06931 tobj->chan = tmpchana; 06932 tobj->peer = tmpchanb; 06933 tobj->return_to_pbx = 1; 06934 06935 if (ast_true(playtone)) { 06936 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, ast_channel_language(tmpchanb))) { 06937 if (ast_waitstream(tmpchanb, "") < 0) 06938 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", ast_channel_name(tmpchanb)); 06939 } 06940 } 06941 06942 chans[0] = tmpchana; 06943 chans[1] = tmpchanb; 06944 06945 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans, 06946 "Response: Success\r\n" 06947 "Channel1: %s\r\n" 06948 "Channel2: %s\r\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb)); 06949 06950 bridge_call_thread_launch(tobj); 06951 06952 astman_send_ack(s, m, "Launched bridge thread with success"); 06953 06954 return 0; 06955 }
| static void add_features_datastores | ( | struct ast_channel * | caller, | |
| struct ast_channel * | callee, | |||
| struct ast_bridge_config * | config | |||
| ) | [static] |
Definition at line 3765 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_dial_features::features_callee, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, ast_datastore::inheritance, ast_dial_features::is_caller, and LOG_WARNING.
Referenced by ast_bridge_call().
03766 { 03767 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 03768 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 03769 03770 ast_channel_lock(caller); 03771 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 03772 ast_channel_unlock(caller); 03773 if (!ds_caller_features) { 03774 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) { 03775 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 03776 return; 03777 } 03778 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 03779 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 03780 ast_datastore_free(ds_caller_features); 03781 return; 03782 } 03783 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 03784 caller_features->is_caller = 1; 03785 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 03786 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 03787 ds_caller_features->data = caller_features; 03788 ast_channel_lock(caller); 03789 ast_channel_datastore_add(caller, ds_caller_features); 03790 ast_channel_unlock(caller); 03791 } else { 03792 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 03793 * flags over from the atxfer to the caller */ 03794 return; 03795 } 03796 03797 ast_channel_lock(callee); 03798 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 03799 ast_channel_unlock(callee); 03800 if (!ds_callee_features) { 03801 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) { 03802 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 03803 return; 03804 } 03805 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 03806 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 03807 ast_datastore_free(ds_callee_features); 03808 return; 03809 } 03810 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 03811 callee_features->is_caller = 0; 03812 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 03813 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 03814 ds_callee_features->data = callee_features; 03815 ast_channel_lock(callee); 03816 ast_channel_datastore_add(callee, ds_callee_features); 03817 ast_channel_unlock(callee); 03818 } 03819 03820 return; 03821 }
| 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 981 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
00982 { 00983 int res; 00984 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00985 char tmp[256]; 00986 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00987 00988 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00989 message[0] = tmp; 00990 res = ast_adsi_load_session(chan, NULL, 0, 1); 00991 if (res == -1) 00992 return res; 00993 return ast_adsi_print(chan, message, justify, 1); 00994 }
| int ast_bridge_call | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config | |||
| ) |
bridge the call and set CDR
Bridge a call, optionally allowing redirection.
| chan | The bridge considers this channel the caller. | |
| peer | The bridge considers this channel the callee. | |
| config | Configuration for this bridge. |
| res | on success. | |
| -1 | on failure to bridge. |
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 3851 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_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_accountcode(), ast_channel_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_NAME, ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_uniqueid(), 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_MCID, AST_CONTROL_OPTION, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, ast_opt_transmit_silence, AST_OPTION_AUDIO_MODE, AST_OPTION_DIGIT_DETECT, AST_OPTION_FAX_DETECT, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_UNBRIDGE, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_write(), ast_channel::caller, ast_channel::cdr, ast_cdr::channel, clear_dialed_interfaces(), 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, ast_frame::len, 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, 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().
03852 { 03853 /* Copy voice back and forth between the two channels. Give the peer 03854 the ability to transfer calls with '#<extension' syntax. */ 03855 struct ast_frame *f; 03856 struct ast_channel *who; 03857 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03858 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03859 char orig_channame[AST_CHANNEL_NAME]; 03860 char orig_peername[AST_CHANNEL_NAME]; 03861 int res; 03862 int diff; 03863 int hasfeatures=0; 03864 int hadfeatures=0; 03865 int autoloopflag; 03866 int sendingdtmfdigit = 0; 03867 int we_disabled_peer_cdr = 0; 03868 struct ast_option_header *aoh; 03869 struct ast_cdr *bridge_cdr = NULL; 03870 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03871 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03872 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03873 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03874 struct ast_silence_generator *silgen = NULL; 03875 const char *h_context; 03876 03877 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer)); 03878 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan)); 03879 03880 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03881 add_features_datastores(chan, peer, config); 03882 03883 /* This is an interesting case. One example is if a ringing channel gets redirected to 03884 * an extension that picks up a parked call. This will make sure that the call taken 03885 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03886 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03887 ast_indicate(peer, AST_CONTROL_RINGING); 03888 } 03889 03890 if (monitor_ok) { 03891 const char *monitor_exec; 03892 struct ast_channel *src = NULL; 03893 if (!monitor_app) { 03894 if (!(monitor_app = pbx_findapp("Monitor"))) 03895 monitor_ok=0; 03896 } 03897 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03898 src = chan; 03899 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03900 src = peer; 03901 if (monitor_app && src) { 03902 char *tmp = ast_strdupa(monitor_exec); 03903 pbx_exec(src, monitor_app, tmp); 03904 } 03905 } 03906 03907 set_config_flags(chan, config); 03908 03909 /* Answer if need be */ 03910 if (chan->_state != AST_STATE_UP) { 03911 if (ast_raw_answer(chan, 1)) { 03912 return -1; 03913 } 03914 } 03915 03916 #ifdef FOR_DEBUG 03917 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 03918 ast_channel_log("Pre-bridge CHAN Channel info", chan); 03919 ast_channel_log("Pre-bridge PEER Channel info", peer); 03920 #endif 03921 /* two channels are being marked as linked here */ 03922 ast_channel_set_linkgroup(chan,peer); 03923 03924 /* copy the userfield from the B-leg to A-leg if applicable */ 03925 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 03926 char tmp[256]; 03927 03928 ast_channel_lock(chan); 03929 if (!ast_strlen_zero(chan->cdr->userfield)) { 03930 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 03931 ast_cdr_appenduserfield(chan, tmp); 03932 } else { 03933 ast_cdr_setuserfield(chan, peer->cdr->userfield); 03934 } 03935 ast_channel_unlock(chan); 03936 /* Don't delete the CDR; just disable it. */ 03937 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03938 we_disabled_peer_cdr = 1; 03939 } 03940 ast_copy_string(orig_channame,ast_channel_name(chan),sizeof(orig_channame)); 03941 ast_copy_string(orig_peername,ast_channel_name(peer),sizeof(orig_peername)); 03942 03943 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 03944 ast_channel_lock_both(chan, peer); 03945 if (chan_cdr) { 03946 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 03947 ast_cdr_update(chan); 03948 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 03949 /* rip any forked CDR's off of the chan_cdr and attach 03950 * them to the bridge_cdr instead */ 03951 bridge_cdr->next = chan_cdr->next; 03952 chan_cdr->next = NULL; 03953 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03954 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03955 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 03956 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03957 } 03958 ast_cdr_setaccount(peer, ast_channel_accountcode(chan)); 03959 } else { 03960 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 03961 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 03962 ast_copy_string(bridge_cdr->channel, ast_channel_name(chan), sizeof(bridge_cdr->channel)); 03963 ast_copy_string(bridge_cdr->dstchannel, ast_channel_name(peer), sizeof(bridge_cdr->dstchannel)); 03964 ast_copy_string(bridge_cdr->uniqueid, ast_channel_uniqueid(chan), sizeof(bridge_cdr->uniqueid)); 03965 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03966 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03967 ast_cdr_setcid(bridge_cdr, chan); 03968 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 03969 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 03970 ast_copy_string(bridge_cdr->accountcode, ast_channel_accountcode(chan), sizeof(bridge_cdr->accountcode)); 03971 /* Destination information */ 03972 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 03973 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 03974 if (peer_cdr) { 03975 bridge_cdr->start = peer_cdr->start; 03976 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03977 } else { 03978 ast_cdr_start(bridge_cdr); 03979 } 03980 } 03981 ast_channel_unlock(chan); 03982 ast_channel_unlock(peer); 03983 03984 ast_debug(4, "bridge answer set, chan answer set\n"); 03985 /* peer_cdr->answer will be set when a macro runs on the peer; 03986 in that case, the bridge answer will be delayed while the 03987 macro plays on the peer channel. The peer answered the call 03988 before the macro started playing. To the phone system, 03989 this is billable time for the call, even tho the caller 03990 hears nothing but ringing while the macro does its thing. */ 03991 03992 /* Another case where the peer cdr's time will be set, is when 03993 A self-parks by pickup up phone and dialing 700, then B 03994 picks up A by dialing its parking slot; there may be more 03995 practical paths that get the same result, tho... in which 03996 case you get the previous answer time from the Park... which 03997 is before the bridge's start time, so I added in the 03998 tvcmp check to the if below */ 03999 04000 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 04001 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 04002 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 04003 if (chan_cdr) { 04004 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 04005 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 04006 } 04007 } else { 04008 ast_cdr_answer(bridge_cdr); 04009 if (chan_cdr) { 04010 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 04011 } 04012 } 04013 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 04014 if (chan_cdr) { 04015 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 04016 } 04017 if (peer_cdr) { 04018 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 04019 } 04020 } 04021 /* the DIALED flag may be set if a dialed channel is transfered 04022 * and then bridged to another channel. In order for the 04023 * bridge CDR to be written, the DIALED flag must not be 04024 * present. */ 04025 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04026 } 04027 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04028 04029 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04030 * a call is being bridged, that the humans in charge know what they're doing. If they 04031 * don't, well, what can we do about that? */ 04032 clear_dialed_interfaces(chan); 04033 clear_dialed_interfaces(peer); 04034 04035 for (;;) { 04036 struct ast_channel *other; /* used later */ 04037 04038 res = ast_channel_bridge(chan, peer, config, &f, &who); 04039 04040 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04041 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04042 /* Zombies are present time to leave! */ 04043 res = -1; 04044 if (f) { 04045 ast_frfree(f); 04046 } 04047 goto before_you_go; 04048 } 04049 04050 /* When frame is not set, we are probably involved in a situation 04051 where we've timed out. 04052 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04053 and also for DTMF_END. If we flow into the following 'if' for both, then 04054 our wait times are cut in half, as both will subtract from the 04055 feature_timer. Not good! 04056 */ 04057 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04058 /* Update feature timer for next pass */ 04059 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04060 if (res == AST_BRIDGE_RETRY) { 04061 /* The feature fully timed out but has not been updated. Skip 04062 * the potential round error from the diff calculation and 04063 * explicitly set to expired. */ 04064 config->feature_timer = -1; 04065 } else { 04066 config->feature_timer -= diff; 04067 } 04068 04069 if (hasfeatures) { 04070 if (config->feature_timer <= 0) { 04071 /* Not *really* out of time, just out of time for 04072 digits to come in for features. */ 04073 ast_debug(1, "Timed out for feature!\n"); 04074 if (!ast_strlen_zero(peer_featurecode)) { 04075 ast_dtmf_stream(chan, peer, peer_featurecode, 0, f ? f->len : 0); 04076 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04077 } 04078 if (!ast_strlen_zero(chan_featurecode)) { 04079 ast_dtmf_stream(peer, chan, chan_featurecode, 0, f ? f->len : 0); 04080 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04081 } 04082 if (f) 04083 ast_frfree(f); 04084 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04085 if (!hasfeatures) { 04086 /* No more digits expected - reset the timer */ 04087 config->feature_timer = 0; 04088 } 04089 hadfeatures = hasfeatures; 04090 /* Continue as we were */ 04091 continue; 04092 } else if (!f) { 04093 /* The bridge returned without a frame and there is a feature in progress. 04094 * However, we don't think the feature has quite yet timed out, so just 04095 * go back into the bridge. */ 04096 continue; 04097 } 04098 } else { 04099 if (config->feature_timer <=0) { 04100 /* We ran out of time */ 04101 config->feature_timer = 0; 04102 who = chan; 04103 if (f) 04104 ast_frfree(f); 04105 f = NULL; 04106 res = 0; 04107 } 04108 } 04109 } 04110 if (res < 0) { 04111 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04112 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", ast_channel_name(chan), ast_channel_name(peer)); 04113 } 04114 goto before_you_go; 04115 } 04116 04117 if (!f || (f->frametype == AST_FRAME_CONTROL && 04118 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04119 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04120 /* 04121 * If the bridge was broken for a hangup that isn't real, 04122 * then don't run the h extension, because the channel isn't 04123 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04124 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04125 */ 04126 ast_channel_lock(chan); 04127 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04128 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 04129 } 04130 ast_channel_unlock(chan); 04131 res = -1; 04132 break; 04133 } 04134 /* many things should be sent to the 'other' channel */ 04135 other = (who == chan) ? peer : chan; 04136 if (f->frametype == AST_FRAME_CONTROL) { 04137 switch (f->subclass.integer) { 04138 case AST_CONTROL_RINGING: 04139 case AST_CONTROL_FLASH: 04140 case AST_CONTROL_MCID: 04141 case -1: 04142 ast_indicate(other, f->subclass.integer); 04143 break; 04144 case AST_CONTROL_CONNECTED_LINE: 04145 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04146 break; 04147 } 04148 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04149 break; 04150 case AST_CONTROL_REDIRECTING: 04151 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04152 break; 04153 } 04154 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04155 break; 04156 case AST_CONTROL_AOC: 04157 case AST_CONTROL_HOLD: 04158 case AST_CONTROL_UNHOLD: 04159 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04160 break; 04161 case AST_CONTROL_OPTION: 04162 aoh = f->data.ptr; 04163 /* Forward option Requests, but only ones we know are safe 04164 * These are ONLY sent by chan_iax2 and I'm not convinced that 04165 * they are useful. I haven't deleted them entirely because I 04166 * just am not sure of the ramifications of removing them. */ 04167 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04168 switch (ntohs(aoh->option)) { 04169 case AST_OPTION_TONE_VERIFY: 04170 case AST_OPTION_TDD: 04171 case AST_OPTION_RELAXDTMF: 04172 case AST_OPTION_AUDIO_MODE: 04173 case AST_OPTION_DIGIT_DETECT: 04174 case AST_OPTION_FAX_DETECT: 04175 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04176 f->datalen - sizeof(struct ast_option_header), 0); 04177 } 04178 } 04179 break; 04180 } 04181 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04182 struct ast_flags *cfg; 04183 char dtmfcode[2] = { f->subclass.integer, }; 04184 size_t featurelen; 04185 04186 if (who == chan) { 04187 featurelen = strlen(chan_featurecode); 04188 cfg = &(config->features_caller); 04189 } else { 04190 featurelen = strlen(peer_featurecode); 04191 cfg = &(config->features_callee); 04192 } 04193 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04194 * DTMF along untouched. If this is not the first digit of a multi-digit code 04195 * then we need to fall through and stream the characters if it matches */ 04196 if (featurelen == 0 04197 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04198 if (option_debug > 3) { 04199 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04200 } 04201 ast_write(other, f); 04202 sendingdtmfdigit = 1; 04203 } else { 04204 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04205 * transmitting something while we hold on to the DTMF waiting for a 04206 * feature. */ 04207 if (!silgen && ast_opt_transmit_silence) { 04208 silgen = ast_channel_start_silence_generator(other); 04209 } 04210 if (option_debug > 3) { 04211 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04212 } 04213 } 04214 } else if (f->frametype == AST_FRAME_DTMF_END) { 04215 char *featurecode; 04216 int sense; 04217 unsigned int dtmfduration = f->len; 04218 04219 hadfeatures = hasfeatures; 04220 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04221 if (who == chan) { 04222 sense = FEATURE_SENSE_CHAN; 04223 featurecode = chan_featurecode; 04224 } else { 04225 sense = FEATURE_SENSE_PEER; 04226 featurecode = peer_featurecode; 04227 } 04228 04229 if (sendingdtmfdigit == 1) { 04230 /* We let the BEGIN go through happily, so let's not bother with the END, 04231 * since we already know it's not something we bother with */ 04232 ast_write(other, f); 04233 sendingdtmfdigit = 0; 04234 } else { 04235 /*! append the event to featurecode. we rely on the string being zero-filled, and 04236 * not overflowing it. 04237 * \todo XXX how do we guarantee the latter ? 04238 */ 04239 featurecode[strlen(featurecode)] = f->subclass.integer; 04240 /* Get rid of the frame before we start doing "stuff" with the channels */ 04241 ast_frfree(f); 04242 f = NULL; 04243 if (silgen) { 04244 ast_channel_stop_silence_generator(other, silgen); 04245 silgen = NULL; 04246 } 04247 config->feature_timer = 0; 04248 res = feature_interpret(chan, peer, config, featurecode, sense); 04249 switch(res) { 04250 case AST_FEATURE_RETURN_PASSDIGITS: 04251 ast_dtmf_stream(other, who, featurecode, 0, dtmfduration); 04252 /* Fall through */ 04253 case AST_FEATURE_RETURN_SUCCESS: 04254 memset(featurecode, 0, sizeof(chan_featurecode)); 04255 break; 04256 } 04257 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04258 res = 0; 04259 } else { 04260 break; 04261 } 04262 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04263 if (hadfeatures && !hasfeatures) { 04264 /* Feature completed or timed out */ 04265 config->feature_timer = 0; 04266 } else if (hasfeatures) { 04267 if (config->timelimit) { 04268 /* No warning next time - we are waiting for feature code */ 04269 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04270 } 04271 config->feature_start_time = ast_tvnow(); 04272 config->feature_timer = featuredigittimeout; 04273 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04274 } 04275 } 04276 } 04277 if (f) 04278 ast_frfree(f); 04279 } 04280 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04281 04282 before_you_go: 04283 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04284 if (silgen) { 04285 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04286 silgen = NULL; 04287 } 04288 04289 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04290 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04291 if (bridge_cdr) { 04292 ast_cdr_discard(bridge_cdr); 04293 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04294 } 04295 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04296 } 04297 04298 if (config->end_bridge_callback) { 04299 config->end_bridge_callback(config->end_bridge_callback_data); 04300 } 04301 04302 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04303 * if it were, then chan belongs to a different thread now, and might have been hung up long 04304 * ago. 04305 */ 04306 if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04307 h_context = NULL; 04308 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04309 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04310 h_context = chan->context; 04311 } else if (!ast_strlen_zero(chan->macrocontext) 04312 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04313 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04314 h_context = chan->macrocontext; 04315 } else { 04316 h_context = NULL; 04317 } 04318 if (h_context) { 04319 struct ast_cdr *swapper = NULL; 04320 char savelastapp[AST_MAX_EXTENSION]; 04321 char savelastdata[AST_MAX_EXTENSION]; 04322 char save_context[AST_MAX_CONTEXT]; 04323 char save_exten[AST_MAX_EXTENSION]; 04324 int save_prio; 04325 int found = 0; /* set if we find at least one match */ 04326 int spawn_error = 0; 04327 04328 /* 04329 * Make sure that the channel is marked as hungup since we are 04330 * going to run the "h" exten on it. 04331 */ 04332 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04333 04334 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04335 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04336 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04337 ast_cdr_end(bridge_cdr); 04338 } 04339 04340 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04341 dialplan code operate on it */ 04342 ast_channel_lock(chan); 04343 if (bridge_cdr) { 04344 swapper = chan->cdr; 04345 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04346 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04347 chan->cdr = bridge_cdr; 04348 } 04349 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04350 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04351 save_prio = chan->priority; 04352 if (h_context != chan->context) { 04353 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04354 } 04355 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04356 chan->priority = 1; 04357 ast_channel_unlock(chan); 04358 04359 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04360 chan->priority, 04361 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04362 &found, 1)) == 0) { 04363 chan->priority++; 04364 } 04365 if (found && spawn_error) { 04366 /* Something bad happened, or a hangup has been requested. */ 04367 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, ast_channel_name(chan)); 04368 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, ast_channel_name(chan)); 04369 } 04370 04371 /* swap it back */ 04372 ast_channel_lock(chan); 04373 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04374 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04375 chan->priority = save_prio; 04376 if (bridge_cdr) { 04377 if (chan->cdr == bridge_cdr) { 04378 chan->cdr = swapper; 04379 } else { 04380 bridge_cdr = NULL; 04381 } 04382 } 04383 /* An "h" exten has been run, so indicate that one has been run. */ 04384 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04385 ast_channel_unlock(chan); 04386 04387 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04388 if (bridge_cdr) { 04389 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04390 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04391 } 04392 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04393 } 04394 04395 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04396 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04397 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 04398 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04399 04400 /* we can post the bridge CDR at this point */ 04401 if (bridge_cdr) { 04402 ast_cdr_end(bridge_cdr); 04403 ast_cdr_detach(bridge_cdr); 04404 } 04405 04406 /* do a specialized reset on the beginning channel 04407 CDR's, if they still exist, so as not to mess up 04408 issues in future bridges; 04409 04410 Here are the rules of the game: 04411 1. The chan and peer channel pointers will not change 04412 during the life of the bridge. 04413 2. But, in transfers, the channel names will change. 04414 between the time the bridge is started, and the 04415 time the channel ends. 04416 Usually, when a channel changes names, it will 04417 also change CDR pointers. 04418 3. Usually, only one of the two channels (chan or peer) 04419 will change names. 04420 4. Usually, if a channel changes names during a bridge, 04421 it is because of a transfer. Usually, in these situations, 04422 it is normal to see 2 bridges running simultaneously, and 04423 it is not unusual to see the two channels that change 04424 swapped between bridges. 04425 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04426 to attend to; if the chan or peer changed names, 04427 we have the before and after attached CDR's. 04428 */ 04429 04430 if (new_chan_cdr) { 04431 struct ast_channel *chan_ptr = NULL; 04432 04433 if (strcasecmp(orig_channame, ast_channel_name(chan)) != 0) { 04434 /* old channel */ 04435 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04436 ast_channel_lock(chan_ptr); 04437 if (!ast_bridged_channel(chan_ptr)) { 04438 struct ast_cdr *cur; 04439 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04440 if (cur == chan_cdr) { 04441 break; 04442 } 04443 } 04444 if (cur) { 04445 ast_cdr_specialized_reset(chan_cdr, 0); 04446 } 04447 } 04448 ast_channel_unlock(chan_ptr); 04449 chan_ptr = ast_channel_unref(chan_ptr); 04450 } 04451 /* new channel */ 04452 ast_cdr_specialized_reset(new_chan_cdr, 0); 04453 } else { 04454 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04455 } 04456 } 04457 04458 { 04459 struct ast_channel *chan_ptr = NULL; 04460 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04461 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)) 04462 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04463 if (strcasecmp(orig_peername, ast_channel_name(peer)) != 0) { 04464 /* old channel */ 04465 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04466 ast_channel_lock(chan_ptr); 04467 if (!ast_bridged_channel(chan_ptr)) { 04468 struct ast_cdr *cur; 04469 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04470 if (cur == peer_cdr) { 04471 break; 04472 } 04473 } 04474 if (cur) { 04475 ast_cdr_specialized_reset(peer_cdr, 0); 04476 } 04477 } 04478 ast_channel_unlock(chan_ptr); 04479 chan_ptr = ast_channel_unref(chan_ptr); 04480 } 04481 /* new channel */ 04482 if (new_peer_cdr) { 04483 ast_cdr_specialized_reset(new_peer_cdr, 0); 04484 } 04485 } else { 04486 if (we_disabled_peer_cdr) { 04487 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04488 } 04489 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04490 } 04491 } 04492 04493 return res; 04494 }
| 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 7390 of file features.c.
References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, ast_bridge_config::end_sound, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, pbx_builtin_getvar_helper(), ast_bridge_config::play_warning, S_OR, ast_bridge_config::start_sound, strsep(), ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by bridge_exec(), and dial_exec_full().
07392 { 07393 char *stringp = ast_strdupa(parse); 07394 char *limit_str, *warning_str, *warnfreq_str; 07395 const char *var; 07396 int play_to_caller = 0, play_to_callee = 0; 07397 int delta; 07398 07399 limit_str = strsep(&stringp, ":"); 07400 warning_str = strsep(&stringp, ":"); 07401 warnfreq_str = strsep(&stringp, ":"); 07402 07403 config->timelimit = atol(limit_str); 07404 if (warning_str) 07405 config->play_warning = atol(warning_str); 07406 if (warnfreq_str) 07407 config->warning_freq = atol(warnfreq_str); 07408 07409 if (!config->timelimit) { 07410 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07411 config->timelimit = config->play_warning = config->warning_freq = 0; 07412 config->warning_sound = NULL; 07413 return -1; /* error */ 07414 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07415 int w = config->warning_freq; 07416 07417 /* 07418 * If the first warning is requested _after_ the entire call 07419 * would end, and no warning frequency is requested, then turn 07420 * off the warning. If a warning frequency is requested, reduce 07421 * the 'first warning' time by that frequency until it falls 07422 * within the call's total time limit. 07423 * 07424 * Graphically: 07425 * timelim->| delta |<-playwarning 07426 * 0__________________|_________________| 07427 * | w | | | | 07428 * 07429 * so the number of intervals to cut is 1+(delta-1)/w 07430 */ 07431 if (w == 0) { 07432 config->play_warning = 0; 07433 } else { 07434 config->play_warning -= w * ( 1 + (delta-1)/w ); 07435 if (config->play_warning < 1) 07436 config->play_warning = config->warning_freq = 0; 07437 } 07438 } 07439 07440 ast_channel_lock(chan); 07441 07442 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07443 play_to_caller = var ? ast_true(var) : 1; 07444 07445 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07446 play_to_callee = var ? ast_true(var) : 0; 07447 07448 if (!play_to_caller && !play_to_callee) 07449 play_to_caller = 1; 07450 07451 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07452 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07453 07454 /* The code looking at config wants a NULL, not just "", to decide 07455 * that the message should not be played, so we replace "" with NULL. 07456 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07457 * not found. 07458 */ 07459 07460 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07461 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07462 07463 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07464 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07465 07466 ast_channel_unlock(chan); 07467 07468 /* undo effect of S(x) in case they are both used */ 07469 calldurationlimit->tv_sec = 0; 07470 calldurationlimit->tv_usec = 0; 07471 07472 /* more efficient to do it like S(x) does since no advanced opts */ 07473 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07474 calldurationlimit->tv_sec = config->timelimit / 1000; 07475 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07476 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07477 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07478 config->timelimit = play_to_caller = play_to_callee = 07479 config->play_warning = config->warning_freq = 0; 07480 } else { 07481 ast_verb(4, "Limit Data for this call:\n"); 07482 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07483 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07484 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07485 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07486 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07487 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07488 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07489 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07490 } 07491 if (play_to_caller) 07492 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07493 if (play_to_callee) 07494 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07495 return 0; 07496 }
| 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 7197 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().
07198 { 07199 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07200 && (chan->_state == AST_STATE_RINGING 07201 || chan->_state == AST_STATE_RING 07202 /* 07203 * Check the down state as well because some SIP devices do not 07204 * give 180 ringing when they can just give 183 session progress 07205 * instead. Issue 14005. (Some ISDN switches as well for that 07206 * matter.) 07207 */ 07208 || chan->_state == AST_STATE_DOWN) 07209 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07210 return 1; 07211 } 07212 return 0; 07213 }
| void ast_channel_log | ( | char * | title, | |
| struct ast_channel * | chan | |||
| ) |
Definition at line 3698 of file features.c.
References ast_channel_accountcode(), ast_channel_dialcontext(), ast_channel_linkedid(), ast_channel_name(), ast_channel_uniqueid(), ast_log(), and LOG_NOTICE.
Referenced by ast_bridge_call().
03699 { 03700 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long) chan); 03701 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n", 03702 ast_channel_name(chan), chan->appl, chan->data, chan->context, chan->exten, chan->priority); 03703 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n", 03704 ast_channel_accountcode(chan), ast_channel_dialcontext(chan), chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority); 03705 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n", 03706 chan->masq, chan->masqr, 03707 chan->_bridge, ast_channel_uniqueid(chan), ast_channel_linkedid(chan)); 03708 if (chan->masqr) { 03709 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n", 03710 ast_channel_name(chan->masqr), chan->masqr->cdr); 03711 } 03712 if (chan->_bridge) { 03713 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", ast_channel_name(chan->_bridge)); 03714 } 03715 03716 ast_log(LOG_NOTICE, "===== done ====\n"); 03717 }
| 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 7273 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_name(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_datastore_alloc, ast_datastore_free(), ast_debug, ast_do_masquerade(), AST_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().
07274 { 07275 struct ast_party_connected_line connected_caller; 07276 struct ast_channel *chans[2] = { chan, target }; 07277 struct ast_datastore *ds_pickup; 07278 const char *chan_name;/*!< A masquerade changes channel names. */ 07279 const char *target_name;/*!< A masquerade changes channel names. */ 07280 int res = -1; 07281 07282 target_name = ast_strdupa(ast_channel_name(target)); 07283 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan)); 07284 07285 /* Mark the target to block any call pickup race. */ 07286 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07287 if (!ds_pickup) { 07288 ast_log(LOG_WARNING, 07289 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07290 return -1; 07291 } 07292 ast_channel_datastore_add(target, ds_pickup); 07293 07294 ast_party_connected_line_init(&connected_caller); 07295 ast_party_connected_line_copy(&connected_caller, &target->connected); 07296 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07297 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07298 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07299 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07300 } 07301 ast_party_connected_line_free(&connected_caller); 07302 07303 ast_channel_lock(chan); 07304 chan_name = ast_strdupa(ast_channel_name(chan)); 07305 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07306 ast_channel_unlock(chan); 07307 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07308 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07309 ast_party_connected_line_free(&connected_caller); 07310 07311 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07312 07313 if (ast_answer(chan)) { 07314 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07315 goto pickup_failed; 07316 } 07317 07318 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07319 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07320 goto pickup_failed; 07321 } 07322 07323 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07324 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07325 07326 if (ast_channel_masquerade(target, chan)) { 07327 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07328 target_name); 07329 goto pickup_failed; 07330 } 07331 07332 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07333 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07334 "Channel: %s\r\n" 07335 "TargetChannel: %s\r\n", 07336 chan_name, target_name); 07337 07338 /* Do the masquerade manually to make sure that it is completed. */ 07339 ast_do_masquerade(target); 07340 res = 0; 07341 07342 pickup_failed: 07343 ast_channel_lock(target); 07344 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07345 ast_datastore_free(ds_pickup); 07346 } 07347 07348 return res; 07349 }
| 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 3286 of file features.c.
References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03286 { 03287 03288 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03289 }
| int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 8142 of file features.c.
References action_bridge(), ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register_xml, ast_pthread_create, ast_register_application2(), AST_TEST_REGISTER, bridge_exec(), do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), parkcall, parked_call_exec(), parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), and parkinglots.
Referenced by main().
08143 { 08144 int res; 08145 08146 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 08147 if (!parkinglots) { 08148 return -1; 08149 } 08150 08151 res = load_config(0); 08152 if (res) { 08153 return res; 08154 } 08155 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); 08156 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 08157 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); 08158 res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL); 08159 if (!res) 08160 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); 08161 if (!res) { 08162 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status); 08163 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park); 08164 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge); 08165 } 08166 08167 res |= ast_devstate_prov_add("Park", metermaidstate); 08168 #if defined(TEST_FRAMEWORK) 08169 res |= AST_TEST_REGISTER(features_test); 08170 #endif /* defined(TEST_FRAMEWORK) */ 08171 08172 return res; 08173 }
| int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6759 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().
06760 { 06761 struct ast_context *con; 06762 int res; 06763 06764 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06765 06766 /* 06767 * Always destroy the parking_con_dial context to remove buildup 06768 * of recalled extensions in the context. At worst, the parked 06769 * call gets hungup attempting to run an invalid extension when 06770 * we are trying to callback the parker or the preset return 06771 * extension. This is a small window of opportunity on an 06772 * execution chain that is not expected to happen very often. 06773 */ 06774 con = ast_context_find(parking_con_dial); 06775 if (con) { 06776 ast_context_destroy(con, registrar); 06777 } 06778 06779 res = load_config(1); 06780 ast_mutex_unlock(&features_reload_lock); 06781 06782 return res; 06783 }
| 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 3019 of file features.c.
References FEATURES_COUNT, find_dynamic_feature(), and ast_call_feature::sname.
Referenced by action_atxfer(), handle_request_info(), and process_config().
03020 { 03021 int x; 03022 for (x = 0; x < FEATURES_COUNT; x++) { 03023 if (!strcasecmp(name, builtin_features[x].sname)) 03024 return &builtin_features[x]; 03025 } 03026 03027 return find_dynamic_feature(name); 03028 }
| int ast_masq_park_call | ( | struct ast_channel * | park_me, | |
| struct ast_channel * | parker, | |||
| int | timeout, | |||
| int * | extout | |||
| ) |
Park a call via a masqueraded channel.
| park_me | Channel to be parked. | |
| parker | Channel parking the call. | |
| timeout | is a timeout in milliseconds | |
| extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
| 0 | on success. | |
| -1 | on failure. |
Definition at line 1764 of file features.c.
References ast_channel_name(), ast_strdupa, masq_park_call(), ast_park_call_args::orig_chan_name, and ast_park_call_args::timeout.
Referenced by handle_soft_key_event_message(), handle_stimulus_message(), parkandannounce_exec(), and rpt_exec().
01765 { 01766 struct ast_park_call_args args = { 01767 .timeout = timeout, 01768 .extout = extout, 01769 }; 01770 01771 if (peer) { 01772 args.orig_chan_name = ast_strdupa(ast_channel_name(peer)); 01773 } 01774 return masq_park_call(rchan, peer, &args); 01775 }
| int ast_masq_park_call_exten | ( | struct ast_channel * | park_me, | |
| struct ast_channel * | parker, | |||
| const char * | park_exten, | |||
| const char * | park_context, | |||
| int | timeout, | |||
| int * | extout | |||
| ) |
Park a call via a masqueraded channel.
| park_me | Channel to be parked. | |
| parker | Channel parking the call. | |
| park_exten | Parking lot access extension | |
| park_context | Parking lot context | |
| timeout | is a timeout in milliseconds | |
| extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
| 0 | on success. | |
| -1 | on failure. |
Definition at line 1710 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), find_parkinglot(), get_parking_exten(), masq_park_call(), ast_park_call_args::orig_chan_name, parkeddynamic, ast_park_call_args::parkinglot, parkinglot_unref(), parse(), park_app_args::pl_name, and ast_park_call_args::timeout.
Referenced by __analog_ss_thread(), analog_ss_thread(), and mgcp_ss().
01711 { 01712 int res; 01713 char *parse; 01714 const char *app_data; 01715 struct ast_exten *exten; 01716 struct park_app_args app_args; 01717 struct ast_park_call_args args = { 01718 .timeout = timeout, 01719 .extout = extout, 01720 }; 01721 01722 if (parker) { 01723 args.orig_chan_name = ast_strdupa(ast_channel_name(parker)); 01724 } 01725 if (!park_exten || !park_context) { 01726 return masq_park_call(park_me, parker, &args); 01727 } 01728 01729 /* 01730 * Determiine if the specified park extension has an exclusive 01731 * parking lot to use. 01732 */ 01733 if (parker && parker != park_me) { 01734 ast_autoservice_start(park_me); 01735 } 01736 exten = get_parking_exten(park_exten, parker, park_context); 01737 if (exten) { 01738 app_data = ast_get_extension_app_data(exten); 01739 if (!app_data) { 01740 app_data = ""; 01741 } 01742 parse = ast_strdupa(app_data); 01743 AST_STANDARD_APP_ARGS(app_args, parse); 01744 01745 if (!ast_strlen_zero(app_args.pl_name)) { 01746 /* Find the specified exclusive parking lot */ 01747 args.parkinglot = find_parkinglot(app_args.pl_name); 01748 if (!args.parkinglot && parkeddynamic) { 01749 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01750 } 01751 } 01752 } 01753 if (parker && parker != park_me) { 01754 ast_autoservice_stop(park_me); 01755 } 01756 01757 res = masq_park_call(park_me, parker, &args); 01758 if (args.parkinglot) { 01759 parkinglot_unref(args.parkinglot); 01760 } 01761 return res; 01762 }
| int ast_park_call | ( | struct ast_channel * | park_me, | |
| struct ast_channel * | parker, | |||
| int | timeout, | |||
| const char * | park_exten, | |||
| int * | extout | |||
| ) |
Park a call and read back parked location.
| park_me | Channel to be parked. | |
| parker | Channel parking the call. | |
| timeout | is a timeout in milliseconds | |
| park_exten | Parking lot access extension (Not used) | |
| extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
| 0 | on success. | |
| -1 | on failure. |
Definition at line 1613 of file features.c.
References park_call_full(), and ast_park_call_args::timeout.
01614 { 01615 struct ast_park_call_args args = { 01616 .timeout = timeout, 01617 .extout = extout, 01618 }; 01619 01620 return park_call_full(park_me, parker, &args); 01621 }
| int ast_park_call_exten | ( | struct ast_channel * | park_me, | |
| struct ast_channel * | parker, | |||
| const char * | park_exten, | |||
| const char * | park_context, | |||
| int | timeout, | |||
| int * | extout | |||
| ) |
Park a call and read back parked location.
| park_me | Channel to be parked. | |
| parker | Channel parking the call. | |
| park_exten | Parking lot access extension | |
| park_context | Parking lot context | |
| timeout | is a timeout in milliseconds | |
| extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
| 0 | on success. | |
| -1 | on failure. |
Definition at line 1562 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().
01563 { 01564 int res; 01565 char *parse; 01566 const char *app_data; 01567 struct ast_exten *exten; 01568 struct park_app_args app_args; 01569 struct ast_park_call_args args = { 01570 .timeout = timeout, 01571 .extout = extout, 01572 }; 01573 01574 if (!park_exten || !park_context) { 01575 return park_call_full(park_me, parker, &args); 01576 } 01577 01578 /* 01579 * Determiine if the specified park extension has an exclusive 01580 * parking lot to use. 01581 */ 01582 if (parker && parker != park_me) { 01583 ast_autoservice_start(park_me); 01584 } 01585 exten = get_parking_exten(park_exten, parker, park_context); 01586 if (exten) { 01587 app_data = ast_get_extension_app_data(exten); 01588 if (!app_data) { 01589 app_data = ""; 01590 } 01591 parse = ast_strdupa(app_data); 01592 AST_STANDARD_APP_ARGS(app_args, parse); 01593 01594 if (!ast_strlen_zero(app_args.pl_name)) { 01595 /* Find the specified exclusive parking lot */ 01596 args.parkinglot = find_parkinglot(app_args.pl_name); 01597 if (!args.parkinglot && parkeddynamic) { 01598 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01599 } 01600 } 01601 } 01602 if (parker && parker != park_me) { 01603 ast_autoservice_stop(park_me); 01604 } 01605 01606 res = park_call_full(park_me, parker, &args); 01607 if (args.parkinglot) { 01608 parkinglot_unref(args.parkinglot); 01609 } 01610 return res; 01611 }
| 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 801 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().
00802 { 00803 return get_parking_exten(exten_str, chan, context) ? 1 : 0; 00804 }
| int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
| chan | channel that initiated pickup. |
< Potential pickup target
Definition at line 7239 of file features.c.
References ast_answer(), ast_channel_callback(), ast_channel_name(), 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().
07240 { 07241 struct ast_channel *target;/*!< Potential pickup target */ 07242 int res = -1; 07243 ast_debug(1, "pickup attempt by %s\n", ast_channel_name(chan)); 07244 07245 /* The found channel is already locked. */ 07246 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07247 if (target) { 07248 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan)); 07249 07250 res = ast_do_pickup(chan, target); 07251 ast_channel_unlock(target); 07252 if (!res) { 07253 if (!ast_strlen_zero(pickupsound)) { 07254 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07255 } 07256 } else { 07257 ast_log(LOG_WARNING, "pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan)); 07258 } 07259 target = ast_channel_unref(target); 07260 } 07261 07262 if (res < 0) { 07263 ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan)); 07264 if (!ast_strlen_zero(pickupfailsound)) { 07265 ast_answer(chan); 07266 ast_stream_and_wait(chan, pickupfailsound, ""); 07267 } 07268 } 07269 07270 return res; 07271 }
| const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 806 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().
00807 { 00808 return pickup_ext; 00809 }
| void ast_rdlock_call_features | ( | void | ) |
Definition at line 3009 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
03010 { 03011 ast_rwlock_rdlock(&features_lock); 03012 }
| void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_list
register new feature into feature_set
Definition at line 2853 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
Referenced by process_applicationmap_line().
02854 { 02855 if (!feature) { 02856 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02857 return; 02858 } 02859 02860 AST_RWLIST_WRLOCK(&feature_list); 02861 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 02862 AST_RWLIST_UNLOCK(&feature_list); 02863 02864 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 02865 }
| void ast_unlock_call_features | ( | void | ) |
Definition at line 3014 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
03015 { 03016 ast_rwlock_unlock(&features_lock); 03017 }
| 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 2933 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
02934 { 02935 if (!feature) { 02936 return; 02937 } 02938 02939 AST_RWLIST_WRLOCK(&feature_list); 02940 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 02941 AST_RWLIST_UNLOCK(&feature_list); 02942 02943 ast_free(feature); 02944 }
| static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 2947 of file features.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_call_feature::feature_entry.
Referenced by process_config().
02948 { 02949 struct ast_call_feature *feature; 02950 02951 AST_RWLIST_WRLOCK(&feature_list); 02952 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 02953 ast_free(feature); 02954 } 02955 AST_RWLIST_UNLOCK(&feature_list); 02956 }
| static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 2973 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().
02974 { 02975 struct feature_group *fg; 02976 struct feature_group_exten *fge; 02977 02978 AST_RWLIST_WRLOCK(&feature_groups); 02979 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 02980 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 02981 ast_string_field_free_memory(fge); 02982 ast_free(fge); 02983 } 02984 02985 ast_string_field_free_memory(fg); 02986 ast_free(fg); 02987 } 02988 AST_RWLIST_UNLOCK(&feature_groups); 02989 }
| static void atxfer_fail_cleanup | ( | struct ast_channel * | transferee, | |
| struct ast_channel * | transferer, | |||
| struct ast_party_connected_line * | connected_line | |||
| ) | [static] |
Definition at line 2396 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().
02397 { 02398 finishup(transferee); 02399 02400 /* 02401 * Restore party B connected line info about party A. 02402 * 02403 * Party B was the caller to party C and is the last known mode 02404 * for party B. 02405 */ 02406 if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) { 02407 ast_channel_update_connected_line(transferer, connected_line, NULL); 02408 } 02409 ast_party_connected_line_free(connected_line); 02410 }
| static void* bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
| data | thread bridge. |
Definition at line 916 of file features.c.
References ast_channel::appl, ast_bridge_call(), ast_channel_name(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, LOG_VERBOSE, LOG_WARNING, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.
Referenced by bridge_call_thread_launch().
00917 { 00918 struct ast_bridge_thread_obj *tobj = data; 00919 int res; 00920 00921 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00922 tobj->chan->data = ast_channel_name(tobj->peer); 00923 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00924 tobj->peer->data = ast_channel_name(tobj->chan); 00925 00926 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00927 00928 if (tobj->return_to_pbx) { 00929 if (!ast_check_hangup(tobj->peer)) { 00930 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", ast_channel_name(tobj->peer)); 00931 res = ast_pbx_start(tobj->peer); 00932 if (res != AST_PBX_SUCCESS) 00933 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", ast_channel_name(tobj->peer)); 00934 } else 00935 ast_hangup(tobj->peer); 00936 if (!ast_check_hangup(tobj->chan)) { 00937 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", ast_channel_name(tobj->chan)); 00938 res = ast_pbx_start(tobj->chan); 00939 if (res != AST_PBX_SUCCESS) 00940 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", ast_channel_name(tobj->chan)); 00941 } else 00942 ast_hangup(tobj->chan); 00943 } else { 00944 ast_hangup(tobj->chan); 00945 ast_hangup(tobj->peer); 00946 } 00947 00948 ast_free(tobj); 00949 00950 return NULL; 00951 }
| static void bridge_call_thread_launch | ( | void * | data | ) | [static] |
create thread for the parked call
| data | Create thread and attributes, call bridge_call_thread |
Definition at line 959 of file features.c.
References ast_pthread_create, bridge_call_thread(), and thread.
Referenced by action_bridge(), and builtin_atxfer().
00960 { 00961 pthread_t thread; 00962 pthread_attr_t attr; 00963 struct sched_param sched; 00964 00965 pthread_attr_init(&attr); 00966 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00967 ast_pthread_create(&thread, &attr, bridge_call_thread, data); 00968 pthread_attr_destroy(&attr); 00969 memset(&sched, 0, sizeof(sched)); 00970 pthread_setschedparam(thread, SCHED_RR, &sched); 00971 }
| static int bridge_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Bridge channels.
| chan | ||
| data | channel to bridge with. |
Definition at line 7508 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_language(), ast_channel_linkedid(), ast_channel_make_compatible(), ast_channel_name(), 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_free, ast_hangup(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_pbx_start(), AST_PBX_SUCCESS, 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().
07509 { 07510 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2]; 07511 char *tmp_data = NULL; 07512 struct ast_flags opts = { 0, }; 07513 struct ast_bridge_config bconfig = { { 0, }, }; 07514 char *opt_args[OPT_ARG_ARRAY_SIZE]; 07515 struct timeval calldurationlimit = { 0, }; 07516 07517 AST_DECLARE_APP_ARGS(args, 07518 AST_APP_ARG(dest_chan); 07519 AST_APP_ARG(options); 07520 ); 07521 07522 if (ast_strlen_zero(data)) { 07523 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 07524 return -1; 07525 } 07526 07527 tmp_data = ast_strdupa(data); 07528 AST_STANDARD_APP_ARGS(args, tmp_data); 07529 if (!ast_strlen_zero(args.options)) 07530 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options); 07531 07532 /* avoid bridge with ourselves */ 07533 if (!strcmp(ast_channel_name(chan), args.dest_chan)) { 07534 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", ast_channel_name(chan)); 07535 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07536 "Response: Failed\r\n" 07537 "Reason: Unable to bridge channel to itself\r\n" 07538 "Channel1: %s\r\n" 07539 "Channel2: %s\r\n", 07540 ast_channel_name(chan), args.dest_chan); 07541 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 07542 return 0; 07543 } 07544 07545 /* make sure we have a valid end point */ 07546 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan, 07547 strlen(args.dest_chan)))) { 07548 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 07549 "cannot get its lock\n", args.dest_chan); 07550 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07551 "Response: Failed\r\n" 07552 "Reason: Cannot grab end point\r\n" 07553 "Channel1: %s\r\n" 07554 "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan); 07555 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 07556 return 0; 07557 } 07558 07559 /* answer the channel if needed */ 07560 if (current_dest_chan->_state != AST_STATE_UP) { 07561 ast_answer(current_dest_chan); 07562 } 07563 07564 /* try to allocate a place holder where current_dest_chan will be placed */ 07565 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 07566 NULL, NULL, ast_channel_linkedid(current_dest_chan), 0, "Bridge/%s", ast_channel_name(current_dest_chan)))) { 07567 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 07568 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 07569 "Response: Failed\r\n" 07570 "Reason: cannot create placeholder\r\n" 07571 "Channel1: %s\r\n" 07572 "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan); 07573 } 07574 07575 do_bridge_masquerade(current_dest_chan, final_dest_chan); 07576 07577 chans[0] = current_dest_chan; 07578 chans[1] = final_dest_chan; 07579 07580 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 07581 /* try to make compatible, send error if we fail */ 07582 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 07583 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(final_dest_chan)); 07584 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07585 "Response: Failed\r\n" 07586 "Reason: Could not make channels compatible for bridge\r\n" 07587 "Channel1: %s\r\n" 07588 "Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan)); 07589 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 07590 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 07591 current_dest_chan = ast_channel_unref(current_dest_chan); 07592 return 0; 07593 } 07594 07595 /* Report that the bridge will be successfull */ 07596 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 07597 "Response: Success\r\n" 07598 "Channel1: %s\r\n" 07599 "Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan)); 07600 07601 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 07602 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 07603 if (!ast_streamfile(final_dest_chan, xfersound, ast_channel_language(final_dest_chan))) { 07604 if (ast_waitstream(final_dest_chan, "") < 0) 07605 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", ast_channel_name(final_dest_chan)); 07606 } 07607 } 07608 07609 current_dest_chan = ast_channel_unref(current_dest_chan); 07610 07611 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) { 07612 if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) 07613 goto done; 07614 } 07615 07616 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) 07617 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT); 07618 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) 07619 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT); 07620 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) 07621 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 07622 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) 07623 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 07624 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR)) 07625 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON); 07626 if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 07627 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON); 07628 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) 07629 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL); 07630 if (ast_test_flag(&opts, OPT_CALLER_PARK)) 07631 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL); 07632 07633 ast_bridge_call(chan, final_dest_chan, &bconfig); 07634 07635 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 07636 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 07637 if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) { 07638 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 07639 final_dest_chan->context, final_dest_chan->exten, 07640 final_dest_chan->priority, ast_channel_name(final_dest_chan)); 07641 07642 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 07643 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", ast_channel_name(final_dest_chan)); 07644 ast_hangup(final_dest_chan); 07645 } else 07646 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", ast_channel_name(final_dest_chan)); 07647 } else { 07648 ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", ast_channel_name(final_dest_chan)); 07649 ast_hangup(final_dest_chan); 07650 } 07651 done: 07652 if (bconfig.warning_sound) { 07653 ast_free((char *)bconfig.warning_sound); 07654 } 07655 if (bconfig.end_sound) { 07656 ast_free((char *)bconfig.end_sound); 07657 } 07658 if (bconfig.start_sound) { 07659 ast_free((char *)bconfig.start_sound); 07660 } 07661 07662 return 0; 07663 }
| static struct parking_dp_context* build_dialplan_useage_context | ( | struct ast_parkinglot * | lot | ) | [static, read] |
Definition at line 6196 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().
06197 { 06198 struct parking_dp_context *ctx_node; 06199 06200 ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con)); 06201 if (!ctx_node) { 06202 return NULL; 06203 } 06204 if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) { 06205 destroy_dialplan_usage_context(ctx_node); 06206 return NULL; 06207 } 06208 strcpy(ctx_node->context, lot->cfg.parking_con); 06209 return ctx_node; 06210 }
| static int build_dialplan_useage_map | ( | struct parking_dp_map * | usage_map, | |
| int | complain | |||
| ) | [static] |
Definition at line 6268 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().
06269 { 06270 int status = 0; 06271 struct ao2_iterator iter; 06272 struct ast_parkinglot *curlot; 06273 06274 /* For all parking lots */ 06275 iter = ao2_iterator_init(parkinglots, 0); 06276 for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) { 06277 /* Add the parking lot to the map. */ 06278 if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) { 06279 ao2_ref(curlot, -1); 06280 status = -1; 06281 break; 06282 } 06283 } 06284 ao2_iterator_destroy(&iter); 06285 06286 return status; 06287 }
| static struct parking_dp_ramp* build_dialplan_useage_ramp | ( | const char * | exten, | |
| int | exclusive | |||
| ) | [static, read] |
Definition at line 5959 of file features.c.
References ast_calloc, parking_dp_ramp::exclusive, and parking_dp_ramp::exten.
Referenced by usage_context_add_ramp().
05960 { 05961 struct parking_dp_ramp *ramp_node; 05962 05963 ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten)); 05964 if (!ramp_node) { 05965 return NULL; 05966 } 05967 ramp_node->exclusive = exclusive; 05968 strcpy(ramp_node->exten, exten); 05969 return ramp_node; 05970 }
| static struct parking_dp_spaces* build_dialplan_useage_spaces | ( | int | start, | |
| int | stop | |||
| ) | [static, read] |
Definition at line 6040 of file features.c.
References ast_calloc, parking_dp_spaces::start, and parking_dp_spaces::stop.
Referenced by usage_context_add_spaces().
06041 { 06042 struct parking_dp_spaces *spaces_node; 06043 06044 spaces_node = ast_calloc(1, sizeof(*spaces_node)); 06045 if (!spaces_node) { 06046 return NULL; 06047 } 06048 spaces_node->start = start; 06049 spaces_node->stop = stop; 06050 return spaces_node; 06051 }
| 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 5566 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().
05567 { 05568 struct ast_parkinglot *parkinglot; 05569 const struct parkinglot_cfg *cfg_defaults; 05570 struct parkinglot_cfg new_cfg; 05571 int cfg_error; 05572 int oldparkinglot = 0; 05573 05574 parkinglot = find_parkinglot(pl_name); 05575 if (parkinglot) { 05576 oldparkinglot = 1; 05577 } else { 05578 parkinglot = create_parkinglot(pl_name); 05579 if (!parkinglot) { 05580 return NULL; 05581 } 05582 } 05583 if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) { 05584 cfg_defaults = &parkinglot_cfg_default_default; 05585 } else { 05586 cfg_defaults = &parkinglot_cfg_default; 05587 } 05588 new_cfg = *cfg_defaults; 05589 05590 ast_debug(1, "Building parking lot %s\n", parkinglot->name); 05591 05592 ao2_lock(parkinglot); 05593 05594 /* Do some config stuff */ 05595 cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var); 05596 if (oldparkinglot) { 05597 if (cfg_error) { 05598 /* Bad configuration read. Keep using the original config. */ 05599 ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n", 05600 parkinglot->name); 05601 cfg_error = 0; 05602 } else if (!AST_LIST_EMPTY(&parkinglot->parkings) 05603 && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) { 05604 /* Try reloading later when parking lot is empty. */ 05605 ast_log(LOG_WARNING, 05606 "Parking lot %s has parked calls. Parking lot changes discarded.\n", 05607 parkinglot->name); 05608 force_reload_load = 1; 05609 } else { 05610 /* Accept the new config */ 05611 parkinglot->cfg = new_cfg; 05612 } 05613 } else { 05614 /* Load the initial parking lot config. */ 05615 parkinglot->cfg = new_cfg; 05616 } 05617 parkinglot->the_mark = 0; 05618 05619 ao2_unlock(parkinglot); 05620 05621 if (cfg_error) { 05622 /* Only new parking lots could have config errors here. */ 05623 ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name); 05624 parkinglot_unref(parkinglot); 05625 return NULL; 05626 } 05627 05628 /* Move it into the list, if it wasn't already there */ 05629 if (!oldparkinglot) { 05630 ao2_link(parkinglots, parkinglot); 05631 } 05632 parkinglot_unref(parkinglot); 05633 05634 return parkinglot; 05635 }
| static int builtin_atxfer | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| void * | data | |||
| ) | [static] |
Attended transfer.
| chan | transfered user | |
| peer | person transfering call | |
| config | ||
| code | ||
| sense | feature options | |
| data | Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel. |
Definition at line 2427 of file features.c.
References ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), 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_language(), ast_channel_linkedid(), ast_channel_lock, ast_channel_masquerade(), ast_channel_name(), 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_channel::context, ast_datastore::data, dial_features_info, ast_bridge_config::end_bridge_callback_data_fixup, ast_channel::exten, feature_request_and_dial(), ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), get_parking_exten(), LOG_WARNING, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_party_connected_line::source, strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xfer_park_call_helper(), xferfailsound, and xfersound.
02428 { 02429 struct ast_channel *transferer;/* Party B */ 02430 struct ast_channel *transferee;/* Party A */ 02431 struct ast_exten *park_exten; 02432 const char *transferer_real_context; 02433 char xferto[256] = ""; 02434 int res; 02435 int outstate=0; 02436 struct ast_channel *newchan; 02437 struct ast_channel *xferchan; 02438 struct ast_bridge_thread_obj *tobj; 02439 struct ast_bridge_config bconfig; 02440 int l; 02441 struct ast_party_connected_line connected_line; 02442 struct ast_datastore *features_datastore; 02443 struct ast_dial_features *dialfeatures = NULL; 02444 char *transferer_tech; 02445 char *transferer_name; 02446 char *transferer_name_orig; 02447 char *dash; 02448 02449 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", ast_channel_name(chan), ast_channel_name(peer), sense); 02450 set_peers(&transferer, &transferee, peer, chan, sense); 02451 transferer_real_context = real_ctx(transferer, transferee); 02452 02453 /* Start autoservice on transferee while we talk to the transferer */ 02454 ast_autoservice_start(transferee); 02455 ast_indicate(transferee, AST_CONTROL_HOLD); 02456 02457 /* Transfer */ 02458 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02459 if (res < 0) { 02460 finishup(transferee); 02461 return -1; 02462 } 02463 if (res > 0) { /* If they've typed a digit already, handle it */ 02464 xferto[0] = (char) res; 02465 } 02466 02467 /* this is specific of atxfer */ 02468 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02469 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02470 finishup(transferee); 02471 return -1; 02472 } 02473 l = strlen(xferto); 02474 if (res == 0) { 02475 if (l) { 02476 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02477 xferto, transferer_real_context); 02478 } else { 02479 /* Does anyone care about this case? */ 02480 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n"); 02481 } 02482 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02483 finishup(transferee); 02484 return AST_FEATURE_RETURN_SUCCESS; 02485 } 02486 02487 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02488 if (park_exten) { 02489 /* We are transfering the transferee to a parking lot. */ 02490 return xfer_park_call_helper(transferee, transferer, park_exten); 02491 } 02492 02493 /* Append context to dialed transfer number. */ 02494 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); 02495 02496 /* If we are performing an attended transfer and we have two channels involved then 02497 copy sound file information to play upon attended transfer completion */ 02498 if (transferee) { 02499 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02500 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02501 02502 if (!ast_strlen_zero(chan1_attended_sound)) { 02503 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 02504 } 02505 if (!ast_strlen_zero(chan2_attended_sound)) { 02506 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 02507 } 02508 } 02509 02510 /* Extract redial transferer information from the channel name. */ 02511 transferer_name_orig = ast_strdupa(ast_channel_name(transferer)); 02512 transferer_name = ast_strdupa(transferer_name_orig); 02513 transferer_tech = strsep(&transferer_name, "/"); 02514 dash = strrchr(transferer_name, '-'); 02515 if (dash) { 02516 /* Trim off channel name sequence/serial number. */ 02517 *dash = '\0'; 02518 } 02519 02520 /* Stop autoservice so we can monitor all parties involved in the transfer. */ 02521 if (ast_autoservice_stop(transferee) < 0) { 02522 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02523 return -1; 02524 } 02525 02526 /* Save connected line info for party B about party A in case transfer fails. */ 02527 ast_party_connected_line_init(&connected_line); 02528 ast_channel_lock(transferer); 02529 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02530 ast_channel_unlock(transferer); 02531 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02532 02533 /* Dial party C */ 02534 newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer, 02535 transferee, "Local", transferer->nativeformats, xferto, 02536 atxfernoanswertimeout, &outstate, ast_channel_language(transferer)); 02537 ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate); 02538 02539 if (!ast_check_hangup(transferer)) { 02540 int hangup_dont = 0; 02541 02542 /* Transferer (party B) is up */ 02543 ast_debug(1, "Actually doing an attended transfer.\n"); 02544 02545 /* Start autoservice on transferee while the transferer deals with party C. */ 02546 ast_autoservice_start(transferee); 02547 02548 ast_indicate(transferer, -1); 02549 if (!newchan) { 02550 /* any reason besides user requested cancel and busy triggers the failed sound */ 02551 switch (outstate) { 02552 case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */ 02553 case AST_CONTROL_BUSY: 02554 case AST_CONTROL_CONGESTION: 02555 if (ast_stream_and_wait(transferer, xfersound, "")) { 02556 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02557 } 02558 break; 02559 default: 02560 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02561 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02562 } 02563 break; 02564 } 02565 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02566 return AST_FEATURE_RETURN_SUCCESS; 02567 } 02568 02569 if (check_compat(transferer, newchan)) { 02570 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02571 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02572 } 02573 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02574 return AST_FEATURE_RETURN_SUCCESS; 02575 } 02576 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 02577 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 02578 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 02579 02580 /* ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we don't 02581 want that to happen here because we're also in another bridge already 02582 */ 02583 if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) { 02584 hangup_dont = 1; 02585 } 02586 /* Let party B and party C talk as long as they want. */ 02587 ast_bridge_call(transferer, newchan, &bconfig); 02588 if (hangup_dont) { 02589 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 02590 } 02591 02592 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 02593 ast_hangup(newchan); 02594 if (ast_stream_and_wait(transferer, xfersound, "")) { 02595 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02596 } 02597 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02598 return AST_FEATURE_RETURN_SUCCESS; 02599 } 02600 02601 /* Transferer (party B) is confirmed hung up at this point. */ 02602 if (check_compat(transferee, newchan)) { 02603 finishup(transferee); 02604 ast_party_connected_line_free(&connected_line); 02605 return -1; 02606 } 02607 02608 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02609 if ((ast_autoservice_stop(transferee) < 0) 02610 || (ast_waitfordigit(transferee, 100) < 0) 02611 || (ast_waitfordigit(newchan, 100) < 0) 02612 || ast_check_hangup(transferee) 02613 || ast_check_hangup(newchan)) { 02614 ast_hangup(newchan); 02615 ast_party_connected_line_free(&connected_line); 02616 return -1; 02617 } 02618 } else if (!ast_check_hangup(transferee)) { 02619 /* Transferer (party B) has hung up at this point. Doing blonde transfer. */ 02620 ast_debug(1, "Actually doing a blonde transfer.\n"); 02621 02622 if (!newchan && !atxferdropcall) { 02623 /* Party C is not available, try to call party B back. */ 02624 unsigned int tries = 0; 02625 02626 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 02627 ast_log(LOG_WARNING, 02628 "Transferer channel name: '%s' cannot be used for callback.\n", 02629 transferer_name_orig); 02630 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02631 ast_party_connected_line_free(&connected_line); 02632 return -1; 02633 } 02634 02635 tries = 0; 02636 for (;;) { 02637 /* Try to get party B back. */ 02638 ast_debug(1, "We're trying to callback %s/%s\n", 02639 transferer_tech, transferer_name); 02640 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02641 transferee, transferee, transferer_tech, 02642 transferee->nativeformats, transferer_name, 02643 atxfernoanswertimeout, &outstate, ast_channel_language(transferer)); 02644 ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n", 02645 !!newchan, outstate); 02646 if (newchan || ast_check_hangup(transferee)) { 02647 break; 02648 } 02649 02650 ++tries; 02651 if (atxfercallbackretries <= tries) { 02652 /* No more callback tries remaining. */ 02653 break; 02654 } 02655 02656 if (atxferloopdelay) { 02657 /* Transfer failed, sleeping */ 02658 ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n", 02659 atxferloopdelay); 02660 ast_safe_sleep(transferee, atxferloopdelay); 02661 if (ast_check_hangup(transferee)) { 02662 ast_party_connected_line_free(&connected_line); 02663 return -1; 02664 } 02665 } 02666 02667 /* Retry dialing party C. */ 02668 ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto); 02669 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02670 transferer, transferee, "Local", 02671 transferee->nativeformats, xferto, 02672 atxfernoanswertimeout, &outstate, ast_channel_language(transferer)); 02673 ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n", 02674 !!newchan, outstate); 02675 if (newchan || ast_check_hangup(transferee)) { 02676 break; 02677 } 02678 } 02679 } 02680 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02681 if (!newchan) { 02682 /* No party C or could not callback party B. */ 02683 ast_party_connected_line_free(&connected_line); 02684 return -1; 02685 } 02686 02687 /* newchan is up, we should prepare transferee and bridge them */ 02688 if (ast_check_hangup(newchan)) { 02689 ast_hangup(newchan); 02690 ast_party_connected_line_free(&connected_line); 02691 return -1; 02692 } 02693 if (check_compat(transferee, newchan)) { 02694 ast_party_connected_line_free(&connected_line); 02695 return -1; 02696 } 02697 } else { 02698 /* 02699 * Both the transferer and transferee have hungup. If newchan 02700 * is up, hang it up as it has no one to talk to. 02701 */ 02702 ast_debug(1, "Everyone is hungup.\n"); 02703 if (newchan) { 02704 ast_hangup(newchan); 02705 } 02706 ast_party_connected_line_free(&connected_line); 02707 return -1; 02708 } 02709 02710 /* Initiate the channel transfer of party A to party C (or recalled party B). */ 02711 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan); 02712 02713 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(transferee), 0, "Transfered/%s", ast_channel_name(transferee)); 02714 if (!xferchan) { 02715 ast_hangup(newchan); 02716 ast_party_connected_line_free(&connected_line); 02717 return -1; 02718 } 02719 02720 /* Give party A a momentary ringback tone during transfer. */ 02721 xferchan->visible_indication = AST_CONTROL_RINGING; 02722 02723 /* Make formats okay */ 02724 xferchan->readformat = transferee->readformat; 02725 xferchan->writeformat = transferee->writeformat; 02726 02727 ast_channel_masquerade(xferchan, transferee); 02728 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 02729 xferchan->_state = AST_STATE_UP; 02730 ast_clear_flag(xferchan, AST_FLAGS_ALL); 02731 02732 /* Do the masquerade manually to make sure that is is completed. */ 02733 ast_do_masquerade(xferchan); 02734 02735 newchan->_state = AST_STATE_UP; 02736 ast_clear_flag(newchan, AST_FLAGS_ALL); 02737 tobj = ast_calloc(1, sizeof(*tobj)); 02738 if (!tobj) { 02739 ast_hangup(xferchan); 02740 ast_hangup(newchan); 02741 ast_party_connected_line_free(&connected_line); 02742 return -1; 02743 } 02744 02745 ast_channel_lock(newchan); 02746 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 02747 dialfeatures = features_datastore->data; 02748 } 02749 ast_channel_unlock(newchan); 02750 02751 if (dialfeatures) { 02752 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 02753 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 02754 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 02755 dialfeatures = NULL; 02756 } 02757 02758 ast_channel_lock(xferchan); 02759 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 02760 dialfeatures = features_datastore->data; 02761 } 02762 ast_channel_unlock(xferchan); 02763 02764 if (dialfeatures) { 02765 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 02766 } 02767 02768 tobj->chan = newchan; 02769 tobj->peer = xferchan; 02770 tobj->bconfig = *config; 02771 02772 if (tobj->bconfig.end_bridge_callback_data_fixup) { 02773 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 02774 } 02775 02776 /* 02777 * xferchan is transferee, and newchan is the transfer target 02778 * So...in a transfer, who is the caller and who is the callee? 02779 * 02780 * When the call is originally made, it is clear who is caller and callee. 02781 * When a transfer occurs, it is my humble opinion that the transferee becomes 02782 * the caller, and the transfer target is the callee. 02783 * 02784 * The problem is that these macros were set with the intention of the original 02785 * caller and callee taking those roles. A transfer can totally mess things up, 02786 * to be technical. What sucks even more is that you can't effectively change 02787 * the macros in the dialplan during the call from the transferer to the transfer 02788 * target because the transferee is stuck with whatever role he originally had. 02789 * 02790 * I think the answer here is just to make sure that it is well documented that 02791 * during a transfer, the transferee is the "caller" and the transfer target 02792 * is the "callee." 02793 * 02794 * This means that if party B calls party A, and party B transfers party A to 02795 * party C, then A has switched roles for the call. Now party A will have the 02796 * caller macro called on his channel instead of the callee macro. 02797 * 02798 * Luckily, the method by which the party B to party C bridge is 02799 * launched above ensures that the transferee is the "chan" on 02800 * the bridge and the transfer target is the "peer," so my idea 02801 * for the roles post-transfer does not require extensive code 02802 * changes. 02803 */ 02804 02805 /* Transfer party C connected line to party A */ 02806 ast_channel_lock(transferer); 02807 /* 02808 * Due to a limitation regarding when callerID is set on a Local channel, 02809 * we use the transferer's connected line information here. 02810 */ 02811 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02812 ast_channel_unlock(transferer); 02813 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02814 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { 02815 ast_channel_update_connected_line(xferchan, &connected_line, NULL); 02816 } 02817 02818 /* Transfer party A connected line to party C */ 02819 ast_channel_lock(xferchan); 02820 ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller); 02821 ast_channel_unlock(xferchan); 02822 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02823 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { 02824 ast_channel_update_connected_line(newchan, &connected_line, NULL); 02825 } 02826 02827 if (ast_stream_and_wait(newchan, xfersound, "")) 02828 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02829 bridge_call_thread_launch(tobj); 02830 02831 ast_party_connected_line_free(&connected_line); 02832 return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */ 02833 }
| 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 2100 of file features.c.
References args, AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, AST_FEATURE_RETURN_SUCCESS, AST_FRAME_DTMF_END, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, LOG_NOTICE, 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.
02101 { 02102 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02103 int x = 0; 02104 size_t len; 02105 struct ast_channel *caller_chan, *callee_chan; 02106 const char *mixmonitor_spy_type = "MixMonitor"; 02107 int count = 0; 02108 02109 if (!mixmonitor_ok) { 02110 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02111 return -1; 02112 } 02113 02114 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 02115 mixmonitor_ok = 0; 02116 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 02117 return -1; 02118 } 02119 02120 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02121 02122 if (!ast_strlen_zero(courtesytone)) { 02123 if (ast_autoservice_start(callee_chan)) 02124 return -1; 02125 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END); 02126 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 02127 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02128 ast_autoservice_stop(callee_chan); 02129 return -1; 02130 } 02131 if (ast_autoservice_stop(callee_chan)) 02132 return -1; 02133 } 02134 02135 ast_channel_lock(callee_chan); 02136 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02137 ast_channel_unlock(callee_chan); 02138 02139 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 02140 if (count > 0) { 02141 02142 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 02143 02144 /* Make sure they are running */ 02145 ast_channel_lock(callee_chan); 02146 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 02147 ast_channel_unlock(callee_chan); 02148 if (count > 0) { 02149 if (!stopmixmonitor_ok) { 02150 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02151 return -1; 02152 } 02153 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 02154 stopmixmonitor_ok = 0; 02155 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 02156 return -1; 02157 } else { 02158 pbx_exec(callee_chan, stopmixmonitor_app, ""); 02159 return AST_FEATURE_RETURN_SUCCESS; 02160 } 02161 } 02162 02163 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 02164 } 02165 02166 if (caller_chan && callee_chan) { 02167 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 02168 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 02169 02170 if (!touch_format) 02171 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 02172 02173 if (!touch_monitor) 02174 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 02175 02176 if (touch_monitor) { 02177 len = strlen(touch_monitor) + 50; 02178 args = alloca(len); 02179 touch_filename = alloca(len); 02180 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 02181 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 02182 } else { 02183 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 02184 caller_chan->caller.id.number.str, ast_channel_name(caller_chan))); 02185 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 02186 callee_chan->caller.id.number.str, ast_channel_name(callee_chan))); 02187 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02188 args = alloca(len); 02189 touch_filename = alloca(len); 02190 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 02191 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 02192 } 02193 02194 for( x = 0; x < strlen(args); x++) { 02195 if (args[x] == '/') 02196 args[x] = '-'; 02197 } 02198 02199 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 02200 02201 pbx_exec(callee_chan, mixmonitor_app, args); 02202 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02203 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 02204 return AST_FEATURE_RETURN_SUCCESS; 02205 02206 } 02207 02208 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 02209 return -1; 02210 02211 }
| 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 2005 of file features.c.
References args, ast_channel_name(), AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, LOG_NOTICE, 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.
02006 { 02007 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 02008 int x = 0; 02009 size_t len; 02010 struct ast_channel *caller_chan, *callee_chan; 02011 const char *automon_message_start = NULL; 02012 const char *automon_message_stop = NULL; 02013 02014 if (!monitor_ok) { 02015 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02016 return -1; 02017 } 02018 02019 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 02020 monitor_ok = 0; 02021 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 02022 return -1; 02023 } 02024 02025 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 02026 if (caller_chan) { /* Find extra messages */ 02027 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 02028 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 02029 } 02030 02031 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 02032 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 02033 return -1; 02034 } 02035 } 02036 02037 if (callee_chan->monitor) { 02038 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 02039 if (!ast_strlen_zero(automon_message_stop)) { 02040 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 02041 } 02042 callee_chan->monitor->stop(callee_chan, 1); 02043 return AST_FEATURE_RETURN_SUCCESS; 02044 } 02045 02046 if (caller_chan && callee_chan) { 02047 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 02048 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 02049 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 02050 02051 if (!touch_format) 02052 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 02053 02054 if (!touch_monitor) 02055 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 02056 02057 if (!touch_monitor_prefix) 02058 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 02059 02060 if (touch_monitor) { 02061 len = strlen(touch_monitor) + 50; 02062 args = alloca(len); 02063 touch_filename = alloca(len); 02064 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 02065 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02066 } else { 02067 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 02068 caller_chan->caller.id.number.str, ast_channel_name(caller_chan))); 02069 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 02070 callee_chan->caller.id.number.str, ast_channel_name(callee_chan))); 02071 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 02072 args = alloca(len); 02073 touch_filename = alloca(len); 02074 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 02075 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 02076 } 02077 02078 for(x = 0; x < strlen(args); x++) { 02079 if (args[x] == '/') 02080 args[x] = '-'; 02081 } 02082 02083 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 02084 02085 pbx_exec(callee_chan, monitor_app, args); 02086 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02087 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 02088 02089 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 02090 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 02091 } 02092 02093 return AST_FEATURE_RETURN_SUCCESS; 02094 } 02095 02096 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 02097 return -1; 02098 }
| static int builtin_blindtransfer | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| void * | data | |||
| ) | [static] |
Blind transfer user to another extension.
| chan | channel to be transfered | |
| peer | channel initiated blind transfer | |
| config | ||
| code | ||
| data | ||
| sense | feature options |
| AST_FEATURE_RETURN_SUCCESS. | ||
| -1 | on failure. |
Definition at line 2256 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_name(), 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().
02257 { 02258 struct ast_channel *transferer; 02259 struct ast_channel *transferee; 02260 struct ast_exten *park_exten; 02261 const char *transferer_real_context; 02262 char xferto[256] = ""; 02263 int res; 02264 02265 ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", ast_channel_name(chan), ast_channel_name(peer), sense); 02266 set_peers(&transferer, &transferee, peer, chan, sense); 02267 transferer_real_context = real_ctx(transferer, transferee); 02268 02269 /* Start autoservice on transferee while we talk to the transferer */ 02270 ast_autoservice_start(transferee); 02271 ast_indicate(transferee, AST_CONTROL_HOLD); 02272 02273 /* Transfer */ 02274 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02275 if (res < 0) { 02276 finishup(transferee); 02277 return -1; /* error ? */ 02278 } 02279 if (res > 0) { /* If they've typed a digit already, handle it */ 02280 xferto[0] = (char) res; 02281 } 02282 02283 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02284 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02285 finishup(transferee); 02286 return -1; 02287 } 02288 if (res == 0) { 02289 if (xferto[0]) { 02290 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02291 xferto, transferer_real_context); 02292 } else { 02293 /* Does anyone care about this case? */ 02294 ast_log(LOG_WARNING, "No digits dialed.\n"); 02295 } 02296 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02297 finishup(transferee); 02298 return AST_FEATURE_RETURN_SUCCESS; 02299 } 02300 02301 park_exten = get_parking_exten(xferto, transferer, transferer_real_context); 02302 if (park_exten) { 02303 /* We are transfering the transferee to a parking lot. */ 02304 return xfer_park_call_helper(transferee, transferer, park_exten); 02305 } 02306 02307 /* Do blind transfer. */ 02308 ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n", 02309 ast_channel_name(transferee), xferto, transferer_real_context); 02310 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee); 02311 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", ast_channel_name(transferee)); 02312 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", ast_channel_name(transferer)); 02313 finishup(transferee); 02314 ast_channel_lock(transferer); 02315 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 02316 transferer->cdr = ast_cdr_alloc(); 02317 if (transferer->cdr) { 02318 ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */ 02319 ast_cdr_start(transferer->cdr); 02320 } 02321 } 02322 ast_channel_unlock(transferer); 02323 if (transferer->cdr) { 02324 struct ast_cdr *swap = transferer->cdr; 02325 02326 ast_debug(1, 02327 "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 02328 ast_channel_name(transferer), ast_channel_name(transferee), transferer->cdr->lastapp, 02329 transferer->cdr->lastdata, transferer->cdr->channel, 02330 transferer->cdr->dstchannel); 02331 ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 02332 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, 02333 transferee->cdr->dstchannel); 02334 ast_debug(1, "transferer_real_context=%s; xferto=%s\n", 02335 transferer_real_context, xferto); 02336 /* swap cdrs-- it will save us some time & work */ 02337 transferer->cdr = transferee->cdr; 02338 transferee->cdr = swap; 02339 } 02340 if (!transferee->pbx) { 02341 /* Doh! Use our handy async_goto functions */ 02342 ast_debug(1, "About to ast_async_goto %s.\n", ast_channel_name(transferee)); 02343 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) { 02344 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 02345 } 02346 02347 /* The transferee is masqueraded and the original bridged channels can be hungup. */ 02348 res = -1; 02349 } else { 02350 /* Set the transferee's new extension, since it exists, using transferer context */ 02351 ast_debug(1, "About to explicit goto %s, it has a PBX.\n", ast_channel_name(transferee)); 02352 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 02353 set_c_e_p(transferee, transferer_real_context, xferto, 0); 02354 02355 /* 02356 * Break the bridge. The transferee needs to resume executing 02357 * dialplan at the xferto location. 02358 */ 02359 res = AST_FEATURE_RETURN_SUCCESSBREAK; 02360 } 02361 check_goto_on_transfer(transferer); 02362 return res; 02363 }
| 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 2213 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
02214 { 02215 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 02216 return AST_FEATURE_RETURN_HANGUP; 02217 }
| 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 1883 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().
01884 { 01885 struct ast_channel *parker; 01886 struct ast_channel *parkee; 01887 struct ast_park_call_args args = { 0, }; 01888 01889 /* 01890 * We used to set chan's exten and priority to "s" and 1 here, 01891 * but this generates (in some cases) an invalid extension, and 01892 * if "s" exists, could errantly cause execution of extensions 01893 * you don't expect. It makes more sense to let nature take its 01894 * course when chan finishes, and let the pbx do its thing and 01895 * hang up when the park is over. 01896 */ 01897 01898 /* Answer if call is not up */ 01899 if (chan->_state != AST_STATE_UP) { 01900 /* 01901 * XXX Why are we doing this? Both of the channels should be up 01902 * since you cannot do DTMF features unless you are bridged. 01903 */ 01904 if (ast_answer(chan)) { 01905 return -1; 01906 } 01907 01908 /* Sleep to allow VoIP streams to settle down */ 01909 if (ast_safe_sleep(chan, 1000)) { 01910 return -1; 01911 } 01912 } 01913 01914 /* one direction used to call park_call.... */ 01915 set_peers(&parker, &parkee, peer, chan, sense); 01916 return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1; 01917 }
| static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
| struct ast_flags * | features_caller, | |||
| char * | options, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 4519 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().
04520 { 04521 int i = 0; 04522 enum { 04523 OPT_CALLEE_REDIRECT = 't', 04524 OPT_CALLER_REDIRECT = 'T', 04525 OPT_CALLEE_AUTOMON = 'w', 04526 OPT_CALLER_AUTOMON = 'W', 04527 OPT_CALLEE_DISCONNECT = 'h', 04528 OPT_CALLER_DISCONNECT = 'H', 04529 OPT_CALLEE_PARKCALL = 'k', 04530 OPT_CALLER_PARKCALL = 'K', 04531 }; 04532 04533 memset(options, 0, len); 04534 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 04535 options[i++] = OPT_CALLER_REDIRECT; 04536 } 04537 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 04538 options[i++] = OPT_CALLER_AUTOMON; 04539 } 04540 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 04541 options[i++] = OPT_CALLER_DISCONNECT; 04542 } 04543 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 04544 options[i++] = OPT_CALLER_PARKCALL; 04545 } 04546 04547 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 04548 options[i++] = OPT_CALLEE_REDIRECT; 04549 } 04550 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 04551 options[i++] = OPT_CALLEE_AUTOMON; 04552 } 04553 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 04554 options[i++] = OPT_CALLEE_DISCONNECT; 04555 } 04556 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 04557 options[i++] = OPT_CALLEE_PARKCALL; 04558 } 04559 04560 return options; 04561 }
| 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 2372 of file features.c.
References ast_channel_make_compatible(), ast_channel_name(), ast_hangup(), ast_log(), and LOG_WARNING.
Referenced by builtin_atxfer().
02373 { 02374 if (ast_channel_make_compatible(c, newchan) < 0) { 02375 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 02376 ast_channel_name(c), ast_channel_name(newchan)); 02377 ast_hangup(newchan); 02378 return -1; 02379 } 02380 return 0; 02381 }
| 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 853 of file features.c.
References ast_channel::_state, ast_channel_alloc, ast_channel_clear_softhangup(), ast_channel_linkedid(), ast_channel_lock, ast_channel_masquerade(), ast_channel_name(), 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().
00854 { 00855 struct ast_channel *xferchan; 00856 const char *val; 00857 char *goto_on_transfer; 00858 char *x; 00859 00860 ast_channel_lock(chan); 00861 val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00862 if (ast_strlen_zero(val)) { 00863 ast_channel_unlock(chan); 00864 return; 00865 } 00866 goto_on_transfer = ast_strdupa(val); 00867 ast_channel_unlock(chan); 00868 00869 ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, ast_channel_name(chan)); 00870 00871 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(chan), 0, 00872 "%s", ast_channel_name(chan)); 00873 if (!xferchan) { 00874 return; 00875 } 00876 00877 /* Make formats okay */ 00878 xferchan->readformat = chan->readformat; 00879 xferchan->writeformat = chan->writeformat; 00880 00881 if (ast_channel_masquerade(xferchan, chan)) { 00882 /* Failed to setup masquerade. */ 00883 ast_hangup(xferchan); 00884 return; 00885 } 00886 00887 for (x = goto_on_transfer; *x; ++x) { 00888 if (*x == '^') { 00889 *x = ','; 00890 } 00891 } 00892 ast_parseable_goto(xferchan, goto_on_transfer); 00893 xferchan->_state = AST_STATE_UP; 00894 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00895 ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL); 00896 00897 if (ast_do_masquerade(xferchan) || ast_pbx_start(xferchan)) { 00898 /* Failed to do masquerade or could not start PBX. */ 00899 ast_hangup(xferchan); 00900 } 00901 }
| static void clear_dialed_interfaces | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 3823 of file features.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_datastore_free(), ast_log(), dialed_interface_info, LOG_DEBUG, and option_debug.
Referenced by ast_bridge_call().
03824 { 03825 struct ast_datastore *di_datastore; 03826 03827 ast_channel_lock(chan); 03828 if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) { 03829 if (option_debug) { 03830 ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", ast_channel_name(chan)); 03831 } 03832 if (!ast_channel_datastore_remove(chan, di_datastore)) { 03833 ast_datastore_free(di_datastore); 03834 } 03835 } 03836 ast_channel_unlock(chan); 03837 }
| 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 4892 of file features.c.
References ao2_ref, ast_debug, ast_parkinglot::cfg, create_parkinglot(), and find_parkinglot().
Referenced by create_dynamic_parkinglot().
04893 { 04894 struct ast_parkinglot *copylot; 04895 04896 if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */ 04897 ao2_ref(copylot, -1); 04898 return NULL; 04899 } 04900 04901 copylot = create_parkinglot(name); 04902 if (!copylot) { 04903 return NULL; 04904 } 04905 04906 ast_debug(1, "Building parking lot %s\n", name); 04907 04908 /* Copy the source parking lot configuration. */ 04909 copylot->cfg = parkinglot->cfg; 04910 04911 return copylot; 04912 }
| static struct ast_parkinglot* create_dynamic_parkinglot | ( | const char * | name, | |
| struct ast_channel * | chan | |||
| ) | [static, read] |
Definition at line 1083 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().
01084 { 01085 const char *dyn_context; 01086 const char *dyn_exten; 01087 const char *dyn_range; 01088 const char *template_name; 01089 struct ast_parkinglot *template_parkinglot = NULL; 01090 struct ast_parkinglot *parkinglot; 01091 int dyn_start; 01092 int dyn_end; 01093 01094 ast_channel_lock(chan); 01095 template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), "")); 01096 dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), "")); 01097 dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), "")); 01098 dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), "")); 01099 ast_channel_unlock(chan); 01100 01101 if (!ast_strlen_zero(template_name)) { 01102 template_parkinglot = find_parkinglot(template_name); 01103 if (!template_parkinglot) { 01104 ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n", 01105 template_name); 01106 } else if (template_parkinglot->cfg.is_invalid) { 01107 ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n", 01108 template_name); 01109 parkinglot_unref(template_parkinglot); 01110 template_parkinglot = NULL; 01111 } 01112 } 01113 if (!template_parkinglot) { 01114 template_parkinglot = parkinglot_addref(default_parkinglot); 01115 ast_debug(1, "Using default parking lot for template\n"); 01116 } 01117 01118 parkinglot = copy_parkinglot(name, template_parkinglot); 01119 if (!parkinglot) { 01120 ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n"); 01121 } else { 01122 /* Configure the dynamic parking lot. */ 01123 if (!ast_strlen_zero(dyn_context)) { 01124 ast_copy_string(parkinglot->cfg.parking_con, dyn_context, 01125 sizeof(parkinglot->cfg.parking_con)); 01126 } 01127 if (!ast_strlen_zero(dyn_exten)) { 01128 ast_copy_string(parkinglot->cfg.parkext, dyn_exten, 01129 sizeof(parkinglot->cfg.parkext)); 01130 } 01131 if (!ast_strlen_zero(dyn_range)) { 01132 if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) { 01133 ast_log(LOG_WARNING, 01134 "Format for parking positions is a-b, where a and b are numbers\n"); 01135 } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) { 01136 ast_log(LOG_WARNING, 01137 "Format for parking positions is a-b, where a <= b\n"); 01138 } else { 01139 parkinglot->cfg.parking_start = dyn_start; 01140 parkinglot->cfg.parking_stop = dyn_end; 01141 } 01142 } 01143 01144 /* 01145 * Sanity check for dynamic parking lot configuration. 01146 * 01147 * XXX It may be desirable to instead check if the dynamic 01148 * parking lot overlaps any existing lots like what is done for 01149 * a reload. 01150 */ 01151 if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) { 01152 if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext) 01153 && parkinglot->cfg.parkext_exclusive) { 01154 ast_log(LOG_WARNING, 01155 "Parking lot '%s' conflicts with template parking lot '%s'!\n" 01156 "Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n", 01157 parkinglot->name, template_parkinglot->name); 01158 } 01159 if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start 01160 && parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop) 01161 || (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop 01162 && parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop) 01163 || (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start 01164 && template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) { 01165 ast_log(LOG_WARNING, 01166 "Parking lot '%s' parking spaces overlap template parking lot '%s'!\n" 01167 "Change PARKINGDYNPOS.\n", 01168 parkinglot->name, template_parkinglot->name); 01169 } 01170 } 01171 01172 parkinglot_activate(parkinglot); 01173 ao2_link(parkinglots, parkinglot); 01174 } 01175 parkinglot_unref(template_parkinglot); 01176 01177 return parkinglot; 01178 }
| static struct ast_parkinglot * create_parkinglot | ( | const char * | name | ) | [static, read] |
Allocate parking lot structure.
Definition at line 5320 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().
05321 { 05322 struct ast_parkinglot *newlot; 05323 05324 if (ast_strlen_zero(name)) { /* No name specified */ 05325 return NULL; 05326 } 05327 05328 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 05329 if (!newlot) 05330 return NULL; 05331 05332 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 05333 newlot->cfg.is_invalid = 1;/* No config is set yet. */ 05334 AST_LIST_HEAD_INIT(&newlot->parkings); 05335 05336 return newlot; 05337 }
| static void destroy_dialplan_usage_context | ( | struct parking_dp_context * | doomed | ) | [static] |
Definition at line 5915 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().
05916 { 05917 struct parking_dp_ramp *ramp; 05918 struct parking_dp_spaces *spaces; 05919 05920 while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) { 05921 ast_free(ramp); 05922 } 05923 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) { 05924 ast_free(spaces); 05925 } 05926 while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) { 05927 ast_free(spaces); 05928 } 05929 ast_free(doomed); 05930 }
| static void destroy_dialplan_usage_map | ( | struct parking_dp_map * | doomed | ) | [static] |
Definition at line 5940 of file features.c.
References AST_LIST_REMOVE_HEAD, and destroy_dialplan_usage_context().
Referenced by load_config().
05941 { 05942 struct parking_dp_context *item; 05943 05944 while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) { 05945 destroy_dialplan_usage_context(item); 05946 } 05947 }
| static void destroy_space | ( | const char * | context, | |
| int | space | |||
| ) | [static] |
Definition at line 6370 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().
06371 { 06372 char exten[AST_MAX_EXTENSION]; 06373 06374 /* Destroy priorities of the parking space that we registered. */ 06375 snprintf(exten, sizeof(exten), "%d", space); 06376 remove_exten_if_exist(context, exten, PRIORITY_HINT); 06377 remove_exten_if_exist(context, exten, 1); 06378 }
| static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 747 of file features.c.
References ast_free.
00748 { 00749 struct ast_dial_features *df = data; 00750 if (df) { 00751 ast_free(df); 00752 } 00753 }
| static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 734 of file features.c.
References ast_calloc.
00735 { 00736 struct ast_dial_features *df = data, *df_copy; 00737 00738 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00739 return NULL; 00740 } 00741 00742 memcpy(df_copy, df, sizeof(*df)); 00743 00744 return df_copy; 00745 }
| static int dialplan_usage_add_parkinglot | ( | struct parking_dp_map * | usage_map, | |
| struct ast_parkinglot * | lot, | |||
| int | complain | |||
| ) | [static] |
Definition at line 6223 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().
06224 { 06225 struct parking_dp_context *cur_ctx; 06226 struct parking_dp_context *new_ctx; 06227 int cmp; 06228 06229 AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) { 06230 cmp = strcmp(lot->cfg.parking_con, cur_ctx->context); 06231 if (cmp > 0) { 06232 /* The parking lot context goes after this node. */ 06233 continue; 06234 } 06235 if (cmp == 0) { 06236 /* This is the node we will add parking lot spaces to the map. */ 06237 return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain); 06238 } 06239 /* The new parking lot context goes before this node. */ 06240 new_ctx = build_dialplan_useage_context(lot); 06241 if (!new_ctx) { 06242 return -1; 06243 } 06244 AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node); 06245 return 0; 06246 } 06247 AST_LIST_TRAVERSE_SAFE_END; 06248 06249 /* New parking lot context goes on the end. */ 06250 new_ctx = build_dialplan_useage_context(lot); 06251 if (!new_ctx) { 06252 return -1; 06253 } 06254 AST_LIST_INSERT_TAIL(usage_map, new_ctx, node); 06255 return 0; 06256 }
| static int dialplan_usage_add_parkinglot_data | ( | struct parking_dp_context * | ctx_node, | |
| struct ast_parkinglot * | lot, | |||
| int | complain | |||
| ) | [static] |
Definition at line 6169 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().
06170 { 06171 if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext, 06172 lot->cfg.parkext_exclusive, lot, complain)) { 06173 return -1; 06174 } 06175 if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start, 06176 lot->cfg.parking_stop, lot, complain)) { 06177 return -1; 06178 } 06179 if (lot->cfg.parkaddhints 06180 && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start, 06181 lot->cfg.parking_stop, lot, 0)) { 06182 return -1; 06183 } 06184 return 0; 06185 }
| static void 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. |
Definition at line 6810 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_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
Referenced by action_bridge(), and bridge_exec().
06811 { 06812 ast_moh_stop(chan); 06813 ast_channel_lock_both(chan, tmpchan); 06814 ast_setstate(tmpchan, chan->_state); 06815 tmpchan->readformat = chan->readformat; 06816 tmpchan->writeformat = chan->writeformat; 06817 ast_channel_unlock(chan); 06818 ast_channel_unlock(tmpchan); 06819 06820 ast_channel_masquerade(tmpchan, chan); 06821 06822 /* must be done without any channel locks held */ 06823 ast_do_masquerade(tmpchan); 06824 06825 /* when returning from bridge, the channel will continue at the next priority */ 06826 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 06827 }
| static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
| ignore | unused var. |
Definition at line 4842 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().
04843 { 04844 struct pollfd *pfds = NULL, *new_pfds = NULL; 04845 int nfds = 0, new_nfds = 0; 04846 04847 for (;;) { 04848 struct ao2_iterator iter; 04849 struct ast_parkinglot *curlot; 04850 int ms = -1; /* poll2 timeout, uninitialized */ 04851 04852 iter = ao2_iterator_init(parkinglots, 0); 04853 while ((curlot = ao2_iterator_next(&iter))) { 04854 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms); 04855 ao2_ref(curlot, -1); 04856 } 04857 ao2_iterator_destroy(&iter); 04858 04859 /* Recycle */ 04860 ast_free(pfds); 04861 pfds = new_pfds; 04862 nfds = new_nfds; 04863 new_pfds = NULL; 04864 new_nfds = 0; 04865 04866 /* Wait for something to happen */ 04867 ast_poll(pfds, nfds, ms); 04868 pthread_testcancel(); 04869 } 04870 /* If this WERE reached, we'd need to free(pfds) */ 04871 return NULL; /* Never reached */ 04872 }
| static int feature_check | ( | struct ast_channel * | chan, | |
| struct ast_flags * | features, | |||
| char * | code | |||
| ) | [static] |
Check if a feature exists.
Definition at line 3292 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().
03292 { 03293 char *chan_dynamic_features; 03294 ast_channel_lock(chan); 03295 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03296 ast_channel_unlock(chan); 03297 03298 return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL); 03299 }
| 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 3039 of file features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, AST_FRAME_DTMF_END, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), and ast_call_feature::sname.
Referenced by process_applicationmap_line().
03040 { 03041 struct ast_app *app; 03042 struct ast_call_feature *feature = data; 03043 struct ast_channel *work, *idle; 03044 int res; 03045 03046 if (!feature) { /* shouldn't ever happen! */ 03047 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 03048 return -1; 03049 } 03050 03051 if (sense == FEATURE_SENSE_CHAN) { 03052 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 03053 return AST_FEATURE_RETURN_KEEPTRYING; 03054 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03055 work = chan; 03056 idle = peer; 03057 } else { 03058 work = peer; 03059 idle = chan; 03060 } 03061 } else { 03062 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 03063 return AST_FEATURE_RETURN_KEEPTRYING; 03064 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 03065 work = peer; 03066 idle = chan; 03067 } else { 03068 work = chan; 03069 idle = peer; 03070 } 03071 } 03072 03073 if (!(app = pbx_findapp(feature->app))) { 03074 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 03075 return -2; 03076 } 03077 03078 ast_autoservice_start(idle); 03079 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END); 03080 03081 if(work && idle) { 03082 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", ast_channel_name(idle)); 03083 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", ast_channel_name(work)); 03084 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname); 03085 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname); 03086 } 03087 03088 if (!ast_strlen_zero(feature->moh_class)) 03089 ast_moh_start(idle, feature->moh_class, NULL); 03090 03091 res = pbx_exec(work, app, feature->app_args); 03092 03093 if (!ast_strlen_zero(feature->moh_class)) 03094 ast_moh_stop(idle); 03095 03096 ast_autoservice_stop(idle); 03097 03098 if (res) { 03099 return AST_FEATURE_RETURN_SUCCESSBREAK; 03100 } 03101 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 03102 }
| 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 3257 of file features.c.
References ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, FEATURE_INTERPRET_DO, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_flags::flags, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
03257 { 03258 03259 char dynamic_features_buf[128]; 03260 const char *peer_dynamic_features, *chan_dynamic_features; 03261 struct ast_flags features; 03262 struct ast_call_feature feature; 03263 if (sense == FEATURE_SENSE_CHAN) { 03264 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 03265 } 03266 else { 03267 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 03268 } 03269 03270 ast_channel_lock(peer); 03271 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 03272 ast_channel_unlock(peer); 03273 03274 ast_channel_lock(chan); 03275 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 03276 ast_channel_unlock(chan); 03277 03278 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,"")); 03279 03280 ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", ast_channel_name(chan), ast_channel_name(peer), code, sense, features.flags, dynamic_features_buf); 03281 03282 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature); 03283 }
| 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 3142 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, ast_call_feature::sname, and strsep().
Referenced by ast_feature_detect(), feature_check(), and feature_interpret().
03145 { 03146 int x; 03147 struct feature_group *fg = NULL; 03148 struct feature_group_exten *fge; 03149 struct ast_call_feature *tmpfeature; 03150 char *tmp, *tok; 03151 int res = AST_FEATURE_RETURN_PASSDIGITS; 03152 int feature_detected = 0; 03153 03154 if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) { 03155 return -1; /* can not run feature operation */ 03156 } 03157 03158 ast_rwlock_rdlock(&features_lock); 03159 for (x = 0; x < FEATURES_COUNT; x++) { 03160 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 03161 !ast_strlen_zero(builtin_features[x].exten)) { 03162 /* Feature is up for consideration */ 03163 if (!strcmp(builtin_features[x].exten, code)) { 03164 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 03165 if (operation == FEATURE_INTERPRET_CHECK) { 03166 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03167 } else if (operation == FEATURE_INTERPRET_DO) { 03168 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 03169 } 03170 if (feature) { 03171 memcpy(feature, &builtin_features[x], sizeof(feature)); 03172 } 03173 feature_detected = 1; 03174 break; 03175 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 03176 if (res == AST_FEATURE_RETURN_PASSDIGITS) { 03177 res = AST_FEATURE_RETURN_STOREDIGITS; 03178 } 03179 } 03180 } 03181 } 03182 ast_rwlock_unlock(&features_lock); 03183 03184 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 03185 return res; 03186 } 03187 03188 tmp = dynamic_features_buf; 03189 03190 while ((tok = strsep(&tmp, "#"))) { 03191 AST_RWLIST_RDLOCK(&feature_groups); 03192 03193 fg = find_group(tok); 03194 03195 if (fg) { 03196 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03197 if (!strcmp(fge->exten, code)) { 03198 if (operation) { 03199 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 03200 } 03201 memcpy(feature, fge->feature, sizeof(feature)); 03202 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03203 AST_RWLIST_UNLOCK(&feature_groups); 03204 break; 03205 } 03206 res = AST_FEATURE_RETURN_PASSDIGITS; 03207 } else if (!strncmp(fge->exten, code, strlen(code))) { 03208 res = AST_FEATURE_RETURN_STOREDIGITS; 03209 } 03210 } 03211 if (fge) { 03212 break; 03213 } 03214 } 03215 03216 AST_RWLIST_UNLOCK(&feature_groups); 03217 03218 AST_RWLIST_RDLOCK(&feature_list); 03219 03220 if (!(tmpfeature = find_dynamic_feature(tok))) { 03221 AST_RWLIST_UNLOCK(&feature_list); 03222 continue; 03223 } 03224 03225 /* Feature is up for consideration */ 03226 if (!strcmp(tmpfeature->exten, code)) { 03227 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 03228 if (operation == FEATURE_INTERPRET_CHECK) { 03229 res = AST_FEATURE_RETURN_SUCCESS; /* We found something */ 03230 } else if (operation == FEATURE_INTERPRET_DO) { 03231 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 03232 } 03233 if (feature) { 03234 memcpy(feature, tmpfeature, sizeof(feature)); 03235 } 03236 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 03237 AST_RWLIST_UNLOCK(&feature_list); 03238 break; 03239 } 03240 res = AST_FEATURE_RETURN_PASSDIGITS; 03241 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 03242 res = AST_FEATURE_RETURN_STOREDIGITS; 03243 03244 AST_RWLIST_UNLOCK(&feature_list); 03245 } 03246 03247 return res; 03248 }
| static struct ast_channel * feature_request_and_dial | ( | struct ast_channel * | caller, | |
| const char * | caller_name, | |||
| struct ast_channel * | requestor, | |||
| struct ast_channel * | transferee, | |||
| const char * | type, | |||
| struct ast_format_cap * | cap, | |||
| const char * | addr, | |||
| int | timeout, | |||
| int * | outstate, | |||
| const char * | language | |||
| ) | [static, read] |
Definition at line 3396 of file features.c.
References ast_channel::_state, ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_call_forward(), ast_channel_connected_line_macro(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_name(), 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_format_cap_add(), ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_frisolate(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_is_deferrable_frame(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_party_connected_line_free(), ast_party_connected_line_set_init(), ast_poll_channel_add(), ast_poll_channel_del(), ast_queue_frame_head(), ast_read(), ast_request(), ast_rwlock_rdlock, ast_rwlock_unlock, AST_STATE_UP, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), ast_channel::caller, cause, 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().
03400 { 03401 int state = 0; 03402 int cause = 0; 03403 int to; 03404 int caller_hungup; 03405 int transferee_hungup; 03406 struct ast_channel *chan; 03407 struct ast_channel *monitor_chans[3]; 03408 struct ast_channel *active_channel; 03409 int res; 03410 int ready = 0; 03411 struct timeval started; 03412 int x, len = 0; 03413 char *disconnect_code = NULL, *dialed_code = NULL; 03414 struct ast_format_cap *tmp_cap; 03415 struct ast_format best_audio_fmt; 03416 struct ast_frame *f; 03417 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; 03418 03419 tmp_cap = ast_format_cap_alloc_nolock(); 03420 if (!tmp_cap) { 03421 if (outstate) { 03422 *outstate = 0; 03423 } 03424 return NULL; 03425 } 03426 ast_best_codec(cap, &best_audio_fmt); 03427 ast_format_cap_add(tmp_cap, &best_audio_fmt); 03428 03429 caller_hungup = ast_check_hangup(caller); 03430 03431 if (!(chan = ast_request(type, tmp_cap, requestor, addr, &cause))) { 03432 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, addr); 03433 switch (cause) { 03434 case AST_CAUSE_BUSY: 03435 state = AST_CONTROL_BUSY; 03436 break; 03437 case AST_CAUSE_CONGESTION: 03438 state = AST_CONTROL_CONGESTION; 03439 break; 03440 default: 03441 state = 0; 03442 break; 03443 } 03444 goto done; 03445 } 03446 03447 ast_channel_language_set(chan, language); 03448 ast_channel_inherit_variables(caller, chan); 03449 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name); 03450 03451 ast_channel_lock(chan); 03452 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller); 03453 ast_channel_unlock(chan); 03454 03455 if (ast_call(chan, addr, timeout)) { 03456 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, addr); 03457 switch (chan->hangupcause) { 03458 case AST_CAUSE_BUSY: 03459 state = AST_CONTROL_BUSY; 03460 break; 03461 case AST_CAUSE_CONGESTION: 03462 state = AST_CONTROL_CONGESTION; 03463 break; 03464 default: 03465 state = 0; 03466 break; 03467 } 03468 goto done; 03469 } 03470 03471 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 03472 ast_rwlock_rdlock(&features_lock); 03473 for (x = 0; x < FEATURES_COUNT; x++) { 03474 if (strcasecmp(builtin_features[x].sname, "disconnect")) 03475 continue; 03476 03477 disconnect_code = builtin_features[x].exten; 03478 len = strlen(disconnect_code) + 1; 03479 dialed_code = alloca(len); 03480 memset(dialed_code, 0, len); 03481 break; 03482 } 03483 ast_rwlock_unlock(&features_lock); 03484 x = 0; 03485 started = ast_tvnow(); 03486 to = timeout; 03487 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); 03488 03489 ast_poll_channel_add(caller, chan); 03490 03491 transferee_hungup = 0; 03492 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) { 03493 int num_chans = 0; 03494 03495 monitor_chans[num_chans++] = transferee; 03496 monitor_chans[num_chans++] = chan; 03497 if (!caller_hungup) { 03498 if (ast_check_hangup(caller)) { 03499 caller_hungup = 1; 03500 03501 #if defined(ATXFER_NULL_TECH) 03502 /* Change caller's name to ensure that it will remain unique. */ 03503 set_new_chan_name(caller); 03504 03505 /* 03506 * Get rid of caller's physical technology so it is free for 03507 * other calls. 03508 */ 03509 set_kill_chan_tech(caller); 03510 #endif /* defined(ATXFER_NULL_TECH) */ 03511 } else { 03512 /* caller is not hungup so monitor it. */ 03513 monitor_chans[num_chans++] = caller; 03514 } 03515 } 03516 03517 /* see if the timeout has been violated */ 03518 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 03519 state = AST_CONTROL_UNHOLD; 03520 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", ast_channel_name(chan)); 03521 break; /*doh! timeout*/ 03522 } 03523 03524 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to); 03525 if (!active_channel) 03526 continue; 03527 03528 f = NULL; 03529 if (transferee == active_channel) { 03530 struct ast_frame *dup_f; 03531 03532 f = ast_read(transferee); 03533 if (f == NULL) { /*doh! where'd he go?*/ 03534 transferee_hungup = 1; 03535 state = 0; 03536 break; 03537 } 03538 if (ast_is_deferrable_frame(f)) { 03539 dup_f = ast_frisolate(f); 03540 if (dup_f) { 03541 if (dup_f == f) { 03542 f = NULL; 03543 } 03544 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); 03545 } 03546 } 03547 } else if (chan == active_channel) { 03548 if (!ast_strlen_zero(ast_channel_call_forward(chan))) { 03549 state = 0; 03550 ast_autoservice_start(transferee); 03551 chan = ast_call_forward(caller, chan, NULL, tmp_cap, NULL, &state); 03552 ast_autoservice_stop(transferee); 03553 if (!chan) { 03554 break; 03555 } 03556 continue; 03557 } 03558 f = ast_read(chan); 03559 if (f == NULL) { /*doh! where'd he go?*/ 03560 switch (chan->hangupcause) { 03561 case AST_CAUSE_BUSY: 03562 state = AST_CONTROL_BUSY; 03563 break; 03564 case AST_CAUSE_CONGESTION: 03565 state = AST_CONTROL_CONGESTION; 03566 break; 03567 default: 03568 state = 0; 03569 break; 03570 } 03571 break; 03572 } 03573 03574 if (f->frametype == AST_FRAME_CONTROL) { 03575 if (f->subclass.integer == AST_CONTROL_RINGING) { 03576 ast_verb(3, "%s is ringing\n", ast_channel_name(chan)); 03577 ast_indicate(caller, AST_CONTROL_RINGING); 03578 } else if (f->subclass.integer == AST_CONTROL_BUSY) { 03579 state = f->subclass.integer; 03580 ast_verb(3, "%s is busy\n", ast_channel_name(chan)); 03581 ast_indicate(caller, AST_CONTROL_BUSY); 03582 ast_frfree(f); 03583 break; 03584 } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) { 03585 ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", ast_channel_name(chan), chan->exten); 03586 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) { 03587 state = f->subclass.integer; 03588 ast_verb(3, "%s is congested\n", ast_channel_name(chan)); 03589 ast_indicate(caller, AST_CONTROL_CONGESTION); 03590 ast_frfree(f); 03591 break; 03592 } else if (f->subclass.integer == AST_CONTROL_ANSWER) { 03593 /* This is what we are hoping for */ 03594 state = f->subclass.integer; 03595 ast_frfree(f); 03596 ready=1; 03597 break; 03598 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) { 03599 if (caller_hungup) { 03600 struct ast_party_connected_line connected; 03601 03602 /* Just save it for the transfer. */ 03603 ast_party_connected_line_set_init(&connected, &caller->connected); 03604 res = ast_connected_line_parse_data(f->data.ptr, f->datalen, 03605 &connected); 03606 if (!res) { 03607 ast_channel_set_connected_line(caller, &connected, NULL); 03608 } 03609 ast_party_connected_line_free(&connected); 03610 } else { 03611 ast_autoservice_start(transferee); 03612 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { 03613 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, 03614 f->data.ptr, f->datalen); 03615 } 03616 ast_autoservice_stop(transferee); 03617 } 03618 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) { 03619 if (!caller_hungup) { 03620 ast_autoservice_start(transferee); 03621 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { 03622 ast_indicate_data(caller, AST_CONTROL_REDIRECTING, 03623 f->data.ptr, f->datalen); 03624 } 03625 ast_autoservice_stop(transferee); 03626 } 03627 } else if (f->subclass.integer != -1 03628 && f->subclass.integer != AST_CONTROL_PROGRESS 03629 && f->subclass.integer != AST_CONTROL_PROCEEDING) { 03630 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer); 03631 } 03632 /* else who cares */ 03633 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03634 ast_write(caller, f); 03635 } 03636 } else if (caller == active_channel) { 03637 f = ast_read(caller); 03638 if (f) { 03639 if (f->frametype == AST_FRAME_DTMF) { 03640 dialed_code[x++] = f->subclass.integer; 03641 dialed_code[x] = '\0'; 03642 if (strlen(dialed_code) == len) { 03643 x = 0; 03644 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 03645 x = 0; 03646 dialed_code[x] = '\0'; 03647 } 03648 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 03649 /* Caller Canceled the call */ 03650 state = AST_CONTROL_UNHOLD; 03651 ast_frfree(f); 03652 break; 03653 } 03654 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03655 ast_write(chan, f); 03656 } 03657 } 03658 } 03659 if (f) 03660 ast_frfree(f); 03661 } /* end while */ 03662 03663 ast_poll_channel_del(caller, chan); 03664 03665 /* 03666 * We need to free all the deferred frames, but we only need to 03667 * queue the deferred frames if no hangup was received. 03668 */ 03669 ast_channel_lock(transferee); 03670 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee)); 03671 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { 03672 if (!transferee_hungup) { 03673 ast_queue_frame_head(transferee, f); 03674 } 03675 ast_frfree(f); 03676 } 03677 ast_channel_unlock(transferee); 03678 03679 done: 03680 ast_indicate(caller, -1); 03681 if (chan && (ready || chan->_state == AST_STATE_UP)) { 03682 state = AST_CONTROL_ANSWER; 03683 } else if (chan) { 03684 ast_hangup(chan); 03685 chan = NULL; 03686 } 03687 03688 tmp_cap = ast_format_cap_destroy(tmp_cap); 03689 03690 if (outstate) 03691 *outstate = state; 03692 03693 return chan; 03694 }
| 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 7215 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.
07216 { 07217 struct ast_channel *target = obj;/*!< Potential pickup target */ 07218 struct ast_channel *chan = data;/*!< Channel wanting to pickup call */ 07219 07220 ast_channel_lock(target); 07221 if (chan != target && (chan->pickupgroup & target->callgroup) 07222 && ast_can_pickup(target)) { 07223 /* Return with the channel still locked on purpose */ 07224 return CMP_MATCH | CMP_STOP; 07225 } 07226 ast_channel_unlock(target); 07227 07228 return 0; 07229 }
| static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static, read] |
find a call feature by name
Definition at line 2959 of file features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by ast_find_call_feature(), feature_interpret_helper(), process_applicationmap_line(), process_config(), and set_config_flags().
02960 { 02961 struct ast_call_feature *tmp; 02962 02963 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 02964 if (!strcasecmp(tmp->sname, name)) { 02965 break; 02966 } 02967 } 02968 02969 return tmp; 02970 }
| 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 2997 of file features.c.
References AST_LIST_TRAVERSE, and feature_group::gname.
Referenced by feature_interpret_helper().
02998 { 02999 struct feature_group *fg = NULL; 03000 03001 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 03002 if (!strcasecmp(fg->gname, name)) 03003 break; 03004 } 03005 03006 return fg; 03007 }
| static struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) | [static, read] |
Find parkinglot by name.
Definition at line 4875 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().
04876 { 04877 struct ast_parkinglot *parkinglot; 04878 04879 if (ast_strlen_zero(name)) { 04880 return NULL; 04881 } 04882 04883 parkinglot = ao2_find(parkinglots, (void *) name, 0); 04884 if (parkinglot) { 04885 ast_debug(1, "Found Parking lot: %s\n", parkinglot->name); 04886 } 04887 04888 return parkinglot; 04889 }
| static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 1000 of file features.c.
References ast_channel_parkinglot(), ast_strlen_zero(), name, and pbx_builtin_getvar_helper().
Referenced by park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().
01001 { 01002 const char *name; 01003 01004 /* The channel variable overrides everything */ 01005 name = pbx_builtin_getvar_helper(chan, "PARKINGLOT"); 01006 if (!name && !ast_strlen_zero(ast_channel_parkinglot(chan))) { 01007 /* Use the channel's parking lot. */ 01008 name = ast_channel_parkinglot(chan); 01009 } 01010 return name; 01011 }
| static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1777 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().
01778 { 01779 ast_indicate(chan, AST_CONTROL_UNHOLD); 01780 01781 return ast_autoservice_stop(chan); 01782 }
| static struct ast_exten* get_parking_exten | ( | const char * | exten_str, | |
| struct ast_channel * | chan, | |||
| const char * | context | |||
| ) | [static, read] |
Definition at line 781 of file features.c.
References 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().
00782 { 00783 struct ast_exten *exten; 00784 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 00785 const char *app_at_exten; 00786 00787 exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, 00788 E_MATCH); 00789 if (!exten) { 00790 return NULL; 00791 } 00792 00793 app_at_exten = ast_get_extension_app(exten); 00794 if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) { 00795 return NULL; 00796 } 00797 00798 return exten; 00799 }
| 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 6672 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), AST_CLI_YESNO, AST_LIST_TRAVERSE, ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_parkinglot::cfg, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, parkinglot_cfg::comebackcontext, parkinglot_cfg::comebackdialtime, parkinglot_cfg::comebacktoorigin, ast_cli_entry::command, ast_call_feature::default_exten, ast_parkinglot::disabled, feature_group_exten::exten, ast_call_feature::exten, ast_cli_args::fd, feature_group_exten::feature, feature_group::features, FEATURES_COUNT, features_lock, ast_call_feature::fname, feature_group::gname, HFS_FORMAT, parkinglot_cfg::mohclass, ast_parkinglot::name, parkinglot_cfg::parkext, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglots, parkinglot_cfg::parkingtime, ast_call_feature::sname, and ast_cli_entry::usage.
06673 { 06674 int i; 06675 struct ast_call_feature *feature; 06676 struct ao2_iterator iter; 06677 struct ast_parkinglot *curlot; 06678 #define HFS_FORMAT "%-25s %-7s %-7s\n" 06679 06680 switch (cmd) { 06681 06682 case CLI_INIT: 06683 e->command = "features show"; 06684 e->usage = 06685 "Usage: features show\n" 06686 " Lists configured features\n"; 06687 return NULL; 06688 case CLI_GENERATE: 06689 return NULL; 06690 } 06691 06692 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 06693 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06694 06695 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 06696 06697 ast_rwlock_rdlock(&features_lock); 06698 for (i = 0; i < FEATURES_COUNT; i++) 06699 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 06700 ast_rwlock_unlock(&features_lock); 06701 06702 ast_cli(a->fd, "\n"); 06703 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 06704 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 06705 if (AST_RWLIST_EMPTY(&feature_list)) { 06706 ast_cli(a->fd, "(none)\n"); 06707 } else { 06708 AST_RWLIST_RDLOCK(&feature_list); 06709 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 06710 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 06711 } 06712 AST_RWLIST_UNLOCK(&feature_list); 06713 } 06714 06715 ast_cli(a->fd, "\nFeature Groups:\n"); 06716 ast_cli(a->fd, "---------------\n"); 06717 if (AST_RWLIST_EMPTY(&feature_groups)) { 06718 ast_cli(a->fd, "(none)\n"); 06719 } else { 06720 struct feature_group *fg; 06721 struct feature_group_exten *fge; 06722 06723 AST_RWLIST_RDLOCK(&feature_groups); 06724 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 06725 ast_cli(a->fd, "===> Group: %s\n", fg->gname); 06726 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 06727 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten); 06728 } 06729 } 06730 AST_RWLIST_UNLOCK(&feature_groups); 06731 } 06732 06733 iter = ao2_iterator_init(parkinglots, 0); 06734 while ((curlot = ao2_iterator_next(&iter))) { 06735 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 06736 ast_cli(a->fd, "------------\n"); 06737 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->cfg.parkext); 06738 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->cfg.parking_con); 06739 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", 06740 curlot->cfg.parking_start, curlot->cfg.parking_stop); 06741 ast_cli(a->fd,"%-22s: %d ms\n", "Parkingtime", curlot->cfg.parkingtime); 06742 ast_cli(a->fd,"%-22s: %s\n", "Comeback to origin", 06743 (curlot->cfg.comebacktoorigin ? "yes" : "no")); 06744 ast_cli(a->fd,"%-22s: %s%s\n", "Comeback context", 06745 curlot->cfg.comebackcontext, (curlot->cfg.comebacktoorigin ? 06746 " (comebacktoorigin=yes, not used)" : "")); 06747 ast_cli(a->fd,"%-22s: %d\n", "Comeback dial time", 06748 curlot->cfg.comebackdialtime); 06749 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->cfg.mohclass); 06750 ast_cli(a->fd,"%-22s: %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled)); 06751 ast_cli(a->fd,"\n"); 06752 ao2_ref(curlot, -1); 06753 } 06754 ao2_iterator_destroy(&iter); 06755 06756 return CLI_SUCCESS; 06757 }
| static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6785 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
06786 { 06787 switch (cmd) { 06788 case CLI_INIT: 06789 e->command = "features reload"; 06790 e->usage = 06791 "Usage: features reload\n" 06792 " Reloads configured call features from features.conf\n"; 06793 return NULL; 06794 case CLI_GENERATE: 06795 return NULL; 06796 } 06797 ast_features_reload(); 06798 06799 return CLI_SUCCESS; 06800 }
| 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 6968 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_entry::args, ast_channel_name(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, parkeduser::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, parkeduser::context, default_parkinglot, ESS, parkeduser::exten, ast_cli_args::fd, ast_parkinglot::name, parkeduser::parkingexten, parkinglots, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.
06969 { 06970 struct parkeduser *cur; 06971 int numparked = 0; 06972 struct ao2_iterator iter; 06973 struct ast_parkinglot *curlot; 06974 06975 switch (cmd) { 06976 case CLI_INIT: 06977 e->command = "parkedcalls show"; 06978 e->usage = 06979 "Usage: parkedcalls show\n" 06980 " List currently parked calls\n"; 06981 return NULL; 06982 case CLI_GENERATE: 06983 return NULL; 06984 } 06985 06986 if (a->argc > e->args) 06987 return CLI_SHOWUSAGE; 06988 06989 ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel", 06990 "Context", "Extension", "Pri", "Timeout"); 06991 06992 iter = ao2_iterator_init(parkinglots, 0); 06993 while ((curlot = ao2_iterator_next(&iter))) { 06994 int lotparked = 0; 06995 06996 /* subtract ref for iterator and for configured parking lot */ 06997 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, 06998 ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot)); 06999 07000 AST_LIST_LOCK(&curlot->parkings); 07001 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 07002 ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n", 07003 cur->parkingexten, ast_channel_name(cur->chan), cur->context, cur->exten, 07004 cur->priority, 07005 (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL))); 07006 ++lotparked; 07007 } 07008 AST_LIST_UNLOCK(&curlot->parkings); 07009 if (lotparked) { 07010 numparked += lotparked; 07011 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, 07012 ESS(lotparked), curlot->name); 07013 } 07014 07015 ao2_ref(curlot, -1); 07016 } 07017 ao2_iterator_destroy(&iter); 07018 07019 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 07020 07021 return CLI_SUCCESS; 07022 }
| static int load_config | ( | int | reload | ) | [static] |
Definition at line 6589 of file features.c.
References ao2_t_callback, ast_config_destroy(), ast_config_load2(), ast_debug, AST_LIST_HEAD_NOLOCK_INIT_VALUE, ast_log(), build_dialplan_useage_map(), build_parkinglot(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_PARKINGLOT, default_parkinglot, destroy_dialplan_usage_map(), force_reload_load, LOG_ERROR, LOG_WARNING, OBJ_NODATA, OBJ_UNLINK, parkinglot_activate_cb(), parkinglot_addref(), parkinglot_is_marked_cb(), parkinglot_markall_cb(), parkinglots, process_config(), and remove_dead_dialplan_useage().
06590 { 06591 struct ast_flags config_flags = { 06592 reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06593 struct ast_config *cfg; 06594 struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06595 struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE; 06596 06597 /* We are reloading now and have already determined if we will force the reload. */ 06598 force_reload_load = 0; 06599 06600 if (!default_parkinglot) { 06601 /* Must create the default default parking lot */ 06602 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 06603 if (!default_parkinglot) { 06604 ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n"); 06605 return -1; 06606 } 06607 ast_debug(1, "Configuration of default default parking lot done.\n"); 06608 parkinglot_addref(default_parkinglot); 06609 } 06610 06611 cfg = ast_config_load2("features.conf", "features", config_flags); 06612 if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06613 /* No sense in asking for reload trouble if nothing changed. */ 06614 ast_debug(1, "features.conf did not change.\n"); 06615 return 0; 06616 } 06617 if (cfg == CONFIG_STATUS_FILEMISSING 06618 || cfg == CONFIG_STATUS_FILEINVALID) { 06619 ast_log(LOG_WARNING, "Could not load features.conf\n"); 06620 return 0; 06621 } 06622 06623 /* Save current parking lot dialplan needs. */ 06624 if (build_dialplan_useage_map(&old_usage_map, 0)) { 06625 destroy_dialplan_usage_map(&old_usage_map); 06626 06627 /* Allow reloading later to see if conditions have improved. */ 06628 force_reload_load = 1; 06629 return -1; 06630 } 06631 06632 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, 06633 "callback to mark all parking lots"); 06634 process_config(cfg); 06635 ast_config_destroy(cfg); 06636 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, 06637 "callback to remove marked parking lots"); 06638 06639 /* Save updated parking lot dialplan needs. */ 06640 if (build_dialplan_useage_map(&new_usage_map, 1)) { 06641 /* 06642 * Yuck, if this failure caused any parking lot dialplan items 06643 * to be lost, they will likely remain lost until Asterisk is 06644 * restarted. 06645 */ 06646 destroy_dialplan_usage_map(&old_usage_map); 06647 destroy_dialplan_usage_map(&new_usage_map); 06648 return -1; 06649 } 06650 06651 /* Remove no longer needed parking lot dialplan usage. */ 06652 remove_dead_dialplan_useage(&old_usage_map, &new_usage_map); 06653 06654 destroy_dialplan_usage_map(&old_usage_map); 06655 destroy_dialplan_usage_map(&new_usage_map); 06656 06657 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL, 06658 "callback to activate all parking lots"); 06659 06660 return 0; 06661 }
| 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 4571 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_name(), ast_channel_unlock, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_debug, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, ast_pbx_start(), ast_read(), ast_realloc, ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, callback_dialoptions(), ast_parkinglot::cfg, parkeduser::chan, parkinglot_cfg::comebackcontext, parkinglot_cfg::comebackdialtime, parkinglot_cfg::comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, 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_parkinglot::name, parkeduser::options_specified, parking_con_dial, parkeduser::parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), parkeduser::start, and ast_frame::subclass.
Referenced by manage_parkinglot().
04572 { 04573 struct ast_channel *chan = pu->chan; /* shorthand */ 04574 int tms; /* timeout for this item */ 04575 int x; /* fd index in channel */ 04576 int parking_complete = 0; 04577 04578 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 04579 if (tms > pu->parkingtime) { 04580 /* 04581 * Call has been parked too long. 04582 * Stop entertaining the caller. 04583 */ 04584 switch (pu->hold_method) { 04585 case AST_CONTROL_HOLD: 04586 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 04587 break; 04588 case AST_CONTROL_RINGING: 04589 ast_indicate(pu->chan, -1); 04590 break; 04591 default: 04592 break; 04593 } 04594 pu->hold_method = 0; 04595 04596 /* Get chan, exten from derived kludge */ 04597 if (pu->peername[0]) { 04598 char *peername; 04599 char *dash; 04600 char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 04601 int i; 04602 04603 peername = ast_strdupa(pu->peername); 04604 dash = strrchr(peername, '-'); 04605 if (dash) { 04606 *dash = '\0'; 04607 } 04608 04609 peername_flat = ast_strdupa(peername); 04610 for (i = 0; peername_flat[i]; i++) { 04611 if (peername_flat[i] == '/') { 04612 peername_flat[i] = '_'; 04613 } 04614 } 04615 04616 if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) { 04617 ast_log(LOG_ERROR, 04618 "Parking dial context '%s' does not exist and unable to create\n", 04619 parking_con_dial); 04620 } else { 04621 char returnexten[AST_MAX_EXTENSION]; 04622 char comebackdialtime[AST_MAX_EXTENSION]; 04623 struct ast_datastore *features_datastore; 04624 struct ast_dial_features *dialfeatures; 04625 04626 if (!strncmp(peername, "Parked/", 7)) { 04627 peername += 7; 04628 } 04629 04630 ast_channel_lock(chan); 04631 features_datastore = ast_channel_datastore_find(chan, &dial_features_info, 04632 NULL); 04633 if (features_datastore && (dialfeatures = features_datastore->data)) { 04634 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 04635 04636 snprintf(returnexten, sizeof(returnexten), "%s,%u,%s", peername, 04637 pu->parkinglot->cfg.comebackdialtime, 04638 callback_dialoptions(&(dialfeatures->features_callee), 04639 &(dialfeatures->features_caller), buf, sizeof(buf))); 04640 } else { /* Existing default */ 04641 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", 04642 ast_channel_name(chan)); 04643 snprintf(returnexten, sizeof(returnexten), "%s,%u,t", peername, 04644 pu->parkinglot->cfg.comebackdialtime); 04645 } 04646 ast_channel_unlock(chan); 04647 04648 snprintf(comebackdialtime, sizeof(comebackdialtime), "%u", 04649 pu->parkinglot->cfg.comebackdialtime); 04650 pbx_builtin_setvar_helper(chan, "COMEBACKDIALTIME", comebackdialtime); 04651 04652 pbx_builtin_setvar_helper(chan, "PARKER", peername); 04653 04654 if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL, 04655 "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) { 04656 ast_log(LOG_ERROR, 04657 "Could not create parking return dial exten: %s@%s\n", 04658 peername_flat, parking_con_dial); 04659 } 04660 } 04661 if (pu->options_specified) { 04662 /* 04663 * Park() was called with overriding return arguments, respect 04664 * those arguments. 04665 */ 04666 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04667 } else if (pu->parkinglot->cfg.comebacktoorigin) { 04668 set_c_e_p(chan, parking_con_dial, peername_flat, 1); 04669 } else { 04670 char parkingslot[AST_MAX_EXTENSION]; 04671 04672 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 04673 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 04674 pbx_builtin_setvar_helper(chan, "PARKEDLOT", pu->parkinglot->name); 04675 set_c_e_p(chan, pu->parkinglot->cfg.comebackcontext, peername_flat, 1); 04676 } 04677 } else { 04678 /* 04679 * They've been waiting too long, send them back to where they 04680 * came. Theoretically they should have their original 04681 * extensions and such, but we copy to be on the safe side. 04682 */ 04683 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04684 } 04685 post_manager_event("ParkedCallTimeOut", pu); 04686 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL); 04687 04688 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", 04689 ast_channel_name(pu->chan), pu->parkingnum, pu->parkinglot->name, pu->chan->context, 04690 pu->chan->exten, pu->chan->priority); 04691 04692 /* Start up the PBX, or hang them up */ 04693 if (ast_pbx_start(chan)) { 04694 ast_log(LOG_WARNING, 04695 "Unable to restart the PBX for user on '%s', hanging them up...\n", 04696 ast_channel_name(pu->chan)); 04697 ast_hangup(chan); 04698 } 04699 04700 /* And take them out of the parking lot */ 04701 parking_complete = 1; 04702 } else { /* still within parking time, process descriptors */ 04703 for (x = 0; x < AST_MAX_FDS; x++) { 04704 struct ast_frame *f; 04705 int y; 04706 04707 if (chan->fds[x] == -1) { 04708 continue; /* nothing on this descriptor */ 04709 } 04710 04711 for (y = 0; y < nfds; y++) { 04712 if (pfds[y].fd == chan->fds[x]) { 04713 /* Found poll record! */ 04714 break; 04715 } 04716 } 04717 if (y == nfds) { 04718 /* Not found */ 04719 continue; 04720 } 04721 04722 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) { 04723 /* Next x */ 04724 continue; 04725 } 04726 04727 if (pfds[y].revents & POLLPRI) { 04728 ast_set_flag(chan, AST_FLAG_EXCEPTION); 04729 } else { 04730 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 04731 } 04732 chan->fdno = x; 04733 04734 /* See if they need servicing */ 04735 f = ast_read(pu->chan); 04736 /* Hangup? */ 04737 if (!f || (f->frametype == AST_FRAME_CONTROL 04738 && f->subclass.integer == AST_CONTROL_HANGUP)) { 04739 if (f) { 04740 ast_frfree(f); 04741 } 04742 post_manager_event("ParkedCallGiveUp", pu); 04743 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", 04744 NULL); 04745 04746 /* There's a problem, hang them up */ 04747 ast_verb(2, "%s got tired of being parked\n", ast_channel_name(chan)); 04748 ast_hangup(chan); 04749 04750 /* And take them out of the parking lot */ 04751 parking_complete = 1; 04752 break; 04753 } else { 04754 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 04755 ast_frfree(f); 04756 if (pu->hold_method == AST_CONTROL_HOLD 04757 && pu->moh_trys < 3 04758 && !chan->generatordata) { 04759 ast_debug(1, 04760 "MOH on parked call stopped by outside source. Restarting on channel %s.\n", 04761 ast_channel_name(chan)); 04762 ast_indicate_data(chan, AST_CONTROL_HOLD, 04763 S_OR(pu->parkinglot->cfg.mohclass, NULL), 04764 (!ast_strlen_zero(pu->parkinglot->cfg.mohclass) 04765 ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0)); 04766 pu->moh_trys++; 04767 } 04768 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 04769 } 04770 } /* End for */ 04771 if (x >= AST_MAX_FDS) { 04772 std: for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */ 04773 if (chan->fds[x] > -1) { 04774 void *tmp = ast_realloc(*new_pfds, 04775 (*new_nfds + 1) * sizeof(struct pollfd)); 04776 04777 if (!tmp) { 04778 continue; 04779 } 04780 *new_pfds = tmp; 04781 (*new_pfds)[*new_nfds].fd = chan->fds[x]; 04782 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI; 04783 (*new_pfds)[*new_nfds].revents = 0; 04784 (*new_nfds)++; 04785 } 04786 } 04787 /* Keep track of our shortest wait */ 04788 if (tms < *ms || *ms < 0) { 04789 *ms = tms; 04790 } 04791 } 04792 } 04793 04794 return parking_complete; 04795 }
| 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 4798 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().
04799 { 04800 struct parkeduser *pu; 04801 struct ast_context *con; 04802 04803 /* Lock parkings list */ 04804 AST_LIST_LOCK(&curlot->parkings); 04805 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 04806 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 04807 continue; 04808 } 04809 if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) { 04810 /* Parking is complete for this call so remove it from the parking lot. */ 04811 con = ast_context_find(pu->parkinglot->cfg.parking_con); 04812 if (con) { 04813 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 04814 ast_log(LOG_WARNING, 04815 "Whoa, failed to remove the parking extension %s@%s!\n", 04816 pu->parkingexten, pu->parkinglot->cfg.parking_con); 04817 } 04818 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, 04819 AST_DEVICE_NOT_INUSE); 04820 } else { 04821 ast_log(LOG_WARNING, 04822 "Whoa, parking lot '%s' context '%s' does not exist.\n", 04823 pu->parkinglot->name, pu->parkinglot->cfg.parking_con); 04824 } 04825 AST_LIST_REMOVE_CURRENT(list); 04826 parkinglot_unref(pu->parkinglot); 04827 ast_free(pu); 04828 } 04829 } 04830 AST_LIST_TRAVERSE_SAFE_END; 04831 AST_LIST_UNLOCK(&curlot->parkings); 04832 }
| 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 7104 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().
07105 { 07106 const char *channel = astman_get_header(m, "Channel"); 07107 const char *channel2 = astman_get_header(m, "Channel2"); 07108 const char *timeout = astman_get_header(m, "Timeout"); 07109 const char *parkinglotname = astman_get_header(m, "Parkinglot"); 07110 char buf[BUFSIZ]; 07111 int res = 0; 07112 struct ast_channel *ch1, *ch2; 07113 struct ast_park_call_args args = { 07114 /* 07115 * Don't say anything to ch2 since AMI is a third party parking 07116 * a call and we will likely crash if we do. 07117 * 07118 * XXX When the AMI action was originally implemented, the 07119 * parking space was announced to ch2. Unfortunately, grabbing 07120 * the ch2 lock and holding it while the announcement is played 07121 * was not really a good thing to do to begin with since it 07122 * could hold up the system. Also holding the lock is no longer 07123 * possible with a masquerade. 07124 * 07125 * Restoring the announcement to ch2 is not easily doable for 07126 * the following reasons: 07127 * 07128 * 1) The AMI manager is not the thread processing ch2. 07129 * 07130 * 2) ch2 could be the same as ch1, bridged to ch1, or some 07131 * random uninvolved channel. 07132 */ 07133 .flags = AST_PARK_OPT_SILENCE, 07134 }; 07135 07136 if (ast_strlen_zero(channel)) { 07137 astman_send_error(s, m, "Channel not specified"); 07138 return 0; 07139 } 07140 07141 if (ast_strlen_zero(channel2)) { 07142 astman_send_error(s, m, "Channel2 not specified"); 07143 return 0; 07144 } 07145 07146 if (!ast_strlen_zero(timeout)) { 07147 if (sscanf(timeout, "%30d", &args.timeout) != 1) { 07148 astman_send_error(s, m, "Invalid timeout value."); 07149 return 0; 07150 } 07151 } 07152 07153 if (!(ch1 = ast_channel_get_by_name(channel))) { 07154 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 07155 astman_send_error(s, m, buf); 07156 return 0; 07157 } 07158 07159 if (!(ch2 = ast_channel_get_by_name(channel2))) { 07160 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 07161 astman_send_error(s, m, buf); 07162 ast_channel_unref(ch1); 07163 return 0; 07164 } 07165 07166 if (!ast_strlen_zero(parkinglotname)) { 07167 args.parkinglot = find_parkinglot(parkinglotname); 07168 } 07169 07170 res = masq_park_call(ch1, ch2, &args); 07171 if (!res) { 07172 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 07173 astman_send_ack(s, m, "Park successful"); 07174 } else { 07175 astman_send_error(s, m, "Park failure"); 07176 } 07177 07178 if (args.parkinglot) { 07179 parkinglot_unref(args.parkinglot); 07180 } 07181 ch1 = ast_channel_unref(ch1); 07182 ch2 = ast_channel_unref(ch2); 07183 07184 return 0; 07185 }
| 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 7038 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_name(), 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().
07039 { 07040 struct parkeduser *cur; 07041 const char *id = astman_get_header(m, "ActionID"); 07042 char idText[256] = ""; 07043 struct ao2_iterator iter; 07044 struct ast_parkinglot *curlot; 07045 int numparked = 0; 07046 07047 if (!ast_strlen_zero(id)) 07048 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 07049 07050 astman_send_ack(s, m, "Parked calls will follow"); 07051 07052 iter = ao2_iterator_init(parkinglots, 0); 07053 while ((curlot = ao2_iterator_next(&iter))) { 07054 AST_LIST_LOCK(&curlot->parkings); 07055 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 07056 astman_append(s, "Event: ParkedCall\r\n" 07057 "Parkinglot: %s\r\n" 07058 "Exten: %d\r\n" 07059 "Channel: %s\r\n" 07060 "From: %s\r\n" 07061 "Timeout: %ld\r\n" 07062 "CallerIDNum: %s\r\n" 07063 "CallerIDName: %s\r\n" 07064 "ConnectedLineNum: %s\r\n" 07065 "ConnectedLineName: %s\r\n" 07066 "%s" 07067 "\r\n", 07068 curlot->name, 07069 cur->parkingnum, ast_channel_name(cur->chan), cur->peername, 07070 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 07071 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""), /* XXX in other places it is <unknown> */ 07072 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""), 07073 S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""), /* XXX in other places it is <unknown> */ 07074 S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""), 07075 idText); 07076 ++numparked; 07077 } 07078 AST_LIST_UNLOCK(&curlot->parkings); 07079 ao2_ref(curlot, -1); 07080 } 07081 ao2_iterator_destroy(&iter); 07082 07083 astman_append(s, 07084 "Event: ParkedCallsComplete\r\n" 07085 "Total: %d\r\n" 07086 "%s" 07087 "\r\n", 07088 numparked, idText); 07089 07090 return RESULT_SUCCESS; 07091 }
| 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 1633 of file features.c.
References ast_channel::amaflags, ast_channel_accountcode(), ast_channel_alloc, ast_channel_linkedid(), ast_channel_masquerade(), ast_channel_name(), 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().
01634 { 01635 struct ast_channel *chan; 01636 01637 /* Make a new, channel that we'll use to masquerade in the real one */ 01638 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, ast_channel_accountcode(rchan), rchan->exten, 01639 rchan->context, ast_channel_linkedid(rchan), rchan->amaflags, "Parked/%s", ast_channel_name(rchan)); 01640 if (!chan) { 01641 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 01642 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01643 if (peer == rchan) { 01644 /* Only have one channel to worry about. */ 01645 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01646 } else if (peer) { 01647 /* Have two different channels to worry about. */ 01648 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01649 } 01650 } 01651 return -1; 01652 } 01653 01654 args->pu = park_space_reserve(rchan, peer, args); 01655 if (!args->pu) { 01656 ast_hangup(chan); 01657 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01658 if (peer == rchan) { 01659 /* Only have one channel to worry about. */ 01660 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01661 } else if (peer) { 01662 /* Have two different channels to worry about. */ 01663 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01664 } 01665 } 01666 return -1; 01667 } 01668 01669 /* Make formats okay */ 01670 chan->readformat = rchan->readformat; 01671 chan->writeformat = rchan->writeformat; 01672 01673 if (ast_channel_masquerade(chan, rchan)) { 01674 park_space_abort(args->pu); 01675 args->pu = NULL; 01676 ast_hangup(chan); 01677 if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) { 01678 if (peer == rchan) { 01679 /* Only have one channel to worry about. */ 01680 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01681 } else if (peer) { 01682 /* Have two different channels to worry about. */ 01683 play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed"); 01684 } 01685 } 01686 return -1; 01687 } 01688 01689 /* Setup the extensions and such */ 01690 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 01691 01692 /* Setup the macro extension and such */ 01693 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext)); 01694 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten)); 01695 chan->macropriority = rchan->macropriority; 01696 01697 /* Manually do the masquerade to make sure it is complete. */ 01698 ast_do_masquerade(chan); 01699 01700 if (peer == rchan) { 01701 peer = chan; 01702 } 01703 01704 /* parking space reserved, return code check unnecessary */ 01705 park_call_full(chan, peer, args); 01706 01707 return 0; 01708 }
| static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 1023 of file features.c.
References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_strdupa, and strsep().
Referenced by ast_features_init().
01024 { 01025 char *context; 01026 char *exten; 01027 01028 context = ast_strdupa(data); 01029 01030 exten = strsep(&context, "@"); 01031 if (!context) 01032 return AST_DEVICE_INVALID; 01033 01034 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 01035 01036 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 01037 return AST_DEVICE_NOT_INUSE; 01038 01039 return AST_DEVICE_INUSE; 01040 }
| 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 1014 of file features.c.
References ast_debug, ast_devstate2str(), and ast_devstate_changed().
Referenced by manage_parkinglot(), park_call_full(), parked_call_exec(), and parkinglot_activate().
01015 { 01016 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 01017 exten, context, ast_devstate2str(state)); 01018 01019 ast_devstate_changed(state, "park:%s@%s", exten, context); 01020 }
| 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 5345 of file features.c.
References ast_add_extension(), AST_MAX_EXTENSION, PRIORITY_HINT, and registrar.
Referenced by parkinglot_activate().
05346 { 05347 int numext; 05348 char device[AST_MAX_EXTENSION]; 05349 char exten[10]; 05350 05351 for (numext = start; numext <= stop; numext++) { 05352 snprintf(exten, sizeof(exten), "%d", numext); 05353 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 05354 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 05355 } 05356 }
| static int park_call_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Park a call.
Definition at line 4921 of file features.c.
References ast_channel::_state, ast_answer(), ast_app_parse_options(), ast_channel_name(), 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(), 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, ast_park_call_args::timeout, and park_app_args::timeout.
Referenced by ast_features_init().
04922 { 04923 /* Cache the original channel name in case we get masqueraded in the middle 04924 * of a park--it is still theoretically possible for a transfer to happen before 04925 * we get here, but it is _really_ unlikely */ 04926 char *orig_chan_name = ast_strdupa(ast_channel_name(chan)); 04927 struct ast_park_call_args args = { 04928 .orig_chan_name = orig_chan_name, 04929 }; 04930 struct ast_flags flags = { 0 }; 04931 char orig_exten[AST_MAX_EXTENSION]; 04932 int orig_priority; 04933 int res; 04934 const char *pl_name; 04935 char *parse; 04936 struct park_app_args app_args; 04937 04938 /* Answer if call is not up */ 04939 if (chan->_state != AST_STATE_UP) { 04940 if (ast_answer(chan)) { 04941 return -1; 04942 } 04943 04944 /* Sleep to allow VoIP streams to settle down */ 04945 if (ast_safe_sleep(chan, 1000)) { 04946 return -1; 04947 } 04948 } 04949 04950 /* Process the dialplan application options. */ 04951 parse = ast_strdupa(data); 04952 AST_STANDARD_APP_ARGS(app_args, parse); 04953 04954 if (!ast_strlen_zero(app_args.timeout)) { 04955 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) { 04956 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 04957 args.timeout = 0; 04958 } 04959 } 04960 if (!ast_strlen_zero(app_args.return_con)) { 04961 args.return_con = app_args.return_con; 04962 } 04963 if (!ast_strlen_zero(app_args.return_ext)) { 04964 args.return_ext = app_args.return_ext; 04965 } 04966 if (!ast_strlen_zero(app_args.return_pri)) { 04967 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) { 04968 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 04969 args.return_pri = 0; 04970 } 04971 } 04972 04973 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 04974 args.flags = flags.flags; 04975 04976 /* 04977 * Setup the exten/priority to be s/1 since we don't know where 04978 * this call should return. 04979 */ 04980 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 04981 orig_priority = chan->priority; 04982 strcpy(chan->exten, "s"); 04983 chan->priority = 1; 04984 04985 /* Park the call */ 04986 if (!ast_strlen_zero(app_args.pl_name)) { 04987 pl_name = app_args.pl_name; 04988 } else { 04989 pl_name = findparkinglotname(chan); 04990 } 04991 if (ast_strlen_zero(pl_name)) { 04992 /* Parking lot is not specified, so use the default parking lot. */ 04993 args.parkinglot = parkinglot_addref(default_parkinglot); 04994 } else { 04995 args.parkinglot = find_parkinglot(pl_name); 04996 if (!args.parkinglot && parkeddynamic) { 04997 args.parkinglot = create_dynamic_parkinglot(pl_name, chan); 04998 } 04999 } 05000 if (args.parkinglot) { 05001 res = masq_park_call(chan, chan, &args); 05002 parkinglot_unref(args.parkinglot); 05003 } else { 05004 /* Parking failed because the parking lot does not exist. */ 05005 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { 05006 ast_stream_and_wait(chan, "pbx-parkingfailed", ""); 05007 } 05008 res = -1; 05009 } 05010 if (res) { 05011 /* Park failed, try to continue in the dialplan. */ 05012 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 05013 chan->priority = orig_priority; 05014 res = 0; 05015 } else { 05016 /* Park succeeded. */ 05017 res = -1; 05018 } 05019 05020 return res; 05021 }
| static int park_call_full | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_park_call_args * | args | |||
| ) | [static] |
Definition at line 1388 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_language(), ast_channel_lock, ast_channel_name(), AST_CHANNEL_NAME, ast_channel_uniqueid(), ast_channel_unlock, ast_channel_unref, ast_clear_flag, AST_CONTROL_HOLD, AST_CONTROL_RINGING, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), ast_manager_event, AST_MAX_CONTEXT, AST_MAX_EXTENSION, AST_PARK_OPT_RINGING, AST_PARK_OPT_SILENCE, ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, ast_channel::caller, ast_parkinglot::cfg, parkeduser::chan, ast_channel::connected, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, ast_park_call_args::extout, parkeduser::hold_method, ast_party_connected_line::id, ast_party_caller::id, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, parkinglot_cfg::mohclass, ast_party_id::name, ast_parkinglot::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkeduser::options_specified, ast_park_call_args::orig_chan_name, park_space_reserve(), parkinglot_cfg::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, parkinglot_cfg::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, ast_park_call_args::pu, registrar, ast_park_call_args::return_con, ast_park_call_args::return_ext, ast_park_call_args::return_pri, S_COR, S_OR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_channel::tech, ast_park_call_args::timeout, ast_channel_tech::type, ast_party_name::valid, and ast_party_number::valid.
Referenced by ast_park_call(), ast_park_call_exten(), and masq_park_call().
01389 { 01390 struct parkeduser *pu = args->pu; 01391 const char *event_from; 01392 char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT]; 01393 01394 if (pu == NULL) { 01395 args->pu = pu = park_space_reserve(chan, peer, args); 01396 if (pu == NULL) { 01397 return -1; 01398 } 01399 } 01400 01401 chan->appl = "Parked Call"; 01402 chan->data = NULL; 01403 01404 pu->chan = chan; 01405 01406 /* Put the parked channel on hold if we have two different channels */ 01407 if (chan != peer) { 01408 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 01409 pu->hold_method = AST_CONTROL_RINGING; 01410 ast_indicate(pu->chan, AST_CONTROL_RINGING); 01411 } else { 01412 pu->hold_method = AST_CONTROL_HOLD; 01413 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01414 S_OR(pu->parkinglot->cfg.mohclass, NULL), 01415 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0); 01416 } 01417 } 01418 01419 pu->start = ast_tvnow(); 01420 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->cfg.parkingtime; 01421 if (args->extout) 01422 *(args->extout) = pu->parkingnum; 01423 01424 if (peer) { 01425 /* 01426 * This is so ugly that it hurts, but implementing 01427 * get_base_channel() on local channels could have ugly side 01428 * effects. We could have 01429 * transferer<->local,1<->local,2<->parking and we need the 01430 * callback name to be that of transferer. Since local,1/2 have 01431 * the same name we can be tricky and just grab the bridged 01432 * channel from the other side of the local. 01433 */ 01434 if (!strcasecmp(peer->tech->type, "Local")) { 01435 struct ast_channel *tmpchan, *base_peer; 01436 char other_side[AST_CHANNEL_NAME]; 01437 char *c; 01438 01439 ast_copy_string(other_side, S_OR(args->orig_chan_name, ast_channel_name(peer)), sizeof(other_side)); 01440 if ((c = strrchr(other_side, ';'))) { 01441 *++c = '1'; 01442 } 01443 if ((tmpchan = ast_channel_get_by_name(other_side))) { 01444 ast_channel_lock(tmpchan); 01445 if ((base_peer = ast_bridged_channel(tmpchan))) { 01446 ast_copy_string(pu->peername, ast_channel_name(base_peer), sizeof(pu->peername)); 01447 } 01448 ast_channel_unlock(tmpchan); 01449 tmpchan = ast_channel_unref(tmpchan); 01450 } 01451 } else { 01452 ast_copy_string(pu->peername, S_OR(args->orig_chan_name, ast_channel_name(peer)), sizeof(pu->peername)); 01453 } 01454 } 01455 01456 /* 01457 * Remember what had been dialed, so that if the parking 01458 * expires, we try to come back to the same place 01459 */ 01460 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri); 01461 01462 /* 01463 * If extension has options specified, they override all other 01464 * possibilities such as the returntoorigin flag and transferred 01465 * context. Information on extension options is lost here, so 01466 * we set a flag 01467 */ 01468 ast_copy_string(pu->context, 01469 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 01470 sizeof(pu->context)); 01471 ast_copy_string(pu->exten, 01472 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 01473 sizeof(pu->exten)); 01474 pu->priority = args->return_pri ? args->return_pri : 01475 (chan->macropriority ? chan->macropriority : chan->priority); 01476 01477 /* 01478 * If parking a channel directly, don't quite yet get parking 01479 * running on it. All parking lot entries are put into the 01480 * parking lot with notquiteyet on. 01481 */ 01482 if (peer != chan) { 01483 pu->notquiteyet = 0; 01484 } 01485 01486 /* Wake up the (presumably select()ing) thread */ 01487 pthread_kill(parking_thread, SIGURG); 01488 ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", 01489 ast_channel_name(pu->chan), pu->parkingnum, pu->parkinglot->name, 01490 pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000)); 01491 01492 ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer); 01493 01494 if (peer) { 01495 event_from = ast_channel_name(peer); 01496 } else { 01497 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 01498 } 01499 01500 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "ParkedCall", 01501 "Exten: %s\r\n" 01502 "Channel: %s\r\n" 01503 "Parkinglot: %s\r\n" 01504 "From: %s\r\n" 01505 "Timeout: %ld\r\n" 01506 "CallerIDNum: %s\r\n" 01507 "CallerIDName: %s\r\n" 01508 "ConnectedLineNum: %s\r\n" 01509 "ConnectedLineName: %s\r\n" 01510 "Uniqueid: %s\r\n", 01511 pu->parkingexten, ast_channel_name(pu->chan), pu->parkinglot->name, event_from ? event_from : "", 01512 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 01513 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 01514 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 01515 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 01516 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 01517 ast_channel_uniqueid(pu->chan) 01518 ); 01519 01520 if (peer && adsipark && ast_adsi_available(peer)) { 01521 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 01522 ast_adsi_unload_session(peer); 01523 } 01524 01525 snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten, 01526 pu->parkinglot->name); 01527 if (ast_add_extension(pu->parkinglot->cfg.parking_con, 1, pu->parkingexten, 1, 01528 NULL, NULL, parkedcall, ast_strdup(app_data), ast_free_ptr, registrar)) { 01529 ast_log(LOG_ERROR, "Could not create parked call exten: %s@%s\n", 01530 pu->parkingexten, pu->parkinglot->cfg.parking_con); 01531 } else { 01532 notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE); 01533 } 01534 01535 AST_LIST_UNLOCK(&pu->parkinglot->parkings); 01536 01537 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 01538 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) 01539 && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(ast_channel_name(peer), args->orig_chan_name))) { 01540 /* 01541 * If a channel is masqueraded into peer while playing back the 01542 * parking space number do not continue playing it back. This 01543 * is the case if an attended transfer occurs. 01544 */ 01545 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01546 /* Tell the peer channel the number of the parking space */ 01547 ast_say_digits(peer, pu->parkingnum, "", ast_channel_language(peer)); 01548 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01549 } 01550 if (peer == chan) { /* pu->notquiteyet = 1 */ 01551 /* Wake up parking thread if we're really done */ 01552 pu->hold_method = AST_CONTROL_HOLD; 01553 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01554 S_OR(pu->parkinglot->cfg.mohclass, NULL), 01555 !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0); 01556 pu->notquiteyet = 0; 01557 pthread_kill(parking_thread, SIGURG); 01558 } 01559 return 0; 01560 }
| static void park_space_abort | ( | struct parkeduser * | pu | ) | [static] |
Definition at line 1190 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().
01191 { 01192 struct ast_parkinglot *parkinglot; 01193 01194 parkinglot = pu->parkinglot; 01195 01196 /* Put back the parking space just allocated. */ 01197 --parkinglot->next_parking_space; 01198 01199 AST_LIST_REMOVE(&parkinglot->parkings, pu, list); 01200 01201 AST_LIST_UNLOCK(&parkinglot->parkings); 01202 parkinglot_unref(parkinglot); 01203 ast_free(pu); 01204 }
| 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 1217 of file features.c.
References ast_calloc, ast_channel_name(), 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().
01218 { 01219 struct parkeduser *pu; 01220 int i; 01221 int parking_space = -1; 01222 const char *parkinglotname; 01223 const char *parkingexten; 01224 struct parkeduser *cur; 01225 struct ast_parkinglot *parkinglot = NULL; 01226 01227 if (args->parkinglot) { 01228 parkinglot = parkinglot_addref(args->parkinglot); 01229 parkinglotname = parkinglot->name; 01230 } else { 01231 if (parker) { 01232 parkinglotname = findparkinglotname(parker); 01233 } else { /* parker was NULL, check park_me (ParkAndAnnounce / res_agi) */ 01234 parkinglotname = findparkinglotname(park_me); 01235 } 01236 if (!ast_strlen_zero(parkinglotname)) { 01237 parkinglot = find_parkinglot(parkinglotname); 01238 } else { 01239 /* Parking lot is not specified, so use the default parking lot. */ 01240 ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n"); 01241 parkinglot = parkinglot_addref(default_parkinglot); 01242 } 01243 } 01244 01245 /* Dynamically create parkinglot */ 01246 if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) { 01247 parkinglot = create_dynamic_parkinglot(parkinglotname, park_me); 01248 } 01249 01250 if (!parkinglot) { 01251 ast_log(LOG_WARNING, "Parking lot not available to park %s.\n", ast_channel_name(park_me)); 01252 return NULL; 01253 } 01254 01255 ast_debug(1, "Parking lot: %s\n", parkinglot->name); 01256 if (parkinglot->disabled || parkinglot->cfg.is_invalid) { 01257 ast_log(LOG_WARNING, "Parking lot %s is not in a useable state.\n", 01258 parkinglot->name); 01259 parkinglot_unref(parkinglot); 01260 return NULL; 01261 } 01262 01263 /* Allocate memory for parking data */ 01264 if (!(pu = ast_calloc(1, sizeof(*pu)))) { 01265 parkinglot_unref(parkinglot); 01266 return NULL; 01267 } 01268 01269 /* Lock parking list */ 01270 AST_LIST_LOCK(&parkinglot->parkings); 01271 01272 /* Check for channel variable PARKINGEXTEN */ 01273 parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(park_me, "PARKINGEXTEN"), "")); 01274 if (!ast_strlen_zero(parkingexten)) { 01275 /*! 01276 * \note The API forces us to specify a numeric parking slot, even 01277 * though the architecture would tend to support non-numeric extensions 01278 * (as are possible with SIP, for example). Hence, we enforce that 01279 * limitation here. If extout was not numeric, we could permit 01280 * arbitrary non-numeric extensions. 01281 */ 01282 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space <= 0) { 01283 ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", 01284 parkingexten); 01285 AST_LIST_UNLOCK(&parkinglot->parkings); 01286 parkinglot_unref(parkinglot); 01287 ast_free(pu); 01288 return NULL; 01289 } 01290 01291 if (parking_space < parkinglot->cfg.parking_start 01292 || parkinglot->cfg.parking_stop < parking_space) { 01293 /* 01294 * Cannot allow park because parking lots are not setup for 01295 * spaces outside of the lot. (Things like dialplan hints don't 01296 * exist for outside lot space.) 01297 */ 01298 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is not in %s (%d-%d).\n", 01299 parking_space, parkinglot->name, parkinglot->cfg.parking_start, 01300 parkinglot->cfg.parking_stop); 01301 AST_LIST_UNLOCK(&parkinglot->parkings); 01302 parkinglot_unref(parkinglot); 01303 ast_free(pu); 01304 return NULL; 01305 } 01306 01307 /* Check if requested parking space is in use. */ 01308 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 01309 if (cur->parkingnum == parking_space) { 01310 ast_log(LOG_WARNING, "PARKINGEXTEN=%d is already in use in %s\n", 01311 parking_space, parkinglot->name); 01312 AST_LIST_UNLOCK(&parkinglot->parkings); 01313 parkinglot_unref(parkinglot); 01314 ast_free(pu); 01315 return NULL; 01316 } 01317 } 01318 } else { 01319 /* PARKINGEXTEN is empty, so find a usable extension in the lot to park the call */ 01320 int start; /* The first slot we look in the parkinglot. It can be randomized. */ 01321 int start_checked = 0; /* flag raised once the first slot is checked */ 01322 01323 /* If using randomize mode, set start to random position on parking range */ 01324 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) { 01325 start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1); 01326 start += parkinglot->cfg.parking_start; 01327 } else if (parkinglot->cfg.parkfindnext 01328 && parkinglot->cfg.parking_start <= parkinglot->next_parking_space 01329 && parkinglot->next_parking_space <= parkinglot->cfg.parking_stop) { 01330 /* Start looking with the next parking space in the lot. */ 01331 start = parkinglot->next_parking_space; 01332 } else { 01333 /* Otherwise, just set it to the start position. */ 01334 start = parkinglot->cfg.parking_start; 01335 } 01336 01337 /* free parking extension linear search: O(n^2) */ 01338 for (i = start; ; i++) { 01339 /* If we are past the end, wrap around to the first parking slot*/ 01340 if (i == parkinglot->cfg.parking_stop + 1) { 01341 i = parkinglot->cfg.parking_start; 01342 } 01343 01344 if (i == start) { 01345 /* At this point, if start_checked, we've exhausted all the possible slots. */ 01346 if (start_checked) { 01347 break; 01348 } else { 01349 start_checked = 1; 01350 } 01351 } 01352 01353 /* Search the list of parked calls already in use for i. If we find it, it's in use. */ 01354 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 01355 if (cur->parkingnum == i) { 01356 break; 01357 } 01358 } 01359 if (!cur) { 01360 /* We found a parking space. */ 01361 parking_space = i; 01362 break; 01363 } 01364 } 01365 if (parking_space == -1) { 01366 /* We did not find a parking space. Lot is full. */ 01367 ast_log(LOG_WARNING, "No more parking spaces in %s\n", parkinglot->name); 01368 AST_LIST_UNLOCK(&parkinglot->parkings); 01369 parkinglot_unref(parkinglot); 01370 ast_free(pu); 01371 return NULL; 01372 } 01373 } 01374 01375 /* Prepare for next parking space search. */ 01376 parkinglot->next_parking_space = parking_space + 1; 01377 01378 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 01379 pu->notquiteyet = 1; 01380 pu->parkingnum = parking_space; 01381 pu->parkinglot = parkinglot; 01382 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list); 01383 01384 return pu; 01385 }
| 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 5024 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_name(), ast_channel_uniqueid(), 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, ast_dial_features::features_caller, find_parkinglot(), findparkinglotname(), parkeduser::hold_method, ast_party_connected_line::id, ast_party_caller::id, LOG_WARNING, 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().
05025 { 05026 int res = 0; 05027 struct ast_channel *peer = NULL; 05028 struct parkeduser *pu; 05029 struct ast_context *con; 05030 char *parse; 05031 const char *pl_name; 05032 int park = 0; 05033 struct ast_bridge_config config; 05034 struct ast_parkinglot *parkinglot; 05035 AST_DECLARE_APP_ARGS(app_args, 05036 AST_APP_ARG(pl_space); /*!< Parking lot space to retrieve if present. */ 05037 AST_APP_ARG(pl_name); /*!< Parking lot name to use if present. */ 05038 AST_APP_ARG(dummy); /*!< Place to put any remaining args string. */ 05039 ); 05040 05041 parse = ast_strdupa(data); 05042 AST_STANDARD_APP_ARGS(app_args, parse); 05043 05044 if (!ast_strlen_zero(app_args.pl_space)) { 05045 if (sscanf(app_args.pl_space, "%30u", &park) != 1) { 05046 ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n", 05047 app_args.pl_space); 05048 park = -1; 05049 } 05050 } 05051 05052 if (!ast_strlen_zero(app_args.pl_name)) { 05053 pl_name = app_args.pl_name; 05054 } else { 05055 pl_name = findparkinglotname(chan); 05056 } 05057 if (ast_strlen_zero(pl_name)) { 05058 /* Parking lot is not specified, so use the default parking lot. */ 05059 parkinglot = parkinglot_addref(default_parkinglot); 05060 } else { 05061 parkinglot = find_parkinglot(pl_name); 05062 if (!parkinglot) { 05063 /* It helps to answer the channel if not already up. :) */ 05064 if (chan->_state != AST_STATE_UP) { 05065 ast_answer(chan); 05066 } 05067 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05068 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", 05069 "pbx-invalidpark", ast_channel_name(chan)); 05070 } 05071 ast_log(LOG_WARNING, 05072 "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n", 05073 ast_channel_name(chan), pl_name); 05074 return -1; 05075 } 05076 } 05077 05078 AST_LIST_LOCK(&parkinglot->parkings); 05079 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 05080 if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park) 05081 && !pu->notquiteyet && !pu->chan->pbx) { 05082 /* The parking space has a call and can be picked up now. */ 05083 AST_LIST_REMOVE_CURRENT(list); 05084 break; 05085 } 05086 } 05087 AST_LIST_TRAVERSE_SAFE_END; 05088 if (pu) { 05089 /* Found a parked call to pickup. */ 05090 peer = pu->chan; 05091 con = ast_context_find(parkinglot->cfg.parking_con); 05092 if (con) { 05093 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) { 05094 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 05095 } else { 05096 notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE); 05097 } 05098 } else { 05099 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 05100 } 05101 05102 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan); 05103 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall", 05104 "Exten: %s\r\n" 05105 "Channel: %s\r\n" 05106 "Parkinglot: %s\r\n" 05107 "From: %s\r\n" 05108 "CallerIDNum: %s\r\n" 05109 "CallerIDName: %s\r\n" 05110 "ConnectedLineNum: %s\r\n" 05111 "ConnectedLineName: %s\r\n" 05112 "Uniqueid: %s\r\n", 05113 pu->parkingexten, ast_channel_name(pu->chan), pu->parkinglot->name, 05114 ast_channel_name(chan), 05115 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 05116 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 05117 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 05118 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 05119 ast_channel_uniqueid(pu->chan) 05120 ); 05121 05122 /* Stop entertaining the caller. */ 05123 switch (pu->hold_method) { 05124 case AST_CONTROL_HOLD: 05125 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 05126 break; 05127 case AST_CONTROL_RINGING: 05128 ast_indicate(pu->chan, -1); 05129 break; 05130 default: 05131 break; 05132 } 05133 pu->hold_method = 0; 05134 05135 parkinglot_unref(pu->parkinglot); 05136 ast_free(pu); 05137 } 05138 AST_LIST_UNLOCK(&parkinglot->parkings); 05139 05140 if (peer) { 05141 /* Update connected line between retrieving call and parked call. */ 05142 struct ast_party_connected_line connected; 05143 05144 ast_party_connected_line_init(&connected); 05145 05146 /* Send our caller-id to peer. */ 05147 ast_channel_lock(chan); 05148 ast_connected_line_copy_from_caller(&connected, &chan->caller); 05149 ast_channel_unlock(chan); 05150 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05151 if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) { 05152 ast_channel_update_connected_line(peer, &connected, NULL); 05153 } 05154 05155 /* 05156 * Get caller-id from peer. 05157 * 05158 * Update the retrieving call before it is answered if possible 05159 * for best results. Some phones do not support updating the 05160 * connected line information after connection. 05161 */ 05162 ast_channel_lock(peer); 05163 ast_connected_line_copy_from_caller(&connected, &peer->caller); 05164 ast_channel_unlock(peer); 05165 connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05166 if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) { 05167 ast_channel_update_connected_line(chan, &connected, NULL); 05168 } 05169 05170 ast_party_connected_line_free(&connected); 05171 } 05172 05173 /* JK02: it helps to answer the channel if not already up */ 05174 if (chan->_state != AST_STATE_UP) { 05175 ast_answer(chan); 05176 } 05177 05178 if (peer) { 05179 struct ast_datastore *features_datastore; 05180 struct ast_dial_features *dialfeatures = NULL; 05181 05182 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 05183 if (!ast_strlen_zero(courtesytone)) { 05184 static const char msg[] = "courtesy tone"; 05185 05186 switch (parkedplay) { 05187 case 0:/* Courtesy tone to pickup chan */ 05188 res = play_message_to_chans(chan, peer, -1, msg, courtesytone); 05189 break; 05190 case 1:/* Courtesy tone to parked chan */ 05191 res = play_message_to_chans(chan, peer, 1, msg, courtesytone); 05192 break; 05193 case 2:/* Courtesy tone to both chans */ 05194 res = play_message_to_chans(chan, peer, 0, msg, courtesytone); 05195 break; 05196 default: 05197 res = 0; 05198 break; 05199 } 05200 if (res) { 05201 ast_hangup(peer); 05202 parkinglot_unref(parkinglot); 05203 return -1; 05204 } 05205 } 05206 05207 res = ast_channel_make_compatible(chan, peer); 05208 if (res < 0) { 05209 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(peer)); 05210 ast_hangup(peer); 05211 parkinglot_unref(parkinglot); 05212 return -1; 05213 } 05214 /* This runs sorta backwards, since we give the incoming channel control, as if it 05215 were the person called. */ 05216 ast_verb(3, "Channel %s connected to parked call %d\n", ast_channel_name(chan), park); 05217 05218 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", ast_channel_name(peer)); 05219 ast_cdr_setdestchan(chan->cdr, ast_channel_name(peer)); 05220 memset(&config, 0, sizeof(struct ast_bridge_config)); 05221 05222 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 05223 ast_channel_lock(peer); 05224 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 05225 dialfeatures = features_datastore->data; 05226 } 05227 05228 /* 05229 * When the datastores for both caller and callee are created, 05230 * both the callee and caller channels use the features_caller 05231 * flag variable to represent themselves. With that said, the 05232 * config.features_callee flags should be copied from the 05233 * datastore's caller feature flags regardless if peer was a 05234 * callee or caller. 05235 */ 05236 if (dialfeatures) { 05237 ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 05238 } 05239 ast_channel_unlock(peer); 05240 05241 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05242 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 05243 } 05244 if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 05245 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 05246 } 05247 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05248 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 05249 } 05250 if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 05251 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 05252 } 05253 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05254 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 05255 } 05256 if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 05257 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 05258 } 05259 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05260 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 05261 } 05262 if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 05263 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 05264 } 05265 05266 res = ast_bridge_call(chan, peer, &config); 05267 05268 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", ast_channel_name(peer)); 05269 ast_cdr_setdestchan(chan->cdr, ast_channel_name(peer)); 05270 05271 /* Simulate the PBX hanging up */ 05272 ast_hangup(peer); 05273 } else { 05274 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) { 05275 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", 05276 ast_channel_name(chan)); 05277 } 05278 ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n", 05279 ast_channel_name(chan), park); 05280 } 05281 05282 parkinglot_unref(parkinglot); 05283 return -1; 05284 }
| static int parkinglot_activate | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 5517 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().
05518 { 05519 int disabled = 0; 05520 char app_data[5 + AST_MAX_CONTEXT]; 05521 05522 /* Create Park option list. Must match with struct park_app_args options. */ 05523 if (parkinglot->cfg.parkext_exclusive) { 05524 /* Specify the parking lot this parking extension parks calls. */ 05525 snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name); 05526 } else { 05527 /* The dialplan must specify which parking lot to use. */ 05528 app_data[0] = '\0'; 05529 } 05530 05531 /* Create context */ 05532 if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) { 05533 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", 05534 parkinglot->cfg.parking_con); 05535 disabled = 1; 05536 05537 /* Add a parking extension into the context */ 05538 } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext, 05539 1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) { 05540 ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n", 05541 parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con); 05542 disabled = 1; 05543 } else { 05544 /* Add parking hints */ 05545 if (parkinglot->cfg.parkaddhints) { 05546 park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start, 05547 parkinglot->cfg.parking_stop); 05548 } 05549 05550 /* 05551 * XXX Not sure why we should need to notify the metermaids for 05552 * this exten. It was originally done for the default parking 05553 * lot entry exten only but should be done for all entry extens 05554 * if we do it for one. 05555 */ 05556 /* Notify metermaids about parking lot entry exten state. */ 05557 notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con, 05558 AST_DEVICE_INUSE); 05559 } 05560 05561 parkinglot->disabled = disabled; 05562 return disabled ? -1 : 0; 05563 }
| static int parkinglot_activate_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6561 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().
06562 { 06563 struct ast_parkinglot *parkinglot = obj; 06564 06565 if (parkinglot->the_mark) { 06566 /* 06567 * Don't activate a parking lot that still bears the_mark since 06568 * it is effectively deleted. 06569 */ 06570 return 0; 06571 } 06572 06573 if (parkinglot_activate(parkinglot)) { 06574 /* 06575 * The parking lot failed to activate. Allow reloading later to 06576 * see if that fixes it. 06577 */ 06578 force_reload_load = 1; 06579 ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name); 06580 } else { 06581 ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n", 06582 parkinglot->name, parkinglot->cfg.parking_start, 06583 parkinglot->cfg.parking_stop); 06584 } 06585 06586 return 0; 06587 }
| static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static, read] |
Definition at line 5296 of file features.c.
References ao2_ref, ast_debug, and ast_parkinglot::name.
Referenced by create_dynamic_parkinglot(), load_config(), park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().
05297 { 05298 int refcount; 05299 05300 refcount = ao2_ref(parkinglot, +1); 05301 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1); 05302 return parkinglot; 05303 }
| static int parkinglot_cmp_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 826 of file features.c.
References CMP_MATCH, CMP_STOP, and ast_parkinglot::name.
Referenced by ast_features_init().
00827 { 00828 struct ast_parkinglot *parkinglot = obj; 00829 struct ast_parkinglot *parkinglot2 = arg; 00830 00831 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0; 00832 }
| static int parkinglot_config_read | ( | const char * | pl_name, | |
| struct parkinglot_cfg * | cfg, | |||
| struct ast_variable * | var | |||
| ) | [static] |
Definition at line 5413 of file features.c.
References ast_copy_string(), ast_log(), ast_strlen_zero(), ast_true(), parkinglot_cfg::comebackcontext, parkinglot_cfg::comebackdialtime, parkinglot_cfg::comebacktoorigin, DEFAULT_COMEBACK_DIAL_TIME, ast_variable::file, parkinglot_cfg::is_invalid, ast_variable::lineno, LOG_WARNING, parkinglot_cfg::mohclass, ast_variable::name, ast_variable::next, parkinglot_cfg::parkaddhints, parkinglot_cfg::parkedcallhangup, parkinglot_cfg::parkedcallrecording, parkinglot_cfg::parkedcallreparking, parkinglot_cfg::parkedcalltransfers, parkinglot_cfg::parkext, parkinglot_cfg::parkext_exclusive, parkinglot_cfg::parkfindnext, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglot_feature_flag_cfg(), parkinglot_cfg::parkingtime, and ast_variable::value.
Referenced by build_parkinglot().
05414 { 05415 int error = 0; 05416 05417 while (var) { 05418 if (!strcasecmp(var->name, "context")) { 05419 ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con)); 05420 } else if (!strcasecmp(var->name, "parkext")) { 05421 ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext)); 05422 } else if (!strcasecmp(var->name, "parkext_exclusive")) { 05423 cfg->parkext_exclusive = ast_true(var->value); 05424 } else if (!strcasecmp(var->name, "parkinghints")) { 05425 cfg->parkaddhints = ast_true(var->value); 05426 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 05427 ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass)); 05428 } else if (!strcasecmp(var->name, "parkingtime")) { 05429 int parkingtime = 0; 05430 05431 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) { 05432 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 05433 error = -1; 05434 } else { 05435 cfg->parkingtime = parkingtime * 1000; 05436 } 05437 } else if (!strcasecmp(var->name, "parkpos")) { 05438 int start = 0; 05439 int end = 0; 05440 05441 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 05442 ast_log(LOG_WARNING, 05443 "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n", 05444 var->lineno, var->file); 05445 error = -1; 05446 } else if (end < start || start <= 0 || end <= 0) { 05447 ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n", 05448 var->lineno, var->file); 05449 error = -1; 05450 } else { 05451 cfg->parking_start = start; 05452 cfg->parking_stop = end; 05453 } 05454 } else if (!strcasecmp(var->name, "findslot")) { 05455 cfg->parkfindnext = (!strcasecmp(var->value, "next")); 05456 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 05457 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var); 05458 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 05459 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var); 05460 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 05461 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var); 05462 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 05463 parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var); 05464 } else if (!strcasecmp(var->name, "comebackcontext")) { 05465 ast_copy_string(cfg->comebackcontext, var->value, sizeof(cfg->comebackcontext)); 05466 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 05467 cfg->comebacktoorigin = ast_true(var->value); 05468 } else if (!strcasecmp(var->name, "comebackdialtime")) { 05469 if ((sscanf(var->value, "%30u", &cfg->comebackdialtime) != 1) 05470 || (cfg->comebackdialtime < 1)) { 05471 ast_log(LOG_WARNING, "%s is not a valid comebackdialtime\n", var->value); 05472 cfg->parkingtime = DEFAULT_COMEBACK_DIAL_TIME; 05473 } 05474 } 05475 var = var->next; 05476 } 05477 05478 /* Check for configuration errors */ 05479 if (ast_strlen_zero(cfg->parking_con)) { 05480 ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name); 05481 error = -1; 05482 } 05483 if (ast_strlen_zero(cfg->parkext)) { 05484 ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name); 05485 error = -1; 05486 } 05487 if (!cfg->parking_start) { 05488 ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name); 05489 error = -1; 05490 } 05491 if (!cfg->comebacktoorigin && ast_strlen_zero(cfg->comebackcontext)) { 05492 ast_log(LOG_WARNING, "Parking lot %s has comebacktoorigin set false" 05493 "but has no comebackcontext.\n", 05494 pl_name); 05495 error = -1; 05496 } 05497 if (error) { 05498 cfg->is_invalid = 1; 05499 } 05500 05501 return error; 05502 }
| static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 5306 of file features.c.
References ast_assert, AST_LIST_EMPTY, AST_LIST_HEAD_DESTROY, and ast_parkinglot::parkings.
Referenced by create_parkinglot().
05307 { 05308 struct ast_parkinglot *doomed = obj; 05309 05310 /* 05311 * No need to destroy parked calls here because any parked call 05312 * holds a parking lot reference. Therefore the parkings list 05313 * must be empty. 05314 */ 05315 ast_assert(AST_LIST_EMPTY(&doomed->parkings)); 05316 AST_LIST_HEAD_DESTROY(&doomed->parkings); 05317 }
| static void parkinglot_feature_flag_cfg | ( | const char * | pl_name, | |
| int * | param, | |||
| struct ast_variable * | var | |||
| ) | [static] |
Definition at line 5390 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().
05391 { 05392 ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value); 05393 if (!strcasecmp(var->value, "both")) { 05394 *param = AST_FEATURE_FLAG_BYBOTH; 05395 } else if (!strcasecmp(var->value, "caller")) { 05396 *param = AST_FEATURE_FLAG_BYCALLER; 05397 } else if (!strcasecmp(var->value, "callee")) { 05398 *param = AST_FEATURE_FLAG_BYCALLEE; 05399 } 05400 }
| static int parkinglot_hash_cb | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 819 of file features.c.
References ast_str_case_hash(), and ast_parkinglot::name.
Referenced by ast_features_init().
00820 { 00821 const struct ast_parkinglot *parkinglot = obj; 00822 00823 return ast_str_case_hash(parkinglot->name); 00824 }
| static int parkinglot_is_marked_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6541 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().
06542 { 06543 struct ast_parkinglot *parkinglot = obj; 06544 06545 if (parkinglot->the_mark) { 06546 if (AST_LIST_EMPTY(&parkinglot->parkings)) { 06547 /* This parking lot can actually be deleted. */ 06548 return CMP_MATCH; 06549 } 06550 /* Try reloading later when parking lot is empty. */ 06551 ast_log(LOG_WARNING, 06552 "Parking lot %s has parked calls. Could not remove.\n", 06553 parkinglot->name); 06554 parkinglot->disabled = 1; 06555 force_reload_load = 1; 06556 } 06557 06558 return 0; 06559 }
| static int parkinglot_markall_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6533 of file features.c.
References ast_parkinglot::the_mark.
Referenced by load_config().
06534 { 06535 struct ast_parkinglot *parkinglot = obj; 06536 06537 parkinglot->the_mark = 1; 06538 return 0; 06539 }
| static void parkinglot_unref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Unreference parkinglot object.
Definition at line 5289 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().
05290 { 05291 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, 05292 ao2_ref(parkinglot, 0) - 1); 05293 ao2_ref(parkinglot, -1); 05294 }
return the first unlocked cdr in a possible chain
Definition at line 3722 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
03723 { 03724 struct ast_cdr *cdr_orig = cdr; 03725 while (cdr) { 03726 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 03727 return cdr; 03728 cdr = cdr->next; 03729 } 03730 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 03731 }
| 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 1985 of file features.c.
References play_message_to_chans().
Referenced by builtin_automonitor().
01986 { 01987 return play_message_to_chans(caller_chan, callee_chan, 0, "automon message", 01988 audiofile); 01989 }
| 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 1931 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().
01932 { 01933 /* Put other channel in autoservice. */ 01934 if (ast_autoservice_start(other)) { 01935 return -1; 01936 } 01937 ast_autoservice_ignore(other, AST_FRAME_DTMF_BEGIN); 01938 ast_autoservice_ignore(other, AST_FRAME_DTMF_END); 01939 if (ast_stream_and_wait(play_to, audiofile, "")) { 01940 ast_log(LOG_WARNING, "Failed to play %s '%s'!\n", msg, audiofile); 01941 ast_autoservice_stop(other); 01942 return -1; 01943 } 01944 if (ast_autoservice_stop(other)) { 01945 return -1; 01946 } 01947 return 0; 01948 }
| 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 1966 of file features.c.
References play_message_on_chan().
Referenced by parked_call_exec(), and play_message_in_bridged_call().
01967 { 01968 /* First play the file to the left channel if requested. */ 01969 if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) { 01970 return -1; 01971 } 01972 01973 /* Then play the file to the right channel if requested. */ 01974 if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) { 01975 return -1; 01976 } 01977 01978 return 0; 01979 }
| static void post_manager_event | ( | const char * | s, | |
| struct parkeduser * | pu | |||
| ) | [static] |
Output parking event to manager.
Definition at line 4497 of file features.c.
References ast_channel_name(), ast_channel_uniqueid(), 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().
04498 { 04499 manager_event(EVENT_FLAG_CALL, s, 04500 "Exten: %s\r\n" 04501 "Channel: %s\r\n" 04502 "Parkinglot: %s\r\n" 04503 "CallerIDNum: %s\r\n" 04504 "CallerIDName: %s\r\n" 04505 "ConnectedLineNum: %s\r\n" 04506 "ConnectedLineName: %s\r\n" 04507 "UniqueID: %s\r\n", 04508 pu->parkingexten, 04509 ast_channel_name(pu->chan), 04510 pu->parkinglot->name, 04511 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 04512 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 04513 S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"), 04514 S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"), 04515 ast_channel_uniqueid(pu->chan) 04516 ); 04517 }
| static void process_applicationmap_line | ( | struct ast_variable * | var | ) | [static] |
Definition at line 5645 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_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, strsep(), and ast_variable::value.
Referenced by process_config().
05646 { 05647 char *tmp_val = ast_strdupa(var->value); 05648 char *activateon; 05649 struct ast_call_feature *feature; 05650 AST_DECLARE_APP_ARGS(args, 05651 AST_APP_ARG(exten); 05652 AST_APP_ARG(activatedby); 05653 AST_APP_ARG(app); 05654 AST_APP_ARG(app_args); 05655 AST_APP_ARG(moh_class); 05656 ); 05657 05658 AST_STANDARD_APP_ARGS(args, tmp_val); 05659 if (strchr(args.app, '(')) { 05660 /* New syntax */ 05661 args.moh_class = args.app_args; 05662 args.app_args = strchr(args.app, '('); 05663 *args.app_args++ = '\0'; 05664 if (args.app_args[strlen(args.app_args) - 1] == ')') { 05665 args.app_args[strlen(args.app_args) - 1] = '\0'; 05666 } 05667 } 05668 05669 activateon = strsep(&args.activatedby, "/"); 05670 05671 /*! \todo XXX var_name or app_args ? */ 05672 if (ast_strlen_zero(args.app) 05673 || ast_strlen_zero(args.exten) 05674 || ast_strlen_zero(activateon) 05675 || ast_strlen_zero(var->name)) { 05676 ast_log(LOG_NOTICE, 05677 "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 05678 args.app, args.exten, activateon, var->name); 05679 return; 05680 } 05681 05682 AST_RWLIST_RDLOCK(&feature_list); 05683 if (find_dynamic_feature(var->name)) { 05684 AST_RWLIST_UNLOCK(&feature_list); 05685 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", 05686 var->name); 05687 return; 05688 } 05689 AST_RWLIST_UNLOCK(&feature_list); 05690 05691 if (!(feature = ast_calloc(1, sizeof(*feature)))) { 05692 return; 05693 } 05694 05695 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 05696 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN); 05697 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN); 05698 05699 if (args.app_args) { 05700 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN); 05701 } 05702 05703 if (args.moh_class) { 05704 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN); 05705 } 05706 05707 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten)); 05708 feature->operation = feature_exec_app; 05709 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 05710 05711 /* Allow caller and callee to be specified for backwards compatability */ 05712 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) { 05713 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 05714 } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) { 05715 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 05716 } else { 05717 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 05718 " must be 'self', or 'peer'\n", var->name); 05719 return; 05720 } 05721 05722 if (ast_strlen_zero(args.activatedby)) { 05723 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05724 } else if (!strcasecmp(args.activatedby, "caller")) { 05725 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 05726 } else if (!strcasecmp(args.activatedby, "callee")) { 05727 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 05728 } else if (!strcasecmp(args.activatedby, "both")) { 05729 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05730 } else { 05731 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 05732 " must be 'caller', or 'callee', or 'both'\n", var->name); 05733 return; 05734 } 05735 05736 ast_register_feature(feature); 05737 05738 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", 05739 var->name, args.app, args.app_args, args.exten); 05740 }
| static int process_config | ( | struct ast_config * | cfg | ) | [static] |
Definition at line 5742 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(), 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().
05743 { 05744 int i; 05745 struct ast_variable *var = NULL; 05746 struct feature_group *fg = NULL; 05747 char *ctg; 05748 static const char * const categories[] = { 05749 /* Categories in features.conf that are not 05750 * to be parsed as group categories 05751 */ 05752 "general", 05753 "featuremap", 05754 "applicationmap" 05755 }; 05756 05757 /* Set general features global defaults. */ 05758 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05759 05760 /* Set global call pickup defaults. */ 05761 strcpy(pickup_ext, "*8"); 05762 pickupsound[0] = '\0'; 05763 pickupfailsound[0] = '\0'; 05764 05765 /* Set global call transfer defaults. */ 05766 strcpy(xfersound, "beep"); 05767 strcpy(xferfailsound, "beeperr"); 05768 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05769 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05770 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05771 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 05772 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05773 05774 /* Set global call parking defaults. */ 05775 courtesytone[0] = '\0'; 05776 parkedplay = 0; 05777 adsipark = 0; 05778 parkeddynamic = 0; 05779 05780 var = ast_variable_browse(cfg, "general"); 05781 build_parkinglot(DEFAULT_PARKINGLOT, var); 05782 for (; var; var = var->next) { 05783 if (!strcasecmp(var->name, "parkeddynamic")) { 05784 parkeddynamic = ast_true(var->value); 05785 } else if (!strcasecmp(var->name, "adsipark")) { 05786 adsipark = ast_true(var->value); 05787 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 05788 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 05789 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 05790 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 05791 } else { 05792 transferdigittimeout = transferdigittimeout * 1000; 05793 } 05794 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 05795 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 05796 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 05797 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 05798 } 05799 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 05800 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 05801 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 05802 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 05803 } else { 05804 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 05805 } 05806 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 05807 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 05808 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 05809 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 05810 } else { 05811 atxferloopdelay *= 1000; 05812 } 05813 } else if (!strcasecmp(var->name, "atxferdropcall")) { 05814 atxferdropcall = ast_true(var->value); 05815 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 05816 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) { 05817 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 05818 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 05819 } 05820 } else if (!strcasecmp(var->name, "courtesytone")) { 05821 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 05822 } else if (!strcasecmp(var->name, "parkedplay")) { 05823 if (!strcasecmp(var->value, "both")) { 05824 parkedplay = 2; 05825 } else if (!strcasecmp(var->value, "parked")) { 05826 parkedplay = 1; 05827 } else { 05828 parkedplay = 0; 05829 } 05830 } else if (!strcasecmp(var->name, "xfersound")) { 05831 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 05832 } else if (!strcasecmp(var->name, "xferfailsound")) { 05833 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 05834 } else if (!strcasecmp(var->name, "pickupexten")) { 05835 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 05836 } else if (!strcasecmp(var->name, "pickupsound")) { 05837 ast_copy_string(pickupsound, var->value, sizeof(pickupsound)); 05838 } else if (!strcasecmp(var->name, "pickupfailsound")) { 05839 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound)); 05840 } 05841 } 05842 05843 unmap_features(); 05844 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 05845 if (remap_feature(var->name, var->value)) { 05846 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 05847 } 05848 } 05849 05850 /* Map a key combination to an application */ 05851 ast_unregister_features(); 05852 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 05853 process_applicationmap_line(var); 05854 } 05855 05856 ast_unregister_groups(); 05857 AST_RWLIST_WRLOCK(&feature_groups); 05858 05859 ctg = NULL; 05860 while ((ctg = ast_category_browse(cfg, ctg))) { 05861 /* Is this a parkinglot definition ? */ 05862 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 05863 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 05864 if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) { 05865 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 05866 } else { 05867 ast_debug(1, "Configured parking context %s\n", ctg); 05868 } 05869 continue; 05870 } 05871 05872 /* No, check if it's a group */ 05873 for (i = 0; i < ARRAY_LEN(categories); i++) { 05874 if (!strcasecmp(categories[i], ctg)) { 05875 break; 05876 } 05877 } 05878 if (i < ARRAY_LEN(categories)) { 05879 continue; 05880 } 05881 05882 if (!(fg = register_group(ctg))) { 05883 continue; 05884 } 05885 05886 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 05887 struct ast_call_feature *feature; 05888 05889 AST_RWLIST_RDLOCK(&feature_list); 05890 if (!(feature = find_dynamic_feature(var->name)) && 05891 !(feature = ast_find_call_feature(var->name))) { 05892 AST_RWLIST_UNLOCK(&feature_list); 05893 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 05894 continue; 05895 } 05896 AST_RWLIST_UNLOCK(&feature_list); 05897 05898 register_group_feature(fg, var->value, feature); 05899 } 05900 } 05901 05902 AST_RWLIST_UNLOCK(&feature_groups); 05903 05904 return 0; 05905 }
| 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 2227 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().
02228 { 02229 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 02230 if (ast_strlen_zero(s)) { 02231 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 02232 } 02233 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 02234 s = transferer->macrocontext; 02235 } 02236 if (ast_strlen_zero(s)) { 02237 s = transferer->context; 02238 } 02239 return s; 02240 }
| static struct feature_group* register_group | ( | const char * | fgname | ) | [static, read] |
Add new feature group.
| fgname | feature group name. |
Definition at line 2874 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().
02875 { 02876 struct feature_group *fg; 02877 02878 if (!fgname) { 02879 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 02880 return NULL; 02881 } 02882 02883 if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) { 02884 return NULL; 02885 } 02886 02887 ast_string_field_set(fg, gname, fgname); 02888 02889 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 02890 02891 ast_verb(2, "Registered group '%s'\n", fg->gname); 02892 02893 return fg; 02894 }
| static void register_group_feature | ( | struct feature_group * | fg, | |
| const char * | exten, | |||
| struct ast_call_feature * | feature | |||
| ) | [static] |
Add feature to group.
| fg | feature group | |
| exten | ||
| feature | feature to add. |
Definition at line 2905 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().
02906 { 02907 struct feature_group_exten *fge; 02908 02909 if (!fg) { 02910 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 02911 return; 02912 } 02913 02914 if (!feature) { 02915 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 02916 return; 02917 } 02918 02919 if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) { 02920 return; 02921 } 02922 02923 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 02924 02925 fge->feature = feature; 02926 02927 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 02928 02929 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 02930 feature->sname, fg->gname, fge->exten); 02931 }
| static int remap_feature | ( | const char * | name, | |
| const char * | value | |||
| ) | [static] |
Definition at line 3114 of file features.c.
References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, FEATURES_COUNT, and features_lock.
Referenced by process_config().
03115 { 03116 int x, res = -1; 03117 03118 ast_rwlock_wrlock(&features_lock); 03119 for (x = 0; x < FEATURES_COUNT; x++) { 03120 if (strcasecmp(builtin_features[x].sname, name)) 03121 continue; 03122 03123 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 03124 res = 0; 03125 break; 03126 } 03127 ast_rwlock_unlock(&features_lock); 03128 03129 return res; 03130 }
| 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 6466 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().
06467 { 06468 remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens); 06469 remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space); 06470 #if 0 06471 /* I don't think we should destroy hints if the parking space still exists. */ 06472 remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint); 06473 #endif 06474 }
| static void remove_dead_dialplan_useage | ( | struct parking_dp_map * | old_map, | |
| struct parking_dp_map * | new_map | |||
| ) | [static] |
Definition at line 6489 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().
06490 { 06491 struct parking_dp_context *old_ctx; 06492 struct parking_dp_context *new_ctx; 06493 struct ast_context *con; 06494 int cmp; 06495 06496 old_ctx = AST_LIST_FIRST(old_map); 06497 new_ctx = AST_LIST_FIRST(new_map); 06498 06499 while (new_ctx) { 06500 if (!old_ctx) { 06501 /* No old contexts left, so no dead stuff can remain. */ 06502 return; 06503 } 06504 cmp = strcmp(old_ctx->context, new_ctx->context); 06505 if (cmp < 0) { 06506 /* New map does not have old map context. */ 06507 con = ast_context_find(old_ctx->context); 06508 if (con) { 06509 ast_context_destroy(con, registrar); 06510 } 06511 old_ctx = AST_LIST_NEXT(old_ctx, node); 06512 continue; 06513 } 06514 if (cmp == 0) { 06515 /* Old and new map have this context. */ 06516 remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx); 06517 old_ctx = AST_LIST_NEXT(old_ctx, node); 06518 } else { 06519 /* Old map does not have new map context. */ 06520 } 06521 new_ctx = AST_LIST_NEXT(new_ctx, node); 06522 } 06523 06524 /* Any old contexts left must be dead. */ 06525 for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) { 06526 con = ast_context_find(old_ctx->context); 06527 if (con) { 06528 ast_context_destroy(con, registrar); 06529 } 06530 } 06531 }
| 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 6325 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().
06326 { 06327 struct parking_dp_ramp *old_ramp; 06328 struct parking_dp_ramp *new_ramp; 06329 int cmp; 06330 06331 old_ramp = AST_LIST_FIRST(old_ramps); 06332 new_ramp = AST_LIST_FIRST(new_ramps); 06333 06334 while (new_ramp) { 06335 if (!old_ramp) { 06336 /* No old ramps left, so no dead ramps can remain. */ 06337 return; 06338 } 06339 cmp = strcmp(old_ramp->exten, new_ramp->exten); 06340 if (cmp < 0) { 06341 /* New map does not have old ramp. */ 06342 remove_exten_if_exist(context, old_ramp->exten, 1); 06343 old_ramp = AST_LIST_NEXT(old_ramp, node); 06344 continue; 06345 } 06346 if (cmp == 0) { 06347 /* Old and new map have this ramp. */ 06348 old_ramp = AST_LIST_NEXT(old_ramp, node); 06349 } else { 06350 /* Old map does not have new ramp. */ 06351 } 06352 new_ramp = AST_LIST_NEXT(new_ramp, node); 06353 } 06354 06355 /* Any old ramps left must be dead. */ 06356 for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) { 06357 remove_exten_if_exist(context, old_ramp->exten, 1); 06358 } 06359 }
| 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 6395 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().
06398 { 06399 struct parking_dp_spaces *old_range; 06400 struct parking_dp_spaces *new_range; 06401 int space;/*!< Current position in the current old range. */ 06402 int stop; 06403 06404 old_range = AST_LIST_FIRST(old_spaces); 06405 new_range = AST_LIST_FIRST(new_spaces); 06406 space = -1; 06407 06408 while (old_range) { 06409 if (space < old_range->start) { 06410 space = old_range->start; 06411 } 06412 if (new_range) { 06413 if (space < new_range->start) { 06414 /* Current position in old range starts before new range. */ 06415 if (old_range->stop < new_range->start) { 06416 /* Old range ends before new range. */ 06417 stop = old_range->stop; 06418 old_range = AST_LIST_NEXT(old_range, node); 06419 } else { 06420 /* Tail of old range overlaps new range. */ 06421 stop = new_range->start - 1; 06422 } 06423 } else if (/* new_range->start <= space && */ space <= new_range->stop) { 06424 /* Current position in old range overlaps new range. */ 06425 if (old_range->stop <= new_range->stop) { 06426 /* Old range ends at or before new range. */ 06427 old_range = AST_LIST_NEXT(old_range, node); 06428 } else { 06429 /* Old range extends beyond end of new range. */ 06430 space = new_range->stop + 1; 06431 new_range = AST_LIST_NEXT(new_range, node); 06432 } 06433 continue; 06434 } else /* if (new_range->stop < space) */ { 06435 /* Current position in old range starts after new range. */ 06436 new_range = AST_LIST_NEXT(new_range, node); 06437 continue; 06438 } 06439 } else { 06440 /* No more new ranges. All remaining old spaces are dead. */ 06441 stop = old_range->stop; 06442 old_range = AST_LIST_NEXT(old_range, node); 06443 } 06444 06445 /* Destroy dead parking spaces. */ 06446 for (; space <= stop; ++space) { 06447 destroy_space(context, space); 06448 } 06449 } 06450 }
| static void remove_exten_if_exist | ( | const char * | context, | |
| const char * | exten, | |||
| int | priority | |||
| ) | [static] |
Definition at line 6299 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().
06300 { 06301 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 06302 06303 if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL, 06304 E_MATCH)) { 06305 ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n", 06306 context, exten, priority); 06307 ast_context_remove_extension(context, exten, priority, registrar); 06308 } 06309 }
| static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
| const char * | features | |||
| ) | [static] |
Definition at line 3733 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().
03734 { 03735 const char *feature; 03736 03737 if (ast_strlen_zero(features)) { 03738 return; 03739 } 03740 03741 for (feature = features; *feature; feature++) { 03742 switch (*feature) { 03743 case 'T' : 03744 case 't' : 03745 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 03746 break; 03747 case 'K' : 03748 case 'k' : 03749 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 03750 break; 03751 case 'H' : 03752 case 'h' : 03753 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 03754 break; 03755 case 'W' : 03756 case 'w' : 03757 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 03758 break; 03759 default : 03760 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 03761 } 03762 } 03763 }
| 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 838 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().
00839 { 00840 ast_copy_string(chan->context, context, sizeof(chan->context)); 00841 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00842 chan->priority = pri; 00843 }
| static void set_config_flags | ( | struct ast_channel * | chan, | |
| struct ast_bridge_config * | config | |||
| ) | [static] |
Definition at line 3301 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(), pbx_builtin_getvar_helper(), and strsep().
Referenced by ast_bridge_call().
03302 { 03303 int x; 03304 03305 ast_clear_flag(config, AST_FLAGS_ALL); 03306 03307 ast_rwlock_rdlock(&features_lock); 03308 for (x = 0; x < FEATURES_COUNT; x++) { 03309 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 03310 continue; 03311 03312 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 03313 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03314 03315 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 03316 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03317 } 03318 ast_rwlock_unlock(&features_lock); 03319 03320 if (!(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 03321 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 03322 03323 if (dynamic_features) { 03324 char *tmp = ast_strdupa(dynamic_features); 03325 char *tok; 03326 struct ast_call_feature *feature; 03327 03328 /* while we have a feature */ 03329 while ((tok = strsep(&tmp, "#"))) { 03330 struct feature_group *fg; 03331 03332 AST_RWLIST_RDLOCK(&feature_groups); 03333 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 03334 struct feature_group_exten *fge; 03335 03336 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 03337 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) { 03338 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03339 } 03340 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) { 03341 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03342 } 03343 } 03344 } 03345 AST_RWLIST_UNLOCK(&feature_groups); 03346 03347 AST_RWLIST_RDLOCK(&feature_list); 03348 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 03349 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) { 03350 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 03351 } 03352 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) { 03353 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 03354 } 03355 } 03356 AST_RWLIST_UNLOCK(&feature_list); 03357 } 03358 } 03359 } 03360 }
| 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 1858 of file features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
01860 { 01861 if (sense == FEATURE_SENSE_PEER) { 01862 *caller = peer; 01863 *callee = chan; 01864 } else { 01865 *callee = peer; 01866 *caller = chan; 01867 } 01868 }
| static void unmap_features | ( | void | ) | [static] |
Definition at line 3104 of file features.c.
References ast_rwlock_unlock, ast_rwlock_wrlock, FEATURES_COUNT, and features_lock.
Referenced by process_config().
03105 { 03106 int x; 03107 03108 ast_rwlock_wrlock(&features_lock); 03109 for (x = 0; x < FEATURES_COUNT; x++) 03110 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 03111 ast_rwlock_unlock(&features_lock); 03112 }
| 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 5985 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().
05986 { 05987 struct parking_dp_ramp *cur_ramp; 05988 struct parking_dp_ramp *new_ramp; 05989 int cmp; 05990 05991 /* Make sure that exclusive is only 0 or 1 */ 05992 if (exclusive) { 05993 exclusive = 1; 05994 } 05995 05996 AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) { 05997 cmp = strcmp(exten, cur_ramp->exten); 05998 if (cmp > 0) { 05999 /* The parking lot ramp goes after this node. */ 06000 continue; 06001 } 06002 if (cmp == 0) { 06003 /* The ramp is already in the map. */ 06004 if (complain && (cur_ramp->exclusive || exclusive)) { 06005 ast_log(LOG_WARNING, 06006 "Parking lot '%s' parkext %s@%s used by another parking lot.\n", 06007 lot->name, exten, lot->cfg.parking_con); 06008 } 06009 return 0; 06010 } 06011 /* The new parking lot ramp goes before this node. */ 06012 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 06013 if (!new_ramp) { 06014 return -1; 06015 } 06016 AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node); 06017 return 0; 06018 } 06019 AST_LIST_TRAVERSE_SAFE_END; 06020 06021 /* New parking lot access ramp goes on the end. */ 06022 new_ramp = build_dialplan_useage_ramp(exten, exclusive); 06023 if (!new_ramp) { 06024 return -1; 06025 } 06026 AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node); 06027 return 0; 06028 }
| 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 6066 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().
06067 { 06068 struct parking_dp_spaces *cur_node; 06069 struct parking_dp_spaces *expand_node; 06070 struct parking_dp_spaces *new_node; 06071 06072 expand_node = NULL; 06073 AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) { 06074 /* NOTE: stop + 1 to combine immediately adjacent nodes into one. */ 06075 if (expand_node) { 06076 /* The previous node is expanding to possibly eat following nodes. */ 06077 if (expand_node->stop + 1 < cur_node->start) { 06078 /* Current node is completely after expanding node. */ 06079 return 0; 06080 } 06081 06082 if (complain 06083 && ((cur_node->start <= start && start <= cur_node->stop) 06084 || (cur_node->start <= stop && stop <= cur_node->stop) 06085 || (start < cur_node->start && cur_node->stop < stop))) { 06086 /* Only complain once per range add. */ 06087 complain = 0; 06088 ast_log(LOG_WARNING, 06089 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06090 lot->name, start, stop, lot->cfg.parking_con); 06091 } 06092 06093 /* Current node is eaten by the expanding node. */ 06094 if (expand_node->stop < cur_node->stop) { 06095 expand_node->stop = cur_node->stop; 06096 } 06097 AST_LIST_REMOVE_CURRENT(node); 06098 ast_free(cur_node); 06099 continue; 06100 } 06101 06102 if (cur_node->stop + 1 < start) { 06103 /* New range is completely after current node. */ 06104 continue; 06105 } 06106 if (stop + 1 < cur_node->start) { 06107 /* New range is completely before current node. */ 06108 new_node = build_dialplan_useage_spaces(start, stop); 06109 if (!new_node) { 06110 return -1; 06111 } 06112 AST_LIST_INSERT_BEFORE_CURRENT(new_node, node); 06113 return 0; 06114 } 06115 06116 if (complain 06117 && ((cur_node->start <= start && start <= cur_node->stop) 06118 || (cur_node->start <= stop && stop <= cur_node->stop) 06119 || (start < cur_node->start && cur_node->stop < stop))) { 06120 /* Only complain once per range add. */ 06121 complain = 0; 06122 ast_log(LOG_WARNING, 06123 "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n", 06124 lot->name, start, stop, lot->cfg.parking_con); 06125 } 06126 06127 /* Current node range overlaps or is immediately adjacent to new range. */ 06128 if (start < cur_node->start) { 06129 /* Expand the current node in the front. */ 06130 cur_node->start = start; 06131 } 06132 if (stop <= cur_node->stop) { 06133 /* Current node is not expanding in the rear. */ 06134 return 0; 06135 } 06136 cur_node->stop = stop; 06137 expand_node = cur_node; 06138 } 06139 AST_LIST_TRAVERSE_SAFE_END; 06140 06141 if (expand_node) { 06142 /* 06143 * The previous node expanded and either ate all following nodes 06144 * or it was the last node. 06145 */ 06146 return 0; 06147 } 06148 06149 /* New range goes on the end. */ 06150 new_node = build_dialplan_useage_spaces(start, stop); 06151 if (!new_node) { 06152 return -1; 06153 } 06154 AST_LIST_INSERT_TAIL(space_map, new_node, node); 06155 return 0; 06156 }
| static int xfer_park_call_helper | ( | struct ast_channel * | park_me, | |
| struct ast_channel * | parker, | |||
| struct ast_exten * | park_exten | |||
| ) | [static] |
Definition at line 1798 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().
01799 { 01800 char *parse; 01801 const char *app_data; 01802 const char *pl_name; 01803 struct ast_park_call_args args = { 0, }; 01804 struct park_app_args app_args; 01805 int res; 01806 01807 app_data = ast_get_extension_app_data(park_exten); 01808 if (!app_data) { 01809 app_data = ""; 01810 } 01811 parse = ast_strdupa(app_data); 01812 AST_STANDARD_APP_ARGS(app_args, parse); 01813 01814 /* Find the parking lot */ 01815 if (!ast_strlen_zero(app_args.pl_name)) { 01816 pl_name = app_args.pl_name; 01817 } else { 01818 pl_name = findparkinglotname(parker); 01819 } 01820 if (ast_strlen_zero(pl_name)) { 01821 /* Parking lot is not specified, so use the default parking lot. */ 01822 args.parkinglot = parkinglot_addref(default_parkinglot); 01823 } else { 01824 args.parkinglot = find_parkinglot(pl_name); 01825 if (!args.parkinglot && parkeddynamic) { 01826 args.parkinglot = create_dynamic_parkinglot(pl_name, park_me); 01827 } 01828 } 01829 01830 if (args.parkinglot) { 01831 /* Park the call */ 01832 res = finishup(park_me); 01833 if (res) { 01834 /* park_me hungup on us. */ 01835 parkinglot_unref(args.parkinglot); 01836 return -1; 01837 } 01838 res = masq_park_call(park_me, parker, &args); 01839 parkinglot_unref(args.parkinglot); 01840 } else { 01841 /* Parking failed because parking lot does not exist. */ 01842 if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { 01843 ast_stream_and_wait(parker, "pbx-parkingfailed", ""); 01844 } 01845 finishup(park_me); 01846 res = -1; 01847 } 01848 01849 return res ? AST_FEATURE_RETURN_SUCCESS : -1; 01850 }
int adsipark [static] |
char* app_bridge = "Bridge" [static] |
Definition at line 7351 of file features.c.
unsigned int atxfercallbackretries [static] |
unsigned int atxferdropcall [static] |
unsigned int atxferloopdelay [static] |
int atxfernoanswertimeout [static] |
struct ast_app_option bridge_exec_options[128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, } [static] |
struct ast_call_feature builtin_features[] [static] |
Definition at line 2840 of file features.c.
struct ast_cli_entry cli_features[] [static] |
Initial value:
{
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 7024 of file features.c.
char courtesytone[256] [static] |
Courtesy tone used to pickup parked calls and on-touch-record
Definition at line 598 of file features.c.
Referenced by builtin_automixmonitor(), builtin_automonitor(), parked_call_exec(), and process_config().
struct ast_parkinglot* default_parkinglot [static] |
Default parking lot.
Will not be NULL while running.
Definition at line 591 of file features.c.
struct ast_datastore_info dial_features_info [static] |
Initial value:
{
.type = "dial-features",
.destroy = dial_features_destroy,
.duplicate = dial_features_duplicate,
}
Definition at line 755 of file features.c.
Referenced by add_features_datastores(), builtin_atxfer(), manage_parked_call(), and parked_call_exec().
int featuredigittimeout [static] |
Definition at line 620 of file features.c.
ast_rwlock_t features_lock = { {0} , NULL, 1 } [static] |
Definition at line 2838 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_MUTEX_INITIALIZER , NULL, 1 } [static] |
Ensure that features.conf reloads on one thread at a time.
Definition at line 615 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 594 of file features.c.
Referenced by build_parkinglot(), load_config(), parkinglot_activate_cb(), and parkinglot_is_marked_cb().
struct ast_app* mixmonitor_app = NULL [static] |
int mixmonitor_ok = 1 [static] |
struct ast_app* monitor_app = NULL [static] |
Definition at line 643 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 644 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
struct ast_app_option park_call_options[128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } [static] |
const char* parkcall = "Park" [static] |
Definition at line 641 of file features.c.
Referenced by ast_features_init(), get_parking_exten(), and parkinglot_activate().
const char* parkedcall = "ParkedCall" [static] |
Definition at line 422 of file features.c.
int parkeddynamic = 0 [static] |
Enable creation of parkinglots dynamically
Definition at line 597 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 596 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 612 of file features.c.
Referenced by ast_features_reload(), and manage_parked_call().
pthread_t parking_thread [static] |
struct parkinglot_cfg parkinglot_cfg_default [static] |
Default configuration for normal parking lots.
Definition at line 5372 of file features.c.
struct parkinglot_cfg parkinglot_cfg_default_default [static] |
Default configuration for default parking lot.
Definition at line 5359 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 584 of file features.c.
Referenced by ast_features_init(), build_dialplan_useage_map(), build_parkinglot(), create_dynamic_parkinglot(), do_parking_thread(), find_parkinglot(), handle_feature_show(), handle_parkedcalls(), load_config(), and manager_parking_status().
struct ast_datastore_info pickup_active [static] |
Initial value:
{
.type = "pickup-active",
}
Definition at line 7193 of file features.c.
char pickup_ext[AST_MAX_EXTENSION] [static] |
Call pickup extension
Definition at line 424 of file features.c.
Referenced by analog_canmatch_featurecode(), and canmatch_featurecode().
char pickupfailsound[256] [static] |
Pickup failure sound
Definition at line 602 of file features.c.
Referenced by ast_pickup_call(), and process_config().
char pickupsound[256] [static] |
Pickup sound
Definition at line 601 of file features.c.
Referenced by ast_pickup_call(), and process_config().
char* registrar = "features" [static] |
Registrar for operations
Definition at line 627 of file features.c.
Referenced by ast_features_reload(), manage_parked_call(), park_add_hints(), park_call_full(), parkinglot_activate(), remove_dead_dialplan_useage(), and remove_exten_if_exist().
struct ast_app* stopmixmonitor_app = NULL [static] |
int stopmixmonitor_ok = 1 [static] |
int transferdigittimeout [static] |
Definition at line 619 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and process_config().
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 600 of file features.c.
Referenced by builtin_atxfer(), and process_config().
char xfersound[256] [static] |
Call transfer sound
Definition at line 599 of file features.c.
Referenced by action_bridge(), bridge_exec(), builtin_atxfer(), local_attended_transfer(), and process_config().
1.5.6