Thu Oct 11 06:35:53 2012

Asterisk developer's documentation


features.c File Reference

Routines implementing call features as call pickup, parking and transfer. More...

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

Include dependency graph for features.c:

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  ast_dial_features
struct  ast_park_call_args
struct  ast_parkinglot
 Structure for parking lots which are put in a container. More...
struct  ast_parkinglot::parkinglot_parklist
struct  feature_ds
struct  feature_exten
struct  feature_group
struct  feature_group_exten
struct  feature_groups
struct  feature_list
struct  park_app_args
struct  parkeduser
 Description of one parked call, added to a list while active, then removed. The list belongs to a parkinglot. More...
struct  parking_dp_context
struct  parking_dp_map
struct  parking_dp_ramp
struct  parking_dp_ramp_map
struct  parking_dp_space_map
struct  parking_dp_spaces
struct  parkinglot_cfg

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_ATXFER_CALLBACK_RETRIES   2
#define DEFAULT_ATXFER_DROP_CALL   0
#define DEFAULT_ATXFER_LOOP_DELAY   10000
#define DEFAULT_COMEBACK_CONTEXT   "parkedcallstimeout"
#define DEFAULT_COMEBACK_DIAL_TIME   30
#define DEFAULT_COMEBACK_TO_ORIGIN   1
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000
#define DEFAULT_PARK_EXTENSION   "700"
#define DEFAULT_PARK_TIME   45000
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
#define FEATURES_COUNT   ARRAY_LEN(builtin_features)
#define HFS_FORMAT   "%-25s %-7s %-7s\n"
#define MAX_DIAL_FEATURE_OPTIONS   30

Enumerations

enum  {
  BRIDGE_OPT_PLAYTONE = (1 << 0), OPT_CALLEE_HANGUP = (1 << 1), OPT_CALLER_HANGUP = (1 << 2), OPT_DURATION_LIMIT = (1 << 3),
  OPT_DURATION_STOP = (1 << 4), OPT_CALLEE_TRANSFER = (1 << 5), OPT_CALLER_TRANSFER = (1 << 6), OPT_CALLEE_MONITOR = (1 << 7),
  OPT_CALLER_MONITOR = (1 << 8), OPT_CALLEE_PARK = (1 << 9), OPT_CALLER_PARK = (1 << 10), OPT_CALLEE_KILL = (1 << 11),
  OPT_CALLEE_GO_ON = (1 << 12)
}
enum  { OPT_ARG_DURATION_LIMIT = 0, OPT_ARG_DURATION_STOP, OPT_ARG_CALLEE_GO_ON, OPT_ARG_ARRAY_SIZE }
enum  ast_park_call_options { AST_PARK_OPT_RINGING = (1 << 0), AST_PARK_OPT_RANDOMIZE = (1 << 1), AST_PARK_OPT_SILENCE = (1 << 2) }
enum  feature_interpret_op { FEATURE_INTERPRET_DETECT, FEATURE_INTERPRET_DO, FEATURE_INTERPRET_CHECK }

Functions

static void __fini_feature_groups (void)
static void __fini_feature_list (void)
static void __init_feature_groups (void)
static void __init_feature_list (void)
static int action_bridge (struct mansession *s, const struct message *m)
 Bridge channels together.
static int add_features_datastore (struct ast_channel *chan, const struct ast_flags *my_features, const struct ast_flags *peer_features)
static void add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
 Announce call parking by ADSI.
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 bridge the call and set CDR
int ast_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit)
 parse L option and read associated channel variables to set warning, warning frequency, and timelimit
int ast_can_pickup (struct ast_channel *chan)
 Test if a channel can be picked up.
void ast_channel_log (char *title, struct ast_channel *chan)
int ast_do_pickup (struct ast_channel *chan, struct ast_channel *target)
 Pickup a call target.
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature)
 detect a feature before bridging
int ast_features_init (void)
int ast_features_reload (void)
 Reload call features from features.conf.
struct ast_call_featureast_find_call_feature (const char *name)
 look for a call feature entry by its sname
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_masq_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout)
 Park a call and read back parked location.
int ast_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
 Park a call and read back parked location.
int ast_parking_ext_valid (const char *exten_str, struct ast_channel *chan, const char *context)
 Determine if parking extension exists in a given context.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
const char * ast_pickup_ext (void)
 Determine system call pickup extension.
struct ast_channelast_pickup_find_by_group (struct ast_channel *chan)
 Find a pickup channel target by group.
void ast_rdlock_call_features (void)
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_list
void ast_unlock_call_features (void)
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
 Remove all features in the list.
static void ast_unregister_groups (void)
 Remove all feature groups in the list.
static void atxfer_fail_cleanup (struct ast_channel *transferee, struct ast_channel *transferer, struct ast_party_connected_line *connected_line)
static void * bridge_call_thread (void *data)
 bridge the call
static void bridge_call_thread_launch (struct ast_bridge_thread_obj *data)
 create thread for the parked call
static int bridge_exec (struct ast_channel *chan, const char *data)
 Bridge channels.
static struct parking_dp_contextbuild_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_rampbuild_dialplan_useage_ramp (const char *exten, int exclusive)
static struct parking_dp_spacesbuild_dialplan_useage_spaces (int start, int stop)
static struct ast_parkinglotbuild_parkinglot (const char *pl_name, struct ast_variable *var)
 Build parkinglot from configuration and chain it in if it doesn't already exist.
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 Attended transfer.
static int builtin_automixmonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 Monitor a channel by DTMF.
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 Blind transfer user to another extension.
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
static int builtin_feature_get_exten (struct ast_channel *chan, const char *feature_name, char *buf, size_t len)
static int builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 support routing for one touch call parking
static char * callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
static int check_compat (struct ast_channel *c, struct ast_channel *newchan)
 make channels compatible
static void check_goto_on_transfer (struct ast_channel *chan)
 Check goto on transfer.
static void clear_dialed_interfaces (struct ast_channel *chan)
static struct ast_parkinglotcopy_parkinglot (const char *name, const struct ast_parkinglot *parkinglot)
 Copy parkinglot and store it with new name.
static struct ast_parkinglotcreate_dynamic_parkinglot (const char *name, struct ast_channel *chan)
static struct ast_parkinglotcreate_parkinglot (const char *name)
 Allocate parking lot structure.
static void destroy_dialplan_usage_context (struct parking_dp_context *doomed)
static void destroy_dialplan_usage_map (struct parking_dp_map *doomed)
static void destroy_space (const char *context, int space)
static void dial_features_destroy (void *data)
static void * dial_features_duplicate (void *data)
static int dialplan_usage_add_parkinglot (struct parking_dp_map *usage_map, struct ast_parkinglot *lot, int complain)
static int dialplan_usage_add_parkinglot_data (struct parking_dp_context *ctx_node, struct ast_parkinglot *lot, int complain)
static int do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan)
 Actual bridge.
static void * do_parking_thread (void *ignore)
 Take care of parked calls and unpark them if needed.
static int feature_check (struct ast_channel *chan, struct ast_flags *features, char *code)
 Check if a feature exists.
static void feature_ds_destroy (void *data)
static int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 exec an app by feature
static int feature_exten_cmp (void *obj, void *arg, int flags)
static int feature_exten_hash (const void *obj, int flags)
static int feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense)
 Check the dynamic features.
static int feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, feature_interpret_op operation, struct ast_call_feature *feature)
 Helper function for feature_interpret and ast_feature_detect.
static int feature_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static struct ast_channelfeature_request_and_dial (struct ast_channel *caller, const char *caller_name, struct ast_channel *requestor, struct ast_channel *transferee, const char *type, struct ast_format_cap *cap, const char *addr, int timeout, int *outstate, const char *language)
static int feature_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static int featuremap_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int featuremap_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static void features_shutdown (void)
static int find_channel_by_group (void *obj, void *arg, void *data, int flags)
static struct ast_call_featurefind_dynamic_feature (const char *name)
 find a call feature by name
static struct feature_groupfind_group (const char *name)
 Find a group by name.
static struct ast_parkinglotfind_parkinglot (const char *name)
 Find parkinglot by name.
static const char * findparkinglotname (struct ast_channel *chan)
 Find parking lot name from channel.
static int finishup (struct ast_channel *chan)
static struct feature_dsget_feature_ds (struct ast_channel *chan)
static struct ast_extenget_parking_exten (const char *exten_str, struct ast_channel *chan, const char *context)
static unsigned int get_parkingtime (struct ast_channel *chan, struct ast_parkinglot *parkinglot)
static char * handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list configured features.
static char * handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list parked calls.
static int load_config (int reload)
static int manage_parked_call (struct parkeduser *pu, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
static void manage_parkinglot (struct ast_parkinglot *curlot, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
 Run management on parkinglots, called once per parkinglot.
static int manager_park (struct mansession *s, const struct message *m)
 Create manager event for parked calls.
static int manager_parking_status (struct mansession *s, const struct message *m)
 Dump parking lot status.
static int manager_parkinglot_list (struct mansession *s, const struct message *m)
static int masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
 Park call via masqueraded channel and announce parking spot on peer channel.
static enum ast_device_state metermaidstate (const char *data)
 metermaids callback from devicestate.c
static void notify_metermaids (const char *exten, char *context, enum ast_device_state state)
 Notify metermaids that we've changed an extension.
static void park_add_hints (const char *context, int start, int stop)
 Add parking hints for all defined parking spaces.
static int park_call_exec (struct ast_channel *chan, const char *data)
 Park a call.
static int park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
static void park_space_abort (struct parkeduser *pu)
static struct parkeduserpark_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_parkinglotparkinglot_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_cdrpick_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_groupregister_group (const char *fgname)
 Add new feature group.
static void register_group_feature (struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
 Add feature to group.
static int remap_feature (const char *name, const char *value)
static void remove_dead_context_usage (const char *context, struct parking_dp_context *old_ctx, struct parking_dp_context *new_ctx)
static void remove_dead_dialplan_useage (struct parking_dp_map *old_map, struct parking_dp_map *new_map)
static void remove_dead_ramp_usage (const char *context, struct parking_dp_ramp_map *old_ramps, struct parking_dp_ramp_map *new_ramps)
static void remove_dead_spaces_usage (const char *context, struct parking_dp_space_map *old_spaces, struct parking_dp_space_map *new_spaces, void(*destroy_space)(const char *context, int space))
static void remove_exten_if_exist (const char *context, const char *exten, int priority)
static void set_bridge_features_on_config (struct ast_bridge_config *config, const char *features)
static void set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri)
 store context, extension and priority
static int set_chan_app_data (struct ast_channel *chan, const char *src_app_data)
static void set_config_flags (struct ast_channel *chan, struct ast_bridge_config *config)
static void set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense)
 set caller and callee according to the direction
static void unmap_features (void)
static int usage_context_add_ramp (struct parking_dp_ramp_map *ramp_map, const char *exten, int exclusive, struct ast_parkinglot *lot, int complain)
static int usage_context_add_spaces (struct parking_dp_space_map *space_map, int start, int stop, struct ast_parkinglot *lot, int complain)
static int xfer_park_call_helper (struct ast_channel *park_me, struct ast_channel *parker, struct ast_exten *park_exten)

Variables

static int adsipark
static char * app_bridge = "Bridge"
static unsigned int atxfercallbackretries
static unsigned int atxferdropcall
static unsigned int atxferloopdelay
static int atxfernoanswertimeout
static struct ast_app_option bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'F' ] = { .flag = OPT_CALLEE_GO_ON , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, }
static struct ast_call_feature builtin_features []
static struct ast_datastore_info channel_app_data_datastore
static struct ast_cli_entry cli_features []
static char courtesytone [256]
static struct ast_parkinglotdefault_parkinglot
 Default parking lot.
static struct ast_datastore_info dial_features_info
static struct ast_datastore_info feature_ds_info
static struct ast_custom_function feature_function
static int featuredigittimeout
static struct ast_custom_function featuremap_function
static ast_rwlock_t features_lock = { {0} , NULL, 1 }
static ast_mutex_t features_reload_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static int force_reload_load
static struct ast_appmixmonitor_app = NULL
static int mixmonitor_ok = 1
static struct ast_appmonitor_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_containerparkinglots
 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_appstopmixmonitor_app = NULL
static int stopmixmonitor_ok = 1
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Detailed Description

Routines implementing call features as call pickup, parking and transfer.

Author:
Mark Spencer <markster@digium.com>

Definition in file features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 528 of file features.c.

#define DEFAULT_ATXFER_CALLBACK_RETRIES   2

Definition at line 523 of file features.c.

Referenced by process_config().

#define DEFAULT_ATXFER_DROP_CALL   0

Do not drop call.

Definition at line 521 of file features.c.

Referenced by process_config().

#define DEFAULT_ATXFER_LOOP_DELAY   10000

ms

Definition at line 522 of file features.c.

Referenced by process_config().

#define DEFAULT_COMEBACK_CONTEXT   "parkedcallstimeout"

Definition at line 524 of file features.c.

#define DEFAULT_COMEBACK_DIAL_TIME   30

Definition at line 526 of file features.c.

Referenced by parkinglot_config_read().

#define DEFAULT_COMEBACK_TO_ORIGIN   1

Definition at line 525 of file features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

ms

Definition at line 519 of file features.c.

Referenced by process_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

ms

Definition at line 520 of file features.c.

Referenced by process_config().

#define DEFAULT_PARK_EXTENSION   "700"

Definition at line 517 of file features.c.

#define DEFAULT_PARK_TIME   45000

ms

Definition at line 516 of file features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

ms

Definition at line 518 of file features.c.

Referenced by process_config().

#define FEATURES_COUNT   ARRAY_LEN(builtin_features)

#define HFS_FORMAT   "%-25s %-7s %-7s\n"

Referenced by handle_feature_show().

#define MAX_DIAL_FEATURE_OPTIONS   30

Definition at line 529 of file features.c.

Referenced by manage_parked_call().


Enumeration Type Documentation

anonymous enum

Enumerator:
BRIDGE_OPT_PLAYTONE 
OPT_CALLEE_HANGUP 
OPT_CALLER_HANGUP 
OPT_DURATION_LIMIT 
OPT_DURATION_STOP 
OPT_CALLEE_TRANSFER 
OPT_CALLER_TRANSFER 
OPT_CALLEE_MONITOR 
OPT_CALLER_MONITOR 
OPT_CALLEE_PARK 
OPT_CALLER_PARK 
OPT_CALLEE_KILL 
OPT_CALLEE_GO_ON 

Definition at line 7940 of file features.c.

07940      {
07941    BRIDGE_OPT_PLAYTONE = (1 << 0),
07942    OPT_CALLEE_HANGUP =  (1 << 1),
07943    OPT_CALLER_HANGUP =  (1 << 2),
07944    OPT_DURATION_LIMIT = (1 << 3),
07945    OPT_DURATION_STOP =  (1 << 4),
07946    OPT_CALLEE_TRANSFER = (1 << 5),
07947    OPT_CALLER_TRANSFER = (1 << 6),
07948    OPT_CALLEE_MONITOR = (1 << 7),
07949    OPT_CALLER_MONITOR = (1 << 8),
07950    OPT_CALLEE_PARK = (1 << 9),
07951    OPT_CALLER_PARK = (1 << 10),
07952    OPT_CALLEE_KILL = (1 << 11),
07953    OPT_CALLEE_GO_ON = (1 << 12),
07954 };

anonymous enum

Enumerator:
OPT_ARG_DURATION_LIMIT 
OPT_ARG_DURATION_STOP 
OPT_ARG_CALLEE_GO_ON 
OPT_ARG_ARRAY_SIZE 

Definition at line 7956 of file features.c.

07956      {
07957    OPT_ARG_DURATION_LIMIT = 0,
07958    OPT_ARG_DURATION_STOP,
07959    OPT_ARG_CALLEE_GO_ON,
07960    /* note: this entry _MUST_ be the last one in the enum */
07961    OPT_ARG_ARRAY_SIZE,
07962 };

Options to pass to park_call_full

Enumerator:
AST_PARK_OPT_RINGING  Provide ringing to the parked caller instead of music on hold
AST_PARK_OPT_RANDOMIZE  Randomly choose a parking spot for the caller instead of choosing the first one that is available.
AST_PARK_OPT_SILENCE  Do not announce the parking number

Definition at line 1275 of file features.c.

01275                            {
01276    /*! Provide ringing to the parked caller instead of music on hold */
01277    AST_PARK_OPT_RINGING =   (1 << 0),
01278    /*! Randomly choose a parking spot for the caller instead of choosing
01279     *  the first one that is available. */
01280    AST_PARK_OPT_RANDOMIZE = (1 << 1),
01281    /*! Do not announce the parking number */
01282    AST_PARK_OPT_SILENCE = (1 << 2),
01283 };

Enumerator:
FEATURE_INTERPRET_DETECT 
FEATURE_INTERPRET_DO 
FEATURE_INTERPRET_CHECK 

Definition at line 549 of file features.c.

00549              {
00550    FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */
00551    FEATURE_INTERPRET_DO,     /* Used by feature_interpret */
00552    FEATURE_INTERPRET_CHECK,  /* Used by feature_check */
00553 } feature_interpret_op;


Function Documentation

static void __fini_feature_groups ( void   )  [static]

Definition at line 547 of file features.c.

00549 {

static void __fini_feature_list ( void   )  [static]

Definition at line 3138 of file features.c.

03142 {

static void __init_feature_groups ( void   )  [static]

Definition at line 547 of file features.c.

00549 {

static void __init_feature_list ( void   )  [static]

Definition at line 3138 of file features.c.

03142 {

static int action_bridge ( struct mansession s,
const struct message m 
) [static]

Bridge channels together.

Parameters:
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.
Return values:
0 

Definition at line 7272 of file features.c.

References ast_answer(), ast_calloc, ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_language(), ast_channel_linkedid(), ast_channel_make_compatible(), ast_channel_name(), ast_channel_unref, ast_hangup(), ast_log(), ast_manager_event_multichan, AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), bridge_call_thread_launch(), ast_bridge_thread_obj::chan, do_bridge_masquerade(), errno, EVENT_FLAG_CALL, LOG_WARNING, ast_bridge_thread_obj::peer, playtone(), ast_bridge_thread_obj::return_to_pbx, and xfersound.

Referenced by ast_features_init().

07273 {
07274    const char *channela = astman_get_header(m, "Channel1");
07275    const char *channelb = astman_get_header(m, "Channel2");
07276    const char *playtone = astman_get_header(m, "Tone");
07277    struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
07278    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
07279    struct ast_bridge_thread_obj *tobj = NULL;
07280    char buf[256];
07281 
07282    /* make sure valid channels were specified */
07283    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
07284       astman_send_error(s, m, "Missing channel parameter in request");
07285       return 0;
07286    }
07287 
07288    /* Start with chana */
07289    chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
07290    if (!chana) {
07291       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
07292       astman_send_error(s, m, buf);
07293       return 0;
07294    }
07295 
07296    /* Answer the channels if needed */
07297    if (ast_channel_state(chana) != AST_STATE_UP)
07298       ast_answer(chana);
07299 
07300    /* create the placeholder channels and grab the other channels */
07301    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
07302       NULL, NULL, ast_channel_linkedid(chana), 0, "Bridge/%s", ast_channel_name(chana)))) {
07303       astman_send_error(s, m, "Unable to create temporary channel!");
07304       chana = ast_channel_unref(chana);
07305       return 0;
07306    }
07307 
07308    if (do_bridge_masquerade(chana, tmpchana)) {
07309       snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela);
07310       astman_send_error(s, m, buf);
07311       ast_hangup(tmpchana);
07312       chana = ast_channel_unref(chana);
07313       return 0;
07314    }
07315 
07316    chana = ast_channel_unref(chana);
07317 
07318    /* now do chanb */
07319    chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
07320    if (!chanb) {
07321       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
07322       astman_send_error(s, m, buf);
07323       ast_hangup(tmpchana);
07324       return 0;
07325    }
07326 
07327    /* Answer the channels if needed */
07328    if (ast_channel_state(chanb) != AST_STATE_UP)
07329       ast_answer(chanb);
07330 
07331    /* create the placeholder channels and grab the other channels */
07332    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
07333       NULL, NULL, ast_channel_linkedid(chanb), 0, "Bridge/%s", ast_channel_name(chanb)))) {
07334       astman_send_error(s, m, "Unable to create temporary channels!");
07335       ast_hangup(tmpchana);
07336       chanb = ast_channel_unref(chanb);
07337       return 0;
07338    }
07339 
07340    if (do_bridge_masquerade(chanb, tmpchanb)) {
07341       snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb);
07342       astman_send_error(s, m, buf);
07343       ast_hangup(tmpchana);
07344       ast_hangup(tmpchanb);
07345       chanb = ast_channel_unref(chanb);
07346       return 0;
07347    }
07348 
07349    chanb = ast_channel_unref(chanb);
07350 
07351    /* make the channels compatible, send error if we fail doing so */
07352    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
07353       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb));
07354       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
07355       ast_hangup(tmpchana);
07356       ast_hangup(tmpchanb);
07357       return 0;
07358    }
07359 
07360    /* setup the bridge thread object and start the bridge */
07361    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
07362       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb), strerror(errno));
07363       astman_send_error(s, m, "Unable to spawn a new bridge thread");
07364       ast_hangup(tmpchana);
07365       ast_hangup(tmpchanb);
07366       return 0;
07367    }
07368 
07369    tobj->chan = tmpchana;
07370    tobj->peer = tmpchanb;
07371    tobj->return_to_pbx = 1;
07372 
07373    if (ast_true(playtone)) {
07374       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, ast_channel_language(tmpchanb))) {
07375          if (ast_waitstream(tmpchanb, "") < 0)
07376             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", ast_channel_name(tmpchanb));
07377       }
07378    }
07379 
07380    chans[0] = tmpchana;
07381    chans[1] = tmpchanb;
07382    /*** DOCUMENTATION
07383       <managerEventInstance>
07384          <synopsis>Raised when a bridge is successfully created due to a manager action.</synopsis>
07385          <syntax>
07386             <parameter name="Response">
07387                <enumlist>
07388                   <enum name="Success"/>
07389                   <enum name="Failed"/>
07390                </enumlist>
07391             </parameter>
07392          </syntax>
07393          <see-also>
07394             <ref type="manager">Bridge</ref>
07395          </see-also>
07396       </managerEventInstance>
07397    ***/
07398    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
07399             "Response: Success\r\n"
07400             "Channel1: %s\r\n"
07401             "Channel2: %s\r\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb));
07402 
07403    bridge_call_thread_launch(tobj);
07404 
07405    astman_send_ack(s, m, "Launched bridge thread with success");
07406 
07407    return 0;
07408 }

static int add_features_datastore ( struct ast_channel chan,
const struct ast_flags my_features,
const struct ast_flags peer_features 
) [static]

Definition at line 905 of file features.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_datastore_alloc, ast_datastore_free(), AST_FLAGS_ALL, ast_log(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, LOG_WARNING, ast_dial_features::my_features, and ast_dial_features::peer_features.

Referenced by add_features_datastores(), and builtin_atxfer().

00906 {
00907    struct ast_datastore *datastore;
00908    struct ast_dial_features *dialfeatures;
00909 
00910    ast_channel_lock(chan);
00911    datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL);
00912    ast_channel_unlock(chan);
00913    if (datastore) {
00914       /* Already exists. */
00915       return 1;
00916    }
00917 
00918    /* Create a new datastore with specified feature flags. */
00919    datastore = ast_datastore_alloc(&dial_features_info, NULL);
00920    if (!datastore) {
00921       ast_log(LOG_WARNING, "Unable to create channel features datastore.\n");
00922       return 0;
00923    }
00924    dialfeatures = ast_calloc(1, sizeof(*dialfeatures));
00925    if (!dialfeatures) {
00926       ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n");
00927       ast_datastore_free(datastore);
00928       return 0;
00929    }
00930    ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL);
00931    ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL);
00932    datastore->inheritance = DATASTORE_INHERIT_FOREVER;
00933    datastore->data = dialfeatures;
00934    ast_channel_lock(chan);
00935    ast_channel_datastore_add(chan, datastore);
00936    ast_channel_unlock(chan);
00937    return 0;
00938 }

static void add_features_datastores ( struct ast_channel caller,
struct ast_channel callee,
struct ast_bridge_config config 
) [static]

Definition at line 4208 of file features.c.

References add_features_datastore(), ast_bridge_config::features_callee, and ast_bridge_config::features_caller.

Referenced by ast_bridge_call().

04209 {
04210    if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) {
04211       /*
04212        * If we don't return here, then when we do a builtin_atxfer we
04213        * will copy the disconnect flags over from the atxfer to the
04214        * callee (Party C).
04215        */
04216       return;
04217    }
04218 
04219    add_features_datastore(callee, &config->features_callee, &config->features_caller);
04220 }

static int adsi_announce_park ( struct ast_channel chan,
char *  parkingexten 
) [static]

Announce call parking by ADSI.

Parameters:
chan .
parkingexten . Create message to show for ADSI, display message.
Return values:
0 on success.
-1 on failure.

Definition at line 1213 of file features.c.

References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.

Referenced by park_call_full().

01214 {
01215    int res;
01216    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
01217    char tmp[256];
01218    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
01219 
01220    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
01221    message[0] = tmp;
01222    res = ast_adsi_load_session(chan, NULL, 0, 1);
01223    if (res == -1)
01224       return res;
01225    return ast_adsi_print(chan, message, justify, 1);
01226 }

int ast_bridge_call ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config 
)

bridge the call and set CDR

Bridge a call, optionally allowing redirection.

Parameters:
chan The bridge considers this channel the caller.
peer The bridge considers this channel the callee.
config Configuration for this bridge.
Set start time, check for two channels,check if monitor on check for feature activation, create new CDR
Return values:
res on success.
-1 on failure to bridge.

TRUE if h-exten or hangup handlers run.

append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.

Todo:
XXX how do we guarantee the latter ?

Definition at line 4250 of file features.c.

References ast_cdr::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_cdr::answer, ast_autoservice_start(), ast_autoservice_stop(), AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_copy_vars(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_accountcode(), ast_channel_amaflags(), ast_channel_appl(), ast_channel_bridge(), ast_channel_caller(), ast_channel_cdr(), ast_channel_cdr_set(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_context(), ast_channel_context_set(), ast_channel_data(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_lock_both, ast_channel_log(), ast_channel_macrocontext(), ast_channel_name(), AST_CHANNEL_NAME, ast_channel_priority(), ast_channel_priority_set(), ast_channel_redirecting_macro(), ast_channel_redirecting_sub(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_softhangup_internal_flag(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_uniqueid(), ast_channel_unlock, ast_channel_unref, ast_channel_visible_indication(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_AOC, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_MCID, AST_CONTROL_OPTION, AST_CONTROL_PVT_CAUSE_CODE, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_opt_transmit_silence, AST_OPTION_AUDIO_MODE, AST_OPTION_DIGIT_DETECT, AST_OPTION_FAX_DETECT, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, ast_pbx_h_exten_run(), ast_pbx_hangup_handler_run(), ast_raw_answer(), ast_set_flag, AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_UNBRIDGE, AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_write(), ast_cdr::channel, clear_dialed_interfaces(), ast_option_header::data, ast_frame::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_start_time, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_frame::frametype, ast_frame_subclass::integer, ast_cdr::lastapp, ast_cdr::lastdata, ast_frame::len, LOG_DEBUG, LOG_WARNING, monitor_app, monitor_ok, ast_cdr::next, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_frame::ptr, S_COR, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_frame::subclass, ast_bridge_config::timelimit, ast_cdr::uniqueid, ast_cdr::userfield, and ast_channel::userfield.

Referenced by app_exec(), bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), parked_call_exec(), and try_calling().

04251 {
04252    /* Copy voice back and forth between the two channels.  Give the peer
04253       the ability to transfer calls with '#<extension' syntax. */
04254    struct ast_frame *f;
04255    struct ast_channel *who;
04256    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
04257    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
04258    char orig_channame[AST_CHANNEL_NAME];
04259    char orig_peername[AST_CHANNEL_NAME];
04260    int res;
04261    int diff;
04262    int hasfeatures=0;
04263    int hadfeatures=0;
04264    int sendingdtmfdigit = 0;
04265    int we_disabled_peer_cdr = 0;
04266    struct ast_option_header *aoh;
04267    struct ast_cdr *bridge_cdr = NULL;
04268    struct ast_cdr *chan_cdr = ast_channel_cdr(chan); /* the proper chan cdr, if there are forked cdrs */
04269    struct ast_cdr *peer_cdr = ast_channel_cdr(peer); /* the proper chan cdr, if there are forked cdrs */
04270    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
04271    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
04272    struct ast_silence_generator *silgen = NULL;
04273    /*! TRUE if h-exten or hangup handlers run. */
04274    int hangup_run = 0;
04275 
04276    pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
04277    pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan));
04278 
04279    /* Clear any BLINDTRANSFER since the transfer has completed. */
04280    pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
04281    pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL);
04282 
04283    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
04284    add_features_datastores(chan, peer, config);
04285 
04286    /* This is an interesting case.  One example is if a ringing channel gets redirected to
04287     * an extension that picks up a parked call.  This will make sure that the call taken
04288     * out of parking gets told that the channel it just got bridged to is still ringing. */
04289    if (ast_channel_state(chan) == AST_STATE_RINGING && ast_channel_visible_indication(peer) != AST_CONTROL_RINGING) {
04290       ast_indicate(peer, AST_CONTROL_RINGING);
04291    }
04292 
04293    if (monitor_ok) {
04294       const char *monitor_exec;
04295       struct ast_channel *src = NULL;
04296       if (!monitor_app) {
04297          if (!(monitor_app = pbx_findapp("Monitor")))
04298             monitor_ok=0;
04299       }
04300       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
04301          src = chan;
04302       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
04303          src = peer;
04304       if (monitor_app && src) {
04305          char *tmp = ast_strdupa(monitor_exec);
04306          pbx_exec(src, monitor_app, tmp);
04307       }
04308    }
04309 
04310    set_config_flags(chan, config);
04311 
04312    /* Answer if need be */
04313    if (ast_channel_state(chan) != AST_STATE_UP) {
04314       if (ast_raw_answer(chan, 1)) {
04315          return -1;
04316       }
04317    }
04318 
04319 #ifdef FOR_DEBUG
04320    /* show the two channels and cdrs involved in the bridge for debug & devel purposes */
04321    ast_channel_log("Pre-bridge CHAN Channel info", chan);
04322    ast_channel_log("Pre-bridge PEER Channel info", peer);
04323 #endif
04324    /* two channels are being marked as linked here */
04325    ast_channel_set_linkgroup(chan,peer);
04326 
04327    /* copy the userfield from the B-leg to A-leg if applicable */
04328    if (ast_channel_cdr(chan) && ast_channel_cdr(peer) && !ast_strlen_zero(ast_channel_cdr(peer)->userfield)) {
04329       char tmp[256];
04330 
04331       ast_channel_lock(chan);
04332       if (!ast_strlen_zero(ast_channel_cdr(chan)->userfield)) {
04333          snprintf(tmp, sizeof(tmp), "%s;%s", ast_channel_cdr(chan)->userfield, ast_channel_cdr(peer)->userfield);
04334          ast_cdr_appenduserfield(chan, tmp);
04335       } else {
04336          ast_cdr_setuserfield(chan, ast_channel_cdr(peer)->userfield);
04337       }
04338       ast_channel_unlock(chan);
04339       /* Don't delete the CDR; just disable it. */
04340       ast_set_flag(ast_channel_cdr(peer), AST_CDR_FLAG_POST_DISABLED);
04341       we_disabled_peer_cdr = 1;
04342    }
04343    ast_copy_string(orig_channame,ast_channel_name(chan),sizeof(orig_channame));
04344    ast_copy_string(orig_peername,ast_channel_name(peer),sizeof(orig_peername));
04345 
04346    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
04347       ast_channel_lock_both(chan, peer);
04348       if (chan_cdr) {
04349          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
04350          ast_cdr_update(chan);
04351          bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
04352          /* rip any forked CDR's off of the chan_cdr and attach
04353           * them to the bridge_cdr instead */
04354          bridge_cdr->next = chan_cdr->next;
04355          chan_cdr->next = NULL;
04356          ast_copy_string(bridge_cdr->lastapp, S_OR(ast_channel_appl(chan), ""), sizeof(bridge_cdr->lastapp));
04357          ast_copy_string(bridge_cdr->lastdata, S_OR(ast_channel_data(chan), ""), sizeof(bridge_cdr->lastdata));
04358          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
04359             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
04360          }
04361          ast_cdr_setaccount(peer, ast_channel_accountcode(chan));
04362       } else {
04363          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
04364          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
04365          ast_copy_string(bridge_cdr->channel, ast_channel_name(chan), sizeof(bridge_cdr->channel));
04366          ast_copy_string(bridge_cdr->dstchannel, ast_channel_name(peer), sizeof(bridge_cdr->dstchannel));
04367          ast_copy_string(bridge_cdr->uniqueid, ast_channel_uniqueid(chan), sizeof(bridge_cdr->uniqueid));
04368          ast_copy_string(bridge_cdr->lastapp, S_OR(ast_channel_appl(chan), ""), sizeof(bridge_cdr->lastapp));
04369          ast_copy_string(bridge_cdr->lastdata, S_OR(ast_channel_data(chan), ""), sizeof(bridge_cdr->lastdata));
04370          ast_cdr_setcid(bridge_cdr, chan);
04371          bridge_cdr->disposition = (ast_channel_state(chan) == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
04372          bridge_cdr->amaflags = ast_channel_amaflags(chan) ? ast_channel_amaflags(chan) :  ast_default_amaflags;
04373          ast_copy_string(bridge_cdr->accountcode, ast_channel_accountcode(chan), sizeof(bridge_cdr->accountcode));
04374          /* Destination information */
04375          ast_copy_string(bridge_cdr->dst, ast_channel_exten(chan), sizeof(bridge_cdr->dst));
04376          ast_copy_string(bridge_cdr->dcontext, ast_channel_context(chan), sizeof(bridge_cdr->dcontext));
04377          if (peer_cdr) {
04378             bridge_cdr->start = peer_cdr->start;
04379             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
04380          } else {
04381             ast_cdr_start(bridge_cdr);
04382          }
04383       }
04384       ast_channel_unlock(chan);
04385       ast_channel_unlock(peer);
04386 
04387       ast_debug(4, "bridge answer set, chan answer set\n");
04388       /* peer_cdr->answer will be set when a macro runs on the peer;
04389          in that case, the bridge answer will be delayed while the
04390          macro plays on the peer channel. The peer answered the call
04391          before the macro started playing. To the phone system,
04392          this is billable time for the call, even tho the caller
04393          hears nothing but ringing while the macro does its thing. */
04394 
04395       /* Another case where the peer cdr's time will be set, is when
04396          A self-parks by pickup up phone and dialing 700, then B
04397          picks up A by dialing its parking slot; there may be more
04398          practical paths that get the same result, tho... in which
04399          case you get the previous answer time from the Park... which
04400          is before the bridge's start time, so I added in the
04401          tvcmp check to the if below */
04402 
04403       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
04404          ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
04405          ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
04406          if (chan_cdr) {
04407             ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
04408             ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
04409          }
04410       } else {
04411          ast_cdr_answer(bridge_cdr);
04412          if (chan_cdr) {
04413             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
04414          }
04415       }
04416       if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
04417          if (chan_cdr) {
04418             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
04419          }
04420          if (peer_cdr) {
04421             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
04422          }
04423       }
04424       /* the DIALED flag may be set if a dialed channel is transfered
04425        * and then bridged to another channel.  In order for the
04426        * bridge CDR to be written, the DIALED flag must not be
04427        * present. */
04428       ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
04429    }
04430    ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer);
04431 
04432    /* If we are bridging a call, stop worrying about forwarding loops. We presume that if
04433     * a call is being bridged, that the humans in charge know what they're doing. If they
04434     * don't, well, what can we do about that? */
04435    clear_dialed_interfaces(chan);
04436    clear_dialed_interfaces(peer);
04437 
04438    for (;;) {
04439       struct ast_channel *other; /* used later */
04440 
04441       res = ast_channel_bridge(chan, peer, config, &f, &who);
04442 
04443       if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
04444          || ast_test_flag(ast_channel_flags(peer), AST_FLAG_ZOMBIE)) {
04445          /* Zombies are present time to leave! */
04446          res = -1;
04447          if (f) {
04448             ast_frfree(f);
04449          }
04450          goto before_you_go;
04451       }
04452 
04453       /* When frame is not set, we are probably involved in a situation
04454          where we've timed out.
04455          When frame is set, we'll come this code twice; once for DTMF_BEGIN
04456          and also for DTMF_END. If we flow into the following 'if' for both, then
04457          our wait times are cut in half, as both will subtract from the
04458          feature_timer. Not good!
04459       */
04460       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
04461          /* Update feature timer for next pass */
04462          diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
04463          if (res == AST_BRIDGE_RETRY) {
04464             /* The feature fully timed out but has not been updated. Skip
04465              * the potential round error from the diff calculation and
04466              * explicitly set to expired. */
04467             config->feature_timer = -1;
04468          } else {
04469             config->feature_timer -= diff;
04470          }
04471 
04472          if (hasfeatures) {
04473             if (config->feature_timer <= 0) {
04474                /* Not *really* out of time, just out of time for
04475                   digits to come in for features. */
04476                ast_debug(1, "Timed out for feature!\n");
04477                if (!ast_strlen_zero(peer_featurecode)) {
04478                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, f ? f->len : 0);
04479                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
04480                }
04481                if (!ast_strlen_zero(chan_featurecode)) {
04482                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, f ? f->len : 0);
04483                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
04484                }
04485                if (f)
04486                   ast_frfree(f);
04487                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
04488                if (!hasfeatures) {
04489                   /* No more digits expected - reset the timer */
04490                   config->feature_timer = 0;
04491                }
04492                hadfeatures = hasfeatures;
04493                /* Continue as we were */
04494                continue;
04495             } else if (!f) {
04496                /* The bridge returned without a frame and there is a feature in progress.
04497                 * However, we don't think the feature has quite yet timed out, so just
04498                 * go back into the bridge. */
04499                continue;
04500             }
04501          } else {
04502             if (config->feature_timer <=0) {
04503                /* We ran out of time */
04504                config->feature_timer = 0;
04505                who = chan;
04506                if (f)
04507                   ast_frfree(f);
04508                f = NULL;
04509                res = 0;
04510             }
04511          }
04512       }
04513       if (res < 0) {
04514          if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) && !ast_test_flag(ast_channel_flags(peer), AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
04515             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", ast_channel_name(chan), ast_channel_name(peer));
04516          }
04517          goto before_you_go;
04518       }
04519 
04520       if (!f || (f->frametype == AST_FRAME_CONTROL &&
04521             (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
04522                f->subclass.integer == AST_CONTROL_CONGESTION))) {
04523          /*
04524           * If the bridge was broken for a hangup that isn't real,
04525           * then don't run the h extension, because the channel isn't
04526           * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO,
04527           * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either.
04528           */
04529          ast_channel_lock(chan);
04530          if (ast_channel_softhangup_internal_flag(chan) & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) {
04531             ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT);
04532          }
04533          ast_channel_unlock(chan);
04534          res = -1;
04535          break;
04536       }
04537       /* many things should be sent to the 'other' channel */
04538       other = (who == chan) ? peer : chan;
04539       if (f->frametype == AST_FRAME_CONTROL) {
04540          switch (f->subclass.integer) {
04541          case AST_CONTROL_RINGING:
04542          case AST_CONTROL_FLASH:
04543          case AST_CONTROL_MCID:
04544          case -1:
04545             ast_indicate(other, f->subclass.integer);
04546             break;
04547          case AST_CONTROL_CONNECTED_LINE:
04548             if (ast_channel_connected_line_sub(who, other, f, 1) &&
04549                ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
04550                ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04551             }
04552             break;
04553          case AST_CONTROL_REDIRECTING:
04554             if (ast_channel_redirecting_sub(who, other, f, 1) &&
04555                ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
04556                ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04557             }
04558             break;
04559          case AST_CONTROL_PVT_CAUSE_CODE:
04560          case AST_CONTROL_AOC:
04561          case AST_CONTROL_HOLD:
04562          case AST_CONTROL_UNHOLD:
04563             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04564             break;
04565          case AST_CONTROL_OPTION:
04566             aoh = f->data.ptr;
04567             /* Forward option Requests, but only ones we know are safe
04568              * These are ONLY sent by chan_iax2 and I'm not convinced that
04569              * they are useful. I haven't deleted them entirely because I
04570              * just am not sure of the ramifications of removing them. */
04571             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
04572                switch (ntohs(aoh->option)) {
04573                case AST_OPTION_TONE_VERIFY:
04574                case AST_OPTION_TDD:
04575                case AST_OPTION_RELAXDTMF:
04576                case AST_OPTION_AUDIO_MODE:
04577                case AST_OPTION_DIGIT_DETECT:
04578                case AST_OPTION_FAX_DETECT:
04579                   ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
04580                      f->datalen - sizeof(struct ast_option_header), 0);
04581                }
04582             }
04583             break;
04584          }
04585       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
04586          struct ast_flags *cfg;
04587          char dtmfcode[2] = { f->subclass.integer, };
04588          size_t featurelen;
04589 
04590          if (who == chan) {
04591             featurelen = strlen(chan_featurecode);
04592             cfg = &(config->features_caller);
04593          } else {
04594             featurelen = strlen(peer_featurecode);
04595             cfg = &(config->features_callee);
04596          }
04597          /* Take a peek if this (possibly) matches a feature. If not, just pass this
04598           * DTMF along untouched. If this is not the first digit of a multi-digit code
04599           * then we need to fall through and stream the characters if it matches */
04600          if (featurelen == 0
04601             && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) {
04602             if (option_debug > 3) {
04603                ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n");
04604             }
04605             ast_write(other, f);
04606             sendingdtmfdigit = 1;
04607          } else {
04608             /* If ast_opt_transmit_silence is set, then we need to make sure we are
04609              * transmitting something while we hold on to the DTMF waiting for a
04610              * feature. */
04611             if (!silgen && ast_opt_transmit_silence) {
04612                silgen = ast_channel_start_silence_generator(other);
04613             }
04614             if (option_debug > 3) {
04615                ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n");
04616             }
04617          }
04618       } else if (f->frametype == AST_FRAME_DTMF_END) {
04619          char *featurecode;
04620          int sense;
04621          unsigned int dtmfduration = f->len;
04622 
04623          hadfeatures = hasfeatures;
04624          /* This cannot overrun because the longest feature is one shorter than our buffer */
04625          if (who == chan) {
04626             sense = FEATURE_SENSE_CHAN;
04627             featurecode = chan_featurecode;
04628          } else  {
04629             sense = FEATURE_SENSE_PEER;
04630             featurecode = peer_featurecode;
04631          }
04632 
04633          if (sendingdtmfdigit == 1) {
04634             /* We let the BEGIN go through happily, so let's not bother with the END,
04635              * since we already know it's not something we bother with */
04636             ast_write(other, f);
04637             sendingdtmfdigit = 0;
04638          } else {
04639             /*! append the event to featurecode. we rely on the string being zero-filled, and
04640              * not overflowing it.
04641              * \todo XXX how do we guarantee the latter ?
04642              */
04643             featurecode[strlen(featurecode)] = f->subclass.integer;
04644             /* Get rid of the frame before we start doing "stuff" with the channels */
04645             ast_frfree(f);
04646             f = NULL;
04647             if (silgen) {
04648                ast_channel_stop_silence_generator(other, silgen);
04649                silgen = NULL;
04650             }
04651             config->feature_timer = 0;
04652             res = feature_interpret(chan, peer, config, featurecode, sense);
04653             switch(res) {
04654             case AST_FEATURE_RETURN_PASSDIGITS:
04655                ast_dtmf_stream(other, who, featurecode, 0, dtmfduration);
04656                /* Fall through */
04657             case AST_FEATURE_RETURN_SUCCESS:
04658                memset(featurecode, 0, sizeof(chan_featurecode));
04659                break;
04660             }
04661             if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
04662                res = 0;
04663             } else {
04664                break;
04665             }
04666             hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
04667             if (hadfeatures && !hasfeatures) {
04668                /* Feature completed or timed out */
04669                config->feature_timer = 0;
04670             } else if (hasfeatures) {
04671                if (config->timelimit) {
04672                   /* No warning next time - we are waiting for feature code */
04673                   ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
04674                }
04675                config->feature_start_time = ast_tvnow();
04676                config->feature_timer = featuredigittimeout;
04677                ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
04678             }
04679          }
04680       }
04681       if (f)
04682          ast_frfree(f);
04683    }
04684    ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer);
04685 
04686 before_you_go:
04687    /* Just in case something weird happened and we didn't clean up the silence generator... */
04688    if (silgen) {
04689       ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen);
04690       silgen = NULL;
04691    }
04692 
04693    if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT)) {
04694       ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
04695       if (bridge_cdr) {
04696          ast_cdr_discard(bridge_cdr);
04697          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
04698       }
04699       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
04700    }
04701 
04702    if (config->end_bridge_callback) {
04703       config->end_bridge_callback(config->end_bridge_callback_data);
04704    }
04705 
04706    if (!ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
04707       struct ast_cdr *swapper = NULL;
04708       char savelastapp[AST_MAX_EXTENSION];
04709       char savelastdata[AST_MAX_EXTENSION];
04710       char save_context[AST_MAX_CONTEXT];
04711       char save_exten[AST_MAX_EXTENSION];
04712       int  save_prio;
04713 
04714       ast_channel_lock(chan);
04715       if (bridge_cdr) {
04716          /*
04717           * Swap the bridge_cdr and the chan cdr for a moment, and let
04718           * the hangup dialplan code operate on it.
04719           */
04720          swapper = ast_channel_cdr(chan);
04721          ast_channel_cdr_set(chan, bridge_cdr);
04722 
04723          /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
04724          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
04725          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
04726       }
04727       ast_copy_string(save_context, ast_channel_context(chan), sizeof(save_context));
04728       ast_copy_string(save_exten, ast_channel_exten(chan), sizeof(save_exten));
04729       save_prio = ast_channel_priority(chan);
04730       ast_channel_unlock(chan);
04731 
04732       ast_autoservice_start(peer);
04733       if (ast_exists_extension(chan, ast_channel_context(chan), "h", 1,
04734          S_COR(ast_channel_caller(chan)->id.number.valid,
04735             ast_channel_caller(chan)->id.number.str, NULL))) {
04736          ast_pbx_h_exten_run(chan, ast_channel_context(chan));
04737          hangup_run = 1;
04738       } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
04739          && ast_exists_extension(chan, ast_channel_macrocontext(chan), "h", 1,
04740             S_COR(ast_channel_caller(chan)->id.number.valid,
04741                ast_channel_caller(chan)->id.number.str, NULL))) {
04742          ast_pbx_h_exten_run(chan, ast_channel_macrocontext(chan));
04743          hangup_run = 1;
04744       }
04745       if (ast_pbx_hangup_handler_run(chan)) {
04746          /* Indicate hangup handlers were run. */
04747          hangup_run = 1;
04748       }
04749       ast_autoservice_stop(peer);
04750 
04751       ast_channel_lock(chan);
04752 
04753       /* swap it back */
04754       ast_channel_context_set(chan, save_context);
04755       ast_channel_exten_set(chan, save_exten);
04756       ast_channel_priority_set(chan, save_prio);
04757       if (bridge_cdr) {
04758          if (ast_channel_cdr(chan) == bridge_cdr) {
04759             ast_channel_cdr_set(chan, swapper);
04760 
04761             /* Restore the lastapp/lastdata */
04762             ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
04763             ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
04764          } else {
04765             bridge_cdr = NULL;
04766          }
04767       }
04768       ast_channel_unlock(chan);
04769    }
04770 
04771    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
04772    new_chan_cdr = pick_unlocked_cdr(ast_channel_cdr(chan)); /* the proper chan cdr, if there are forked cdrs */
04773 
04774    /*
04775     * If the channel CDR has been modified during the call, record
04776     * the changes in the bridge cdr, BUT, if hangup_run, the CDR
04777     * got swapped so don't overwrite what was done in the
04778     * h-extension or hangup handlers.  What a mess.  This is why
04779     * you never touch CDR code.
04780     */
04781    if (new_chan_cdr && bridge_cdr && !hangup_run) {
04782       ast_cdr_copy_vars(bridge_cdr, new_chan_cdr);
04783       ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield));
04784       bridge_cdr->amaflags = new_chan_cdr->amaflags;
04785       ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode));
04786       if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
04787          ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
04788       }
04789    }
04790 
04791    /* we can post the bridge CDR at this point */
04792    if (bridge_cdr) {
04793       ast_cdr_end(bridge_cdr);
04794       ast_cdr_detach(bridge_cdr);
04795    }
04796 
04797    /* do a specialized reset on the beginning channel
04798       CDR's, if they still exist, so as not to mess up
04799       issues in future bridges;
04800 
04801       Here are the rules of the game:
04802       1. The chan and peer channel pointers will not change
04803          during the life of the bridge.
04804       2. But, in transfers, the channel names will change.
04805          between the time the bridge is started, and the
04806          time the channel ends.
04807          Usually, when a channel changes names, it will
04808          also change CDR pointers.
04809       3. Usually, only one of the two channels (chan or peer)
04810          will change names.
04811       4. Usually, if a channel changes names during a bridge,
04812          it is because of a transfer. Usually, in these situations,
04813          it is normal to see 2 bridges running simultaneously, and
04814          it is not unusual to see the two channels that change
04815          swapped between bridges.
04816       5. After a bridge occurs, we have 2 or 3 channels' CDRs
04817          to attend to; if the chan or peer changed names,
04818          we have the before and after attached CDR's.
04819    */
04820 
04821    if (new_chan_cdr) {
04822       struct ast_channel *chan_ptr = NULL;
04823 
04824       if (strcasecmp(orig_channame, ast_channel_name(chan)) != 0) {
04825          /* old channel */
04826          if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
04827             ast_channel_lock(chan_ptr);
04828             if (!ast_bridged_channel(chan_ptr)) {
04829                struct ast_cdr *cur;
04830                for (cur = ast_channel_cdr(chan_ptr); cur; cur = cur->next) {
04831                   if (cur == chan_cdr) {
04832                      break;
04833                   }
04834                }
04835                if (cur) {
04836                   ast_cdr_specialized_reset(chan_cdr, 0);
04837                }
04838             }
04839             ast_channel_unlock(chan_ptr);
04840             chan_ptr = ast_channel_unref(chan_ptr);
04841          }
04842          /* new channel */
04843          ast_cdr_specialized_reset(new_chan_cdr, 0);
04844       } else {
04845          ast_cdr_specialized_reset(ast_channel_cdr(chan), 0); /* nothing changed, reset the chan cdr  */
04846       }
04847    }
04848 
04849    {
04850       struct ast_channel *chan_ptr = NULL;
04851       new_peer_cdr = pick_unlocked_cdr(ast_channel_cdr(peer)); /* the proper chan cdr, if there are forked cdrs */
04852       if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED))
04853          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
04854       if (strcasecmp(orig_peername, ast_channel_name(peer)) != 0) {
04855          /* old channel */
04856          if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
04857             ast_channel_lock(chan_ptr);
04858             if (!ast_bridged_channel(chan_ptr)) {
04859                struct ast_cdr *cur;
04860                for (cur = ast_channel_cdr(chan_ptr); cur; cur = cur->next) {
04861                   if (cur == peer_cdr) {
04862                      break;
04863                   }
04864                }
04865                if (cur) {
04866                   ast_cdr_specialized_reset(peer_cdr, 0);
04867                }
04868             }
04869             ast_channel_unlock(chan_ptr);
04870             chan_ptr = ast_channel_unref(chan_ptr);
04871          }
04872          /* new channel */
04873          if (new_peer_cdr) {
04874             ast_cdr_specialized_reset(new_peer_cdr, 0);
04875          }
04876       } else {
04877          if (we_disabled_peer_cdr) {
04878             ast_clear_flag(ast_channel_cdr(peer), AST_CDR_FLAG_POST_DISABLED);
04879          }
04880          ast_cdr_specialized_reset(ast_channel_cdr(peer), 0); /* nothing changed, reset the peer cdr  */
04881       }
04882    }
04883 
04884    return res;
04885 }

int ast_bridge_timelimit ( struct ast_channel chan,
struct ast_bridge_config config,
char *  parse,
struct timeval *  calldurationlimit 
)

parse L option and read associated channel variables to set warning, warning frequency, and timelimit

Note:
caller must be aware of freeing memory for warning_sound, end_sound, and start_sound

Definition at line 7980 of file features.c.

References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, ast_bridge_config::end_sound, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, pbx_builtin_getvar_helper(), ast_bridge_config::play_warning, S_OR, ast_bridge_config::start_sound, strsep(), ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by bridge_exec(), and dial_exec_full().

07982 {
07983    char *stringp = ast_strdupa(parse);
07984    char *limit_str, *warning_str, *warnfreq_str;
07985    const char *var;
07986    int play_to_caller = 0, play_to_callee = 0;
07987    int delta;
07988 
07989    limit_str = strsep(&stringp, ":");
07990    warning_str = strsep(&stringp, ":");
07991    warnfreq_str = strsep(&stringp, ":");
07992 
07993    config->timelimit = atol(limit_str);
07994    if (warning_str)
07995       config->play_warning = atol(warning_str);
07996    if (warnfreq_str)
07997       config->warning_freq = atol(warnfreq_str);
07998 
07999    if (!config->timelimit) {
08000       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
08001       config->timelimit = config->play_warning = config->warning_freq = 0;
08002       config->warning_sound = NULL;
08003       return -1; /* error */
08004    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
08005       int w = config->warning_freq;
08006 
08007       /*
08008        * If the first warning is requested _after_ the entire call
08009        * would end, and no warning frequency is requested, then turn
08010        * off the warning. If a warning frequency is requested, reduce
08011        * the 'first warning' time by that frequency until it falls
08012        * within the call's total time limit.
08013        *
08014        * Graphically:
08015        *                timelim->|    delta        |<-playwarning
08016        *      0__________________|_________________|
08017        *                       | w  |    |    |    |
08018        *
08019        * so the number of intervals to cut is 1+(delta-1)/w
08020        */
08021       if (w == 0) {
08022          config->play_warning = 0;
08023       } else {
08024          config->play_warning -= w * ( 1 + (delta-1)/w );
08025          if (config->play_warning < 1)
08026             config->play_warning = config->warning_freq = 0;
08027       }
08028    }
08029 
08030    ast_channel_lock(chan);
08031 
08032    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
08033    play_to_caller = var ? ast_true(var) : 1;
08034 
08035    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
08036    play_to_callee = var ? ast_true(var) : 0;
08037 
08038    if (!play_to_caller && !play_to_callee)
08039       play_to_caller = 1;
08040 
08041    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
08042    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
08043 
08044    /* The code looking at config wants a NULL, not just "", to decide
08045     * that the message should not be played, so we replace "" with NULL.
08046     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
08047     * not found.
08048     */
08049 
08050    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
08051    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
08052 
08053    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
08054    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
08055 
08056    ast_channel_unlock(chan);
08057 
08058    /* undo effect of S(x) in case they are both used */
08059    calldurationlimit->tv_sec = 0;
08060    calldurationlimit->tv_usec = 0;
08061 
08062    /* more efficient to do it like S(x) does since no advanced opts */
08063    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
08064       calldurationlimit->tv_sec = config->timelimit / 1000;
08065       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
08066       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
08067          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
08068       config->timelimit = play_to_caller = play_to_callee =
08069       config->play_warning = config->warning_freq = 0;
08070    } else {
08071       ast_verb(4, "Limit Data for this call:\n");
08072       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
08073       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
08074       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
08075       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
08076       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
08077       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
08078       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
08079       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
08080    }
08081    if (play_to_caller)
08082       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
08083    if (play_to_callee)
08084       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
08085    return 0;
08086 }

int ast_can_pickup ( struct ast_channel chan  ) 

Test if a channel can be picked up.

Parameters:
chan Channel to test if can be picked up.
Note:
This function assumes that chan is locked.
Returns:
TRUE if channel can be picked up.

Definition at line 7688 of file features.c.

References ast_channel_datastore_find(), ast_channel_flags(), ast_channel_masq(), ast_channel_pbx(), AST_FLAG_ZOMBIE, AST_STATE_DOWN, AST_STATE_RING, AST_STATE_RINGING, and ast_test_flag.

Referenced by ast_pickup_find_by_group(), find_by_mark(), find_by_part(), find_channel_by_group(), pickup_by_exten(), and pickup_by_name_cb().

07689 {
07690    if (!ast_channel_pbx(chan) && !ast_channel_masq(chan) && !ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
07691       && (ast_channel_state(chan) == AST_STATE_RINGING
07692          || ast_channel_state(chan) == AST_STATE_RING
07693          /*
07694           * Check the down state as well because some SIP devices do not
07695           * give 180 ringing when they can just give 183 session progress
07696           * instead.  Issue 14005.  (Some ISDN switches as well for that
07697           * matter.)
07698           */
07699          || ast_channel_state(chan) == AST_STATE_DOWN)
07700       && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07701       return 1;
07702    }
07703    return 0;
07704 }

void ast_channel_log ( char *  title,
struct ast_channel chan 
)

Definition at line 4141 of file features.c.

References ast_channel_accountcode(), ast_channel_amaflags(), ast_channel_appl(), ast_channel_cdr(), ast_channel_context(), ast_channel_data(), ast_channel_dialcontext(), ast_channel_exten(), ast_channel_internal_bridged_channel(), ast_channel_linkedid(), ast_channel_macrocontext(), ast_channel_macroexten(), ast_channel_macropriority(), ast_channel_masq(), ast_channel_masqr(), ast_channel_name(), ast_channel_priority(), ast_channel_uniqueid(), ast_log(), and LOG_NOTICE.

Referenced by ast_bridge_call().

04142 {
04143    ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long) chan);
04144    ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
04145       ast_channel_name(chan), ast_channel_appl(chan), ast_channel_data(chan), ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
04146    ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
04147       ast_channel_accountcode(chan), ast_channel_dialcontext(chan), ast_channel_amaflags(chan), ast_channel_macrocontext(chan), ast_channel_macroexten(chan), ast_channel_macropriority(chan));
04148    ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
04149       ast_channel_masq(chan), ast_channel_masqr(chan),
04150       ast_channel_internal_bridged_channel(chan), ast_channel_uniqueid(chan), ast_channel_linkedid(chan));
04151    if (ast_channel_masqr(chan)) {
04152       ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
04153          ast_channel_name(ast_channel_masqr(chan)), ast_channel_cdr(ast_channel_masqr(chan)));
04154    }
04155    if (ast_channel_internal_bridged_channel(chan)) {
04156       ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", ast_channel_name(ast_channel_internal_bridged_channel(chan)));
04157    }
04158 
04159    ast_log(LOG_NOTICE, "===== done ====\n");
04160 }

int ast_do_pickup ( struct ast_channel chan,
struct ast_channel target 
)

Pickup a call target.

Parameters:
chan channel that initiated pickup.
target channel to be picked up.
Note:
This function assumes that target is locked.
Return values:
0 on success.
-1 on failure.

< A masquerade changes channel names.

< A masquerade changes channel names.

Definition at line 7846 of file features.c.

References ast_answer(), AST_CAUSE_ANSWERED_ELSEWHERE, AST_CEL_PICKUP, ast_cel_report_event(), ast_channel_caller(), ast_channel_connected(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_datastore_add(), ast_channel_datastore_remove(), ast_channel_hangupcause_set(), ast_channel_lock, ast_channel_masquerade(), ast_channel_name(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_datastore_alloc, ast_datastore_free(), ast_debug, ast_do_masquerade(), ast_log(), ast_manager_event_multichan, ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_party_id_reset(), ast_queue_control(), ast_strdupa, EVENT_FLAG_CALL, LOG_WARNING, ast_party_connected_line::priv, and ast_party_connected_line::source.

Referenced by ast_pickup_call(), pickup_by_channel(), pickup_by_exten(), pickup_by_group(), pickup_by_mark(), and pickup_by_part().

07847 {
07848    struct ast_party_connected_line connected_caller;
07849    struct ast_channel *chans[2] = { chan, target };
07850    struct ast_datastore *ds_pickup;
07851    const char *chan_name;/*!< A masquerade changes channel names. */
07852    const char *target_name;/*!< A masquerade changes channel names. */
07853    int res = -1;
07854 
07855    target_name = ast_strdupa(ast_channel_name(target));
07856    ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));
07857 
07858    /* Mark the target to block any call pickup race. */
07859    ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07860    if (!ds_pickup) {
07861       ast_log(LOG_WARNING,
07862          "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07863       return -1;
07864    }
07865    ast_channel_datastore_add(target, ds_pickup);
07866 
07867    ast_party_connected_line_init(&connected_caller);
07868    ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target));
07869    ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
07870    /* Reset any earlier private connected id representation */
07871    ast_party_id_reset(&connected_caller.priv);
07872 
07873    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07874    if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) &&
07875       ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07876       ast_channel_update_connected_line(chan, &connected_caller, NULL);
07877    }
07878    ast_party_connected_line_free(&connected_caller);
07879 
07880    ast_channel_lock(chan);
07881    chan_name = ast_strdupa(ast_channel_name(chan));
07882    ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan));
07883    ast_channel_unlock(chan);
07884    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07885 
07886    ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07887 
07888    if (ast_answer(chan)) {
07889       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07890       goto pickup_failed;
07891    }
07892 
07893    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07894       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07895       goto pickup_failed;
07896    }
07897 
07898    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07899 
07900    /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
07901    ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);
07902 
07903    if (ast_channel_masquerade(target, chan)) {
07904       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07905          target_name);
07906       goto pickup_failed;
07907    }
07908 
07909    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
07910    /*** DOCUMENTATION
07911       <managerEventInstance>
07912          <synopsis>Raised when a call pickup occurs.</synopsis>
07913          <syntax>
07914             <parameter name="Channel"><para>The name of the channel that initiated the pickup.</para></parameter>
07915             <parameter name="TargetChannel"><para>The name of the channel that is being picked up.</para></parameter>
07916          </syntax>
07917       </managerEventInstance>
07918    ***/
07919    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07920       "Channel: %s\r\n"
07921       "TargetChannel: %s\r\n",
07922       chan_name, target_name);
07923 
07924    /* Do the masquerade manually to make sure that it is completed. */
07925    ast_do_masquerade(target);
07926    res = 0;
07927 
07928 pickup_failed:
07929    ast_channel_lock(target);
07930    if (!ast_channel_datastore_remove(target, ds_pickup)) {
07931       ast_datastore_free(ds_pickup);
07932    }
07933    ast_party_connected_line_free(&connected_caller);
07934 
07935    return res;
07936 }

int ast_feature_detect ( struct ast_channel chan,
struct ast_flags features,
const char *  code,
struct ast_call_feature feature 
)

detect a feature before bridging

Parameters:
chan 
features an ast_flags ptr
code ptr of input code
feature 
Return values:
ast_call_feature ptr to be set if found

Definition at line 3725 of file features.c.

References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

03725                                                                                                                                  {
03726 
03727    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03728 }

int ast_features_init ( void   ) 

Provided by features.c

Definition at line 8978 of file features.c.

References __ast_custom_function_register(), action_bridge(), ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register_xml_core, ast_pthread_create, ast_register_application2(), ast_register_atexit(), AST_TEST_REGISTER, bridge_exec(), do_parking_thread(), EVENT_FLAG_CALL, features_shutdown(), load_config(), manager_park(), manager_parking_status(), manager_parkinglot_list(), metermaidstate(), park_call_exec(), parkcall, parked_call_exec(), parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), and parkinglots.

Referenced by main().

08979 {
08980    int res;
08981 
08982    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
08983    if (!parkinglots) {
08984       return -1;
08985    }
08986 
08987    res = load_config(0);
08988    if (res) {
08989       return res;
08990    }
08991    ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
08992    if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) {
08993       return -1;
08994    }
08995    ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
08996    res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL);
08997    if (!res)
08998       res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
08999    if (!res) {
09000       ast_manager_register_xml_core("ParkedCalls", 0, manager_parking_status);
09001       ast_manager_register_xml_core("Parkinglots", 0, manager_parkinglot_list);
09002       ast_manager_register_xml_core("Park", EVENT_FLAG_CALL, manager_park);
09003       ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge);
09004    }
09005    res |= __ast_custom_function_register(&feature_function, NULL);
09006    res |= __ast_custom_function_register(&featuremap_function, NULL);
09007 
09008    res |= ast_devstate_prov_add("Park", metermaidstate);
09009 #if defined(TEST_FRAMEWORK)
09010    res |= AST_TEST_REGISTER(features_test);
09011 #endif   /* defined(TEST_FRAMEWORK) */
09012 
09013    ast_register_atexit(features_shutdown);
09014 
09015    return res;
09016 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 7176 of file features.c.

References ast_context_destroy(), ast_context_find(), ast_mutex_lock, ast_mutex_unlock, features_reload_lock, load_config(), parking_con_dial, and registrar.

Referenced by handle_features_reload().

07177 {
07178    struct ast_context *con;
07179    int res;
07180 
07181    ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
07182 
07183    /*
07184     * Always destroy the parking_con_dial context to remove buildup
07185     * of recalled extensions in the context.  At worst, the parked
07186     * call gets hungup attempting to run an invalid extension when
07187     * we are trying to callback the parker or the preset return
07188     * extension.  This is a small window of opportunity on an
07189     * execution chain that is not expected to happen very often.
07190     */
07191    con = ast_context_find(parking_con_dial);
07192    if (con) {
07193       ast_context_destroy(con, registrar);
07194    }
07195 
07196    res = load_config(1);
07197    ast_mutex_unlock(&features_reload_lock);
07198 
07199    return res;
07200 }

struct ast_call_feature* ast_find_call_feature ( const char *  name  )  [read]

look for a call feature entry by its sname

Parameters:
name a string ptr, should match "automon", "blindxfer", "atxfer", etc.

Definition at line 3311 of file features.c.

References FEATURES_COUNT, find_dynamic_feature(), and ast_call_feature::sname.

Referenced by action_atxfer(), builtin_feature_get_exten(), featuremap_write(), handle_request_info(), and process_config().

03312 {
03313    int x;
03314    for (x = 0; x < FEATURES_COUNT; x++) {
03315       if (!strcasecmp(name, builtin_features[x].sname))
03316          return &builtin_features[x];
03317    }
03318 
03319    return find_dynamic_feature(name);
03320 }

int ast_masq_park_call ( struct ast_channel park_me,
struct ast_channel parker,
int  timeout,
int *  extout 
)

Park a call via a masqueraded channel.

Parameters:
park_me Channel to be parked.
parker Channel parking the call.
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.
Masquerade the park_me channel into a new, empty channel which is then parked.

Note:
Use ast_masq_park_call_exten() instead.
Return values:
0 on success.
-1 on failure.

Definition at line 2023 of file features.c.

References ast_channel_name(), ast_strdupa, masq_park_call(), ast_park_call_args::orig_chan_name, and ast_park_call_args::timeout.

Referenced by handle_soft_key_event_message(), handle_stimulus_message(), and parkandannounce_exec().

02024 {
02025    struct ast_park_call_args args = {
02026       .timeout = timeout,
02027       .extout = extout,
02028    };
02029 
02030    if (peer) {
02031       args.orig_chan_name = ast_strdupa(ast_channel_name(peer));
02032    }
02033    return masq_park_call(rchan, peer, &args);
02034 }

int ast_masq_park_call_exten ( struct ast_channel park_me,
struct ast_channel parker,
const char *  park_exten,
const char *  park_context,
int  timeout,
int *  extout 
)

Park a call via a masqueraded channel.

Since:
1.8.9
Parameters:
park_me Channel to be parked.
parker Channel parking the call.
park_exten Parking lot access extension
park_context Parking lot context
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.
Masquerade the park_me channel into a new, empty channel which is then parked.

Return values:
0 on success.
-1 on failure.

Definition at line 1969 of file features.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), find_parkinglot(), get_parking_exten(), masq_park_call(), ast_park_call_args::orig_chan_name, parkeddynamic, ast_park_call_args::parkinglot, parkinglot_unref(), parse(), park_app_args::pl_name, and ast_park_call_args::timeout.

Referenced by __analog_ss_thread(), analog_ss_thread(), and mgcp_ss().

01970 {
01971    int res;
01972    char *parse;
01973    const char *app_data;
01974    struct ast_exten *exten;
01975    struct park_app_args app_args;
01976    struct ast_park_call_args args = {
01977       .timeout = timeout,
01978       .extout = extout,
01979    };
01980 
01981    if (parker) {
01982       args.orig_chan_name = ast_strdupa(ast_channel_name(parker));
01983    }
01984    if (!park_exten || !park_context) {
01985       return masq_park_call(park_me, parker, &args);
01986    }
01987 
01988    /*
01989     * Determiine if the specified park extension has an exclusive
01990     * parking lot to use.
01991     */
01992    if (parker && parker != park_me) {
01993       ast_autoservice_start(park_me);
01994    }
01995    exten = get_parking_exten(park_exten, parker, park_context);
01996    if (exten) {
01997       app_data = ast_get_extension_app_data(exten);
01998       if (!app_data) {
01999          app_data = "";
02000       }
02001       parse = ast_strdupa(app_data);
02002       AST_STANDARD_APP_ARGS(app_args, parse);
02003 
02004       if (!ast_strlen_zero(app_args.pl_name)) {
02005          /* Find the specified exclusive parking lot */
02006          args.parkinglot = find_parkinglot(app_args.pl_name);
02007          if (!args.parkinglot && parkeddynamic) {
02008             args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
02009          }
02010       }
02011    }
02012    if (parker && parker != park_me) {
02013       ast_autoservice_stop(park_me);
02014    }
02015 
02016    res = masq_park_call(park_me, parker, &args);
02017    if (args.parkinglot) {
02018       parkinglot_unref(args.parkinglot);
02019    }
02020    return res;
02021 }

int ast_park_call ( struct ast_channel park_me,
struct ast_channel parker,
int  timeout,
const char *  park_exten,
int *  extout 
)

Park a call and read back parked location.

Parameters:
park_me Channel to be parked.
parker Channel parking the call.
timeout is a timeout in milliseconds
park_exten Parking lot access extension (Not used)
extout is a parameter to an int that will hold the parked location, or NULL if you want.
Park the park_me channel, and read back the parked location to the parker channel. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context).

Note:
Use ast_park_call_exten() instead.
Return values:
0 on success.
-1 on failure.

Definition at line 1872 of file features.c.

References park_call_full(), and ast_park_call_args::timeout.

01873 {
01874    struct ast_park_call_args args = {
01875       .timeout = timeout,
01876       .extout = extout,
01877    };
01878 
01879    return park_call_full(park_me, parker, &args);
01880 }

int ast_park_call_exten ( struct ast_channel park_me,
struct ast_channel parker,
const char *  park_exten,
const char *  park_context,
int  timeout,
int *  extout 
)

Park a call and read back parked location.

Since:
1.8.9
Parameters:
park_me Channel to be parked.
parker Channel parking the call.
park_exten Parking lot access extension
park_context Parking lot context
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.
Park the park_me channel, and read back the parked location to the parker channel. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context).

Return values:
0 on success.
-1 on failure.

Definition at line 1821 of file features.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), find_parkinglot(), get_parking_exten(), park_call_full(), parkeddynamic, ast_park_call_args::parkinglot, parkinglot_unref(), parse(), park_app_args::pl_name, and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

01822 {
01823    int res;
01824    char *parse;
01825    const char *app_data;
01826    struct ast_exten *exten;
01827    struct park_app_args app_args;
01828    struct ast_park_call_args args = {
01829       .timeout = timeout,
01830       .extout = extout,
01831    };
01832 
01833    if (!park_exten || !park_context) {
01834       return park_call_full(park_me, parker, &args);
01835    }
01836 
01837    /*
01838     * Determiine if the specified park extension has an exclusive
01839     * parking lot to use.
01840     */
01841    if (parker && parker != park_me) {
01842       ast_autoservice_start(park_me);
01843    }
01844    exten = get_parking_exten(park_exten, parker, park_context);
01845    if (exten) {
01846       app_data = ast_get_extension_app_data(exten);
01847       if (!app_data) {
01848          app_data = "";
01849       }
01850       parse = ast_strdupa(app_data);
01851       AST_STANDARD_APP_ARGS(app_args, parse);
01852 
01853       if (!ast_strlen_zero(app_args.pl_name)) {
01854          /* Find the specified exclusive parking lot */
01855          args.parkinglot = find_parkinglot(app_args.pl_name);
01856          if (!args.parkinglot && parkeddynamic) {
01857             args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
01858          }
01859       }
01860    }
01861    if (parker && parker != park_me) {
01862       ast_autoservice_stop(park_me);
01863    }
01864 
01865    res = park_call_full(park_me, parker, &args);
01866    if (args.parkinglot) {
01867       parkinglot_unref(args.parkinglot);
01868    }
01869    return res;
01870 }

int ast_parking_ext_valid ( const char *  exten_str,
struct ast_channel chan,
const char *  context 
)

Determine if parking extension exists in a given context.

Return values:
0 if extension does not exist
1 if extension does exist

Definition at line 981 of file features.c.

References get_parking_exten().

Referenced by __analog_ss_thread(), analog_ss_thread(), dp_lookup(), handle_request_refer(), mgcp_ss(), and socket_process_helper().

00982 {
00983    return get_parking_exten(exten_str, chan, context) ? 1 : 0;
00984 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Parameters:
chan channel that initiated pickup.
Walk list of channels, checking it is not itself, channel is pbx one, check that the callgroup for both channels are the same and the channel is ringing. Answer calling channel, flag channel as answered on queue, masq channels together.

< Potential pickup target

Definition at line 7811 of file features.c.

References ast_answer(), ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_debug, ast_do_pickup(), ast_log(), ast_pickup_find_by_group(), ast_stream_and_wait(), ast_strlen_zero(), LOG_NOTICE, LOG_WARNING, pbx_builtin_setvar_helper(), pickupfailsound, and pickupsound.

Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), handle_call_outgoing(), mgcp_ss(), and sip_pickup_thread().

07812 {
07813    struct ast_channel *target;/*!< Potential pickup target */
07814    int res = -1;
07815 
07816    ast_debug(1, "pickup attempt by %s\n", ast_channel_name(chan));
07817 
07818    /* The found channel is already locked. */
07819    target = ast_pickup_find_by_group(chan);
07820    if (target) {
07821       ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan));
07822 
07823       res = ast_do_pickup(chan, target);
07824       ast_channel_unlock(target);
07825       if (!res) {
07826          if (!ast_strlen_zero(pickupsound)) {
07827             pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07828          }
07829       } else {
07830          ast_log(LOG_WARNING, "pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan));
07831       }
07832       target = ast_channel_unref(target);
07833    }
07834 
07835    if (res < 0) {
07836       ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan));
07837       if (!ast_strlen_zero(pickupfailsound)) {
07838          ast_answer(chan);
07839          ast_stream_and_wait(chan, pickupfailsound, "");
07840       }
07841    }
07842 
07843    return res;
07844 }

const char* ast_pickup_ext ( void   ) 

struct ast_channel* ast_pickup_find_by_group ( struct ast_channel chan  )  [read]

Find a pickup channel target by group.

Parameters:
chan channel that initiated pickup.
Return values:
target on success. The returned channel is locked and reffed.
NULL on error.

< Candidate channels found to pickup.

< Potential pickup target

< Potential new older target

Definition at line 7744 of file features.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_container_alloc_options, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, ast_can_pickup(), ast_channel_callback(), ast_channel_creationtime(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_tvcmp(), and find_channel_by_group().

Referenced by ast_pickup_call(), and pickup_by_group().

07745 {
07746    struct ao2_container *candidates;/*!< Candidate channels found to pickup. */
07747    struct ast_channel *target;/*!< Potential pickup target */
07748 
07749    candidates = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
07750    if (!candidates) {
07751       return NULL;
07752    }
07753 
07754    /* Find all candidate targets by group. */
07755    ast_channel_callback(find_channel_by_group, chan, candidates, 0);
07756 
07757    /* Find the oldest pickup target candidate */
07758    target = NULL;
07759    for (;;) {
07760       struct ast_channel *candidate;/*!< Potential new older target */
07761       struct ao2_iterator iter;
07762 
07763       iter = ao2_iterator_init(candidates, 0);
07764       while ((candidate = ao2_iterator_next(&iter))) {
07765          if (!target) {
07766             /* First target. */
07767             target = candidate;
07768             continue;
07769          }
07770          if (ast_tvcmp(ast_channel_creationtime(candidate), ast_channel_creationtime(target)) < 0) {
07771             /* We have a new target. */
07772             ast_channel_unref(target);
07773             target = candidate;
07774             continue;
07775          }
07776          ast_channel_unref(candidate);
07777       }
07778       ao2_iterator_destroy(&iter);
07779       if (!target) {
07780          /* No candidates found. */
07781          break;
07782       }
07783 
07784       /* The found channel must be locked and ref'd. */
07785       ast_channel_lock(target);
07786 
07787       /* Recheck pickup ability */
07788       if (ast_can_pickup(target)) {
07789          /* This is the channel to pickup. */
07790          break;
07791       }
07792 
07793       /* Someone else picked it up or the call went away. */
07794       ast_channel_unlock(target);
07795       ao2_unlink(candidates, target);
07796       target = ast_channel_unref(target);
07797    }
07798    ao2_ref(candidates, -1);
07799 
07800    return target;
07801 }

void ast_rdlock_call_features ( void   ) 

Definition at line 3297 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by builtin_feature_get_exten(), featuremap_read(), and handle_request_info().

03298 {
03299    ast_rwlock_rdlock(&features_lock);
03300 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_list

register new feature into feature_set

Definition at line 3141 of file features.c.

References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.

Referenced by process_applicationmap_line().

03142 {
03143    if (!feature) {
03144       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
03145       return;
03146    }
03147 
03148    AST_RWLIST_WRLOCK(&feature_list);
03149    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
03150    AST_RWLIST_UNLOCK(&feature_list);
03151 
03152    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
03153 }

void ast_unlock_call_features ( void   ) 

Definition at line 3302 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by builtin_feature_get_exten(), featuremap_read(), and handle_request_info().

03303 {
03304    ast_rwlock_unlock(&features_lock);
03305 }

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 3221 of file features.c.

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

03222 {
03223    if (!feature) {
03224       return;
03225    }
03226 
03227    AST_RWLIST_WRLOCK(&feature_list);
03228    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
03229    AST_RWLIST_UNLOCK(&feature_list);
03230 
03231    ast_free(feature);
03232 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 3235 of file features.c.

References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_call_feature::feature_entry.

Referenced by process_config().

03236 {
03237    struct ast_call_feature *feature;
03238 
03239    AST_RWLIST_WRLOCK(&feature_list);
03240    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
03241       ast_free(feature);
03242    }
03243    AST_RWLIST_UNLOCK(&feature_list);
03244 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

Definition at line 3261 of file features.c.

References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, and feature_group::features.

Referenced by process_config().

03262 {
03263    struct feature_group *fg;
03264    struct feature_group_exten *fge;
03265 
03266    AST_RWLIST_WRLOCK(&feature_groups);
03267    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
03268       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
03269          ast_string_field_free_memory(fge);
03270          ast_free(fge);
03271       }
03272 
03273       ast_string_field_free_memory(fg);
03274       ast_free(fg);
03275    }
03276    AST_RWLIST_UNLOCK(&feature_groups);
03277 }

static void atxfer_fail_cleanup ( struct ast_channel transferee,
struct ast_channel transferer,
struct ast_party_connected_line connected_line 
) [static]

Definition at line 2640 of file features.c.

References ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_update_connected_line(), ast_party_connected_line_free(), and finishup().

Referenced by builtin_atxfer().

02641 {
02642    finishup(transferee);
02643 
02644    /*
02645     * Restore party B connected line info about party A.
02646     *
02647     * Party B was the caller to party C and is the last known mode
02648     * for party B.
02649     */
02650    if (ast_channel_connected_line_sub(transferee, transferer, connected_line, 0) &&
02651       ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
02652       ast_channel_update_connected_line(transferer, connected_line, NULL);
02653    }
02654    ast_party_connected_line_free(connected_line);
02655 }

static void* bridge_call_thread ( void *  data  )  [static]

bridge the call

Parameters:
data thread bridge.
Set Last Data for respective channels, reset cdr for channels bridge call, check if we're going back to dialplan if not hangup both legs of the call

Definition at line 1125 of file features.c.

References ast_autoservice_chan_hangup_peer(), ast_bridge_call(), ast_callid_threadassoc_add(), ast_callid_unref, ast_channel_appl_set(), ast_channel_data_set(), ast_channel_name(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::callid, ast_bridge_thread_obj::chan, LOG_VERBOSE, LOG_WARNING, ast_bridge_thread_obj::peer, ast_bridge_thread_obj::return_to_pbx, and set_chan_app_data().

Referenced by bridge_call_thread_launch().

01126 {
01127    struct ast_bridge_thread_obj *tobj = data;
01128 
01129    if (tobj->callid) {
01130       ast_callid_threadassoc_add(tobj->callid);
01131       /* Need to deref and set to null since ast_bridge_thread_obj has no common destructor */
01132       tobj->callid = ast_callid_unref(tobj->callid);
01133    }
01134 
01135    ast_channel_appl_set(tobj->chan, !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge");
01136    if (set_chan_app_data(tobj->chan, ast_channel_name(tobj->peer))) {
01137       ast_channel_data_set(tobj->chan, "(Empty)");
01138    }
01139    ast_channel_appl_set(tobj->peer, !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge");
01140    if (set_chan_app_data(tobj->peer, ast_channel_name(tobj->chan))) {
01141       ast_channel_data_set(tobj->peer, "(Empty)");
01142    }
01143 
01144    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
01145 
01146    if (tobj->return_to_pbx) {
01147       if (!ast_check_hangup(tobj->peer)) {
01148          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", ast_channel_name(tobj->peer));
01149          if (ast_pbx_start(tobj->peer)) {
01150             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", ast_channel_name(tobj->peer));
01151             ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer);
01152          }
01153       } else {
01154          ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer);
01155       }
01156       if (!ast_check_hangup(tobj->chan)) {
01157          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", ast_channel_name(tobj->chan));
01158          if (ast_pbx_start(tobj->chan)) {
01159             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", ast_channel_name(tobj->chan));
01160             ast_hangup(tobj->chan);
01161          }
01162       } else {
01163          ast_hangup(tobj->chan);
01164       }
01165    } else {
01166       ast_hangup(tobj->chan);
01167       ast_hangup(tobj->peer);
01168    }
01169 
01170    ast_free(tobj);
01171 
01172    return NULL;
01173 }

static void bridge_call_thread_launch ( struct ast_bridge_thread_obj data  )  [static]

create thread for the parked call

Parameters:
data Create thread and attributes, call bridge_call_thread

Definition at line 1181 of file features.c.

References ast_callid_unref, ast_hangup(), ast_log(), ast_pthread_create, ast_read_threadstorage_callid(), bridge_call_thread(), ast_bridge_thread_obj::callid, ast_bridge_thread_obj::chan, LOG_ERROR, ast_bridge_thread_obj::peer, and thread.

Referenced by action_bridge(), and builtin_atxfer().

01182 {
01183    pthread_t thread;
01184    pthread_attr_t attr;
01185    struct sched_param sched;
01186 
01187    /* This needs to be unreffed once it has been associated with the new thread. */
01188    data->callid = ast_read_threadstorage_callid();
01189 
01190    pthread_attr_init(&attr);
01191    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01192    if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) {
01193       /* Failed to create thread. Ditch the reference to callid. */
01194       ast_callid_unref(data->callid);
01195       ast_hangup(data->chan);
01196       ast_hangup(data->peer);
01197       ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n");
01198       return;
01199    }
01200    pthread_attr_destroy(&attr);
01201    memset(&sched, 0, sizeof(sched));
01202    pthread_setschedparam(thread, SCHED_RR, &sched);
01203 }

static int bridge_exec ( struct ast_channel chan,
const char *  data 
) [static]

Bridge channels.

Parameters:
chan 
data channel to bridge with.
Split data, check we aren't bridging with ourself, check valid channel, answer call if not already, check compatible channels, setup bridge config now bridge call, if transfered party hangs up return to PBX extension.

Definition at line 8098 of file features.c.

References args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_autoservice_chan_hangup_peer(), ast_bridge_call(), ast_bridge_timelimit(), ast_channel_alloc, ast_channel_context(), ast_channel_exten(), ast_channel_flags(), ast_channel_get_by_name_prefix(), ast_channel_language(), ast_channel_linkedid(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_name(), ast_channel_priority(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAG_BRIDGE_HANGUP_DONT, ast_free, ast_goto_if_exists(), ast_hangup(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_parseable_goto(), ast_pbx_start(), ast_replace_subargument_delimiter(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, do_bridge_masquerade(), ast_bridge_config::end_sound, EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_CALLEE_GO_ON, OPT_ARG_DURATION_LIMIT, OPT_CALLEE_GO_ON, OPT_CALLEE_HANGUP, OPT_CALLEE_KILL, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DURATION_LIMIT, pbx_builtin_setvar_helper(), ast_bridge_config::start_sound, ast_bridge_config::warning_sound, and xfersound.

Referenced by ast_features_init().

08099 {
08100    struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
08101    char *tmp_data  = NULL;
08102    struct ast_flags opts = { 0, };
08103    struct ast_bridge_config bconfig = { { 0, }, };
08104    char *opt_args[OPT_ARG_ARRAY_SIZE];
08105    struct timeval calldurationlimit = { 0, };
08106 
08107    AST_DECLARE_APP_ARGS(args,
08108       AST_APP_ARG(dest_chan);
08109       AST_APP_ARG(options);
08110    );
08111 
08112    if (ast_strlen_zero(data)) {
08113       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
08114       return -1;
08115    }
08116 
08117    tmp_data = ast_strdupa(data);
08118    AST_STANDARD_APP_ARGS(args, tmp_data);
08119    if (!ast_strlen_zero(args.options))
08120       ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
08121 
08122    /* avoid bridge with ourselves */
08123    if (!strcmp(ast_channel_name(chan), args.dest_chan)) {
08124       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", ast_channel_name(chan));
08125       /*** DOCUMENTATION
08126          <managerEventInstance>
08127             <synopsis>Raised when an error occurs during bridge creation.</synopsis>
08128             <see-also>
08129                <ref type="application">Bridge</ref>
08130             </see-also>
08131          </managerEventInstance>
08132       ***/
08133       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
08134          "Response: Failed\r\n"
08135          "Reason: Unable to bridge channel to itself\r\n"
08136          "Channel1: %s\r\n"
08137          "Channel2: %s\r\n",
08138          ast_channel_name(chan), args.dest_chan);
08139       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
08140       return 0;
08141    }
08142 
08143    /* make sure we have a valid end point */
08144    if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
08145          strlen(args.dest_chan)))) {
08146       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
08147          args.dest_chan);
08148       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
08149          "Response: Failed\r\n"
08150          "Reason: Channel2 does not exist\r\n"
08151          "Channel1: %s\r\n"
08152          "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
08153       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
08154       return 0;
08155    }
08156 
08157    /* try to allocate a place holder where current_dest_chan will be placed */
08158    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
08159       NULL, NULL, ast_channel_linkedid(current_dest_chan), 0, "Bridge/%s", ast_channel_name(current_dest_chan)))) {
08160       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
08161       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
08162          "Response: Failed\r\n"
08163          "Reason: Cannot create placeholder channel\r\n"
08164          "Channel1: %s\r\n"
08165          "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
08166       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
08167       ast_channel_unref(current_dest_chan);
08168       return 0;
08169    }
08170 
08171    if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
08172       && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
08173       && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
08174       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
08175          "Response: Failed\r\n"
08176          "Reason: Cannot setup bridge time limit\r\n"
08177          "Channel1: %s\r\n"
08178          "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
08179       ast_hangup(final_dest_chan);
08180       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
08181       current_dest_chan = ast_channel_unref(current_dest_chan);
08182       goto done;
08183    }
08184 
08185    if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) {
08186       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
08187          "Response: Failed\r\n"
08188          "Reason: Cannot masquerade channels\r\n"
08189          "Channel1: %s\r\n"
08190          "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
08191       ast_hangup(final_dest_chan);
08192       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
08193       current_dest_chan = ast_channel_unref(current_dest_chan);
08194       goto done;
08195    }
08196 
08197    /* answer the channel if needed */
08198    if (ast_channel_state(final_dest_chan) != AST_STATE_UP) {
08199       ast_answer(final_dest_chan);
08200    }
08201 
08202    chans[0] = current_dest_chan;
08203    chans[1] = final_dest_chan;
08204 
08205    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
08206    /* try to make compatible, send error if we fail */
08207    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
08208       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
08209       ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
08210          "Response: Failed\r\n"
08211          "Reason: Could not make channels compatible for bridge\r\n"
08212          "Channel1: %s\r\n"
08213          "Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
08214 
08215       /* Maybe we should return this channel to the PBX? */
08216       ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
08217 
08218       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
08219       current_dest_chan = ast_channel_unref(current_dest_chan);
08220       goto done;
08221    }
08222 
08223    /* Report that the bridge will be successfull */
08224    /*** DOCUMENTATION
08225       <managerEventInstance>
08226          <synopsis>Raised when the bridge is created successfully.</synopsis>
08227          <see-also>
08228             <ref type="application">Bridge</ref>
08229          </see-also>
08230       </managerEventInstance>
08231    ***/
08232    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
08233       "Response: Success\r\n"
08234       "Channel1: %s\r\n"
08235       "Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
08236 
08237    current_dest_chan = ast_channel_unref(current_dest_chan);
08238 
08239    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */
08240    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
08241       if (!ast_streamfile(final_dest_chan, xfersound, ast_channel_language(final_dest_chan))) {
08242          if (ast_waitstream(final_dest_chan, "") < 0)
08243             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", ast_channel_name(final_dest_chan));
08244       }
08245    }
08246 
08247    if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
08248       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
08249    if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
08250       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
08251    if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
08252       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
08253    if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
08254       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
08255    if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
08256       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
08257    if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
08258       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
08259    if (ast_test_flag(&opts, OPT_CALLEE_PARK))
08260       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
08261    if (ast_test_flag(&opts, OPT_CALLER_PARK))
08262       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
08263 
08264    /*
08265     * Don't let the after-bridge code run the h-exten.  We want to
08266     * continue in the dialplan.
08267     */
08268    ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT);
08269    ast_bridge_call(chan, final_dest_chan, &bconfig);
08270 
08271    /* The bridge has ended, set BRIDGERESULT to SUCCESS. */
08272    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
08273 
08274    /* If the other channel has not been hung up, return it to the PBX */
08275    if (!ast_check_hangup(final_dest_chan)) {
08276       if (ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
08277          char *caller_context;
08278          char *caller_extension;
08279          int caller_priority;
08280          int goto_opt;
08281 
08282          ast_channel_lock(chan);
08283          caller_context = ast_strdupa(ast_channel_context(chan));
08284          caller_extension = ast_strdupa(ast_channel_exten(chan));
08285          caller_priority = ast_channel_priority(chan);
08286          ast_channel_unlock(chan);
08287 
08288          if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
08289             ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
08290             /* Set current dialplan position to bridger dialplan position */
08291             goto_opt = ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority)
08292                /* Then perform the goto */
08293                || ast_parseable_goto(final_dest_chan, opt_args[OPT_ARG_CALLEE_GO_ON]);
08294          } else { /* F() */
08295             goto_opt = ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority + 1);
08296          }
08297          if (goto_opt || ast_pbx_start(final_dest_chan)) {
08298             ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
08299          }
08300       } else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
08301          ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
08302             ast_channel_context(final_dest_chan), ast_channel_exten(final_dest_chan),
08303             ast_channel_priority(final_dest_chan), ast_channel_name(final_dest_chan));
08304 
08305          if (ast_pbx_start(final_dest_chan)) {
08306             ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", ast_channel_name(final_dest_chan));
08307             ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
08308          } else {
08309             ast_debug(1, "SUCCESS continuing PBX on chan %s\n", ast_channel_name(final_dest_chan));
08310          }
08311       } else {
08312          ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
08313       }
08314    } else {
08315       ast_debug(1, "chan %s was hungup\n", ast_channel_name(final_dest_chan));
08316       ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
08317    }
08318 done:
08319    ast_free((char *) bconfig.warning_sound);
08320    ast_free((char *) bconfig.end_sound);
08321    ast_free((char *) bconfig.start_sound);
08322 
08323    return 0;
08324 }

static struct parking_dp_context* build_dialplan_useage_context ( struct ast_parkinglot lot  )  [static, read]

Definition at line 6614 of file features.c.

References ast_calloc, ast_parkinglot::cfg, parking_dp_context::context, destroy_dialplan_usage_context(), dialplan_usage_add_parkinglot_data(), and parkinglot_cfg::parking_con.

Referenced by dialplan_usage_add_parkinglot().

06615 {
06616    struct parking_dp_context *ctx_node;
06617 
06618    ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con));
06619    if (!ctx_node) {
06620       return NULL;
06621    }
06622    if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) {
06623       destroy_dialplan_usage_context(ctx_node);
06624       return NULL;
06625    }
06626    strcpy(ctx_node->context, lot->cfg.parking_con);
06627    return ctx_node;
06628 }

static int build_dialplan_useage_map ( struct parking_dp_map usage_map,
int  complain 
) [static]

Definition at line 6686 of file features.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, dialplan_usage_add_parkinglot(), parkinglots, and status.

Referenced by load_config().

06687 {
06688    int status = 0;
06689    struct ao2_iterator iter;
06690    struct ast_parkinglot *curlot;
06691 
06692    /* For all parking lots */
06693    iter = ao2_iterator_init(parkinglots, 0);
06694    for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) {
06695       /* Add the parking lot to the map. */
06696       if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) {
06697          ao2_ref(curlot, -1);
06698          status = -1;
06699          break;
06700       }
06701    }
06702    ao2_iterator_destroy(&iter);
06703 
06704    return status;
06705 }

static struct parking_dp_ramp* build_dialplan_useage_ramp ( const char *  exten,
int  exclusive 
) [static, read]

Definition at line 6377 of file features.c.

References ast_calloc, parking_dp_ramp::exclusive, and parking_dp_ramp::exten.

Referenced by usage_context_add_ramp().

06378 {
06379    struct parking_dp_ramp *ramp_node;
06380 
06381    ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten));
06382    if (!ramp_node) {
06383       return NULL;
06384    }
06385    ramp_node->exclusive = exclusive;
06386    strcpy(ramp_node->exten, exten);
06387    return ramp_node;
06388 }

static struct parking_dp_spaces* build_dialplan_useage_spaces ( int  start,
int  stop 
) [static, read]

Definition at line 6458 of file features.c.

References ast_calloc, parking_dp_spaces::start, and parking_dp_spaces::stop.

Referenced by usage_context_add_spaces().

06459 {
06460    struct parking_dp_spaces *spaces_node;
06461 
06462    spaces_node = ast_calloc(1, sizeof(*spaces_node));
06463    if (!spaces_node) {
06464       return NULL;
06465    }
06466    spaces_node->start = start;
06467    spaces_node->stop = stop;
06468    return spaces_node;
06469 }

static struct ast_parkinglot* build_parkinglot ( const char *  pl_name,
struct ast_variable var 
) [static, read]

Build parkinglot from configuration and chain it in if it doesn't already exist.

Definition at line 5982 of file features.c.

References ao2_link, ao2_lock, ao2_unlock, ast_debug, AST_LIST_EMPTY, ast_log(), ast_parkinglot::cfg, create_parkinglot(), DEFAULT_PARKINGLOT, find_parkinglot(), force_reload_load, LOG_WARNING, ast_parkinglot::name, parkinglot_config_read(), parkinglot_unref(), parkinglots, ast_parkinglot::parkings, and ast_parkinglot::the_mark.

Referenced by load_config(), and process_config().

05983 {
05984    struct ast_parkinglot *parkinglot;
05985    const struct parkinglot_cfg *cfg_defaults;
05986    struct parkinglot_cfg new_cfg;
05987    int cfg_error;
05988    int oldparkinglot = 0;
05989 
05990    parkinglot = find_parkinglot(pl_name);
05991    if (parkinglot) {
05992       oldparkinglot = 1;
05993    } else {
05994       parkinglot = create_parkinglot(pl_name);
05995       if (!parkinglot) {
05996          return NULL;
05997       }
05998    }
05999    if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) {
06000       cfg_defaults = &parkinglot_cfg_default_default;
06001    } else {
06002       cfg_defaults = &parkinglot_cfg_default;
06003    }
06004    new_cfg = *cfg_defaults;
06005 
06006    ast_debug(1, "Building parking lot %s\n", parkinglot->name);
06007 
06008    ao2_lock(parkinglot);
06009 
06010    /* Do some config stuff */
06011    cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var);
06012    if (oldparkinglot) {
06013       if (cfg_error) {
06014          /* Bad configuration read.  Keep using the original config. */
06015          ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n",
06016             parkinglot->name);
06017          cfg_error = 0;
06018       } else if (!AST_LIST_EMPTY(&parkinglot->parkings)
06019          && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) {
06020          /* Try reloading later when parking lot is empty. */
06021          ast_log(LOG_WARNING,
06022             "Parking lot %s has parked calls.  Parking lot changes discarded.\n",
06023             parkinglot->name);
06024          force_reload_load = 1;
06025       } else {
06026          /* Accept the new config */
06027          parkinglot->cfg = new_cfg;
06028       }
06029    } else {
06030       /* Load the initial parking lot config. */
06031       parkinglot->cfg = new_cfg;
06032    }
06033    parkinglot->the_mark = 0;
06034 
06035    ao2_unlock(parkinglot);
06036 
06037    if (cfg_error) {
06038       /* Only new parking lots could have config errors here. */
06039       ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name);
06040       parkinglot_unref(parkinglot);
06041       return NULL;
06042    }
06043 
06044    /* Move it into the list, if it wasn't already there */
06045    if (!oldparkinglot) {
06046       ao2_link(parkinglots, parkinglot);
06047    }
06048    parkinglot_unref(parkinglot);
06049 
06050    return parkinglot;
06051 }

static int builtin_atxfer ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
void *  data 
) [static]

Attended transfer.

Parameters:
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.
Returns:
-1 on failure

Definition at line 2672 of file features.c.

References add_features_datastore(), ast_app_dtget(), ast_autoservice_chan_hangup_peer(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_calloc, AST_CEL_ATTENDEDTRANSFER, ast_cel_report_event(), ast_channel_alloc, ast_channel_caller(), ast_channel_connected(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_context(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_flags(), ast_channel_language(), ast_channel_linkedid(), ast_channel_lock, ast_channel_masquerade(), ast_channel_name(), ast_channel_nativeformats(), ast_channel_priority(), ast_channel_readformat(), ast_channel_state_set(), ast_channel_unlock, ast_channel_update_connected_line(), ast_channel_visible_indication_set(), ast_channel_writeformat(), ast_check_hangup(), ast_clear_flag, ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_do_masquerade(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAGS_ALL, ast_format_copy(), ast_hangup(), ast_indicate(), ast_log(), ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), atxfer_fail_cleanup(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, ast_bridge_thread_obj::bconfig, bridge_call_thread_launch(), ast_bridge_thread_obj::chan, check_compat(), ast_datastore::data, dial_features_info, ast_bridge_config::end_bridge_callback_data_fixup, feature_request_and_dial(), ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), get_parking_exten(), LOG_WARNING, ast_dial_features::my_features, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_bridge_thread_obj::peer, ast_dial_features::peer_features, real_ctx(), set_peers(), ast_party_connected_line::source, strsep(), transferdigittimeout, xfer_park_call_helper(), xferfailsound, and xfersound.

02673 {
02674    struct ast_channel *transferer;/* Party B */
02675    struct ast_channel *transferee;/* Party A */
02676    struct ast_exten *park_exten;
02677    const char *chan1_attended_sound;
02678    const char *chan2_attended_sound;
02679    const char *transferer_real_context;
02680    char xferto[256] = "";
02681    int res;
02682    int outstate=0;
02683    struct ast_channel *newchan;
02684    struct ast_channel *xferchan;
02685    struct ast_bridge_thread_obj *tobj;
02686    struct ast_bridge_config bconfig;
02687    int l;
02688    struct ast_party_connected_line connected_line;
02689    struct ast_datastore *features_datastore;
02690    struct ast_dial_features *dialfeatures;
02691    char *transferer_tech;
02692    char *transferer_name;
02693    char *transferer_name_orig;
02694    char *dash;
02695 
02696    ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", ast_channel_name(chan), ast_channel_name(peer), sense);
02697    set_peers(&transferer, &transferee, peer, chan, sense);
02698    transferer_real_context = real_ctx(transferer, transferee);
02699 
02700    /* Start autoservice on transferee while we talk to the transferer */
02701    ast_autoservice_start(transferee);
02702    ast_indicate(transferee, AST_CONTROL_HOLD);
02703 
02704    /* Transfer */
02705    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02706    if (res < 0) {
02707       finishup(transferee);
02708       return -1;
02709    }
02710    if (res > 0) { /* If they've typed a digit already, handle it */
02711       xferto[0] = (char) res;
02712    }
02713 
02714    /* this is specific of atxfer */
02715    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02716    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
02717       finishup(transferee);
02718       return -1;
02719    }
02720    l = strlen(xferto);
02721    if (res == 0) {
02722       if (l) {
02723          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02724             xferto, transferer_real_context);
02725       } else {
02726          /* Does anyone care about this case? */
02727          ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
02728       }
02729       ast_stream_and_wait(transferer, "pbx-invalid", "");
02730       finishup(transferee);
02731       return AST_FEATURE_RETURN_SUCCESS;
02732    }
02733 
02734    park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
02735    if (park_exten) {
02736       /* We are transfering the transferee to a parking lot. */
02737       return xfer_park_call_helper(transferee, transferer, park_exten);
02738    }
02739 
02740    /*
02741     * Append context to dialed transfer number.
02742     *
02743     * NOTE: The local channel needs the /n flag so party C will use
02744     * the feature flags set by the dialplan when calling that
02745     * party.
02746     */
02747    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
02748 
02749    /* If we are performing an attended transfer and we have two channels involved then
02750       copy sound file information to play upon attended transfer completion */
02751    chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02752    chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02753    if (!ast_strlen_zero(chan1_attended_sound)) {
02754       pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
02755    }
02756    if (!ast_strlen_zero(chan2_attended_sound)) {
02757       pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
02758    }
02759 
02760    /* Extract redial transferer information from the channel name. */
02761    transferer_name_orig = ast_strdupa(ast_channel_name(transferer));
02762    transferer_name = ast_strdupa(transferer_name_orig);
02763    transferer_tech = strsep(&transferer_name, "/");
02764    dash = strrchr(transferer_name, '-');
02765    if (dash) {
02766       /* Trim off channel name sequence/serial number. */
02767       *dash = '\0';
02768    }
02769 
02770    /* Stop autoservice so we can monitor all parties involved in the transfer. */
02771    if (ast_autoservice_stop(transferee) < 0) {
02772       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02773       return -1;
02774    }
02775 
02776    /* Save connected line info for party B about party A in case transfer fails. */
02777    ast_party_connected_line_init(&connected_line);
02778    ast_channel_lock(transferer);
02779    ast_party_connected_line_copy(&connected_line, ast_channel_connected(transferer));
02780    ast_channel_unlock(transferer);
02781    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02782 
02783    /* Dial party C */
02784    newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
02785       transferee, "Local", ast_channel_nativeformats(transferer), xferto,
02786       atxfernoanswertimeout, &outstate, ast_channel_language(transferer));
02787    ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
02788 
02789    if (!ast_check_hangup(transferer)) {
02790       int hangup_dont = 0;
02791 
02792       /* Transferer (party B) is up */
02793       ast_debug(1, "Actually doing an attended transfer.\n");
02794 
02795       /* Start autoservice on transferee while the transferer deals with party C. */
02796       ast_autoservice_start(transferee);
02797 
02798       ast_indicate(transferer, -1);
02799       if (!newchan) {
02800          /* any reason besides user requested cancel and busy triggers the failed sound */
02801          switch (outstate) {
02802          case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */
02803          case AST_CONTROL_BUSY:
02804          case AST_CONTROL_CONGESTION:
02805             if (ast_stream_and_wait(transferer, xfersound, "")) {
02806                ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02807             }
02808             break;
02809          default:
02810             if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02811                ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02812             }
02813             break;
02814          }
02815          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02816          return AST_FEATURE_RETURN_SUCCESS;
02817       }
02818 
02819       if (check_compat(transferer, newchan)) {
02820          if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02821             ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02822          }
02823          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02824          return AST_FEATURE_RETURN_SUCCESS;
02825       }
02826       memset(&bconfig,0,sizeof(struct ast_bridge_config));
02827       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
02828       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
02829 
02830       /*
02831        * ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we
02832        * don't want that to happen here because the transferer is in
02833        * another bridge already.
02834        */
02835       if (ast_test_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT)) {
02836          hangup_dont = 1;
02837       }
02838 
02839       /*
02840        * Don't let the after-bridge code run the h-exten.  It is the
02841        * wrong bridge to run the h-exten after.
02842        */
02843       ast_set_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT);
02844 
02845       /*
02846        * Let party B and C talk as long as they want while party A
02847        * languishes in autoservice listening to MOH.
02848        */
02849       ast_bridge_call(transferer, newchan, &bconfig);
02850 
02851       if (hangup_dont) {
02852          /* Restore the AST_FLAG_BRIDGE_HANGUP_DONT flag */
02853          ast_set_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT);
02854       }
02855 
02856       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
02857          ast_autoservice_chan_hangup_peer(transferer, newchan);
02858          if (ast_stream_and_wait(transferer, xfersound, "")) {
02859             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02860          }
02861          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02862          return AST_FEATURE_RETURN_SUCCESS;
02863       }
02864 
02865       /* Transferer (party B) is confirmed hung up at this point. */
02866       if (check_compat(transferee, newchan)) {
02867          finishup(transferee);
02868          ast_party_connected_line_free(&connected_line);
02869          return -1;
02870       }
02871 
02872       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02873       if ((ast_autoservice_stop(transferee) < 0)
02874          || (ast_waitfordigit(transferee, 100) < 0)
02875          || (ast_waitfordigit(newchan, 100) < 0)
02876          || ast_check_hangup(transferee)
02877          || ast_check_hangup(newchan)) {
02878          ast_hangup(newchan);
02879          ast_party_connected_line_free(&connected_line);
02880          return -1;
02881       }
02882    } else if (!ast_check_hangup(transferee)) {
02883       /* Transferer (party B) has hung up at this point.  Doing blonde transfer. */
02884       ast_debug(1, "Actually doing a blonde transfer.\n");
02885 
02886       if (!newchan && !atxferdropcall) {
02887          /* Party C is not available, try to call party B back. */
02888          unsigned int tries = 0;
02889 
02890          if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
02891             ast_log(LOG_WARNING,
02892                "Transferer channel name: '%s' cannot be used for callback.\n",
02893                transferer_name_orig);
02894             ast_indicate(transferee, AST_CONTROL_UNHOLD);
02895             ast_party_connected_line_free(&connected_line);
02896             return -1;
02897          }
02898 
02899          tries = 0;
02900          for (;;) {
02901             /* Try to get party B back. */
02902             ast_debug(1, "We're trying to callback %s/%s\n",
02903                transferer_tech, transferer_name);
02904             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02905                transferee, transferee, transferer_tech,
02906                ast_channel_nativeformats(transferee), transferer_name,
02907                atxfernoanswertimeout, &outstate, ast_channel_language(transferer));
02908             ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
02909                !!newchan, outstate);
02910             if (newchan) {
02911                /*
02912                 * We have recalled party B (newchan).  We need to give this
02913                 * call leg the same feature flags as the original party B call
02914                 * leg.
02915                 */
02916                ast_channel_lock(transferer);
02917                features_datastore = ast_channel_datastore_find(transferer,
02918                   &dial_features_info, NULL);
02919                if (features_datastore && (dialfeatures = features_datastore->data)) {
02920                   struct ast_flags my_features = { 0 };
02921                   struct ast_flags peer_features = { 0 };
02922 
02923                   ast_copy_flags(&my_features, &dialfeatures->my_features,
02924                      AST_FLAGS_ALL);
02925                   ast_copy_flags(&peer_features, &dialfeatures->peer_features,
02926                      AST_FLAGS_ALL);
02927                   ast_channel_unlock(transferer);
02928                   add_features_datastore(newchan, &my_features, &peer_features);
02929                } else {
02930                   ast_channel_unlock(transferer);
02931                }
02932                break;
02933             }
02934             if (ast_check_hangup(transferee)) {
02935                break;
02936             }
02937 
02938             ++tries;
02939             if (atxfercallbackretries <= tries) {
02940                /* No more callback tries remaining. */
02941                break;
02942             }
02943 
02944             if (atxferloopdelay) {
02945                /* Transfer failed, sleeping */
02946                ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n",
02947                   atxferloopdelay);
02948                ast_safe_sleep(transferee, atxferloopdelay);
02949                if (ast_check_hangup(transferee)) {
02950                   ast_party_connected_line_free(&connected_line);
02951                   return -1;
02952                }
02953             }
02954 
02955             /* Retry dialing party C. */
02956             ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
02957             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02958                transferer, transferee, "Local",
02959                ast_channel_nativeformats(transferee), xferto,
02960                atxfernoanswertimeout, &outstate, ast_channel_language(transferer));
02961             ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
02962                !!newchan, outstate);
02963             if (newchan || ast_check_hangup(transferee)) {
02964                break;
02965             }
02966          }
02967       }
02968       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02969       if (!newchan) {
02970          /* No party C or could not callback party B. */
02971          ast_party_connected_line_free(&connected_line);
02972          return -1;
02973       }
02974 
02975       /* newchan is up, we should prepare transferee and bridge them */
02976       if (ast_check_hangup(newchan)) {
02977          ast_autoservice_chan_hangup_peer(transferee, newchan);
02978          ast_party_connected_line_free(&connected_line);
02979          return -1;
02980       }
02981       if (check_compat(transferee, newchan)) {
02982          ast_party_connected_line_free(&connected_line);
02983          return -1;
02984       }
02985    } else {
02986       /*
02987        * Both the transferer and transferee have hungup.  If newchan
02988        * is up, hang it up as it has no one to talk to.
02989        */
02990       ast_debug(1, "Everyone is hungup.\n");
02991       if (newchan) {
02992          ast_hangup(newchan);
02993       }
02994       ast_party_connected_line_free(&connected_line);
02995       return -1;
02996    }
02997 
02998    /* Initiate the channel transfer of party A to party C (or recalled party B). */
02999    ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
03000 
03001    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(transferee), 0, "Transfered/%s", ast_channel_name(transferee));
03002    if (!xferchan) {
03003       ast_autoservice_chan_hangup_peer(transferee, newchan);
03004       ast_party_connected_line_free(&connected_line);
03005       return -1;
03006    }
03007 
03008    /* Give party A a momentary ringback tone during transfer. */
03009    ast_channel_visible_indication_set(xferchan, AST_CONTROL_RINGING);
03010 
03011    /* Make formats okay */
03012    ast_format_copy(ast_channel_readformat(xferchan), ast_channel_readformat(transferee));
03013    ast_format_copy(ast_channel_writeformat(xferchan), ast_channel_writeformat(transferee));
03014 
03015    if (ast_channel_masquerade(xferchan, transferee)) {
03016       ast_hangup(xferchan);
03017       ast_autoservice_chan_hangup_peer(transferee, newchan);
03018       ast_party_connected_line_free(&connected_line);
03019       return -1;
03020    }
03021    ast_explicit_goto(xferchan, ast_channel_context(transferee), ast_channel_exten(transferee), ast_channel_priority(transferee));
03022    ast_channel_state_set(xferchan, AST_STATE_UP);
03023    ast_clear_flag(ast_channel_flags(xferchan), AST_FLAGS_ALL);
03024 
03025    /* Do the masquerade manually to make sure that is is completed. */
03026    ast_do_masquerade(xferchan);
03027 
03028    ast_channel_state_set(newchan, AST_STATE_UP);
03029    ast_clear_flag(ast_channel_flags(newchan), AST_FLAGS_ALL);
03030    tobj = ast_calloc(1, sizeof(*tobj));
03031    if (!tobj) {
03032       ast_hangup(xferchan);
03033       ast_hangup(newchan);
03034       ast_party_connected_line_free(&connected_line);
03035       return -1;
03036    }
03037 
03038    tobj->chan = newchan;
03039    tobj->peer = xferchan;
03040    tobj->bconfig = *config;
03041 
03042    ast_channel_lock(newchan);
03043    features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL);
03044    if (features_datastore && (dialfeatures = features_datastore->data)) {
03045       ast_copy_flags(&tobj->bconfig.features_callee, &dialfeatures->my_features,
03046          AST_FLAGS_ALL);
03047    }
03048    ast_channel_unlock(newchan);
03049 
03050    ast_channel_lock(xferchan);
03051    features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL);
03052    if (features_datastore && (dialfeatures = features_datastore->data)) {
03053       ast_copy_flags(&tobj->bconfig.features_caller, &dialfeatures->my_features,
03054          AST_FLAGS_ALL);
03055    }
03056    ast_channel_unlock(xferchan);
03057 
03058    if (tobj->bconfig.end_bridge_callback_data_fixup) {
03059       tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
03060    }
03061 
03062    /*
03063     * xferchan is transferee, and newchan is the transfer target
03064     * So...in a transfer, who is the caller and who is the callee?
03065     *
03066     * When the call is originally made, it is clear who is caller and callee.
03067     * When a transfer occurs, it is my humble opinion that the transferee becomes
03068     * the caller, and the transfer target is the callee.
03069     *
03070     * The problem is that these macros were set with the intention of the original
03071     * caller and callee taking those roles.  A transfer can totally mess things up,
03072     * to be technical.  What sucks even more is that you can't effectively change
03073     * the macros in the dialplan during the call from the transferer to the transfer
03074     * target because the transferee is stuck with whatever role he originally had.
03075     *
03076     * I think the answer here is just to make sure that it is well documented that
03077     * during a transfer, the transferee is the "caller" and the transfer target
03078     * is the "callee."
03079     *
03080     * This means that if party B calls party A, and party B transfers party A to
03081     * party C, then A has switched roles for the call.  Now party A will have the
03082     * caller macro called on his channel instead of the callee macro.
03083     *
03084     * Luckily, the method by which the party B to party C bridge is
03085     * launched above ensures that the transferee is the "chan" on
03086     * the bridge and the transfer target is the "peer," so my idea
03087     * for the roles post-transfer does not require extensive code
03088     * changes.
03089     */
03090 
03091    /* Transfer party C connected line to party A */
03092    ast_channel_lock(transferer);
03093    /*
03094     * Due to a limitation regarding when callerID is set on a Local channel,
03095     * we use the transferer's connected line information here.
03096     */
03097    ast_party_connected_line_copy(&connected_line, ast_channel_connected(transferer));
03098    ast_channel_unlock(transferer);
03099    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
03100    if (ast_channel_connected_line_sub(newchan, xferchan, &connected_line, 0) &&
03101       ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
03102       ast_channel_update_connected_line(xferchan, &connected_line, NULL);
03103    }
03104 
03105    /* Transfer party A connected line to party C */
03106    ast_channel_lock(xferchan);
03107    ast_connected_line_copy_from_caller(&connected_line, ast_channel_caller(xferchan));
03108    ast_channel_unlock(xferchan);
03109    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
03110    if (ast_channel_connected_line_sub(xferchan, newchan, &connected_line, 0) &&
03111       ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
03112       ast_channel_update_connected_line(newchan, &connected_line, NULL);
03113    }
03114 
03115    if (ast_stream_and_wait(newchan, xfersound, ""))
03116       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
03117    bridge_call_thread_launch(tobj);
03118 
03119    ast_party_connected_line_free(&connected_line);
03120    return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */
03121 }

static int builtin_automixmonitor ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
void *  data 
) [static]

Definition at line 2357 of file features.c.

References args, ast_alloca, AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_caller(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, AST_FEATURE_RETURN_SUCCESS, AST_FRAME_DTMF_END, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, courtesytone, LOG_ERROR, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_COR, S_OR, set_peers(), stopmixmonitor_app, and stopmixmonitor_ok.

02358 {
02359    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
02360    int x = 0;
02361    size_t len;
02362    struct ast_channel *caller_chan, *callee_chan;
02363    const char *mixmonitor_spy_type = "MixMonitor";
02364    const char *touch_format;
02365    const char *touch_monitor;
02366    int count = 0;
02367 
02368    if (!mixmonitor_ok) {
02369       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
02370       return -1;
02371    }
02372 
02373    if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
02374       mixmonitor_ok = 0;
02375       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
02376       return -1;
02377    }
02378 
02379    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
02380 
02381    if (!ast_strlen_zero(courtesytone)) {
02382       if (ast_autoservice_start(callee_chan))
02383          return -1;
02384       ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
02385       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
02386          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02387          ast_autoservice_stop(callee_chan);
02388          return -1;
02389       }
02390       if (ast_autoservice_stop(callee_chan))
02391          return -1;
02392    }
02393 
02394    ast_channel_lock(callee_chan);
02395    count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
02396    ast_channel_unlock(callee_chan);
02397 
02398    /* This means a mixmonitor is attached to the channel, running or not is unknown. */
02399    if (count > 0) {
02400       ast_verb(3, "User hit '%s' to stop recording call.\n", code);
02401 
02402       /* Make sure they are running */
02403       ast_channel_lock(callee_chan);
02404       count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
02405       ast_channel_unlock(callee_chan);
02406       if (count > 0) {
02407          if (!stopmixmonitor_ok) {
02408             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
02409             return -1;
02410          }
02411          if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
02412             stopmixmonitor_ok = 0;
02413             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
02414             return -1;
02415          } else {
02416             pbx_exec(callee_chan, stopmixmonitor_app, "");
02417             return AST_FEATURE_RETURN_SUCCESS;
02418          }
02419       }
02420 
02421       ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n");
02422    }
02423 
02424    touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
02425    touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
02426 
02427    if (!touch_format)
02428       touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
02429 
02430    if (!touch_monitor)
02431       touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
02432 
02433    if (touch_monitor) {
02434       len = strlen(touch_monitor) + 50;
02435       args = ast_alloca(len);
02436       touch_filename = ast_alloca(len);
02437       snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
02438       snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
02439    } else {
02440       caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(caller_chan)->id.number.valid,
02441          ast_channel_caller(caller_chan)->id.number.str, ast_channel_name(caller_chan)));
02442       callee_chan_id = ast_strdupa(S_COR(ast_channel_caller(callee_chan)->id.number.valid,
02443          ast_channel_caller(callee_chan)->id.number.str, ast_channel_name(callee_chan)));
02444       len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
02445       args = ast_alloca(len);
02446       touch_filename = ast_alloca(len);
02447       snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
02448       snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
02449    }
02450 
02451    for( x = 0; x < strlen(args); x++) {
02452       if (args[x] == '/')
02453          args[x] = '-';
02454    }
02455 
02456    ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
02457 
02458    pbx_exec(callee_chan, mixmonitor_app, args);
02459    pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
02460    pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
02461    return AST_FEATURE_RETURN_SUCCESS;
02462 }

static int builtin_automonitor ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
void *  data 
) [static]

Monitor a channel by DTMF.

Parameters:
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.
Return values:
AST_FEATURE_RETURN_SUCCESS on success.
-1 on error.

Definition at line 2264 of file features.c.

References args, ast_alloca, ast_channel_caller(), ast_channel_monitor(), ast_channel_name(), AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, courtesytone, LOG_ERROR, monitor_app, monitor_ok, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_COR, S_OR, set_peers(), and ast_channel_monitor::stop.

02265 {
02266    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
02267    int x = 0;
02268    size_t len;
02269    struct ast_channel *caller_chan, *callee_chan;
02270    const char *automon_message_start = NULL;
02271    const char *automon_message_stop = NULL;
02272    const char *touch_format = NULL;
02273    const char *touch_monitor = NULL;
02274    const char *touch_monitor_prefix = NULL;
02275 
02276    if (!monitor_ok) {
02277       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
02278       return -1;
02279    }
02280 
02281    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
02282       monitor_ok = 0;
02283       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
02284       return -1;
02285    }
02286 
02287    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
02288 
02289    /* Find extra messages */
02290    automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
02291    automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
02292 
02293    if (!ast_strlen_zero(courtesytone)) {  /* Play courtesy tone if configured */
02294       if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
02295          return -1;
02296       }
02297    }
02298 
02299    if (ast_channel_monitor(callee_chan)) {
02300       ast_verb(4, "User hit '%s' to stop recording call.\n", code);
02301       if (!ast_strlen_zero(automon_message_stop)) {
02302          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
02303       }
02304       ast_channel_monitor(callee_chan)->stop(callee_chan, 1);
02305       return AST_FEATURE_RETURN_SUCCESS;
02306    }
02307 
02308    touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
02309    touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
02310    touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
02311 
02312    if (!touch_format)
02313       touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
02314 
02315    if (!touch_monitor)
02316       touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
02317 
02318    if (!touch_monitor_prefix)
02319       touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
02320 
02321    if (touch_monitor) {
02322       len = strlen(touch_monitor) + 50;
02323       args = ast_alloca(len);
02324       touch_filename = ast_alloca(len);
02325       snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
02326       snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
02327    } else {
02328       caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(caller_chan)->id.number.valid,
02329          ast_channel_caller(caller_chan)->id.number.str, ast_channel_name(caller_chan)));
02330       callee_chan_id = ast_strdupa(S_COR(ast_channel_caller(callee_chan)->id.number.valid,
02331          ast_channel_caller(callee_chan)->id.number.str, ast_channel_name(callee_chan)));
02332       len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
02333       args = ast_alloca(len);
02334       touch_filename = ast_alloca(len);
02335       snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
02336       snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
02337    }
02338 
02339    for(x = 0; x < strlen(args); x++) {
02340       if (args[x] == '/')
02341          args[x] = '-';
02342    }
02343 
02344    ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
02345 
02346    pbx_exec(callee_chan, monitor_app, args);
02347    pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
02348    pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
02349 
02350    if (!ast_strlen_zero(automon_message_start)) {  /* Play start message for both channels */
02351       play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
02352    }
02353 
02354    return AST_FEATURE_RETURN_SUCCESS;
02355 }

static int builtin_blindtransfer ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
void *  data 
) [static]

Blind transfer user to another extension.

Parameters:
chan channel to be transfered
peer channel initiated blind transfer
config 
code 
data 
sense feature options
Place chan on hold, check if transferred to parkinglot extension, otherwise check extension exists and transfer caller.
Return values:
AST_FEATURE_RETURN_SUCCESS. 
-1 on failure.

Definition at line 2507 of file features.c.

References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CEL_BLINDTRANSFER, ast_cel_report_event(), ast_channel_cdr(), ast_channel_cdr_set(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_pbx(), ast_channel_unlock, AST_CONTROL_HOLD, ast_debug, AST_DIGIT_ANY, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, AST_FLAG_BRIDGE_HANGUP_DONT, ast_indicate(), ast_log(), ast_set_flag, ast_strdupa, ast_stream_and_wait(), ast_verb, ast_cdr::channel, check_goto_on_transfer(), ast_cdr::dstchannel, finishup(), get_parking_exten(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, pbx_builtin_setvar_helper(), real_ctx(), set_peers(), transferdigittimeout, and xfer_park_call_helper().

02508 {
02509    struct ast_channel *transferer;
02510    struct ast_channel *transferee;
02511    struct ast_exten *park_exten;
02512    const char *transferer_real_context;
02513    char xferto[256] = "";
02514    int res;
02515 
02516    ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", ast_channel_name(chan), ast_channel_name(peer), sense);
02517    set_peers(&transferer, &transferee, peer, chan, sense);
02518    transferer_real_context = ast_strdupa(real_ctx(transferer, transferee));
02519 
02520    /* Start autoservice on transferee while we talk to the transferer */
02521    ast_autoservice_start(transferee);
02522    ast_indicate(transferee, AST_CONTROL_HOLD);
02523 
02524    /* Transfer */
02525    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02526    if (res < 0) {
02527       finishup(transferee);
02528       return -1; /* error ? */
02529    }
02530    if (res > 0) { /* If they've typed a digit already, handle it */
02531       xferto[0] = (char) res;
02532    }
02533 
02534    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02535    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
02536       finishup(transferee);
02537       return -1;
02538    }
02539    if (res == 0) {
02540       if (xferto[0]) {
02541          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02542             xferto, transferer_real_context);
02543       } else {
02544          /* Does anyone care about this case? */
02545          ast_log(LOG_WARNING, "No digits dialed.\n");
02546       }
02547       ast_stream_and_wait(transferer, "pbx-invalid", "");
02548       finishup(transferee);
02549       return AST_FEATURE_RETURN_SUCCESS;
02550    }
02551 
02552    park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
02553    if (park_exten) {
02554       /* We are transfering the transferee to a parking lot. */
02555       return xfer_park_call_helper(transferee, transferer, park_exten);
02556    }
02557 
02558    /* Do blind transfer. */
02559    ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n",
02560       ast_channel_name(transferee), xferto, transferer_real_context);
02561    ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
02562    pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", ast_channel_name(transferee));
02563    pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", ast_channel_name(transferer));
02564    finishup(transferee);
02565    ast_channel_lock(transferer);
02566    if (!ast_channel_cdr(transferer)) {
02567       /* this code should never get called (in a perfect world) */
02568       ast_channel_cdr_set(transferer, ast_cdr_alloc());
02569       if (ast_channel_cdr(transferer)) {
02570          ast_cdr_init(ast_channel_cdr(transferer), transferer); /* initialize our channel's cdr */
02571          ast_cdr_start(ast_channel_cdr(transferer));
02572       }
02573    }
02574    ast_channel_unlock(transferer);
02575    if (ast_channel_cdr(transferer)) {
02576       struct ast_cdr *swap = ast_channel_cdr(transferer);
02577 
02578       ast_debug(1,
02579          "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
02580          ast_channel_name(transferer), ast_channel_name(transferee), ast_channel_cdr(transferer)->lastapp,
02581          ast_channel_cdr(transferer)->lastdata, ast_channel_cdr(transferer)->channel,
02582          ast_channel_cdr(transferer)->dstchannel);
02583       ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
02584          ast_channel_cdr(transferee)->lastapp, ast_channel_cdr(transferee)->lastdata, ast_channel_cdr(transferee)->channel,
02585          ast_channel_cdr(transferee)->dstchannel);
02586       ast_debug(1, "transferer_real_context=%s; xferto=%s\n",
02587          transferer_real_context, xferto);
02588       /* swap cdrs-- it will save us some time & work */
02589       ast_channel_cdr_set(transferer, ast_channel_cdr(transferee));
02590       ast_channel_cdr_set(transferee, swap);
02591    }
02592 
02593    res = ast_channel_pbx(transferee) ? AST_FEATURE_RETURN_SUCCESSBREAK : -1;
02594 
02595    /* Doh!  Use our handy async_goto functions */
02596    if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) {
02597       ast_log(LOG_WARNING, "Async goto failed :-(\n");
02598       res = -1;
02599    } else if (res == AST_FEATURE_RETURN_SUCCESSBREAK) {
02600       /* Don't let the after-bridge code run the h-exten */
02601       ast_channel_lock(transferee);
02602       ast_set_flag(ast_channel_flags(transferee), AST_FLAG_BRIDGE_HANGUP_DONT);
02603       ast_channel_unlock(transferee);
02604    }
02605    check_goto_on_transfer(transferer);
02606    return res;
02607 }

static int builtin_disconnect ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
void *  data 
) [static]

Definition at line 2464 of file features.c.

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

02465 {
02466    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
02467    return AST_FEATURE_RETURN_HANGUP;
02468 }

static int builtin_feature_get_exten ( struct ast_channel chan,
const char *  feature_name,
char *  buf,
size_t  len 
) [static]

Definition at line 3423 of file features.c.

References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_find_call_feature(), ast_rdlock_call_features(), ast_unlock_call_features(), feature_exten::exten, ast_call_feature::exten, feature_ds::feature_map, get_feature_ds(), and OBJ_KEY.

Referenced by feature_interpret_helper(), and featuremap_read().

03425 {
03426    struct ast_call_feature *feature;
03427    struct feature_ds *feature_ds;
03428    struct feature_exten *fe = NULL;
03429 
03430    *buf = '\0';
03431 
03432    if (!(feature = ast_find_call_feature(feature_name))) {
03433       return -1;
03434    }
03435 
03436    ast_copy_string(buf, feature->exten, len);
03437 
03438    ast_unlock_call_features();
03439 
03440    ast_channel_lock(chan);
03441    if ((feature_ds = get_feature_ds(chan))) {
03442       fe = ao2_find(feature_ds->feature_map, feature_name, OBJ_KEY);
03443    }
03444    ast_channel_unlock(chan);
03445 
03446    ast_rdlock_call_features();
03447 
03448    if (fe) {
03449       ao2_lock(fe);
03450       ast_copy_string(buf, fe->exten, len);
03451       ao2_unlock(fe);
03452       ao2_ref(fe, -1);
03453       fe = NULL;
03454    }
03455 
03456    return 0;
03457 }

static int builtin_parkcall ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
void *  data 
) [static]

support routing for one touch call parking

Parameters:
chan channel parking call
peer channel to be parked
config unsed
code unused
sense feature options
data unused
Return values:
-1 on successful park.
-1 on chan hangup.
AST_FEATURE_RETURN_SUCCESS on error to keep the bridge connected.

Definition at line 2142 of file features.c.

References ast_answer(), AST_FEATURE_RETURN_SUCCESS, ast_safe_sleep(), AST_STATE_UP, masq_park_call(), and set_peers().

02143 {
02144    struct ast_channel *parker;
02145    struct ast_channel *parkee;
02146    struct ast_park_call_args args = { 0, };
02147 
02148    /*
02149     * We used to set chan's exten and priority to "s" and 1 here,
02150     * but this generates (in some cases) an invalid extension, and
02151     * if "s" exists, could errantly cause execution of extensions
02152     * you don't expect.  It makes more sense to let nature take its
02153     * course when chan finishes, and let the pbx do its thing and
02154     * hang up when the park is over.
02155     */
02156 
02157    /* Answer if call is not up */
02158    if (ast_channel_state(chan) != AST_STATE_UP) {
02159       /*
02160        * XXX Why are we doing this?  Both of the channels should be up
02161        * since you cannot do DTMF features unless you are bridged.
02162        */
02163       if (ast_answer(chan)) {
02164          return -1;
02165       }
02166 
02167       /* Sleep to allow VoIP streams to settle down */
02168       if (ast_safe_sleep(chan, 1000)) {
02169          return -1;
02170       }
02171    }
02172 
02173    /* one direction used to call park_call.... */
02174    set_peers(&parker, &parkee, peer, chan, sense);
02175    return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1;
02176 }

static char* callback_dialoptions ( struct ast_flags features_callee,
struct ast_flags features_caller,
char *  options,
size_t  len 
) [static]

Definition at line 4910 of file features.c.

References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_test_flag, OPT_CALLEE_AUTOMON, and OPT_CALLER_AUTOMON.

Referenced by manage_parked_call().

04911 {
04912    int i = 0;
04913    enum {
04914       OPT_CALLEE_REDIRECT   = 't',
04915       OPT_CALLER_REDIRECT   = 'T',
04916       OPT_CALLEE_AUTOMON    = 'w',
04917       OPT_CALLER_AUTOMON    = 'W',
04918       OPT_CALLEE_DISCONNECT = 'h',
04919       OPT_CALLER_DISCONNECT = 'H',
04920       OPT_CALLEE_PARKCALL   = 'k',
04921       OPT_CALLER_PARKCALL   = 'K',
04922    };
04923 
04924    memset(options, 0, len);
04925    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
04926       options[i++] = OPT_CALLER_REDIRECT;
04927    }
04928    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
04929       options[i++] = OPT_CALLER_AUTOMON;
04930    }
04931    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
04932       options[i++] = OPT_CALLER_DISCONNECT;
04933    }
04934    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
04935       options[i++] = OPT_CALLER_PARKCALL;
04936    }
04937 
04938    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
04939       options[i++] = OPT_CALLEE_REDIRECT;
04940    }
04941    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
04942       options[i++] = OPT_CALLEE_AUTOMON;
04943    }
04944    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
04945       options[i++] = OPT_CALLEE_DISCONNECT;
04946    }
04947    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
04948       options[i++] = OPT_CALLEE_PARKCALL;
04949    }
04950 
04951    return options;
04952 }

static int check_compat ( struct ast_channel c,
struct ast_channel newchan 
) [static]

make channels compatible

Parameters:
c 
newchan 
Return values:
0 on success.
-1 on failure.

Definition at line 2616 of file features.c.

References ast_autoservice_chan_hangup_peer(), ast_channel_make_compatible(), ast_channel_name(), ast_log(), and LOG_WARNING.

Referenced by builtin_atxfer().

02617 {
02618    if (ast_channel_make_compatible(c, newchan) < 0) {
02619       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
02620          ast_channel_name(c), ast_channel_name(newchan));
02621       ast_autoservice_chan_hangup_peer(c, newchan);
02622       return -1;
02623    }
02624    return 0;
02625 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Check goto on transfer.

Parameters:
chan Check if channel has 'GOTO_ON_BLINDXFR' set, if not exit. When found make sure the types are compatible. Check if channel is valid if so start the new channel else hangup the call.

Definition at line 1034 of file features.c.

References ast_channel_alloc, ast_channel_clear_softhangup(), ast_channel_flags(), ast_channel_linkedid(), ast_channel_lock, ast_channel_masquerade(), ast_channel_name(), ast_channel_readformat(), ast_channel_state_set(), ast_channel_unlock, ast_channel_writeformat(), ast_clear_flag, ast_debug, ast_do_masquerade(), AST_FLAGS_ALL, ast_format_copy(), ast_hangup(), ast_parseable_goto(), ast_pbx_start(), AST_SOFTHANGUP_ALL, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), and pbx_builtin_getvar_helper().

Referenced by builtin_blindtransfer().

01035 {
01036    struct ast_channel *xferchan;
01037    const char *val;
01038    char *goto_on_transfer;
01039    char *x;
01040 
01041    ast_channel_lock(chan);
01042    val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
01043    if (ast_strlen_zero(val)) {
01044       ast_channel_unlock(chan);
01045       return;
01046    }
01047    goto_on_transfer = ast_strdupa(val);
01048    ast_channel_unlock(chan);
01049 
01050    ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, ast_channel_name(chan));
01051 
01052    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(chan), 0,
01053       "%s", ast_channel_name(chan));
01054    if (!xferchan) {
01055       return;
01056    }
01057 
01058    /* Make formats okay */
01059    ast_format_copy(ast_channel_readformat(xferchan), ast_channel_readformat(chan));
01060    ast_format_copy(ast_channel_writeformat(xferchan), ast_channel_writeformat(chan));
01061 
01062    if (ast_channel_masquerade(xferchan, chan)) {
01063       /* Failed to setup masquerade. */
01064       ast_hangup(xferchan);
01065       return;
01066    }
01067 
01068    for (x = goto_on_transfer; *x; ++x) {
01069       if (*x == '^') {
01070          *x = ',';
01071       }
01072    }
01073    ast_parseable_goto(xferchan, goto_on_transfer);
01074    ast_channel_state_set(xferchan, AST_STATE_UP);
01075    ast_clear_flag(ast_channel_flags(xferchan), AST_FLAGS_ALL);
01076    ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
01077 
01078    ast_do_masquerade(xferchan);
01079    if (ast_pbx_start(xferchan)) {
01080       /* Failed to start PBX. */
01081       ast_hangup(xferchan);
01082    }
01083 }

static void clear_dialed_interfaces ( struct ast_channel chan  )  [static]

Definition at line 4222 of file features.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_datastore_free(), ast_log(), dialed_interface_info, LOG_DEBUG, and option_debug.

Referenced by ast_bridge_call().

04223 {
04224    struct ast_datastore *di_datastore;
04225 
04226    ast_channel_lock(chan);
04227    if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
04228       if (option_debug) {
04229          ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", ast_channel_name(chan));
04230       }
04231       if (!ast_channel_datastore_remove(chan, di_datastore)) {
04232          ast_datastore_free(di_datastore);
04233       }
04234    }
04235    ast_channel_unlock(chan);
04236 }

static struct ast_parkinglot * copy_parkinglot ( const char *  name,
const struct ast_parkinglot parkinglot 
) [static, read]

Copy parkinglot and store it with new name.

Definition at line 5285 of file features.c.

References ao2_ref, ast_debug, ast_parkinglot::cfg, create_parkinglot(), and find_parkinglot().

Referenced by create_dynamic_parkinglot().

05286 {
05287    struct ast_parkinglot *copylot;
05288 
05289    if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
05290       ao2_ref(copylot, -1);
05291       return NULL;
05292    }
05293 
05294    copylot = create_parkinglot(name);
05295    if (!copylot) {
05296       return NULL;
05297    }
05298 
05299    ast_debug(1, "Building parking lot %s\n", name);
05300 
05301    /* Copy the source parking lot configuration. */
05302    copylot->cfg = parkinglot->cfg;
05303 
05304    return copylot;
05305 }

static struct ast_parkinglot* create_dynamic_parkinglot ( const char *  name,
struct ast_channel chan 
) [static, read]

Definition at line 1315 of file features.c.

References ao2_link, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, ast_log(), ast_strdupa, ast_strlen_zero(), ast_parkinglot::cfg, copy_parkinglot(), default_parkinglot, find_parkinglot(), parkinglot_cfg::is_invalid, LOG_ERROR, LOG_WARNING, ast_parkinglot::name, parkinglot_cfg::parkext, parkinglot_cfg::parkext_exclusive, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglot_activate(), parkinglot_addref(), parkinglot_unref(), parkinglots, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_masq_park_call_exten(), ast_park_call_exten(), park_call_exec(), park_space_reserve(), and xfer_park_call_helper().

01316 {
01317    const char *dyn_context;
01318    const char *dyn_exten;
01319    const char *dyn_range;
01320    const char *template_name;
01321    struct ast_parkinglot *template_parkinglot = NULL;
01322    struct ast_parkinglot *parkinglot;
01323    int dyn_start;
01324    int dyn_end;
01325 
01326    ast_channel_lock(chan);
01327    template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
01328    dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
01329    dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), ""));
01330    dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
01331    ast_channel_unlock(chan);
01332 
01333    if (!ast_strlen_zero(template_name)) {
01334       template_parkinglot = find_parkinglot(template_name);
01335       if (!template_parkinglot) {
01336          ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n",
01337             template_name);
01338       } else if (template_parkinglot->cfg.is_invalid) {
01339          ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n",
01340             template_name);
01341          parkinglot_unref(template_parkinglot);
01342          template_parkinglot = NULL;
01343       }
01344    }
01345    if (!template_parkinglot) {
01346       template_parkinglot = parkinglot_addref(default_parkinglot);
01347       ast_debug(1, "Using default parking lot for template\n");
01348    }
01349 
01350    parkinglot = copy_parkinglot(name, template_parkinglot);
01351    if (!parkinglot) {
01352       ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
01353    } else {
01354       /* Configure the dynamic parking lot. */
01355       if (!ast_strlen_zero(dyn_context)) {
01356          ast_copy_string(parkinglot->cfg.parking_con, dyn_context,
01357             sizeof(parkinglot->cfg.parking_con));
01358       }
01359       if (!ast_strlen_zero(dyn_exten)) {
01360          ast_copy_string(parkinglot->cfg.parkext, dyn_exten,
01361             sizeof(parkinglot->cfg.parkext));
01362       }
01363       if (!ast_strlen_zero(dyn_range)) {
01364          if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
01365             ast_log(LOG_WARNING,
01366                "Format for parking positions is a-b, where a and b are numbers\n");
01367          } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) {
01368             ast_log(LOG_WARNING,
01369                "Format for parking positions is a-b, where a <= b\n");
01370          } else {
01371             parkinglot->cfg.parking_start = dyn_start;
01372             parkinglot->cfg.parking_stop = dyn_end;
01373          }
01374       }
01375 
01376       /*
01377        * Sanity check for dynamic parking lot configuration.
01378        *
01379        * XXX It may be desirable to instead check if the dynamic
01380        * parking lot overlaps any existing lots like what is done for
01381        * a reload.
01382        */
01383       if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) {
01384          if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext)
01385             && parkinglot->cfg.parkext_exclusive) {
01386             ast_log(LOG_WARNING,
01387                "Parking lot '%s' conflicts with template parking lot '%s'!\n"
01388                "Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n",
01389                parkinglot->name, template_parkinglot->name);
01390          }
01391          if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start
01392                && parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop)
01393             || (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop
01394                && parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop)
01395             || (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start
01396                && template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) {
01397             ast_log(LOG_WARNING,
01398                "Parking lot '%s' parking spaces overlap template parking lot '%s'!\n"
01399                "Change PARKINGDYNPOS.\n",
01400                parkinglot->name, template_parkinglot->name);
01401          }
01402       }
01403 
01404       parkinglot_activate(parkinglot);
01405       ao2_link(parkinglots, parkinglot);
01406    }
01407    parkinglot_unref(template_parkinglot);
01408 
01409    return parkinglot;
01410 }

static struct ast_parkinglot * create_parkinglot ( const char *  name  )  [static, read]

Allocate parking lot structure.

Definition at line 5736 of file features.c.

References ao2_alloc, ast_copy_string(), AST_LIST_HEAD_INIT, ast_strlen_zero(), ast_parkinglot::cfg, parkinglot_cfg::is_invalid, ast_parkinglot::name, parkinglot_destroy(), and ast_parkinglot::parkings.

Referenced by build_parkinglot(), and copy_parkinglot().

05737 {
05738    struct ast_parkinglot *newlot;
05739 
05740    if (ast_strlen_zero(name)) { /* No name specified */
05741       return NULL;
05742    }
05743 
05744    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
05745    if (!newlot)
05746       return NULL;
05747 
05748    ast_copy_string(newlot->name, name, sizeof(newlot->name));
05749    newlot->cfg.is_invalid = 1;/* No config is set yet. */
05750    AST_LIST_HEAD_INIT(&newlot->parkings);
05751 
05752    return newlot;
05753 }

static void destroy_dialplan_usage_context ( struct parking_dp_context doomed  )  [static]

Definition at line 6333 of file features.c.

References parking_dp_context::access_extens, ast_free, AST_LIST_REMOVE_HEAD, parking_dp_context::hints, and parking_dp_context::spaces.

Referenced by build_dialplan_useage_context(), and destroy_dialplan_usage_map().

06334 {
06335    struct parking_dp_ramp *ramp;
06336    struct parking_dp_spaces *spaces;
06337 
06338    while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) {
06339       ast_free(ramp);
06340    }
06341    while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) {
06342       ast_free(spaces);
06343    }
06344    while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) {
06345       ast_free(spaces);
06346    }
06347    ast_free(doomed);
06348 }

static void destroy_dialplan_usage_map ( struct parking_dp_map doomed  )  [static]

Definition at line 6358 of file features.c.

References AST_LIST_REMOVE_HEAD, and destroy_dialplan_usage_context().

Referenced by load_config().

06359 {
06360    struct parking_dp_context *item;
06361 
06362    while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) {
06363       destroy_dialplan_usage_context(item);
06364    }
06365 }

static void destroy_space ( const char *  context,
int  space 
) [static]

Definition at line 6788 of file features.c.

References AST_MAX_EXTENSION, PRIORITY_HINT, and remove_exten_if_exist().

Referenced by remove_dead_context_usage(), and remove_dead_spaces_usage().

06789 {
06790    char exten[AST_MAX_EXTENSION];
06791 
06792    /* Destroy priorities of the parking space that we registered. */
06793    snprintf(exten, sizeof(exten), "%d", space);
06794    remove_exten_if_exist(context, exten, PRIORITY_HINT);
06795    remove_exten_if_exist(context, exten, 1);
06796 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 881 of file features.c.

References ast_free.

00882 {
00883    struct ast_dial_features *df = data;
00884    if (df) {
00885       ast_free(df);
00886    }
00887 }

static void* dial_features_duplicate ( void *  data  )  [static]

Definition at line 868 of file features.c.

References ast_calloc.

00869 {
00870    struct ast_dial_features *df = data, *df_copy;
00871 
00872    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00873       return NULL;
00874    }
00875 
00876    memcpy(df_copy, df, sizeof(*df));
00877 
00878    return df_copy;
00879 }

static int dialplan_usage_add_parkinglot ( struct parking_dp_map usage_map,
struct ast_parkinglot lot,
int  complain 
) [static]

Definition at line 6641 of file features.c.

References AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, build_dialplan_useage_context(), ast_parkinglot::cfg, parking_dp_context::context, dialplan_usage_add_parkinglot_data(), and parkinglot_cfg::parking_con.

Referenced by build_dialplan_useage_map().

06642 {
06643    struct parking_dp_context *cur_ctx;
06644    struct parking_dp_context *new_ctx;
06645    int cmp;
06646 
06647    AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) {
06648       cmp = strcmp(lot->cfg.parking_con, cur_ctx->context);
06649       if (cmp > 0) {
06650          /* The parking lot context goes after this node. */
06651          continue;
06652       }
06653       if (cmp == 0) {
06654          /* This is the node we will add parking lot spaces to the map. */
06655          return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain);
06656       }
06657       /* The new parking lot context goes before this node. */
06658       new_ctx = build_dialplan_useage_context(lot);
06659       if (!new_ctx) {
06660          return -1;
06661       }
06662       AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node);
06663       return 0;
06664    }
06665    AST_LIST_TRAVERSE_SAFE_END;
06666 
06667    /* New parking lot context goes on the end. */
06668    new_ctx = build_dialplan_useage_context(lot);
06669    if (!new_ctx) {
06670       return -1;
06671    }
06672    AST_LIST_INSERT_TAIL(usage_map, new_ctx, node);
06673    return 0;
06674 }

static int dialplan_usage_add_parkinglot_data ( struct parking_dp_context ctx_node,
struct ast_parkinglot lot,
int  complain 
) [static]

Definition at line 6587 of file features.c.

References parking_dp_context::access_extens, ast_parkinglot::cfg, parking_dp_context::hints, parkinglot_cfg::parkaddhints, parkinglot_cfg::parkext, parkinglot_cfg::parkext_exclusive, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parking_dp_context::spaces, usage_context_add_ramp(), and usage_context_add_spaces().

Referenced by build_dialplan_useage_context(), and dialplan_usage_add_parkinglot().

06588 {
06589    if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext,
06590       lot->cfg.parkext_exclusive, lot, complain)) {
06591       return -1;
06592    }
06593    if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start,
06594       lot->cfg.parking_stop, lot, complain)) {
06595       return -1;
06596    }
06597    if (lot->cfg.parkaddhints
06598       && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start,
06599          lot->cfg.parking_stop, lot, 0)) {
06600       return -1;
06601    }
06602    return 0;
06603 }

static int do_bridge_masquerade ( struct ast_channel chan,
struct ast_channel tmpchan 
) [static]

Actual bridge.

Parameters:
chan 
tmpchan Stop hold music, lock both channels, masq channels, after bridge return channel to next priority.
Return values:
0 on success.
-1 on error.

Definition at line 7230 of file features.c.

References ast_channel_context(), ast_channel_exten(), ast_channel_lock_both, ast_channel_masquerade(), ast_channel_priority(), ast_channel_readformat(), ast_channel_unlock, ast_channel_writeformat(), ast_do_masquerade(), ast_explicit_goto(), ast_format_copy(), ast_moh_stop(), ast_setstate(), and ast_strdupa.

Referenced by action_bridge(), and bridge_exec().

07231 {
07232    const char *context;
07233    const char *exten;
07234    int priority;
07235 
07236    ast_moh_stop(chan);
07237    ast_channel_lock_both(chan, tmpchan);
07238    context = ast_strdupa(ast_channel_context(chan));
07239    exten = ast_strdupa(ast_channel_exten(chan));
07240    priority = ast_channel_priority(chan);
07241    ast_setstate(tmpchan, ast_channel_state(chan));
07242    ast_format_copy(ast_channel_readformat(tmpchan), ast_channel_readformat(chan));
07243    ast_format_copy(ast_channel_writeformat(tmpchan), ast_channel_writeformat(chan));
07244    ast_channel_unlock(chan);
07245    ast_channel_unlock(tmpchan);
07246 
07247    /* Masquerade setup and execution must be done without any channel locks held */
07248    if (ast_channel_masquerade(tmpchan, chan)) {
07249       return -1;
07250    }
07251    ast_do_masquerade(tmpchan);
07252 
07253    /* when returning from bridge, the channel will continue at the next priority */
07254    ast_explicit_goto(tmpchan, context, exten, priority + 1);
07255 
07256    return 0;
07257 }

static void* do_parking_thread ( void *  ignore  )  [static]

Take care of parked calls and unpark them if needed.

Parameters:
ignore unused var.
Start inf loop, lock parking lot, check if any parked channels have gone above timeout if so, remove channel from parking lot and return it to the extension that parked it. Check if parked channel decided to hangup, wait until next FD via select().

Definition at line 5235 of file features.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_free, ast_poll, manage_parkinglot(), and parkinglots.

Referenced by ast_features_init().

05236 {
05237    struct pollfd *pfds = NULL, *new_pfds = NULL;
05238    int nfds = 0, new_nfds = 0;
05239 
05240    for (;;) {
05241       struct ao2_iterator iter;
05242       struct ast_parkinglot *curlot;
05243       int ms = -1;   /* poll2 timeout, uninitialized */
05244 
05245       iter = ao2_iterator_init(parkinglots, 0);
05246       while ((curlot = ao2_iterator_next(&iter))) {
05247          manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
05248          ao2_ref(curlot, -1);
05249       }
05250       ao2_iterator_destroy(&iter);
05251 
05252       /* Recycle */
05253       ast_free(pfds);
05254       pfds = new_pfds;
05255       nfds = new_nfds;
05256       new_pfds = NULL;
05257       new_nfds = 0;
05258 
05259       /* Wait for something to happen */
05260       ast_poll(pfds, nfds, ms);
05261       pthread_testcancel();
05262    }
05263    /* If this WERE reached, we'd need to free(pfds) */
05264    return NULL;   /* Never reached */
05265 }

static int feature_check ( struct ast_channel chan,
struct ast_flags features,
char *  code 
) [static]

Check if a feature exists.

Definition at line 3731 of file features.c.

References ast_channel_lock, ast_channel_unlock, ast_strdupa, FEATURE_INTERPRET_CHECK, feature_interpret_helper(), pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

03731                                                                                            {
03732    char *chan_dynamic_features;
03733    ast_channel_lock(chan);
03734    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03735    ast_channel_unlock(chan);
03736 
03737    return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL);
03738 }

static void feature_ds_destroy ( void *  data  )  [static]

Definition at line 3341 of file features.c.

References ao2_ref, ast_free, and feature_ds::feature_map.

Referenced by get_feature_ds().

03342 {
03343    struct feature_ds *feature_ds = data;
03344 
03345    if (feature_ds->feature_map) {
03346       ao2_ref(feature_ds->feature_map, -1);
03347       feature_ds->feature_map = NULL;
03348    }
03349 
03350    ast_free(feature_ds);
03351 }

static int feature_exec_app ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
void *  data 
) [static]

exec an app by feature

Parameters:
chan,peer,config,code,sense,data Find a feature, determine which channel activated
Return values:
AST_FEATURE_RETURN_NO_HANGUP_PEER 
-1 error.
-2 when an application cannot be found.

Todo:
XXX should probably return res

Definition at line 3468 of file features.c.

References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, AST_FRAME_DTMF_END, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), and ast_call_feature::sname.

Referenced by process_applicationmap_line().

03469 {
03470    struct ast_app *app;
03471    struct ast_call_feature *feature = data;
03472    struct ast_channel *work, *idle;
03473    int res;
03474 
03475    if (!feature) { /* shouldn't ever happen! */
03476       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
03477       return -1;
03478    }
03479 
03480    if (sense == FEATURE_SENSE_CHAN) {
03481       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
03482          return AST_FEATURE_RETURN_KEEPTRYING;
03483       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03484          work = chan;
03485          idle = peer;
03486       } else {
03487          work = peer;
03488          idle = chan;
03489       }
03490    } else {
03491       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
03492          return AST_FEATURE_RETURN_KEEPTRYING;
03493       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03494          work = peer;
03495          idle = chan;
03496       } else {
03497          work = chan;
03498          idle = peer;
03499       }
03500    }
03501 
03502    if (!(app = pbx_findapp(feature->app))) {
03503       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
03504       return -2;
03505    }
03506 
03507    ast_autoservice_start(idle);
03508    ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
03509 
03510    pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", ast_channel_name(idle));
03511    pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", ast_channel_name(work));
03512    pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
03513    pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
03514 
03515    if (!ast_strlen_zero(feature->moh_class))
03516       ast_moh_start(idle, feature->moh_class, NULL);
03517 
03518    res = pbx_exec(work, app, feature->app_args);
03519 
03520    if (!ast_strlen_zero(feature->moh_class))
03521       ast_moh_stop(idle);
03522 
03523    ast_autoservice_stop(idle);
03524 
03525    if (res) {
03526       return AST_FEATURE_RETURN_SUCCESSBREAK;
03527    }
03528    return AST_FEATURE_RETURN_SUCCESS;  /*! \todo XXX should probably return res */
03529 }

static int feature_exten_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 3366 of file features.c.

References CMP_MATCH, CMP_STOP, OBJ_KEY, and feature_exten::sname.

Referenced by get_feature_ds().

03367 {
03368    const struct feature_exten *fe = obj, *fe2 = arg;
03369    const char *sname = arg;
03370 
03371    return !strcmp(fe->sname, flags & OBJ_KEY ? sname : fe2->sname) ?
03372          CMP_MATCH | CMP_STOP : 0;
03373 }

static int feature_exten_hash ( const void *  obj,
int  flags 
) [static]

Definition at line 3358 of file features.c.

References ast_str_hash(), OBJ_KEY, and feature_exten::sname.

Referenced by get_feature_ds().

03359 {
03360    const struct feature_exten *fe = obj;
03361    const char *sname = obj;
03362 
03363    return ast_str_hash(flags & OBJ_KEY ? sname : fe->sname);
03364 }

static int feature_interpret ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense 
) [static]

Check the dynamic features.

Parameters:
chan,peer,config,code,sense 
Return values:
res on success.
-1 on failure.

Definition at line 3694 of file features.c.

References ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, FEATURE_INTERPRET_DO, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_flags::flags, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

03694                                                                                                                                                 {
03695 
03696    char dynamic_features_buf[128];
03697    const char *peer_dynamic_features, *chan_dynamic_features;
03698    struct ast_flags features;
03699    struct ast_call_feature feature;
03700    if (sense == FEATURE_SENSE_CHAN) {
03701       /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
03702       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
03703    }
03704    else {
03705       /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
03706       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
03707    }
03708 
03709    ast_channel_lock(peer);
03710    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
03711    ast_channel_unlock(peer);
03712 
03713    ast_channel_lock(chan);
03714    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03715    ast_channel_unlock(chan);
03716 
03717    snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,""));
03718 
03719    ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", ast_channel_name(chan), ast_channel_name(peer), code, sense, features.flags, dynamic_features_buf);
03720 
03721    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
03722 }

static int feature_interpret_helper ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
char *  dynamic_features_buf,
struct ast_flags features,
feature_interpret_op  operation,
struct ast_call_feature feature 
) [static]

Helper function for feature_interpret and ast_feature_detect.

Parameters:
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.
Return values:
res on success.
-1 on failure.

Definition at line 3569 of file features.c.

References ast_debug, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_STOREDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_strlen_zero(), ast_test_flag, ast_verb, builtin_feature_get_exten(), ast_call_feature::exten, feature_group_exten::exten, feature_group_exten::feature, FEATURE_INTERPRET_CHECK, FEATURE_INTERPRET_DO, ast_call_feature::feature_mask, FEATURE_MAX_LEN, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), find_group(), ast_call_feature::fname, ast_call_feature::operation, ast_call_feature::sname, and strsep().

Referenced by ast_feature_detect(), feature_check(), and feature_interpret().

03572 {
03573    int x;
03574    struct feature_group *fg = NULL;
03575    struct feature_group_exten *fge;
03576    struct ast_call_feature *tmpfeature;
03577    char *tmp, *tok;
03578    int res = AST_FEATURE_RETURN_PASSDIGITS;
03579    int feature_detected = 0;
03580 
03581    if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) {
03582       return -1; /* can not run feature operation */
03583    }
03584 
03585    ast_rwlock_rdlock(&features_lock);
03586    for (x = 0; x < FEATURES_COUNT; x++) {
03587       char feature_exten[FEATURE_MAX_LEN] = "";
03588 
03589       if (!ast_test_flag(features, builtin_features[x].feature_mask)) {
03590          continue;
03591       }
03592 
03593       if (builtin_feature_get_exten(chan, builtin_features[x].sname, feature_exten, sizeof(feature_exten))) {
03594          continue;
03595       }
03596 
03597       /* Feature is up for consideration */
03598 
03599       if (!strcmp(feature_exten, code)) {
03600          ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, feature_exten);
03601          if (operation == FEATURE_INTERPRET_CHECK) {
03602             res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
03603          } else if (operation == FEATURE_INTERPRET_DO) {
03604             res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
03605          }
03606          if (feature) {
03607             memcpy(feature, &builtin_features[x], sizeof(*feature));
03608          }
03609          feature_detected = 1;
03610          break;
03611       } else if (!strncmp(feature_exten, code, strlen(code))) {
03612          if (res == AST_FEATURE_RETURN_PASSDIGITS) {
03613             res = AST_FEATURE_RETURN_STOREDIGITS;
03614          }
03615       }
03616    }
03617    ast_rwlock_unlock(&features_lock);
03618 
03619    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
03620       return res;
03621    }
03622 
03623    tmp = dynamic_features_buf;
03624 
03625    while ((tok = strsep(&tmp, "#"))) {
03626       AST_RWLIST_RDLOCK(&feature_groups);
03627 
03628       fg = find_group(tok);
03629 
03630       if (fg) {
03631          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03632             if (!strcmp(fge->exten, code)) {
03633                if (operation) {
03634                   res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
03635                }
03636                if (feature) {
03637                   memcpy(feature, fge->feature, sizeof(*feature));
03638                }
03639                if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03640                   AST_RWLIST_UNLOCK(&feature_groups);
03641                   break;
03642                }
03643                res = AST_FEATURE_RETURN_PASSDIGITS;
03644             } else if (!strncmp(fge->exten, code, strlen(code))) {
03645                res = AST_FEATURE_RETURN_STOREDIGITS;
03646             }
03647          }
03648          if (fge) {
03649             break;
03650          }
03651       }
03652 
03653       AST_RWLIST_UNLOCK(&feature_groups);
03654 
03655       AST_RWLIST_RDLOCK(&feature_list);
03656 
03657       if (!(tmpfeature = find_dynamic_feature(tok))) {
03658          AST_RWLIST_UNLOCK(&feature_list);
03659          continue;
03660       }
03661 
03662       /* Feature is up for consideration */
03663       if (!strcmp(tmpfeature->exten, code)) {
03664          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
03665          if (operation == FEATURE_INTERPRET_CHECK) {
03666             res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
03667          } else if (operation == FEATURE_INTERPRET_DO) {
03668             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
03669          }
03670          if (feature) {
03671             memcpy(feature, tmpfeature, sizeof(*feature));
03672          }
03673          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03674             AST_RWLIST_UNLOCK(&feature_list);
03675             break;
03676          }
03677          res = AST_FEATURE_RETURN_PASSDIGITS;
03678       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
03679          res = AST_FEATURE_RETURN_STOREDIGITS;
03680 
03681       AST_RWLIST_UNLOCK(&feature_list);
03682    }
03683 
03684    return res;
03685 }

static int feature_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 8846 of file features.c.

References ast_log(), get_parkingtime(), and LOG_WARNING.

08848 {
08849    int res = 0;
08850 
08851    if (!strcasecmp(data, "parkingtime")) {
08852       snprintf(buf, len, "%u", get_parkingtime(chan, NULL) / 1000);
08853    } else {
08854       ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
08855       res = -1;
08856    }
08857 
08858    return res;
08859 }

static struct ast_channel * feature_request_and_dial ( struct ast_channel caller,
const char *  caller_name,
struct ast_channel requestor,
struct ast_channel transferee,
const char *  type,
struct ast_format_cap cap,
const char *  addr,
int  timeout,
int *  outstate,
const char *  language 
) [static, read]

Definition at line 3835 of file features.c.

References ast_alloca, ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_call_forward(), ast_channel_caller(), ast_channel_connected(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_exten(), ast_channel_hangupcause(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_name(), ast_channel_redirecting_macro(), ast_channel_redirecting_sub(), ast_channel_set_connected_line(), ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), ast_connected_line_parse_data(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_INCOMPLETE, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_PVT_CAUSE_CODE, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_format_cap_add(), ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_frisolate(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_is_deferrable_frame(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_party_connected_line_free(), ast_party_connected_line_set_init(), ast_poll_channel_add(), ast_poll_channel_del(), ast_queue_frame_head(), ast_read(), ast_request(), ast_rwlock_rdlock, ast_rwlock_unlock, AST_STATE_UP, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), cause, ast_frame::data, ast_frame::datalen, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_frame::frametype, ast_frame_subclass::integer, LOG_NOTICE, pbx_builtin_setvar_helper(), ast_frame::ptr, and ast_frame::subclass.

Referenced by builtin_atxfer().

03839 {
03840    int state = 0;
03841    int cause = 0;
03842    int to;
03843    int caller_hungup;
03844    int transferee_hungup;
03845    struct ast_channel *chan;
03846    struct ast_channel *monitor_chans[3];
03847    struct ast_channel *active_channel;
03848    int res;
03849    int ready = 0;
03850    struct timeval started;
03851    int x, len = 0;
03852    char *disconnect_code = NULL, *dialed_code = NULL;
03853    struct ast_format_cap *tmp_cap;
03854    struct ast_format best_audio_fmt;
03855    struct ast_frame *f;
03856    AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
03857 
03858    tmp_cap = ast_format_cap_alloc_nolock();
03859    if (!tmp_cap) {
03860       if (outstate) {
03861          *outstate = 0;
03862       }
03863       return NULL;
03864    }
03865    ast_best_codec(cap, &best_audio_fmt);
03866    ast_format_cap_add(tmp_cap, &best_audio_fmt);
03867 
03868    caller_hungup = ast_check_hangup(caller);
03869 
03870    if (!(chan = ast_request(type, tmp_cap, requestor, addr, &cause))) {
03871       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, addr);
03872       switch (cause) {
03873       case AST_CAUSE_BUSY:
03874          state = AST_CONTROL_BUSY;
03875          break;
03876       case AST_CAUSE_CONGESTION:
03877          state = AST_CONTROL_CONGESTION;
03878          break;
03879       default:
03880          state = 0;
03881          break;
03882       }
03883       goto done;
03884    }
03885 
03886    ast_channel_language_set(chan, language);
03887    ast_channel_inherit_variables(caller, chan);
03888    pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
03889 
03890    ast_channel_lock(chan);
03891    ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(requestor));
03892    ast_channel_unlock(chan);
03893 
03894    if (ast_call(chan, addr, timeout)) {
03895       ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, addr);
03896       switch (ast_channel_hangupcause(chan)) {
03897       case AST_CAUSE_BUSY:
03898          state = AST_CONTROL_BUSY;
03899          break;
03900       case AST_CAUSE_CONGESTION:
03901          state = AST_CONTROL_CONGESTION;
03902          break;
03903       default:
03904          state = 0;
03905          break;
03906       }
03907       goto done;
03908    }
03909 
03910    /* support dialing of the featuremap disconnect code while performing an attended tranfer */
03911    ast_rwlock_rdlock(&features_lock);
03912    for (x = 0; x < FEATURES_COUNT; x++) {
03913       if (strcasecmp(builtin_features[x].sname, "disconnect"))
03914          continue;
03915 
03916       disconnect_code = builtin_features[x].exten;
03917       len = strlen(disconnect_code) + 1;
03918       dialed_code = ast_alloca(len);
03919       memset(dialed_code, 0, len);
03920       break;
03921    }
03922    ast_rwlock_unlock(&features_lock);
03923    x = 0;
03924    started = ast_tvnow();
03925    to = timeout;
03926    AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
03927 
03928    ast_poll_channel_add(caller, chan);
03929 
03930    transferee_hungup = 0;
03931    while (!ast_check_hangup(transferee) && (ast_channel_state(chan) != AST_STATE_UP)) {
03932       int num_chans = 0;
03933 
03934       monitor_chans[num_chans++] = transferee;
03935       monitor_chans[num_chans++] = chan;
03936       if (!caller_hungup) {
03937          if (ast_check_hangup(caller)) {
03938             caller_hungup = 1;
03939 
03940 #if defined(ATXFER_NULL_TECH)
03941             /* Change caller's name to ensure that it will remain unique. */
03942             set_new_chan_name(caller);
03943 
03944             /*
03945              * Get rid of caller's physical technology so it is free for
03946              * other calls.
03947              */
03948             set_kill_chan_tech(caller);
03949 #endif   /* defined(ATXFER_NULL_TECH) */
03950          } else {
03951             /* caller is not hungup so monitor it. */
03952             monitor_chans[num_chans++] = caller;
03953          }
03954       }
03955 
03956       /* see if the timeout has been violated */
03957       if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
03958          state = AST_CONTROL_UNHOLD;
03959          ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", ast_channel_name(chan));
03960          break; /*doh! timeout*/
03961       }
03962 
03963       active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
03964       if (!active_channel)
03965          continue;
03966 
03967       f = NULL;
03968       if (transferee == active_channel) {
03969          struct ast_frame *dup_f;
03970 
03971          f = ast_read(transferee);
03972          if (f == NULL) { /*doh! where'd he go?*/
03973             transferee_hungup = 1;
03974             state = 0;
03975             break;
03976          }
03977          if (ast_is_deferrable_frame(f)) {
03978             dup_f = ast_frisolate(f);
03979             if (dup_f) {
03980                if (dup_f == f) {
03981                   f = NULL;
03982                }
03983                AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
03984             }
03985          }
03986       } else if (chan == active_channel) {
03987          if (!ast_strlen_zero(ast_channel_call_forward(chan))) {
03988             state = 0;
03989             ast_autoservice_start(transferee);
03990             chan = ast_call_forward(caller, chan, NULL, tmp_cap, NULL, &state);
03991             ast_autoservice_stop(transferee);
03992             if (!chan) {
03993                break;
03994             }
03995             continue;
03996          }
03997          f = ast_read(chan);
03998          if (f == NULL) { /*doh! where'd he go?*/
03999             switch (ast_channel_hangupcause(chan)) {
04000             case AST_CAUSE_BUSY:
04001                state = AST_CONTROL_BUSY;
04002                break;
04003             case AST_CAUSE_CONGESTION:
04004                state = AST_CONTROL_CONGESTION;
04005                break;
04006             default:
04007                state = 0;
04008                break;
04009             }
04010             break;
04011          }
04012 
04013          if (f->frametype == AST_FRAME_CONTROL) {
04014             if (f->subclass.integer == AST_CONTROL_RINGING) {
04015                ast_verb(3, "%s is ringing\n", ast_channel_name(chan));
04016                ast_indicate(caller, AST_CONTROL_RINGING);
04017             } else if (f->subclass.integer == AST_CONTROL_BUSY) {
04018                state = f->subclass.integer;
04019                ast_verb(3, "%s is busy\n", ast_channel_name(chan));
04020                ast_indicate(caller, AST_CONTROL_BUSY);
04021                ast_frfree(f);
04022                break;
04023             } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) {
04024                ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", ast_channel_name(chan), ast_channel_exten(chan));
04025             } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
04026                state = f->subclass.integer;
04027                ast_verb(3, "%s is congested\n", ast_channel_name(chan));
04028                ast_indicate(caller, AST_CONTROL_CONGESTION);
04029                ast_frfree(f);
04030                break;
04031             } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
04032                /* This is what we are hoping for */
04033                state = f->subclass.integer;
04034                ast_frfree(f);
04035                ready=1;
04036                break;
04037             } else if (f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
04038                ast_indicate_data(caller, AST_CONTROL_PVT_CAUSE_CODE, f->data.ptr, f->datalen);
04039             } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
04040                if (caller_hungup) {
04041                   struct ast_party_connected_line connected;
04042 
04043                   /* Just save it for the transfer. */
04044                   ast_party_connected_line_set_init(&connected, ast_channel_connected(caller));
04045                   res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
04046                      &connected);
04047                   if (!res) {
04048                      ast_channel_set_connected_line(caller, &connected, NULL);
04049                   }
04050                   ast_party_connected_line_free(&connected);
04051                } else {
04052                   ast_autoservice_start(transferee);
04053                   if (ast_channel_connected_line_sub(chan, caller, f, 1) &&
04054                      ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
04055                      ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
04056                         f->data.ptr, f->datalen);
04057                   }
04058                   ast_autoservice_stop(transferee);
04059                }
04060             } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
04061                if (!caller_hungup) {
04062                   ast_autoservice_start(transferee);
04063                   if (ast_channel_redirecting_sub(chan, caller, f, 1) &&
04064                      ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
04065                      ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
04066                         f->data.ptr, f->datalen);
04067                   }
04068                   ast_autoservice_stop(transferee);
04069                }
04070             } else if (f->subclass.integer != -1
04071                && f->subclass.integer != AST_CONTROL_PROGRESS
04072                && f->subclass.integer != AST_CONTROL_PROCEEDING) {
04073                ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
04074             }
04075             /* else who cares */
04076          } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
04077             ast_write(caller, f);
04078          }
04079       } else if (caller == active_channel) {
04080          f = ast_read(caller);
04081          if (f) {
04082             if (f->frametype == AST_FRAME_DTMF) {
04083                dialed_code[x++] = f->subclass.integer;
04084                dialed_code[x] = '\0';
04085                if (strlen(dialed_code) == len) {
04086                   x = 0;
04087                } else if (x && strncmp(dialed_code, disconnect_code, x)) {
04088                   x = 0;
04089                   dialed_code[x] = '\0';
04090                }
04091                if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
04092                   /* Caller Canceled the call */
04093                   state = AST_CONTROL_UNHOLD;
04094                   ast_frfree(f);
04095                   break;
04096                }
04097             } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
04098                ast_write(chan, f);
04099             }
04100          }
04101       }
04102       if (f)
04103          ast_frfree(f);
04104    } /* end while */
04105 
04106    ast_poll_channel_del(caller, chan);
04107 
04108    /*
04109     * We need to free all the deferred frames, but we only need to
04110     * queue the deferred frames if no hangup was received.
04111     */
04112    ast_channel_lock(transferee);
04113    transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
04114    while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
04115       if (!transferee_hungup) {
04116          ast_queue_frame_head(transferee, f);
04117       }
04118       ast_frfree(f);
04119    }
04120    ast_channel_unlock(transferee);
04121 
04122 done:
04123    ast_indicate(caller, -1);
04124    if (chan && (ready || ast_channel_state(chan) == AST_STATE_UP)) {
04125       state = AST_CONTROL_ANSWER;
04126    } else if (chan) {
04127       ast_hangup(chan);
04128       chan = NULL;
04129    }
04130 
04131    tmp_cap = ast_format_cap_destroy(tmp_cap);
04132 
04133    if (outstate)
04134       *outstate = state;
04135 
04136    return chan;
04137 }

static int feature_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Definition at line 8861 of file features.c.

References ast_channel_lock, ast_channel_unlock, ast_log(), get_feature_ds(), LOG_WARNING, feature_ds::parkingtime, and feature_ds::parkingtime_is_set.

08863 {
08864    int res = 0;
08865    struct feature_ds *feature_ds;
08866 
08867    ast_channel_lock(chan);
08868 
08869    if (!(feature_ds = get_feature_ds(chan))) {
08870       res = -1;
08871       goto return_cleanup;
08872    }
08873 
08874    if (!strcasecmp(data, "parkingtime")) {
08875       feature_ds->parkingtime_is_set = 1;
08876       if (sscanf(value, "%30u", &feature_ds->parkingtime) == 1) {
08877          feature_ds->parkingtime *= 1000; /* stored in ms */
08878       } else {
08879          ast_log(LOG_WARNING, "'%s' is not a valid parkingtime\n", value);
08880          feature_ds->parkingtime_is_set = 0;
08881          res = -1;
08882       }
08883    } else {
08884       ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
08885       res = -1;
08886    }
08887 
08888 return_cleanup:
08889    ast_channel_unlock(chan);
08890 
08891    return res;
08892 }

static int featuremap_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 8894 of file features.c.

References ast_log(), ast_rdlock_call_features(), ast_unlock_call_features(), builtin_feature_get_exten(), and LOG_WARNING.

08896 {
08897    int res;
08898 
08899    ast_rdlock_call_features();
08900 
08901    if ((res = builtin_feature_get_exten(chan, data, buf, len))) {
08902       ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
08903    }
08904 
08905    ast_unlock_call_features();
08906 
08907    return res;
08908 }

static int featuremap_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Definition at line 8910 of file features.c.

References ao2_alloc, ao2_find, ao2_link, ao2_lock, ao2_ref, ao2_unlock, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_find_call_feature(), ast_log(), feature_exten::exten, feature_ds::feature_map, get_feature_ds(), LOG_WARNING, OBJ_KEY, and feature_exten::sname.

08912 {
08913    struct feature_ds *feature_ds;
08914    struct feature_exten *fe;
08915 
08916    if (!ast_find_call_feature(data)) {
08917       ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
08918       return -1;
08919    }
08920 
08921    ast_channel_lock(chan);
08922 
08923    if (!(feature_ds = get_feature_ds(chan))) {
08924       ast_channel_unlock(chan);
08925       return -1;
08926    }
08927 
08928    if (!(fe = ao2_find(feature_ds->feature_map, data, OBJ_KEY))) {
08929       if (!(fe = ao2_alloc(sizeof(*fe), NULL))) {
08930          ast_channel_unlock(chan);
08931          return -1;
08932       }
08933       ast_copy_string(fe->sname, data, sizeof(fe->sname));
08934       ao2_link(feature_ds->feature_map, fe);
08935    }
08936 
08937    ast_channel_unlock(chan);
08938 
08939    ao2_lock(fe);
08940    ast_copy_string(fe->exten, value, sizeof(fe->exten));
08941    ao2_unlock(fe);
08942    ao2_ref(fe, -1);
08943    fe = NULL;
08944 
08945    return 0;
08946 }

static void features_shutdown ( void   )  [static]

static int find_channel_by_group ( void *  obj,
void *  arg,
void *  data,
int  flags 
) [static]

< Potential pickup target

< Channel wanting to pickup call

< Candidate channels found.

Definition at line 7706 of file features.c.

References ao2_link, ast_can_pickup(), ast_channel_callgroup(), ast_channel_lock, ast_channel_named_callgroups(), ast_channel_named_pickupgroups(), ast_channel_pickupgroup(), ast_channel_trylock, ast_channel_unlock, and ast_namedgroups_intersect().

Referenced by ast_pickup_find_by_group().

07707 {
07708    struct ast_channel *target = obj;/*!< Potential pickup target */
07709    struct ast_channel *chan = arg;/*!< Channel wanting to pickup call */
07710 
07711    if (chan == target) {
07712       return 0;
07713    }
07714 
07715    ast_channel_lock(target);
07716    if (ast_can_pickup(target)) {
07717       /* Lock both channels. */
07718       while (ast_channel_trylock(chan)) {
07719          ast_channel_unlock(target);
07720          sched_yield();
07721          ast_channel_lock(target);
07722       }
07723 
07724       /*
07725        * Both callgroup and namedcallgroup pickup variants are
07726        * matched independently.  Checking for named group match is
07727        * done last since it's a more expensive operation.
07728        */
07729       if ((ast_channel_pickupgroup(chan) & ast_channel_callgroup(target))
07730          || (ast_namedgroups_intersect(ast_channel_named_pickupgroups(chan),
07731             ast_channel_named_callgroups(target)))) {
07732          struct ao2_container *candidates = data;/*!< Candidate channels found. */
07733 
07734          /* This is a candidate to pickup */
07735          ao2_link(candidates, target);
07736       }
07737       ast_channel_unlock(chan);
07738    }
07739    ast_channel_unlock(target);
07740 
07741    return 0;
07742 }

static struct ast_call_feature* find_dynamic_feature ( const char *  name  )  [static, read]

find a call feature by name

Definition at line 3247 of file features.c.

References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.

Referenced by ast_find_call_feature(), feature_interpret_helper(), process_applicationmap_line(), process_config(), and set_config_flags().

03248 {
03249    struct ast_call_feature *tmp;
03250 
03251    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
03252       if (!strcasecmp(tmp->sname, name)) {
03253          break;
03254       }
03255    }
03256 
03257    return tmp;
03258 }

static struct feature_group* find_group ( const char *  name  )  [static, read]

Find a group by name.

Parameters:
name feature name
Return values:
feature group on success.
NULL on failure.

Definition at line 3285 of file features.c.

References AST_LIST_TRAVERSE, and feature_group::gname.

Referenced by feature_interpret_helper().

03286 {
03287    struct feature_group *fg = NULL;
03288 
03289    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
03290       if (!strcasecmp(fg->gname, name))
03291          break;
03292    }
03293 
03294    return fg;
03295 }

static struct ast_parkinglot * find_parkinglot ( const char *  name  )  [static, read]

Find parkinglot by name.

Definition at line 5268 of file features.c.

References ao2_find, ast_debug, ast_strlen_zero(), ast_parkinglot::name, and parkinglots.

Referenced by ast_masq_park_call_exten(), ast_park_call_exten(), build_parkinglot(), copy_parkinglot(), create_dynamic_parkinglot(), get_parkingtime(), manager_park(), park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().

05269 {
05270    struct ast_parkinglot *parkinglot;
05271 
05272    if (ast_strlen_zero(name)) {
05273       return NULL;
05274    }
05275 
05276    parkinglot = ao2_find(parkinglots, (void *) name, 0);
05277    if (parkinglot) {
05278       ast_debug(1, "Found Parking lot: %s\n", parkinglot->name);
05279    }
05280 
05281    return parkinglot;
05282 }

static const char* findparkinglotname ( struct ast_channel chan  )  [static]

Find parking lot name from channel.

Note:
Channel needs to be locked while the returned string is in use.

Definition at line 1232 of file features.c.

References ast_channel_parkinglot(), ast_strlen_zero(), name, and pbx_builtin_getvar_helper().

Referenced by park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().

01233 {
01234    const char *name;
01235 
01236    /* The channel variable overrides everything */
01237    name = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
01238    if (!name && !ast_strlen_zero(ast_channel_parkinglot(chan))) {
01239       /* Use the channel's parking lot. */
01240       name = ast_channel_parkinglot(chan);
01241    }
01242    return name;
01243 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 2036 of file features.c.

References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().

Referenced by atxfer_fail_cleanup(), builtin_atxfer(), builtin_blindtransfer(), and xfer_park_call_helper().

02037 {
02038    ast_indicate(chan, AST_CONTROL_UNHOLD);
02039 
02040    return ast_autoservice_stop(chan);
02041 }

static struct feature_ds* get_feature_ds ( struct ast_channel chan  )  [static, read]

Definition at line 3383 of file features.c.

References ao2_container_alloc, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_datastore_alloc, ast_datastore::data, feature_ds_destroy(), feature_exten_cmp(), feature_exten_hash(), and feature_ds::feature_map.

Referenced by builtin_feature_get_exten(), feature_write(), featuremap_write(), and get_parkingtime().

03384 {
03385    struct feature_ds *feature_ds;
03386    struct ast_datastore *ds;
03387 
03388    if ((ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
03389       feature_ds = ds->data;
03390       return feature_ds;
03391    }
03392 
03393    if (!(feature_ds = ast_calloc(1, sizeof(*feature_ds)))) {
03394       return NULL;
03395    }
03396 
03397    if (!(feature_ds->feature_map = ao2_container_alloc(7, feature_exten_hash, feature_exten_cmp))) {
03398       feature_ds_destroy(feature_ds);
03399       return NULL;
03400    }
03401 
03402    if (!(ds = ast_datastore_alloc(&feature_ds_info, NULL))) {
03403       feature_ds_destroy(feature_ds);
03404       return NULL;
03405    }
03406 
03407    ds->data = feature_ds;
03408 
03409    ast_channel_datastore_add(chan, ds);
03410 
03411    return feature_ds;
03412 }

static struct ast_exten* get_parking_exten ( const char *  exten_str,
struct ast_channel chan,
const char *  context 
) [static, read]

Definition at line 960 of file features.c.

References ast_debug, ast_get_extension_app(), E_MATCH, parkcall, pbx_find_extension(), and pbx_find_info::stacklen.

Referenced by ast_masq_park_call_exten(), ast_park_call_exten(), ast_parking_ext_valid(), builtin_atxfer(), and builtin_blindtransfer().

00961 {
00962    struct ast_exten *exten;
00963    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
00964    const char *app_at_exten;
00965 
00966    ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context);
00967    exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
00968       E_MATCH);
00969    if (!exten) {
00970       return NULL;
00971    }
00972 
00973    app_at_exten = ast_get_extension_app(exten);
00974    if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) {
00975       return NULL;
00976    }
00977 
00978    return exten;
00979 }

static unsigned int get_parkingtime ( struct ast_channel chan,
struct ast_parkinglot parkinglot 
) [static]

Definition at line 8807 of file features.c.

References ast_channel_lock, ast_channel_parkinglot(), ast_channel_unlock, ast_strdupa, ast_strlen_zero(), ast_parkinglot::cfg, default_parkinglot, find_parkinglot(), get_feature_ds(), parkinglot_addref(), parkinglot_unref(), parkinglot_cfg::parkingtime, feature_ds::parkingtime, feature_ds::parkingtime_is_set, and S_OR.

Referenced by feature_read(), and park_call_full().

08808 {
08809    const char *parkinglot_name;
08810    struct feature_ds *feature_ds;
08811    unsigned int parkingtime;
08812 
08813    ast_channel_lock(chan);
08814 
08815    feature_ds = get_feature_ds(chan);
08816    if (feature_ds && feature_ds->parkingtime_is_set) {
08817       parkingtime = feature_ds->parkingtime;
08818       ast_channel_unlock(chan);
08819       return parkingtime;
08820    }
08821 
08822    parkinglot_name = ast_strdupa(S_OR(ast_channel_parkinglot(chan), ""));
08823 
08824    ast_channel_unlock(chan);
08825 
08826    if (!parkinglot) {
08827       if (!ast_strlen_zero(parkinglot_name)) {
08828          parkinglot = find_parkinglot(parkinglot_name);
08829       }
08830 
08831       if (!parkinglot) {
08832          parkinglot = parkinglot_addref(default_parkinglot);
08833       }
08834    } else {
08835       /* Just to balance the unref below */
08836       parkinglot_addref(parkinglot);
08837    }
08838 
08839    parkingtime = parkinglot->cfg.parkingtime;
08840 
08841    parkinglot_unref(parkinglot);
08842 
08843    return parkingtime;
08844 }

static char* handle_feature_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command to list configured features.

Parameters:
e 
cmd 
a 
Return values:
CLI_SUCCESS on success.
NULL when tab completion is used.

Definition at line 7089 of file features.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), AST_CLI_YESNO, AST_LIST_TRAVERSE, ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_parkinglot::cfg, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, parkinglot_cfg::comebackcontext, parkinglot_cfg::comebackdialtime, parkinglot_cfg::comebacktoorigin, ast_cli_entry::command, ast_call_feature::default_exten, ast_parkinglot::disabled, feature_group_exten::exten, ast_call_feature::exten, ast_cli_args::fd, feature_group_exten::feature, feature_group::features, FEATURES_COUNT, features_lock, ast_call_feature::fname, feature_group::gname, HFS_FORMAT, parkinglot_cfg::mohclass, ast_parkinglot::name, parkinglot_cfg::parkext, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglots, parkinglot_cfg::parkingtime, ast_call_feature::sname, and ast_cli_entry::usage.

07090 {
07091    int i;
07092    struct ast_call_feature *feature;
07093    struct ao2_iterator iter;
07094    struct ast_parkinglot *curlot;
07095 #define HFS_FORMAT "%-25s %-7s %-7s\n"
07096 
07097    switch (cmd) {
07098 
07099    case CLI_INIT:
07100       e->command = "features show";
07101       e->usage =
07102          "Usage: features show\n"
07103          "       Lists configured features\n";
07104       return NULL;
07105    case CLI_GENERATE:
07106       return NULL;
07107    }
07108 
07109    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
07110    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
07111 
07112    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
07113 
07114    ast_rwlock_rdlock(&features_lock);
07115    for (i = 0; i < FEATURES_COUNT; i++)
07116       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
07117    ast_rwlock_unlock(&features_lock);
07118 
07119    ast_cli(a->fd, "\n");
07120    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
07121    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
07122    if (AST_RWLIST_EMPTY(&feature_list)) {
07123       ast_cli(a->fd, "(none)\n");
07124    } else {
07125       AST_RWLIST_RDLOCK(&feature_list);
07126       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
07127          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
07128       }
07129       AST_RWLIST_UNLOCK(&feature_list);
07130    }
07131 
07132    ast_cli(a->fd, "\nFeature Groups:\n");
07133    ast_cli(a->fd, "---------------\n");
07134    if (AST_RWLIST_EMPTY(&feature_groups)) {
07135       ast_cli(a->fd, "(none)\n");
07136    } else {
07137       struct feature_group *fg;
07138       struct feature_group_exten *fge;
07139 
07140       AST_RWLIST_RDLOCK(&feature_groups);
07141       AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
07142          ast_cli(a->fd, "===> Group: %s\n", fg->gname);
07143          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
07144             ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
07145          }
07146       }
07147       AST_RWLIST_UNLOCK(&feature_groups);
07148    }
07149 
07150    iter = ao2_iterator_init(parkinglots, 0);
07151    while ((curlot = ao2_iterator_next(&iter))) {
07152       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
07153       ast_cli(a->fd, "------------\n");
07154       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", curlot->cfg.parkext);
07155       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->cfg.parking_con);
07156       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions",
07157          curlot->cfg.parking_start, curlot->cfg.parking_stop);
07158       ast_cli(a->fd,"%-22s:      %u ms\n", "Parkingtime", curlot->cfg.parkingtime);
07159       ast_cli(a->fd,"%-22s:      %s\n", "Comeback to origin",
07160             (curlot->cfg.comebacktoorigin ? "yes" : "no"));
07161       ast_cli(a->fd,"%-22s:      %s%s\n", "Comeback context",
07162             curlot->cfg.comebackcontext, (curlot->cfg.comebacktoorigin ?
07163                " (comebacktoorigin=yes, not used)" : ""));
07164       ast_cli(a->fd,"%-22s:      %d\n", "Comeback dial time",
07165             curlot->cfg.comebackdialtime);
07166       ast_cli(a->fd,"%-22s:      %s\n", "MusicOnHold class", curlot->cfg.mohclass);
07167       ast_cli(a->fd,"%-22s:      %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled));
07168       ast_cli(a->fd,"\n");
07169       ao2_ref(curlot, -1);
07170    }
07171    ao2_iterator_destroy(&iter);
07172 
07173    return CLI_SUCCESS;
07174 }

static char* handle_features_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7202 of file features.c.

References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.

07203 {
07204    switch (cmd) {
07205    case CLI_INIT:
07206       e->command = "features reload";
07207       e->usage =
07208          "Usage: features reload\n"
07209          "       Reloads configured call features from features.conf\n";
07210       return NULL;
07211    case CLI_GENERATE:
07212       return NULL;
07213    }
07214    ast_features_reload();
07215 
07216    return CLI_SUCCESS;
07217 }

static char* handle_parkedcalls ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command to list parked calls.

Parameters:
e 
cmd 
a Check right usage, lock parking lot, display parked calls, unlock parking lot list.
Return values:
CLI_SUCCESS on success.
CLI_SHOWUSAGE on incorrect number of arguments.
NULL when tab completion is used.

Definition at line 7421 of file features.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_entry::args, ast_channel_name(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, parkeduser::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, parkeduser::context, default_parkinglot, ESS, parkeduser::exten, ast_cli_args::fd, ast_parkinglot::name, parkeduser::parkingexten, parkinglots, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.

07422 {
07423    struct parkeduser *cur;
07424    int numparked = 0;
07425    struct ao2_iterator iter;
07426    struct ast_parkinglot *curlot;
07427 
07428    switch (cmd) {
07429    case CLI_INIT:
07430       e->command = "parkedcalls show";
07431       e->usage =
07432          "Usage: parkedcalls show\n"
07433          "       List currently parked calls\n";
07434       return NULL;
07435    case CLI_GENERATE:
07436       return NULL;
07437    }
07438 
07439    if (a->argc > e->args)
07440       return CLI_SHOWUSAGE;
07441 
07442    ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel",
07443       "Context", "Extension", "Pri", "Timeout");
07444 
07445    iter = ao2_iterator_init(parkinglots, 0);
07446    while ((curlot = ao2_iterator_next(&iter))) {
07447       int lotparked = 0;
07448 
07449       /* subtract ref for iterator and for configured parking lot */
07450       ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name,
07451          ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot));
07452 
07453       AST_LIST_LOCK(&curlot->parkings);
07454       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
07455          ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n",
07456             cur->parkingexten, ast_channel_name(cur->chan), cur->context, cur->exten,
07457             cur->priority,
07458             (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL)));
07459          ++lotparked;
07460       }
07461       AST_LIST_UNLOCK(&curlot->parkings);
07462       if (lotparked) {
07463          numparked += lotparked;
07464          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked,
07465             ESS(lotparked), curlot->name);
07466       }
07467 
07468       ao2_ref(curlot, -1);
07469    }
07470    ao2_iterator_destroy(&iter);
07471 
07472    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
07473 
07474    return CLI_SUCCESS;
07475 }

static int load_config ( int  reload  )  [static]

Definition at line 7007 of file features.c.

References ao2_t_callback, ast_config_destroy(), ast_config_load2(), ast_debug, AST_LIST_HEAD_NOLOCK_INIT_VALUE, ast_log(), build_dialplan_useage_map(), build_parkinglot(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_PARKINGLOT, default_parkinglot, destroy_dialplan_usage_map(), force_reload_load, LOG_ERROR, LOG_WARNING, OBJ_NODATA, OBJ_UNLINK, parkinglot_activate_cb(), parkinglot_is_marked_cb(), parkinglot_markall_cb(), parkinglots, process_config(), and remove_dead_dialplan_useage().

07008 {
07009    struct ast_flags config_flags = {
07010       reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 };
07011    struct ast_config *cfg;
07012    struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
07013    struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
07014 
07015    /* We are reloading now and have already determined if we will force the reload. */
07016    force_reload_load = 0;
07017 
07018    if (!default_parkinglot) {
07019       /* Must create the default default parking lot */
07020       default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
07021       if (!default_parkinglot) {
07022          ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n");
07023          return -1;
07024       }
07025       ast_debug(1, "Configuration of default default parking lot done.\n");
07026    }
07027 
07028    cfg = ast_config_load2("features.conf", "features", config_flags);
07029    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
07030       /* No sense in asking for reload trouble if nothing changed. */
07031       ast_debug(1, "features.conf did not change.\n");
07032       return 0;
07033    }
07034    if (cfg == CONFIG_STATUS_FILEMISSING
07035       || cfg == CONFIG_STATUS_FILEINVALID) {
07036       ast_log(LOG_WARNING, "Could not load features.conf\n");
07037       return 0;
07038    }
07039 
07040    /* Save current parking lot dialplan needs. */
07041    if (build_dialplan_useage_map(&old_usage_map, 0)) {
07042       destroy_dialplan_usage_map(&old_usage_map);
07043 
07044       /* Allow reloading later to see if conditions have improved. */
07045       force_reload_load = 1;
07046       return -1;
07047    }
07048 
07049    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL,
07050       "callback to mark all parking lots");
07051    process_config(cfg);
07052    ast_config_destroy(cfg);
07053    ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL,
07054       "callback to remove marked parking lots");
07055 
07056    /* Save updated parking lot dialplan needs. */
07057    if (build_dialplan_useage_map(&new_usage_map, 1)) {
07058       /*
07059        * Yuck, if this failure caused any parking lot dialplan items
07060        * to be lost, they will likely remain lost until Asterisk is
07061        * restarted.
07062        */
07063       destroy_dialplan_usage_map(&old_usage_map);
07064       destroy_dialplan_usage_map(&new_usage_map);
07065       return -1;
07066    }
07067 
07068    /* Remove no longer needed parking lot dialplan usage. */
07069    remove_dead_dialplan_useage(&old_usage_map, &new_usage_map);
07070 
07071    destroy_dialplan_usage_map(&old_usage_map);
07072    destroy_dialplan_usage_map(&new_usage_map);
07073 
07074    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL,
07075       "callback to activate all parking lots");
07076 
07077    return 0;
07078 }

static int manage_parked_call ( struct parkeduser pu,
const struct pollfd *  pfds,
int  nfds,
struct pollfd **  new_pfds,
int *  new_nfds,
int *  ms 
) [static]

Definition at line 4962 of file features.c.

References ast_add_extension(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_context(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_fd(), ast_channel_fd_isset(), ast_channel_fdno_set(), ast_channel_flags(), ast_channel_generatordata(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_unlock, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_debug, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, ast_pbx_start(), ast_read(), ast_realloc, ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, callback_dialoptions(), ast_parkinglot::cfg, parkeduser::chan, parkinglot_cfg::comebackcontext, parkinglot_cfg::comebackdialtime, parkinglot_cfg::comebacktoorigin, parkeduser::context, ast_datastore::data, dial_features_info, parkeduser::exten, f, ast_frame::frametype, parkeduser::hold_method, ast_frame_subclass::integer, LOG_ERROR, LOG_NOTICE, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, parkinglot_cfg::mohclass, ast_dial_features::my_features, ast_parkinglot::name, parkeduser::options_specified, parking_con_dial, parkeduser::parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_setvar_helper(), ast_dial_features::peer_features, parkeduser::peername, post_manager_event(), parkeduser::priority, registrar, S_OR, set_c_e_p(), parkeduser::start, and ast_frame::subclass.

Referenced by manage_parkinglot().

04963 {
04964    struct ast_channel *chan = pu->chan;   /* shorthand */
04965    int tms;        /* timeout for this item */
04966    int x;          /* fd index in channel */
04967 
04968    tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04969    if (tms > pu->parkingtime) {
04970       /*
04971        * Call has been parked too long.
04972        * Stop entertaining the caller.
04973        */
04974       switch (pu->hold_method) {
04975       case AST_CONTROL_HOLD:
04976          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04977          break;
04978       case AST_CONTROL_RINGING:
04979          ast_indicate(pu->chan, -1);
04980          break;
04981       default:
04982          break;
04983       }
04984       pu->hold_method = 0;
04985 
04986       /* Get chan, exten from derived kludge */
04987       if (pu->peername[0]) {
04988          char *peername;
04989          char *dash;
04990          char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
04991          int i;
04992 
04993          peername = ast_strdupa(pu->peername);
04994          dash = strrchr(peername, '-');
04995          if (dash) {
04996             *dash = '\0';
04997          }
04998 
04999          peername_flat = ast_strdupa(peername);
05000          for (i = 0; peername_flat[i]; i++) {
05001             if (peername_flat[i] == '/') {
05002                peername_flat[i] = '_';
05003             }
05004          }
05005 
05006          if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) {
05007             ast_log(LOG_ERROR,
05008                "Parking dial context '%s' does not exist and unable to create\n",
05009                parking_con_dial);
05010          } else {
05011             char returnexten[AST_MAX_EXTENSION];
05012             char comebackdialtime[AST_MAX_EXTENSION];
05013             struct ast_datastore *features_datastore;
05014             struct ast_dial_features *dialfeatures;
05015 
05016             if (!strncmp(peername, "Parked/", 7)) {
05017                peername += 7;
05018             }
05019 
05020             ast_channel_lock(chan);
05021             features_datastore = ast_channel_datastore_find(chan, &dial_features_info,
05022                NULL);
05023             if (features_datastore && (dialfeatures = features_datastore->data)) {
05024                char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
05025 
05026                snprintf(returnexten, sizeof(returnexten), "%s,%u,%s", peername,
05027                   pu->parkinglot->cfg.comebackdialtime,
05028                   callback_dialoptions(&dialfeatures->peer_features,
05029                      &dialfeatures->my_features, buf, sizeof(buf)));
05030             } else { /* Existing default */
05031                ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n",
05032                   ast_channel_name(chan));
05033                snprintf(returnexten, sizeof(returnexten), "%s,%u,t", peername,
05034                   pu->parkinglot->cfg.comebackdialtime);
05035             }
05036             ast_channel_unlock(chan);
05037 
05038             snprintf(comebackdialtime, sizeof(comebackdialtime), "%u",
05039                   pu->parkinglot->cfg.comebackdialtime);
05040             pbx_builtin_setvar_helper(chan, "COMEBACKDIALTIME", comebackdialtime);
05041 
05042             pbx_builtin_setvar_helper(chan, "PARKER", peername);
05043 
05044             if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL,
05045                "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) {
05046                ast_log(LOG_ERROR,
05047                   "Could not create parking return dial exten: %s@%s\n",
05048                   peername_flat, parking_con_dial);
05049             }
05050          }
05051          if (pu->options_specified) {
05052             /*
05053              * Park() was called with overriding return arguments, respect
05054              * those arguments.
05055              */
05056             set_c_e_p(chan, pu->context, pu->exten, pu->priority);
05057          } else if (pu->parkinglot->cfg.comebacktoorigin) {
05058             set_c_e_p(chan, parking_con_dial, peername_flat, 1);
05059          } else {
05060             char parkingslot[AST_MAX_EXTENSION];
05061 
05062             snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
05063             pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
05064             pbx_builtin_setvar_helper(chan, "PARKEDLOT", pu->parkinglot->name);
05065             set_c_e_p(chan, pu->parkinglot->cfg.comebackcontext, peername_flat, 1);
05066          }
05067       } else {
05068          /*
05069           * They've been waiting too long, send them back to where they
05070           * came.  Theoretically they should have their original
05071           * extensions and such, but we copy to be on the safe side.
05072           */
05073          set_c_e_p(chan, pu->context, pu->exten, pu->priority);
05074       }
05075       post_manager_event("ParkedCallTimeOut", pu);
05076       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
05077 
05078       ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n",
05079          ast_channel_name(pu->chan), pu->parkingnum, pu->parkinglot->name, ast_channel_context(pu->chan),
05080          ast_channel_exten(pu->chan), ast_channel_priority(pu->chan));
05081 
05082       /* Start up the PBX, or hang them up */
05083       if (ast_pbx_start(chan))  {
05084          ast_log(LOG_WARNING,
05085             "Unable to restart the PBX for user on '%s', hanging them up...\n",
05086             ast_channel_name(pu->chan));
05087          ast_hangup(chan);
05088       }
05089 
05090       /* And take them out of the parking lot */
05091       return 1;
05092    }
05093 
05094    /* still within parking time, process descriptors */
05095    if (pfds) {
05096       for (x = 0; x < AST_MAX_FDS; x++) {
05097          struct ast_frame *f;
05098          int y;
05099 
05100          if (!ast_channel_fd_isset(chan, x)) {
05101             continue;   /* nothing on this descriptor */
05102          }
05103 
05104          for (y = 0; y < nfds; y++) {
05105             if (pfds[y].fd == ast_channel_fd(chan, x)) {
05106                /* Found poll record! */
05107                break;
05108             }
05109          }
05110          if (y == nfds) {
05111             /* Not found */
05112             continue;
05113          }
05114 
05115          if (!(pfds[y].revents & (