Thu Sep 7 01:03:28 2017

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"

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

static int action_bridge (struct mansession *s, const struct message *m)
 Bridge channels together.
static int add_features_datastore (struct ast_channel *chan, const struct ast_flags *my_features, const struct ast_flags *peer_features)
static void add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
 Announce call parking by ADSI.
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 bridge the call and set CDR
void ast_bridge_end_dtmf (struct ast_channel *chan, char digit, struct timeval start, const char *why)
 Simulate a DTMF end on a broken bridge channel.
int ast_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit)
 parse L option and read associated channel variables to set warning, warning frequency, and timelimit
int ast_can_pickup (struct ast_channel *chan)
 Test if a channel can be picked up.
void ast_channel_log (char *title, struct ast_channel *chan)
int ast_do_pickup (struct ast_channel *chan, struct ast_channel *target)
 Pickup a call target.
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature)
 detect a feature before bridging
int ast_features_init (void)
int ast_features_reload (void)
 Reload call features from features.conf.
struct ast_call_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.
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_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 int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 exec an app by feature
static int feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense)
 Check the dynamic features.
static int feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, feature_interpret_op operation, struct ast_call_feature *feature)
 Helper function for feature_interpret and ast_feature_detect.
static struct ast_channelfeature_request_and_dial (struct ast_channel *caller, const char *caller_name, struct ast_channel *requestor, struct ast_channel *transferee, const char *type, format_t format, void *data, int timeout, int *outstate, const char *language)
static void features_shutdown (void)
static int find_channel_by_group (void *obj, void *arg, void *data, int flags)
static struct ast_call_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 ast_extenget_parking_exten (const char *exten_str, struct ast_channel *chan, const char *context)
static char * handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list configured features.
static char * handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list parked calls.
static int load_config (int reload)
static int manage_parked_call (struct parkeduser *pu, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
static void manage_parkinglot (struct ast_parkinglot *curlot, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
 Run management on parkinglots, called once per parkinglot.
static int manager_park (struct mansession *s, const struct message *m)
 Create manager event for parked calls.
static int manager_parking_status (struct mansession *s, const struct message *m)
 Dump parking lot status.
static int masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
 Park call via masqueraded channel and announce parking spot on peer channel.
static enum ast_device_state metermaidstate (const char *data)
 metermaids callback from devicestate.c
static void notify_metermaids (const char *exten, char *context, enum ast_device_state state)
 Notify metermaids that we've changed an extension.
static void park_add_hints (const char *context, int start, int stop)
 Add parking hints for all defined parking spaces.
static int park_call_exec (struct ast_channel *chan, const char *data)
 Park a call.
static int park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
static void park_space_abort (struct parkeduser *pu)
static struct 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_channel *peer, struct ast_bridge_config *config)
static void set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense)
 set caller and callee according to the direction
static void unmap_features (void)
static int usage_context_add_ramp (struct parking_dp_ramp_map *ramp_map, const char *exten, int exclusive, struct ast_parkinglot *lot, int complain)
static int usage_context_add_spaces (struct parking_dp_space_map *space_map, int start, int stop, struct ast_parkinglot *lot, int complain)
static int xfer_park_call_helper (struct ast_channel *park_me, struct ast_channel *parker, struct ast_exten *park_exten)

Variables

static int adsipark
static char * app_bridge = "Bridge"
static unsigned int atxfercallbackretries
static unsigned int atxferdropcall
static unsigned int atxferloopdelay
static int atxfernoanswertimeout
static struct ast_app_option bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, }
static struct ast_call_feature builtin_features []
static struct ast_datastore_info channel_app_data_datastore
static struct ast_cli_entry cli_features []
static int comebacktoorigin = 1
static char courtesytone [256]
static struct ast_parkinglotdefault_parkinglot
 Default parking lot.
static struct ast_datastore_info dial_features_info
static int featuredigittimeout
static ast_rwlock_t features_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 }
static ast_mutex_t features_reload_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static int force_reload_load
static struct ast_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 char parkingretalertinfo [256]
static char parkingretcidname [256]
static char parkingretdahdiring [3]
static struct ast_datastore_info pickup_active
static char pickup_ext [AST_MAX_EXTENSION]
static char pickupfailsound [256]
static char pickupsound [256]
static char * registrar = "features"
static struct ast_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 392 of file features.c.

#define DEFAULT_ATXFER_CALLBACK_RETRIES   2

Definition at line 390 of file features.c.

Referenced by process_config().

#define DEFAULT_ATXFER_DROP_CALL   0

Do not drop call.

Definition at line 388 of file features.c.

Referenced by process_config().

#define DEFAULT_ATXFER_LOOP_DELAY   10000

ms

Definition at line 389 of file features.c.

Referenced by process_config().

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

ms

Definition at line 386 of file features.c.

Referenced by process_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

ms

Definition at line 387 of file features.c.

Referenced by process_config().

#define DEFAULT_PARK_EXTENSION   "700"

Definition at line 384 of file features.c.

#define DEFAULT_PARK_TIME   45000

ms

Definition at line 383 of file features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

ms

Definition at line 385 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 393 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 

Definition at line 7495 of file features.c.

07495      {
07496    BRIDGE_OPT_PLAYTONE = (1 << 0),
07497    OPT_CALLEE_HANGUP =  (1 << 1),
07498    OPT_CALLER_HANGUP =  (1 << 2),
07499    OPT_DURATION_LIMIT = (1 << 3),
07500    OPT_DURATION_STOP =  (1 << 4),
07501    OPT_CALLEE_TRANSFER = (1 << 5),
07502    OPT_CALLER_TRANSFER = (1 << 6),
07503    OPT_CALLEE_MONITOR = (1 << 7),
07504    OPT_CALLER_MONITOR = (1 << 8),
07505    OPT_CALLEE_PARK = (1 << 9),
07506    OPT_CALLER_PARK = (1 << 10),
07507    OPT_CALLEE_KILL = (1 << 11),
07508 };

anonymous enum
Enumerator:
OPT_ARG_DURATION_LIMIT 
OPT_ARG_DURATION_STOP 
OPT_ARG_ARRAY_SIZE 

Definition at line 7510 of file features.c.

07510      {
07511    OPT_ARG_DURATION_LIMIT = 0,
07512    OPT_ARG_DURATION_STOP,
07513    /* note: this entry _MUST_ be the last one in the enum */
07514    OPT_ARG_ARRAY_SIZE,
07515 };

Options to pass to park_call_full

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 1125 of file features.c.

01125                            {
01126    /*! Provide ringing to the parked caller instead of music on hold */
01127    AST_PARK_OPT_RINGING =   (1 << 0),
01128    /*! Randomly choose a parking spot for the caller instead of choosing
01129     *  the first one that is available. */
01130    AST_PARK_OPT_RANDOMIZE = (1 << 1),
01131    /*! Do not announce the parking number */
01132    AST_PARK_OPT_SILENCE = (1 << 2),
01133 };

Enumerator:
FEATURE_INTERPRET_DETECT 
FEATURE_INTERPRET_DO 
FEATURE_INTERPRET_CHECK 

Definition at line 413 of file features.c.

00413              {
00414    FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */
00415    FEATURE_INTERPRET_DO,     /* Used by feature_interpret */
00416    FEATURE_INTERPRET_CHECK,  /* Used by feature_check */
00417 } feature_interpret_op;


Function Documentation

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 6975 of file features.c.

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

Referenced by ast_features_init().

06976 {
06977    const char *channela = astman_get_header(m, "Channel1");
06978    const char *channelb = astman_get_header(m, "Channel2");
06979    const char *playtone = astman_get_header(m, "Tone");
06980    struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
06981    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
06982    struct ast_bridge_thread_obj *tobj = NULL;
06983    char buf[256];
06984 
06985    /* make sure valid channels were specified */
06986    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
06987       astman_send_error(s, m, "Missing channel parameter in request");
06988       return 0;
06989    }
06990 
06991    /* Start with chana */
06992    chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
06993    if (!chana) {
06994       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
06995       astman_send_error(s, m, buf);
06996       return 0;
06997    }
06998 
06999    /* Answer the channels if needed */
07000    if (chana->_state != AST_STATE_UP)
07001       ast_answer(chana);
07002 
07003    /* create the placeholder channels and grab the other channels */
07004    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
07005       NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
07006       astman_send_error(s, m, "Unable to create temporary channel!");
07007       chana = ast_channel_unref(chana);
07008       return 0;
07009    }
07010 
07011    if (do_bridge_masquerade(chana, tmpchana)) {
07012       snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela);
07013       astman_send_error(s, m, buf);
07014       ast_hangup(tmpchana);
07015       chana = ast_channel_unref(chana);
07016       return 0;
07017    }
07018 
07019    chana = ast_channel_unref(chana);
07020 
07021    /* now do chanb */
07022    chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
07023    if (!chanb) {
07024       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
07025       astman_send_error(s, m, buf);
07026       ast_hangup(tmpchana);
07027       return 0;
07028    }
07029 
07030    /* Answer the channels if needed */
07031    if (chanb->_state != AST_STATE_UP)
07032       ast_answer(chanb);
07033 
07034    /* create the placeholder channels and grab the other channels */
07035    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
07036       NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
07037       astman_send_error(s, m, "Unable to create temporary channels!");
07038       ast_hangup(tmpchana);
07039       chanb = ast_channel_unref(chanb);
07040       return 0;
07041    }
07042 
07043    if (do_bridge_masquerade(chanb, tmpchanb)) {
07044       snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb);
07045       astman_send_error(s, m, buf);
07046       ast_hangup(tmpchana);
07047       ast_hangup(tmpchanb);
07048       chanb = ast_channel_unref(chanb);
07049       return 0;
07050    }
07051 
07052    chanb = ast_channel_unref(chanb);
07053 
07054    /* make the channels compatible, send error if we fail doing so */
07055    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
07056       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
07057       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
07058       ast_hangup(tmpchana);
07059       ast_hangup(tmpchanb);
07060       return 0;
07061    }
07062 
07063    /* setup the bridge thread object and start the bridge */
07064    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
07065       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
07066       astman_send_error(s, m, "Unable to spawn a new bridge thread");
07067       ast_hangup(tmpchana);
07068       ast_hangup(tmpchanb);
07069       return 0;
07070    }
07071 
07072    tobj->chan = tmpchana;
07073    tobj->peer = tmpchanb;
07074    tobj->return_to_pbx = 1;
07075 
07076    if (ast_true(playtone)) {
07077       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
07078          if (ast_waitstream(tmpchanb, "") < 0)
07079             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
07080       }
07081    }
07082 
07083    chans[0] = tmpchana;
07084    chans[1] = tmpchanb;
07085 
07086    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
07087             "Response: Success\r\n"
07088             "Channel1: %s\r\n"
07089             "Channel2: %s\r\n", tmpchana->name, tmpchanb->name);
07090 
07091    bridge_call_thread_launch(tobj);
07092 
07093    astman_send_ack(s, m, "Launched bridge thread with success");
07094 
07095    return 0;
07096 }

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

Definition at line 768 of file features.c.

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

Referenced by add_features_datastores(), and builtin_atxfer().

00769 {
00770    struct ast_datastore *datastore;
00771    struct ast_dial_features *dialfeatures;
00772 
00773    ast_channel_lock(chan);
00774    datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL);
00775    ast_channel_unlock(chan);
00776    if (datastore) {
00777       /* Already exists. */
00778       return 1;
00779    }
00780 
00781    /* Create a new datastore with specified feature flags. */
00782    datastore = ast_datastore_alloc(&dial_features_info, NULL);
00783    if (!datastore) {
00784       ast_log(LOG_WARNING, "Unable to create channel features datastore.\n");
00785       return 0;
00786    }
00787    dialfeatures = ast_calloc(1, sizeof(*dialfeatures));
00788    if (!dialfeatures) {
00789       ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n");
00790       ast_datastore_free(datastore);
00791       return 0;
00792    }
00793    ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL);
00794    ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL);
00795    datastore->inheritance = DATASTORE_INHERIT_FOREVER;
00796    datastore->data = dialfeatures;
00797    ast_channel_lock(chan);
00798    ast_channel_datastore_add(chan, datastore);
00799    ast_channel_unlock(chan);
00800    return 0;
00801 }

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

Definition at line 3897 of file features.c.

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

Referenced by ast_bridge_call().

03898 {
03899    if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) {
03900       /*
03901        * If we don't return here, then when we do a builtin_atxfer we
03902        * will copy the disconnect flags over from the atxfer to the
03903        * callee (Party C).
03904        */
03905       return;
03906    }
03907 
03908    add_features_datastore(callee, &config->features_callee, &config->features_caller);
03909 }

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

Announce call parking by ADSI.

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

Definition at line 1063 of file features.c.

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

Referenced by park_call_full().

01064 {
01065    int res;
01066    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
01067    char tmp[256];
01068    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
01069 
01070    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
01071    message[0] = tmp;
01072    res = ast_adsi_load_session(chan, NULL, 0, 1);
01073    if (res == -1)
01074       return res;
01075    return ast_adsi_print(chan, message, justify, 1);
01076 }

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

bridge the call and set CDR

Bridge a call, optionally allowing redirection.

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.

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 3960 of file features.c.

References ast_channel::_softhangup, ast_channel::_state, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, ast_bridge_end_dtmf(), AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_copy_vars(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_bridge(), ast_channel_connected_line_macro(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_lock_both, ast_channel_log(), AST_CHANNEL_NAME, ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_clear_flag, AST_CONTROL_AOC, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, ast_opt_transmit_silence, AST_OPTION_AUDIO_MODE, AST_OPTION_DIGIT_DETECT, AST_OPTION_FAX_DETECT, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_UNBRIDGE, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_write(), ast_channel::caller, ast_channel::cdr, ast_cdr::channel, clear_dialed_interfaces(), ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_start_time, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_frame::frametype, ast_party_caller::id, ast_frame_subclass::integer, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, monitor_app, monitor_ok, ast_cdr::next, ast_party_id::number, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, ast_frame::ptr, S_COR, S_OR, ast_channel::sending_dtmf_digit, ast_channel::sending_dtmf_tv, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_party_number::str, ast_frame::subclass, ast_bridge_config::timelimit, ast_cdr::uniqueid, ast_cdr::userfield, ast_party_number::valid, and ast_channel::visible_indication.

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

03961 {
03962    /* Copy voice back and forth between the two channels.  Give the peer
03963       the ability to transfer calls with '#<extension' syntax. */
03964    struct ast_frame *f;
03965    struct ast_channel *who;
03966    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
03967    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
03968    char orig_channame[AST_CHANNEL_NAME];
03969    char orig_peername[AST_CHANNEL_NAME];
03970    int res;
03971    int diff;
03972    int hasfeatures=0;
03973    int hadfeatures=0;
03974    int autoloopflag;
03975    int sendingdtmfdigit = 0;
03976    int we_disabled_peer_cdr = 0;
03977    struct ast_option_header *aoh;
03978    struct ast_cdr *bridge_cdr = NULL;
03979    struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */
03980    struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */
03981    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
03982    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
03983    struct ast_silence_generator *silgen = NULL;
03984    const char *h_context;
03985 
03986    pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
03987    pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
03988 
03989    /* Clear any BLINDTRANSFER since the transfer has completed. */
03990    pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
03991    pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL);
03992 
03993    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
03994    add_features_datastores(chan, peer, config);
03995 
03996    /* This is an interesting case.  One example is if a ringing channel gets redirected to
03997     * an extension that picks up a parked call.  This will make sure that the call taken
03998     * out of parking gets told that the channel it just got bridged to is still ringing. */
03999    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
04000       ast_indicate(peer, AST_CONTROL_RINGING);
04001    }
04002 
04003    if (monitor_ok) {
04004       const char *monitor_exec;
04005       struct ast_channel *src = NULL;
04006       if (!monitor_app) {
04007          if (!(monitor_app = pbx_findapp("Monitor")))
04008             monitor_ok=0;
04009       }
04010       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
04011          src = chan;
04012       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
04013          src = peer;
04014       if (monitor_app && src) {
04015          char *tmp = ast_strdupa(monitor_exec);
04016          pbx_exec(src, monitor_app, tmp);
04017       }
04018    }
04019 
04020    set_config_flags(chan, peer, config);
04021 
04022    /* Answer if need be */
04023    if (chan->_state != AST_STATE_UP) {
04024       if (ast_raw_answer(chan, 1)) {
04025          return -1;
04026       }
04027    }
04028 
04029 #ifdef FOR_DEBUG
04030    /* show the two channels and cdrs involved in the bridge for debug & devel purposes */
04031    ast_channel_log("Pre-bridge CHAN Channel info", chan);
04032    ast_channel_log("Pre-bridge PEER Channel info", peer);
04033 #endif
04034    /* two channels are being marked as linked here */
04035    ast_channel_set_linkgroup(chan,peer);
04036 
04037    /* copy the userfield from the B-leg to A-leg if applicable */
04038    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
04039       char tmp[256];
04040 
04041       ast_channel_lock(chan);
04042       if (!ast_strlen_zero(chan->cdr->userfield)) {
04043          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
04044          ast_cdr_appenduserfield(chan, tmp);
04045       } else {
04046          ast_cdr_setuserfield(chan, peer->cdr->userfield);
04047       }
04048       ast_channel_unlock(chan);
04049       /* Don't delete the CDR; just disable it. */
04050       ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
04051       we_disabled_peer_cdr = 1;
04052    }
04053    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
04054    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
04055 
04056    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
04057       ast_channel_lock_both(chan, peer);
04058       if (chan_cdr) {
04059          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
04060          ast_cdr_update(chan);
04061          bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
04062          /* rip any forked CDR's off of the chan_cdr and attach
04063           * them to the bridge_cdr instead */
04064          bridge_cdr->next = chan_cdr->next;
04065          chan_cdr->next = NULL;
04066          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
04067          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
04068          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
04069             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
04070          }
04071          ast_cdr_setaccount(peer, chan->accountcode);
04072       } else {
04073          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
04074          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
04075          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
04076          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
04077          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
04078          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
04079          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
04080          ast_cdr_setcid(bridge_cdr, chan);
04081          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
04082          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
04083          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
04084          /* Destination information */
04085          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
04086          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
04087          if (peer_cdr) {
04088             bridge_cdr->start = peer_cdr->start;
04089             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
04090          } else {
04091             ast_cdr_start(bridge_cdr);
04092          }
04093       }
04094       ast_channel_unlock(chan);
04095       ast_channel_unlock(peer);
04096 
04097       ast_debug(4,"bridge answer set, chan answer set\n");
04098       /* peer_cdr->answer will be set when a macro runs on the peer;
04099          in that case, the bridge answer will be delayed while the
04100          macro plays on the peer channel. The peer answered the call
04101          before the macro started playing. To the phone system,
04102          this is billable time for the call, even tho the caller
04103          hears nothing but ringing while the macro does its thing. */
04104 
04105       /* Another case where the peer cdr's time will be set, is when
04106          A self-parks by pickup up phone and dialing 700, then B
04107          picks up A by dialing its parking slot; there may be more 
04108          practical paths that get the same result, tho... in which
04109          case you get the previous answer time from the Park... which
04110          is before the bridge's start time, so I added in the 
04111          tvcmp check to the if below */
04112 
04113       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
04114          ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
04115          ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
04116          if (chan_cdr) {
04117             ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
04118             ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
04119          }
04120       } else {
04121          ast_cdr_answer(bridge_cdr);
04122          if (chan_cdr) {
04123             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
04124          }
04125       }
04126       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
04127          if (chan_cdr) {
04128             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
04129          }
04130          if (peer_cdr) {
04131             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
04132          }
04133       }
04134       /* the DIALED flag may be set if a dialed channel is transferred
04135        * and then bridged to another channel.  In order for the
04136        * bridge CDR to be written, the DIALED flag must not be
04137        * present. */
04138       ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
04139    }
04140    ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer);
04141 
04142    /* If we are bridging a call, stop worrying about forwarding loops. We presume that if
04143     * a call is being bridged, that the humans in charge know what they're doing. If they
04144     * don't, well, what can we do about that? */
04145    clear_dialed_interfaces(chan);
04146    clear_dialed_interfaces(peer);
04147 
04148    for (;;) {
04149       struct ast_channel *other; /* used later */
04150    
04151       res = ast_channel_bridge(chan, peer, config, &f, &who);
04152 
04153       if (ast_test_flag(chan, AST_FLAG_ZOMBIE)
04154          || ast_test_flag(peer, AST_FLAG_ZOMBIE)) {
04155          /* Zombies are present time to leave! */
04156          res = -1;
04157          if (f) {
04158             ast_frfree(f);
04159          }
04160          goto before_you_go;
04161       }
04162 
04163       /* When frame is not set, we are probably involved in a situation
04164          where we've timed out.
04165          When frame is set, we'll come this code twice; once for DTMF_BEGIN
04166          and also for DTMF_END. If we flow into the following 'if' for both, then 
04167          our wait times are cut in half, as both will subtract from the
04168          feature_timer. Not good!
04169       */
04170       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
04171          /* Update feature timer for next pass */
04172          diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
04173          if (res == AST_BRIDGE_RETRY) {
04174             /* The feature fully timed out but has not been updated. Skip
04175              * the potential round error from the diff calculation and
04176              * explicitly set to expired. */
04177             config->feature_timer = -1;
04178          } else {
04179             config->feature_timer -= diff;
04180          }
04181 
04182          if (hasfeatures) {
04183             if (config->feature_timer <= 0) {
04184                /* Not *really* out of time, just out of time for
04185                   digits to come in for features. */
04186                ast_debug(1, "Timed out for feature!\n");
04187                if (!ast_strlen_zero(peer_featurecode)) {
04188                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
04189                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
04190                }
04191                if (!ast_strlen_zero(chan_featurecode)) {
04192                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
04193                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
04194                }
04195                if (f)
04196                   ast_frfree(f);
04197                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
04198                if (!hasfeatures) {
04199                   /* No more digits expected - reset the timer */
04200                   config->feature_timer = 0;
04201                }
04202                hadfeatures = hasfeatures;
04203                /* Continue as we were */
04204                continue;
04205             } else if (!f) {
04206                /* The bridge returned without a frame and there is a feature in progress.
04207                 * However, we don't think the feature has quite yet timed out, so just
04208                 * go back into the bridge. */
04209                continue;
04210             }
04211          } else {
04212             if (config->feature_timer <=0) {
04213                /* We ran out of time */
04214                config->feature_timer = 0;
04215                who = chan;
04216                if (f)
04217                   ast_frfree(f);
04218                f = NULL;
04219                res = 0;
04220             }
04221          }
04222       }
04223       if (res < 0) {
04224          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
04225             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
04226          }
04227          goto before_you_go;
04228       }
04229       
04230       if (!f || (f->frametype == AST_FRAME_CONTROL &&
04231             (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
04232                f->subclass.integer == AST_CONTROL_CONGESTION))) {
04233          res = -1;
04234          break;
04235       }
04236       /* many things should be sent to the 'other' channel */
04237       other = (who == chan) ? peer : chan;
04238       if (f->frametype == AST_FRAME_CONTROL) {
04239          switch (f->subclass.integer) {
04240          case AST_CONTROL_RINGING:
04241          case AST_CONTROL_FLASH:
04242          case -1:
04243             ast_indicate(other, f->subclass.integer);
04244             break;
04245          case AST_CONTROL_CONNECTED_LINE:
04246             if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
04247                break;
04248             }
04249             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04250             break;
04251          case AST_CONTROL_REDIRECTING:
04252             if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
04253                break;
04254             }
04255             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04256             break;
04257          case AST_CONTROL_AOC:
04258          case AST_CONTROL_HOLD:
04259          case AST_CONTROL_UNHOLD:
04260             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
04261             break;
04262          case AST_CONTROL_OPTION:
04263             aoh = f->data.ptr;
04264             /* Forward option Requests, but only ones we know are safe
04265              * These are ONLY sent by chan_iax2 and I'm not convinced that
04266              * they are useful. I haven't deleted them entirely because I
04267              * just am not sure of the ramifications of removing them. */
04268             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
04269                   switch (ntohs(aoh->option)) {
04270                case AST_OPTION_TONE_VERIFY:
04271                case AST_OPTION_TDD:
04272                case AST_OPTION_RELAXDTMF:
04273                case AST_OPTION_AUDIO_MODE:
04274                case AST_OPTION_DIGIT_DETECT:
04275                case AST_OPTION_FAX_DETECT:
04276                   ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
04277                      f->datalen - sizeof(struct ast_option_header), 0);
04278                }
04279             }
04280             break;
04281          }
04282       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
04283          struct ast_flags *cfg;
04284          char dtmfcode[2] = { f->subclass.integer, };
04285          size_t featurelen;
04286 
04287          if (who == chan) {
04288             featurelen = strlen(chan_featurecode);
04289             cfg = &(config->features_caller);
04290          } else {
04291             featurelen = strlen(peer_featurecode);
04292             cfg = &(config->features_callee);
04293          }
04294          /* Take a peek if this (possibly) matches a feature. If not, just pass this
04295           * DTMF along untouched. If this is not the first digit of a multi-digit code
04296           * then we need to fall through and stream the characters if it matches */
04297          if (featurelen == 0
04298             && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) {
04299             if (option_debug > 3) {
04300                ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n");
04301             }
04302             ast_write(other, f);
04303             sendingdtmfdigit = 1;
04304          } else {
04305             /* If ast_opt_transmit_silence is set, then we need to make sure we are
04306              * transmitting something while we hold on to the DTMF waiting for a
04307              * feature. */
04308             if (!silgen && ast_opt_transmit_silence) {
04309                silgen = ast_channel_start_silence_generator(other);
04310             }
04311             if (option_debug > 3) {
04312                ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n");
04313             }
04314          }
04315       } else if (f->frametype == AST_FRAME_DTMF_END) {
04316          char *featurecode;
04317          int sense;
04318 
04319          hadfeatures = hasfeatures;
04320          /* This cannot overrun because the longest feature is one shorter than our buffer */
04321          if (who == chan) {
04322             sense = FEATURE_SENSE_CHAN;
04323             featurecode = chan_featurecode;
04324          } else  {
04325             sense = FEATURE_SENSE_PEER;
04326             featurecode = peer_featurecode;
04327          }
04328 
04329          if (sendingdtmfdigit == 1) {
04330             /* We let the BEGIN go through happily, so let's not bother with the END,
04331              * since we already know it's not something we bother with */
04332             ast_write(other, f);
04333             sendingdtmfdigit = 0;
04334          } else {
04335             /*! append the event to featurecode. we rely on the string being zero-filled, and
04336              * not overflowing it. 
04337              * \todo XXX how do we guarantee the latter ?
04338              */
04339             featurecode[strlen(featurecode)] = f->subclass.integer;
04340             /* Get rid of the frame before we start doing "stuff" with the channels */
04341             ast_frfree(f);
04342             f = NULL;
04343             if (silgen) {
04344                ast_channel_stop_silence_generator(other, silgen);
04345                silgen = NULL;
04346             }
04347             config->feature_timer = 0;
04348             res = feature_interpret(chan, peer, config, featurecode, sense);
04349             switch(res) {
04350             case AST_FEATURE_RETURN_PASSDIGITS:
04351                ast_dtmf_stream(other, who, featurecode, 0, 0);
04352                /* Fall through */
04353             case AST_FEATURE_RETURN_SUCCESS:
04354                memset(featurecode, 0, sizeof(chan_featurecode));
04355                break;
04356             }
04357             if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
04358                res = 0;
04359             } else {
04360                break;
04361             }
04362             hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
04363             if (hadfeatures && !hasfeatures) {
04364                /* Feature completed or timed out */
04365                config->feature_timer = 0;
04366             } else if (hasfeatures) {
04367                if (config->timelimit) {
04368                   /* No warning next time - we are waiting for feature code */
04369                   ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
04370                }
04371                config->feature_start_time = ast_tvnow();
04372                config->feature_timer = featuredigittimeout;
04373                ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
04374             }
04375          }
04376       }
04377       if (f)
04378          ast_frfree(f);
04379    }
04380    ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer);
04381 
04382 before_you_go:
04383    if (chan->sending_dtmf_digit) {
04384       ast_bridge_end_dtmf(chan, chan->sending_dtmf_digit, chan->sending_dtmf_tv,
04385          "bridge end");
04386    }
04387    if (peer->sending_dtmf_digit) {
04388       ast_bridge_end_dtmf(peer, peer->sending_dtmf_digit, peer->sending_dtmf_tv,
04389          "bridge end");
04390    }
04391 
04392    /* Just in case something weird happened and we didn't clean up the silence generator... */
04393    if (silgen) {
04394       ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen);
04395       silgen = NULL;
04396    }
04397 
04398    /* Wait for any dual redirect to complete. */
04399    while (ast_test_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) {
04400       sched_yield();
04401    }
04402 
04403    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
04404       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
04405       if (bridge_cdr) {
04406          ast_cdr_discard(bridge_cdr);
04407          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
04408       }
04409       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
04410    }
04411 
04412    if (config->end_bridge_callback) {
04413       config->end_bridge_callback(config->end_bridge_callback_data);
04414    }
04415 
04416    /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 
04417     * if it were, then chan belongs to a different thread now, and might have been hung up long
04418     * ago.
04419     */
04420    if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) {
04421       /*
04422        * If the bridge was broken for a hangup that isn't real,
04423        * then don't run the h extension, because the channel isn't
04424        * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO,
04425        * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either.
04426        */
04427       h_context = NULL;
04428    } else if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
04429       h_context = NULL;
04430    } else if (ast_exists_extension(chan, chan->context, "h", 1,
04431       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
04432       h_context = chan->context;
04433    } else if (!ast_strlen_zero(chan->macrocontext)
04434       && ast_exists_extension(chan, chan->macrocontext, "h", 1,
04435          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
04436       h_context = chan->macrocontext;
04437    } else {
04438       h_context = NULL;
04439    }
04440    if (h_context) {
04441       struct ast_cdr *swapper = NULL;
04442       char savelastapp[AST_MAX_EXTENSION];
04443       char savelastdata[AST_MAX_EXTENSION];
04444       char save_context[AST_MAX_CONTEXT];
04445       char save_exten[AST_MAX_EXTENSION];
04446       int  save_prio;
04447       int  found = 0;   /* set if we find at least one match */
04448       int  spawn_error = 0;
04449 
04450       /*
04451        * Make sure that the channel is marked as hungup since we are
04452        * going to run the "h" exten on it.
04453        */
04454       ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD);
04455 
04456       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
04457       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
04458       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
04459          ast_cdr_end(bridge_cdr);
04460       }
04461 
04462       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
04463          dialplan code operate on it */
04464       ast_channel_lock(chan);
04465       if (bridge_cdr) {
04466          swapper = chan->cdr;
04467          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
04468          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
04469          chan->cdr = bridge_cdr;
04470       }
04471       ast_copy_string(save_context, chan->context, sizeof(save_context));
04472       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
04473       save_prio = chan->priority;
04474       if (h_context != chan->context) {
04475          ast_copy_string(chan->context, h_context, sizeof(chan->context));
04476       }
04477       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
04478       chan->priority = 1;
04479       ast_channel_unlock(chan);
04480 
04481       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten,
04482          chan->priority,
04483          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
04484          &found, 1)) == 0) {
04485          chan->priority++;
04486       }
04487       if (found && spawn_error) {
04488          /* Something bad happened, or a hangup has been requested. */
04489          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
04490          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
04491       }
04492 
04493       /* swap it back */
04494       ast_channel_lock(chan);
04495       ast_copy_string(chan->context, save_context, sizeof(chan->context));
04496       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
04497       chan->priority = save_prio;
04498       if (bridge_cdr) {
04499          if (chan->cdr == bridge_cdr) {
04500             chan->cdr = swapper;
04501          } else {
04502             bridge_cdr = NULL;
04503          }
04504       }
04505       /* An "h" exten has been run, so indicate that one has been run. */
04506       ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
04507       ast_channel_unlock(chan);
04508 
04509       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
04510       if (bridge_cdr) {
04511          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
04512          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
04513       }
04514       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
04515    }
04516    
04517    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
04518    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
04519    /* If the channel CDR has been modified during the call, record the changes in the bridge cdr,
04520     * BUT, if we've gone through the h extension block above, the CDR got swapped so don't overwrite
04521     * what was done in the h extension. What a mess. This is why you never touch CDR code. */
04522    if (new_chan_cdr && bridge_cdr && !h_context) {
04523       ast_cdr_copy_vars(bridge_cdr, new_chan_cdr);
04524       ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield));
04525       bridge_cdr->amaflags = new_chan_cdr->amaflags;
04526       ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode));
04527       if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
04528          ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
04529       }
04530    }
04531 
04532    /* we can post the bridge CDR at this point */
04533    if (bridge_cdr) {
04534       ast_cdr_end(bridge_cdr);
04535       ast_cdr_detach(bridge_cdr);
04536    }
04537    
04538    /* do a specialized reset on the beginning channel
04539       CDR's, if they still exist, so as not to mess up
04540       issues in future bridges;
04541       
04542       Here are the rules of the game:
04543       1. The chan and peer channel pointers will not change
04544          during the life of the bridge.
04545       2. But, in transfers, the channel names will change.
04546          between the time the bridge is started, and the
04547          time the channel ends. 
04548          Usually, when a channel changes names, it will
04549          also change CDR pointers.
04550       3. Usually, only one of the two channels (chan or peer)
04551          will change names.
04552       4. Usually, if a channel changes names during a bridge,
04553          it is because of a transfer. Usually, in these situations,
04554          it is normal to see 2 bridges running simultaneously, and
04555          it is not unusual to see the two channels that change
04556          swapped between bridges.
04557       5. After a bridge occurs, we have 2 or 3 channels' CDRs
04558          to attend to; if the chan or peer changed names,
04559          we have the before and after attached CDR's.
04560    */
04561 
04562    if (new_chan_cdr) {
04563       struct ast_channel *chan_ptr = NULL;
04564 
04565       if (strcasecmp(orig_channame, chan->name) != 0) { 
04566          /* old channel */
04567          if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
04568             ast_channel_lock(chan_ptr);
04569             if (!ast_bridged_channel(chan_ptr)) {
04570                struct ast_cdr *cur;
04571                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
04572                   if (cur == chan_cdr) {
04573                      break;
04574                   }
04575                }
04576                if (cur) {
04577                   ast_cdr_specialized_reset(chan_cdr, 0);
04578                }
04579             }
04580             ast_channel_unlock(chan_ptr);
04581             chan_ptr = ast_channel_unref(chan_ptr);
04582          }
04583          /* new channel */
04584          ast_cdr_specialized_reset(new_chan_cdr, 0);
04585       } else {
04586          ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr  */
04587       }
04588    }
04589 
04590    {
04591       struct ast_channel *chan_ptr = NULL;
04592       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
04593       if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED))
04594          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
04595       if (strcasecmp(orig_peername, peer->name) != 0) { 
04596          /* old channel */
04597          if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
04598             ast_channel_lock(chan_ptr);
04599             if (!ast_bridged_channel(chan_ptr)) {
04600                struct ast_cdr *cur;
04601                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
04602                   if (cur == peer_cdr) {
04603                      break;
04604                   }
04605                }
04606                if (cur) {
04607                   ast_cdr_specialized_reset(peer_cdr, 0);
04608                }
04609             }
04610             ast_channel_unlock(chan_ptr);
04611             chan_ptr = ast_channel_unref(chan_ptr);
04612          }
04613          /* new channel */
04614          if (new_peer_cdr) {
04615             ast_cdr_specialized_reset(new_peer_cdr, 0);
04616          }
04617       } else {
04618          if (we_disabled_peer_cdr) {
04619             ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
04620          }
04621          ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr  */
04622       }
04623    }
04624    
04625    return res;
04626 }

void ast_bridge_end_dtmf ( struct ast_channel chan,
char  digit,
struct timeval  start,
const char *  why 
)

Simulate a DTMF end on a broken bridge channel.

Parameters:
chan Channel sending DTMF that has not ended.
digit DTMF digit to stop.
start DTMF digit start time.
why Reason bridge broken.
Returns:
Nothing

Definition at line 3927 of file features.c.

References ast_channel::_softhangup, ast_channel_lock, ast_channel_unlock, AST_FLAG_ZOMBIE, ast_log(), ast_senddigit_end(), AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), and LOG_DTMF.

Referenced by ast_bridge_call(), and ast_do_masquerade().

03928 {
03929    int dead;
03930    long duration;
03931 
03932    ast_channel_lock(chan);
03933    dead = ast_test_flag(chan, AST_FLAG_ZOMBIE)
03934       || (chan->_softhangup
03935          & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE));
03936    ast_channel_unlock(chan);
03937    if (dead) {
03938       /* Channel is a zombie or a real hangup. */
03939       return;
03940    }
03941 
03942    duration = ast_tvdiff_ms(ast_tvnow(), start);
03943    ast_senddigit_end(chan, digit, duration);
03944    ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n",
03945       digit, chan->name, why, duration);
03946 }

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

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

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

Definition at line 7532 of file features.c.

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

Referenced by bridge_exec(), and dial_exec_full().

07534 {
07535    char *stringp = ast_strdupa(parse);
07536    char *limit_str, *warning_str, *warnfreq_str;
07537    const char *var;
07538    int play_to_caller = 0, play_to_callee = 0;
07539    int delta;
07540 
07541    limit_str = strsep(&stringp, ":");
07542    warning_str = strsep(&stringp, ":");
07543    warnfreq_str = strsep(&stringp, ":");
07544 
07545    config->timelimit = atol(limit_str);
07546    if (warning_str)
07547       config->play_warning = atol(warning_str);
07548    if (warnfreq_str)
07549       config->warning_freq = atol(warnfreq_str);
07550 
07551    if (!config->timelimit) {
07552       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07553       config->timelimit = config->play_warning = config->warning_freq = 0;
07554       config->warning_sound = NULL;
07555       return -1; /* error */
07556    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07557       int w = config->warning_freq;
07558 
07559       /*
07560        * If the first warning is requested _after_ the entire call
07561        * would end, and no warning frequency is requested, then turn
07562        * off the warning. If a warning frequency is requested, reduce
07563        * the 'first warning' time by that frequency until it falls
07564        * within the call's total time limit.
07565        *
07566        * Graphically:
07567        *                timelim->|    delta        |<-playwarning
07568        *      0__________________|_________________|
07569        *                       | w  |    |    |    |
07570        *
07571        * so the number of intervals to cut is 1+(delta-1)/w
07572        */
07573       if (w == 0) {
07574          config->play_warning = 0;
07575       } else {
07576          config->play_warning -= w * ( 1 + (delta-1)/w );
07577          if (config->play_warning < 1)
07578             config->play_warning = config->warning_freq = 0;
07579       }
07580    }
07581    
07582    ast_channel_lock(chan);
07583 
07584    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07585    play_to_caller = var ? ast_true(var) : 1;
07586 
07587    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07588    play_to_callee = var ? ast_true(var) : 0;
07589 
07590    if (!play_to_caller && !play_to_callee)
07591       play_to_caller = 1;
07592 
07593    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07594    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07595 
07596    /* The code looking at config wants a NULL, not just "", to decide
07597     * that the message should not be played, so we replace "" with NULL.
07598     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
07599     * not found.
07600     */
07601 
07602    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07603    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07604 
07605    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07606    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07607 
07608    ast_channel_unlock(chan);
07609 
07610    /* undo effect of S(x) in case they are both used */
07611    calldurationlimit->tv_sec = 0;
07612    calldurationlimit->tv_usec = 0;
07613 
07614    /* more efficient to do it like S(x) does since no advanced opts */
07615    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07616       calldurationlimit->tv_sec = config->timelimit / 1000;
07617       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07618       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07619          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07620       config->timelimit = play_to_caller = play_to_callee =
07621       config->play_warning = config->warning_freq = 0;
07622    } else {
07623       ast_verb(4, "Limit Data for this call:\n");
07624       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07625       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07626       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07627       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07628       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07629       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
07630       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
07631       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
07632    }
07633    if (play_to_caller)
07634       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07635    if (play_to_callee)
07636       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07637    return 0;
07638 }

int ast_can_pickup ( struct ast_channel chan  ) 

Test if a channel can be picked up.

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 7338 of file features.c.

References ast_channel::_state, ast_channel_datastore_find(), AST_FLAG_ZOMBIE, AST_STATE_DOWN, AST_STATE_RING, AST_STATE_RINGING, ast_test_flag, ast_channel::masq, and ast_channel::pbx.

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

07339 {
07340    if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07341       && (chan->_state == AST_STATE_RINGING
07342          || chan->_state == AST_STATE_RING
07343          /*
07344           * Check the down state as well because some SIP devices do not
07345           * give 180 ringing when they can just give 183 session progress
07346           * instead.  Issue 14005.  (Some ISDN switches as well for that
07347           * matter.)
07348           */
07349          || chan->_state == AST_STATE_DOWN)
07350       && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07351       return 1;
07352    }
07353    return 0;
07354 }

void ast_channel_log ( char *  title,
struct ast_channel chan 
)

Definition at line 3832 of file features.c.

References ast_log(), and LOG_NOTICE.

Referenced by ast_bridge_call().

03833 {
03834        ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
03835        ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
03836                        chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
03837        ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
03838                        chan->accountcode, chan->dialcontext, (unsigned)chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
03839        ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
03840                        chan->masq, chan->masqr,
03841                        chan->_bridge, chan->uniqueid, chan->linkedid);
03842        if (chan->masqr)
03843                ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
03844                                chan->masqr->name, chan->masqr->cdr);
03845        if (chan->_bridge)
03846                ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
03847 
03848    ast_log(LOG_NOTICE, "===== done ====\n");
03849 }

int ast_do_pickup ( struct ast_channel chan,
struct ast_channel target 
)

Pickup a call target.

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 7414 of file features.c.

References ast_answer(), AST_CEL_PICKUP, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_datastore_add(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_masquerade(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_datastore_alloc, ast_datastore_free(), ast_debug, ast_do_masquerade(), AST_FLAG_ANSWERED_ELSEWHERE, ast_log(), ast_manager_event_multichan, ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_queue_control(), ast_set_flag, ast_strdupa, ast_channel::caller, ast_channel::connected, EVENT_FLAG_CALL, LOG_WARNING, and ast_party_connected_line::source.

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

07415 {
07416    struct ast_party_connected_line connected_caller;
07417    struct ast_channel *chans[2] = { chan, target };
07418    struct ast_datastore *ds_pickup;
07419    const char *chan_name;/*!< A masquerade changes channel names. */
07420    const char *target_name;/*!< A masquerade changes channel names. */
07421    int res = -1;
07422 
07423    target_name = ast_strdupa(target->name);
07424    ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name);
07425 
07426    /* Mark the target to block any call pickup race. */
07427    ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07428    if (!ds_pickup) {
07429       ast_log(LOG_WARNING,
07430          "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07431       return -1;
07432    }
07433    ast_channel_datastore_add(target, ds_pickup);
07434 
07435    ast_party_connected_line_init(&connected_caller);
07436    ast_party_connected_line_copy(&connected_caller, &target->connected);
07437    ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
07438    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07439    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07440       ast_channel_update_connected_line(chan, &connected_caller, NULL);
07441    }
07442    ast_party_connected_line_free(&connected_caller);
07443 
07444    ast_channel_lock(chan);
07445    chan_name = ast_strdupa(chan->name);
07446    ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07447    ast_channel_unlock(chan);
07448    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07449 
07450    ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07451 
07452    if (ast_answer(chan)) {
07453       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07454       goto pickup_failed;
07455    }
07456 
07457    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07458       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07459       goto pickup_failed;
07460    }
07461    
07462    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07463 
07464    /* setting this flag to generate a reason header in the cancel message to the ringing channel */
07465    ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07466 
07467    if (ast_channel_masquerade(target, chan)) {
07468       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07469          target_name);
07470       goto pickup_failed;
07471    }
07472 
07473    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
07474    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07475       "Channel: %s\r\n"
07476       "TargetChannel: %s\r\n",
07477       chan_name, target_name);
07478 
07479    /* Do the masquerade manually to make sure that it is completed. */
07480    ast_do_masquerade(target);
07481    res = 0;
07482 
07483 pickup_failed:
07484    ast_channel_lock(target);
07485    if (!ast_channel_datastore_remove(target, ds_pickup)) {
07486       ast_datastore_free(ds_pickup);
07487    }
07488    ast_party_connected_line_free(&connected_caller);
07489 
07490    return res;
07491 }

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

detect a feature before bridging

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 3434 of file features.c.

References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

03434                                                                                                                                  {
03435 
03436    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03437 }

int ast_features_init ( void   ) 

Provided by features.c

Definition at line 8336 of file features.c.

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

Referenced by main().

08337 {
08338    int res;
08339 
08340    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
08341    if (!parkinglots) {
08342       return -1;
08343    }
08344 
08345    res = load_config(0);
08346    if (res) {
08347       return res;
08348    }
08349    ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
08350    if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) {
08351       return -1;
08352    }
08353    ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
08354    res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL);
08355    if (!res)
08356       res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
08357    if (!res) {
08358       ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
08359       ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
08360       ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
08361    }
08362 
08363    res |= ast_devstate_prov_add("Park", metermaidstate);
08364 #if defined(TEST_FRAMEWORK)
08365    res |= AST_TEST_REGISTER(features_test);
08366 #endif   /* defined(TEST_FRAMEWORK) */
08367 
08368    ast_register_atexit(features_shutdown);
08369 
08370    return res;
08371 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 6879 of file features.c.

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

Referenced by handle_features_reload().

06880 {
06881    struct ast_context *con;
06882    int res;
06883 
06884    ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
06885 
06886    /*
06887     * Always destroy the parking_con_dial context to remove buildup
06888     * of recalled extensions in the context.  At worst, the parked
06889     * call gets hungup attempting to run an invalid extension when
06890     * we are trying to callback the parker or the preset return
06891     * extension.  This is a small window of opportunity on an
06892     * execution chain that is not expected to happen very often.
06893     */
06894    con = ast_context_find(parking_con_dial);
06895    if (con) {
06896       ast_context_destroy(con, registrar);
06897    }
06898 
06899    res = load_config(1);
06900    ast_mutex_unlock(&features_reload_lock);
06901 
06902    return res;
06903 }

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

look for a call feature entry by its sname

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

Definition at line 3160 of file features.c.

References FEATURES_COUNT, and ast_call_feature::sname.

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

03161 {
03162    int x;
03163    for (x = 0; x < FEATURES_COUNT; x++) {
03164       if (!strcasecmp(name, builtin_features[x].sname))
03165          return &builtin_features[x];
03166    }
03167    return NULL;
03168 }

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

Park a call via a masqueraded channel.

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 1857 of file features.c.

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

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

01858 {
01859    struct ast_park_call_args args = {
01860       .timeout = timeout,
01861       .extout = extout,
01862    };
01863 
01864    if (peer) {
01865       args.orig_chan_name = ast_strdupa(peer->name);
01866    }
01867    return masq_park_call(rchan, peer, &args);
01868 }

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

Park a call via a masqueraded channel.

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 1803 of file features.c.

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

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

01804 {
01805    int res;
01806    char *parse;
01807    const char *app_data;
01808    struct ast_exten *exten;
01809    struct park_app_args app_args;
01810    struct ast_park_call_args args = {
01811       .timeout = timeout,
01812       .extout = extout,
01813    };
01814 
01815    if (parker) {
01816       args.orig_chan_name = ast_strdupa(parker->name);
01817    }
01818    if (!park_exten || !park_context) {
01819       return masq_park_call(park_me, parker, &args);
01820    }
01821 
01822    /*
01823     * Determiine if the specified park extension has an exclusive
01824     * parking lot to use.
01825     */
01826    if (parker && parker != park_me) {
01827       ast_autoservice_start(park_me);
01828    }
01829    exten = get_parking_exten(park_exten, parker, park_context);
01830    if (exten) {
01831       app_data = ast_get_extension_app_data(exten);
01832       if (!app_data) {
01833          app_data = "";
01834       }
01835       parse = ast_strdupa(app_data);
01836       AST_STANDARD_APP_ARGS(app_args, parse);
01837    
01838       if (!ast_strlen_zero(app_args.pl_name)) {
01839          /* Find the specified exclusive parking lot */
01840          args.parkinglot = find_parkinglot(app_args.pl_name);
01841          if (!args.parkinglot && parkeddynamic) {
01842             args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
01843          }
01844       }
01845    }
01846    if (parker && parker != park_me) {
01847       ast_autoservice_stop(park_me);
01848    }
01849 
01850    res = masq_park_call(park_me, parker, &args);
01851    if (args.parkinglot) {
01852       parkinglot_unref(args.parkinglot);
01853    }
01854    return res;
01855 }

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

Park a call and read back parked location.

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 1706 of file features.c.

References park_call_full(), and ast_park_call_args::timeout.

01707 {
01708    struct ast_park_call_args args = {
01709       .timeout = timeout,
01710       .extout = extout,
01711    };
01712 
01713    return park_call_full(park_me, parker, &args);
01714 }

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

Park a call and read back parked location.

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 1655 of file features.c.

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

Referenced by iax_park_thread(), and sip_park_thread().

01656 {
01657    int res;
01658    char *parse;
01659    const char *app_data;
01660    struct ast_exten *exten;
01661    struct park_app_args app_args;
01662    struct ast_park_call_args args = {
01663       .timeout = timeout,
01664       .extout = extout,
01665    };
01666 
01667    if (!park_exten || !park_context) {
01668       return park_call_full(park_me, parker, &args);
01669    }
01670 
01671    /*
01672     * Determiine if the specified park extension has an exclusive
01673     * parking lot to use.
01674     */
01675    if (parker && parker != park_me) {
01676       ast_autoservice_start(park_me);
01677    }
01678    exten = get_parking_exten(park_exten, parker, park_context);
01679    if (exten) {
01680       app_data = ast_get_extension_app_data(exten);
01681       if (!app_data) {
01682          app_data = "";
01683       }
01684       parse = ast_strdupa(app_data);
01685       AST_STANDARD_APP_ARGS(app_args, parse);
01686    
01687       if (!ast_strlen_zero(app_args.pl_name)) {
01688          /* Find the specified exclusive parking lot */
01689          args.parkinglot = find_parkinglot(app_args.pl_name);
01690          if (!args.parkinglot && parkeddynamic) {
01691             args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
01692          }
01693       }
01694    }
01695    if (parker && parker != park_me) {
01696       ast_autoservice_stop(park_me);
01697    }
01698 
01699    res = park_call_full(park_me, parker, &args);
01700    if (args.parkinglot) {
01701       parkinglot_unref(args.parkinglot);
01702    }
01703    return res;
01704 }

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

Determine if parking extension exists in a given context.

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

Definition at line 844 of file features.c.

References get_parking_exten().

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

00845 {
00846    return get_parking_exten(exten_str, chan, context) ? 1 : 0;
00847 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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 7380 of file features.c.

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

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

07381 {
07382    struct ast_channel *target;/*!< Potential pickup target */
07383    int res = -1;
07384    ast_debug(1, "pickup attempt by %s\n", chan->name);
07385 
07386    /* The found channel is already locked. */
07387    target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07388    if (target) {
07389       ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
07390 
07391       res = ast_do_pickup(chan, target);
07392       ast_channel_unlock(target);
07393       if (!res) {
07394          if (!ast_strlen_zero(pickupsound)) {
07395             pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07396          }
07397       } else {
07398          ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name);
07399       }
07400       target = ast_channel_unref(target);
07401    }
07402 
07403    if (res < 0) {
07404       ast_debug(1, "No call pickup possible... for %s\n", chan->name);
07405       if (!ast_strlen_zero(pickupfailsound)) {
07406          ast_answer(chan);
07407          ast_stream_and_wait(chan, pickupfailsound, "");
07408       }
07409    }
07410 
07411    return res;
07412 }

const char* ast_pickup_ext ( void   ) 
void ast_rdlock_call_features ( void   ) 

Definition at line 3150 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

03151 {
03152    ast_rwlock_rdlock(&features_lock);
03153 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_list

register new feature into feature_set

Definition at line 2994 of file features.c.

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

Referenced by process_applicationmap_line().

02995 {
02996    if (!feature) {
02997       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02998       return;
02999    }
03000   
03001    AST_RWLIST_WRLOCK(&feature_list);
03002    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
03003    AST_RWLIST_UNLOCK(&feature_list);
03004 
03005    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
03006 }

void ast_unlock_call_features ( void   ) 

Definition at line 3155 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

03156 {
03157    ast_rwlock_unlock(&features_lock);
03158 }

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 3074 of file features.c.

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

03075 {
03076    if (!feature) {
03077       return;
03078    }
03079 
03080    AST_RWLIST_WRLOCK(&feature_list);
03081    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
03082    AST_RWLIST_UNLOCK(&feature_list);
03083 
03084    ast_free(feature);
03085 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 3088 of file features.c.

References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by process_config().

03089 {
03090    struct ast_call_feature *feature;
03091 
03092    AST_RWLIST_WRLOCK(&feature_list);
03093    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
03094       ast_free(feature);
03095    }
03096    AST_RWLIST_UNLOCK(&feature_list);
03097 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

Definition at line 3114 of file features.c.

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

Referenced by process_config().

03115 {
03116    struct feature_group *fg;
03117    struct feature_group_exten *fge;
03118 
03119    AST_RWLIST_WRLOCK(&feature_groups);
03120    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
03121       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
03122          ast_string_field_free_memory(fge);
03123          ast_free(fge);
03124       }
03125 
03126       ast_string_field_free_memory(fg);
03127       ast_free(fg);
03128    }
03129    AST_RWLIST_UNLOCK(&feature_groups);
03130 }

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

Definition at line 2490 of file features.c.

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

Referenced by builtin_atxfer().

02491 {
02492    finishup(transferee);
02493 
02494    /*
02495     * Restore party B connected line info about party A.
02496     *
02497     * Party B was the caller to party C and is the last known mode
02498     * for party B.
02499     */
02500    if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
02501       ast_channel_update_connected_line(transferer, connected_line, NULL);
02502    }
02503    ast_party_connected_line_free(connected_line);
02504 }

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

bridge the call

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 987 of file features.c.

References ast_channel::appl, ast_bridge_call(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, LOG_VERBOSE, LOG_WARNING, ast_bridge_thread_obj::peer, ast_bridge_thread_obj::return_to_pbx, and set_chan_app_data().

Referenced by bridge_call_thread_launch().

00988 {
00989    struct ast_bridge_thread_obj *tobj = data;
00990 
00991    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00992    if (set_chan_app_data(tobj->chan, tobj->peer->name)) {
00993       tobj->chan->data = "(Empty)";
00994    }
00995    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00996    if (set_chan_app_data(tobj->peer, tobj->chan->name)) {
00997       tobj->peer->data = "(Empty)";
00998    }
00999 
01000    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
01001 
01002    if (tobj->return_to_pbx) {
01003       if (!ast_check_hangup(tobj->peer)) {
01004          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
01005          if (ast_pbx_start(tobj->peer)) {
01006             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
01007             ast_hangup(tobj->peer);
01008          }
01009       } else {
01010          ast_hangup(tobj->peer);
01011       }
01012       if (!ast_check_hangup(tobj->chan)) {
01013          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
01014          if (ast_pbx_start(tobj->chan)) {
01015             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
01016             ast_hangup(tobj->chan);
01017          }
01018       } else {
01019          ast_hangup(tobj->chan);
01020       }
01021    } else {
01022       ast_hangup(tobj->chan);
01023       ast_hangup(tobj->peer);
01024    }
01025 
01026    ast_free(tobj);
01027 
01028    return NULL;
01029 }

static void bridge_call_thread_launch ( struct ast_bridge_thread_obj data  )  [static]

create thread for the parked call

Parameters:
data Create thread and attributes, call bridge_call_thread

Definition at line 1037 of file features.c.

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

Referenced by action_bridge(), and builtin_atxfer().

01038 {
01039    pthread_t thread;
01040    pthread_attr_t attr;
01041    struct sched_param sched;
01042 
01043    pthread_attr_init(&attr);
01044    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01045    if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) {
01046       ast_hangup(data->chan);
01047       ast_hangup(data->peer);
01048       ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n");
01049    }
01050    pthread_attr_destroy(&attr);
01051    memset(&sched, 0, sizeof(sched));
01052    pthread_setschedparam(thread, SCHED_RR, &sched);
01053 }

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

Bridge channels.

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 transferred party hangs up return to PBX extension.

Definition at line 7650 of file features.c.

References ast_channel::_state, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_bridge_timelimit(), ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_make_compatible(), ast_channel_unref, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAG_BRIDGE_HANGUP_DONT, ast_free, ast_hangup(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_pbx_start(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, ast_channel::context, do_bridge_masquerade(), ast_bridge_config::end_sound, EVENT_FLAG_CALL, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_DURATION_LIMIT, OPT_CALLEE_HANGUP, OPT_CALLEE_KILL, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DURATION_LIMIT, pbx_builtin_setvar_helper(), ast_channel::priority, ast_bridge_config::start_sound, ast_bridge_config::warning_sound, and xfersound.

Referenced by ast_features_init().

07651 {
07652    struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
07653    char *tmp_data  = NULL;
07654    struct ast_flags opts = { 0, };
07655    struct ast_bridge_config bconfig = { { 0, }, };
07656    char *opt_args[OPT_ARG_ARRAY_SIZE];
07657    struct timeval calldurationlimit = { 0, };
07658 
07659    AST_DECLARE_APP_ARGS(args,
07660       AST_APP_ARG(dest_chan);
07661       AST_APP_ARG(options);
07662    );
07663 
07664    if (ast_strlen_zero(data)) {
07665       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
07666       return -1;
07667    }
07668 
07669    tmp_data = ast_strdupa(data);
07670    AST_STANDARD_APP_ARGS(args, tmp_data);
07671    if (!ast_strlen_zero(args.options))
07672       ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
07673 
07674    /* avoid bridge with ourselves */
07675    if (!strcmp(chan->name, args.dest_chan)) {
07676       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
07677       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07678          "Response: Failed\r\n"
07679          "Reason: Unable to bridge channel to itself\r\n"
07680          "Channel1: %s\r\n"
07681          "Channel2: %s\r\n",
07682          chan->name, args.dest_chan);
07683       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
07684       return 0;
07685    }
07686 
07687    /* make sure we have a valid end point */
07688    if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
07689          strlen(args.dest_chan)))) {
07690       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
07691          args.dest_chan);
07692       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07693          "Response: Failed\r\n"
07694          "Reason: Channel2 does not exist\r\n"
07695          "Channel1: %s\r\n"
07696          "Channel2: %s\r\n", chan->name, args.dest_chan);
07697       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
07698       return 0;
07699    }
07700 
07701    /* try to allocate a place holder where current_dest_chan will be placed */
07702    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
07703       NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
07704       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
07705       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07706          "Response: Failed\r\n"
07707          "Reason: Cannot create placeholder channel\r\n"
07708          "Channel1: %s\r\n"
07709          "Channel2: %s\r\n", chan->name, args.dest_chan);
07710       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07711       ast_channel_unref(current_dest_chan);
07712       return 0;
07713    }
07714 
07715    if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
07716       && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
07717       && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
07718       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07719          "Response: Failed\r\n"
07720          "Reason: Cannot setup bridge time limit\r\n"
07721          "Channel1: %s\r\n"
07722          "Channel2: %s\r\n", chan->name, args.dest_chan);
07723       ast_hangup(final_dest_chan);
07724       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07725       current_dest_chan = ast_channel_unref(current_dest_chan);
07726       goto done;
07727    }
07728 
07729    if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) {
07730       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07731          "Response: Failed\r\n"
07732          "Reason: Cannot masquerade channels\r\n"
07733          "Channel1: %s\r\n"
07734          "Channel2: %s\r\n", chan->name, args.dest_chan);
07735       ast_hangup(final_dest_chan);
07736       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07737       current_dest_chan = ast_channel_unref(current_dest_chan);
07738       goto done;
07739    }
07740 
07741    /* answer the channel if needed */
07742    if (final_dest_chan->_state != AST_STATE_UP) {
07743       ast_answer(final_dest_chan);
07744    }
07745 
07746    chans[0] = current_dest_chan;
07747    chans[1] = final_dest_chan;
07748 
07749    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
07750    /* try to make compatible, send error if we fail */
07751    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
07752       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
07753       ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07754          "Response: Failed\r\n"
07755          "Reason: Could not make channels compatible for bridge\r\n"
07756          "Channel1: %s\r\n"
07757          "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07758 
07759       /* Maybe we should return this channel to the PBX? */
07760       ast_hangup(final_dest_chan);
07761 
07762       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
07763       current_dest_chan = ast_channel_unref(current_dest_chan);
07764       goto done;
07765    }
07766 
07767    /* Report that the bridge will be successfull */
07768    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07769       "Response: Success\r\n"
07770       "Channel1: %s\r\n"
07771       "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07772 
07773    current_dest_chan = ast_channel_unref(current_dest_chan);
07774 
07775    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
07776    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
07777       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
07778          if (ast_waitstream(final_dest_chan, "") < 0)
07779             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
07780       }
07781    }
07782 
07783    if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
07784       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
07785    if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
07786       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
07787    if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
07788       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
07789    if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
07790       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
07791    if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
07792       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
07793    if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
07794       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
07795    if (ast_test_flag(&opts, OPT_CALLEE_PARK))
07796       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
07797    if (ast_test_flag(&opts, OPT_CALLER_PARK))
07798       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
07799 
07800    /*
07801     * Don't let the after-bridge code run the h-exten.  We want to
07802     * continue in the dialplan.
07803     */
07804    ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
07805    ast_bridge_call(chan, final_dest_chan, &bconfig);
07806 
07807    /* The bridge has ended, set BRIDGERESULT to SUCCESS. */
07808    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
07809 
07810    /* If the other channel has not been hung up, return it to the PBX */
07811    if (!ast_check_hangup(final_dest_chan)) {
07812       if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
07813          ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
07814             final_dest_chan->context, final_dest_chan->exten,
07815             final_dest_chan->priority, final_dest_chan->name);
07816 
07817          if (ast_pbx_start(final_dest_chan)) {
07818             ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
07819             ast_hangup(final_dest_chan);
07820          } else {
07821             ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
07822          }
07823       } else {
07824          ast_hangup(final_dest_chan);
07825       }
07826    } else {
07827       ast_debug(1, "chan %s was hungup\n", final_dest_chan->name);
07828       ast_hangup(final_dest_chan);
07829    }
07830 done:
07831    ast_free((char *) bconfig.warning_sound);
07832    ast_free((char *) bconfig.end_sound);
07833    ast_free((char *) bconfig.start_sound);
07834 
07835    return 0;
07836 }

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

Definition at line 6324 of file features.c.

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

Referenced by dialplan_usage_add_parkinglot().

06325 {
06326    struct parking_dp_context *ctx_node;
06327 
06328    ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con));
06329    if (!ctx_node) {
06330       return NULL;
06331    }
06332    if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) {
06333       destroy_dialplan_usage_context(ctx_node);
06334       return NULL;
06335    }
06336    strcpy(ctx_node->context, lot->cfg.parking_con);
06337    return ctx_node;
06338 }

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

Definition at line 6396 of file features.c.

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

Referenced by load_config().

06397 {
06398    int status = 0;
06399    struct ao2_iterator iter;
06400    struct ast_parkinglot *curlot;
06401 
06402    /* For all parking lots */
06403    iter = ao2_iterator_init(parkinglots, 0);
06404    for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) {
06405       /* Add the parking lot to the map. */
06406       if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) {
06407          ao2_ref(curlot, -1);
06408          status = -1;
06409          break;
06410       }
06411    }
06412    ao2_iterator_destroy(&iter);
06413 
06414    return status;
06415 }

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

Definition at line 6087 of file features.c.

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

Referenced by usage_context_add_ramp().

06088 {
06089    struct parking_dp_ramp *ramp_node;
06090 
06091    ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten));
06092    if (!ramp_node) {
06093       return NULL;
06094    }
06095    ramp_node->exclusive = exclusive;
06096    strcpy(ramp_node->exten, exten);
06097    return ramp_node;
06098 }

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

Definition at line 6168 of file features.c.

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

Referenced by usage_context_add_spaces().

06169 {
06170    struct parking_dp_spaces *spaces_node;
06171 
06172    spaces_node = ast_calloc(1, sizeof(*spaces_node));
06173    if (!spaces_node) {
06174       return NULL;
06175    }
06176    spaces_node->start = start;
06177    spaces_node->stop = stop;
06178    return spaces_node;
06179 }

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

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

Definition at line 5689 of file features.c.

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

Referenced by load_config(), and process_config().

05690 {
05691    struct ast_parkinglot *parkinglot;
05692    const struct parkinglot_cfg *cfg_defaults;
05693    struct parkinglot_cfg new_cfg;
05694    int cfg_error;
05695    int oldparkinglot = 0;
05696 
05697    parkinglot = find_parkinglot(pl_name);
05698    if (parkinglot) {
05699       oldparkinglot = 1;
05700    } else {
05701       parkinglot = create_parkinglot(pl_name);
05702       if (!parkinglot) {
05703          return NULL;
05704       }
05705    }
05706    if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) {
05707       cfg_defaults = &parkinglot_cfg_default_default;
05708    } else {
05709       cfg_defaults = &parkinglot_cfg_default;
05710    }
05711    new_cfg = *cfg_defaults;
05712 
05713    ast_debug(1, "Building parking lot %s\n", parkinglot->name);
05714 
05715    ao2_lock(parkinglot);
05716 
05717    /* Do some config stuff */
05718    cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var);
05719    if (oldparkinglot) {
05720       if (cfg_error) {
05721          /* Bad configuration read.  Keep using the original config. */
05722          ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n",
05723             parkinglot->name);
05724          cfg_error = 0;
05725       } else if (!AST_LIST_EMPTY(&parkinglot->parkings)
05726          && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) {
05727          /* Try reloading later when parking lot is empty. */
05728          ast_log(LOG_WARNING,
05729             "Parking lot %s has parked calls.  Parking lot changes discarded.\n",
05730             parkinglot->name);
05731          force_reload_load = 1;
05732       } else {
05733          /* Accept the new config */
05734          parkinglot->cfg = new_cfg;
05735       }
05736    } else {
05737       /* Load the initial parking lot config. */
05738       parkinglot->cfg = new_cfg;
05739    }
05740    parkinglot->the_mark = 0;
05741 
05742    ao2_unlock(parkinglot);
05743 
05744    if (cfg_error) {
05745       /* Only new parking lots could have config errors here. */
05746       ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name);
05747       parkinglot_unref(parkinglot);
05748       return NULL;
05749    }
05750 
05751    /* Move it into the list, if it wasn't already there */
05752    if (!oldparkinglot) {
05753       ao2_link(parkinglots, parkinglot);
05754    }
05755    parkinglot_unref(parkinglot);
05756 
05757    return parkinglot;
05758 }

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

Attended transfer.

Parameters:
chan transferred user
peer person transfering call
config 
code 
sense feature options
data Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel.
Returns:
-1 on failure

Definition at line 2521 of file features.c.

References ast_channel::_state, add_features_datastore(), ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_calloc, AST_CEL_ATTENDEDTRANSFER, ast_cel_report_event(), ast_channel_alloc, ast_channel_connected_line_macro(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_channel_update_connected_line(), ast_check_hangup(), ast_clear_flag, ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_do_masquerade(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAGS_ALL, ast_hangup(), ast_indicate(), ast_log(), ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), atxfer_fail_cleanup(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, ast_bridge_thread_obj::bconfig, bridge_call_thread_launch(), ast_channel::caller, ast_bridge_thread_obj::chan, check_compat(), ast_channel::connected, ast_datastore::data, dial_features_info, ast_bridge_config::end_bridge_callback_data_fixup, feature_request_and_dial(), ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), get_parking_exten(), LOG_WARNING, ast_dial_features::my_features, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_bridge_thread_obj::peer, ast_dial_features::peer_features, ast_channel::readformat, real_ctx(), set_peers(), ast_party_connected_line::source, transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xfer_park_call_helper(), xferfailsound, and xfersound.

02522 {
02523    struct ast_channel *transferer;/* Party B */
02524    struct ast_channel *transferee;/* Party A */
02525    struct ast_exten *park_exten;
02526    const char *chan1_attended_sound;
02527    const char *chan2_attended_sound;
02528    const char *transferer_real_context;
02529    char xferto[256] = "";
02530    int res;
02531    int outstate=0;
02532    struct ast_channel *newchan;
02533    struct ast_channel *xferchan;
02534    struct ast_bridge_thread_obj *tobj;
02535    struct ast_bridge_config bconfig;
02536    int l;
02537    struct ast_party_connected_line connected_line;
02538    struct ast_datastore *features_datastore;
02539    struct ast_dial_features *dialfeatures;
02540    char *transferer_tech;
02541    char *transferer_name;
02542    char *transferer_name_orig;
02543    char *dash;
02544 
02545    ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02546    set_peers(&transferer, &transferee, peer, chan, sense);
02547    transferer_real_context = real_ctx(transferer, transferee);
02548 
02549    /* Start autoservice on transferee while we talk to the transferer */
02550    ast_autoservice_start(transferee);
02551    ast_indicate(transferee, AST_CONTROL_HOLD);
02552 
02553    /* Transfer */
02554    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02555    if (res < 0) {
02556       finishup(transferee);
02557       return -1;
02558    }
02559    if (res > 0) { /* If they've typed a digit already, handle it */
02560       xferto[0] = (char) res;
02561    }
02562 
02563    /* this is specific of atxfer */
02564    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02565    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
02566       finishup(transferee);
02567       return -1;
02568    }
02569    l = strlen(xferto);
02570    if (res == 0) {
02571       if (l) {
02572          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02573             xferto, transferer_real_context);
02574       } else {
02575          /* Does anyone care about this case? */
02576          ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
02577       }
02578       ast_stream_and_wait(transferer, "pbx-invalid", "");
02579       finishup(transferee);
02580       return AST_FEATURE_RETURN_SUCCESS;
02581    }
02582 
02583    park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
02584    if (park_exten) {
02585       /* We are transfering the transferee to a parking lot. */
02586       return xfer_park_call_helper(transferee, transferer, park_exten);
02587    }
02588 
02589    /*
02590     * Append context to dialed transfer number.
02591     *
02592     * NOTE: The local channel needs the /n flag so party C will use
02593     * the feature flags set by the dialplan when calling that
02594     * party.
02595     */
02596    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
02597 
02598    /* If we are performing an attended transfer and we have two channels involved then
02599       copy sound file information to play upon attended transfer completion */
02600    chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02601    chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02602    if (!ast_strlen_zero(chan1_attended_sound)) {
02603       pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
02604    }
02605    if (!ast_strlen_zero(chan2_attended_sound)) {
02606       pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
02607    }
02608 
02609    /* Extract redial transferer information from the channel name. */
02610    transferer_name_orig = ast_strdupa(transferer->name);
02611    transferer_name = ast_strdupa(transferer_name_orig);
02612    transferer_tech = strsep(&transferer_name, "/");
02613    dash = strrchr(transferer_name, '-');
02614    if (dash) {
02615       /* Trim off channel name sequence/serial number. */
02616       *dash = '\0';
02617    }
02618 
02619    /* Stop autoservice so we can monitor all parties involved in the transfer. */
02620    if (ast_autoservice_stop(transferee) < 0) {
02621       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02622       return -1;
02623    }
02624 
02625    /* Save connected line info for party B about party A in case transfer fails. */
02626    ast_party_connected_line_init(&connected_line);
02627    ast_channel_lock(transferer);
02628    ast_party_connected_line_copy(&connected_line, &transferer->connected);
02629    ast_channel_unlock(transferer);
02630    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02631 
02632    /* Dial party C */
02633    newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
02634       transferee, "Local", ast_best_codec(transferer->nativeformats), xferto,
02635       atxfernoanswertimeout, &outstate, transferer->language);
02636    ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
02637 
02638    if (!ast_check_hangup(transferer)) {
02639       int hangup_dont = 0;
02640 
02641       /* Transferer (party B) is up */
02642       ast_debug(1, "Actually doing an attended transfer.\n");
02643 
02644       /* Start autoservice on transferee while the transferer deals with party C. */
02645       ast_autoservice_start(transferee);
02646 
02647       ast_indicate(transferer, -1);
02648       if (!newchan) {
02649          /* any reason besides user requested cancel and busy triggers the failed sound */
02650          switch (outstate) {
02651          case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */
02652          case AST_CONTROL_BUSY:
02653          case AST_CONTROL_CONGESTION:
02654             if (ast_stream_and_wait(transferer, xfersound, "")) {
02655                ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02656             }
02657             break;
02658          default:
02659             if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02660                ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02661             }
02662             break;
02663          }
02664          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02665          return AST_FEATURE_RETURN_SUCCESS;
02666       }
02667 
02668       if (check_compat(transferer, newchan)) {
02669          if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02670             ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02671          }
02672          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02673          return AST_FEATURE_RETURN_SUCCESS;
02674       }
02675       memset(&bconfig,0,sizeof(struct ast_bridge_config));
02676       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
02677       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
02678 
02679       /*
02680        * ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we
02681        * don't want that to happen here because the transferer is in
02682        * another bridge already.
02683        */
02684       if (ast_test_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT)) {
02685          hangup_dont = 1;
02686       }
02687 
02688       /*
02689        * Don't let the after-bridge code run the h-exten.  It is the
02690        * wrong bridge to run the h-exten after.
02691        */
02692       ast_set_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT);
02693 
02694       /*
02695        * Let party B and C talk as long as they want while party A
02696        * languishes in autoservice listening to MOH.
02697        */
02698       ast_bridge_call(transferer, newchan, &bconfig);
02699 
02700       if (hangup_dont) {
02701          /* Restore the AST_FLAG_BRIDGE_HANGUP_DONT flag */
02702          ast_set_flag(transferer, AST_FLAG_BRIDGE_HANGUP_DONT);
02703       }
02704 
02705       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
02706          ast_hangup(newchan);
02707          if (ast_stream_and_wait(transferer, xfersound, "")) {
02708             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02709          }
02710          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02711          return AST_FEATURE_RETURN_SUCCESS;
02712       }
02713 
02714       /* Transferer (party B) is confirmed hung up at this point. */
02715       if (check_compat(transferee, newchan)) {
02716          finishup(transferee);
02717          ast_party_connected_line_free(&connected_line);
02718          return -1;
02719       }
02720 
02721       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02722       if ((ast_autoservice_stop(transferee) < 0)
02723          || (ast_waitfordigit(transferee, 100) < 0)
02724          || (ast_waitfordigit(newchan, 100) < 0)
02725          || ast_check_hangup(transferee)
02726          || ast_check_hangup(newchan)) {
02727          ast_hangup(newchan);
02728          ast_party_connected_line_free(&connected_line);
02729          return -1;
02730       }
02731    } else if (!ast_check_hangup(transferee)) {
02732       /* Transferer (party B) has hung up at this point.  Doing blonde transfer. */
02733       ast_debug(1, "Actually doing a blonde transfer.\n");
02734 
02735       if (!newchan && !atxferdropcall) {
02736          /* Party C is not available, try to call party B back. */
02737          unsigned int tries = 0;
02738 
02739          if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
02740             ast_log(LOG_WARNING,
02741                "Transferer channel name: '%s' cannot be used for callback.\n",
02742                transferer_name_orig);
02743             ast_indicate(transferee, AST_CONTROL_UNHOLD);
02744             ast_party_connected_line_free(&connected_line);
02745             return -1;
02746          }
02747 
02748          tries = 0;
02749          for (;;) {
02750             /* Try to get party B back. */
02751             ast_debug(1, "We're trying to callback %s/%s\n",
02752                transferer_tech, transferer_name);
02753             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02754                transferee, transferee, transferer_tech,
02755                ast_best_codec(transferee->nativeformats), transferer_name,
02756                atxfernoanswertimeout, &outstate, transferer->language);
02757             ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
02758                !!newchan, outstate);
02759             if (newchan) {
02760                /*
02761                 * We have recalled party B (newchan).  We need to give this
02762                 * call leg the same feature flags as the original party B call
02763                 * leg.
02764                 */
02765                ast_channel_lock(transferer);
02766                features_datastore = ast_channel_datastore_find(transferer,
02767                   &dial_features_info, NULL);
02768                if (features_datastore && (dialfeatures = features_datastore->data)) {
02769                   struct ast_flags my_features = { 0 };
02770                   struct ast_flags peer_features = { 0 };
02771 
02772                   ast_copy_flags(&my_features, &dialfeatures->my_features,
02773                      AST_FLAGS_ALL);
02774                   ast_copy_flags(&peer_features, &dialfeatures->peer_features,
02775                      AST_FLAGS_ALL);
02776                   ast_channel_unlock(transferer);
02777                   add_features_datastore(newchan, &my_features, &peer_features);
02778                } else {
02779                   ast_channel_unlock(transferer);
02780                }
02781                break;
02782             }
02783             if (ast_check_hangup(transferee)) {
02784                break;
02785             }
02786 
02787             ++tries;
02788             if (atxfercallbackretries <= tries) {
02789                /* No more callback tries remaining. */
02790                break;
02791             }
02792 
02793             if (atxferloopdelay) {
02794                /* Transfer failed, sleeping */
02795                ast_debug(1, "Sleeping for %u ms before retrying atxfer.\n",
02796                   atxferloopdelay);
02797                ast_safe_sleep(transferee, atxferloopdelay);
02798                if (ast_check_hangup(transferee)) {
02799                   ast_party_connected_line_free(&connected_line);
02800                   return -1;
02801                }
02802             }
02803 
02804             /* Retry dialing party C. */
02805             ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
02806             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02807                transferer, transferee, "Local",
02808                ast_best_codec(transferee->nativeformats), xferto,
02809                atxfernoanswertimeout, &outstate, transferer->language);
02810             ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
02811                !!newchan, outstate);
02812             if (newchan || ast_check_hangup(transferee)) {
02813                break;
02814             }
02815          }
02816       }
02817       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02818       if (!newchan) {
02819          /* No party C or could not callback party B. */
02820          ast_party_connected_line_free(&connected_line);
02821          return -1;
02822       }
02823 
02824       /* newchan is up, we should prepare transferee and bridge them */
02825       if (ast_check_hangup(newchan)) {
02826          ast_hangup(newchan);
02827          ast_party_connected_line_free(&connected_line);
02828          return -1;
02829       }
02830       if (check_compat(transferee, newchan)) {
02831          ast_party_connected_line_free(&connected_line);
02832          return -1;
02833       }
02834    } else {
02835       /*
02836        * Both the transferer and transferee have hungup.  If newchan
02837        * is up, hang it up as it has no one to talk to.
02838        */
02839       ast_debug(1, "Everyone is hungup.\n");
02840       if (newchan) {
02841          ast_hangup(newchan);
02842       }
02843       ast_party_connected_line_free(&connected_line);
02844       return -1;
02845    }
02846 
02847    /* Initiate the channel transfer of party A to party C (or recalled party B). */
02848    ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
02849 
02850    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name);
02851    if (!xferchan) {
02852       ast_hangup(newchan);
02853       ast_party_connected_line_free(&connected_line);
02854       return -1;
02855    }
02856 
02857    /* Give party A a momentary ringback tone during transfer. */
02858    xferchan->visible_indication = AST_CONTROL_RINGING;
02859 
02860    /* Make formats okay */
02861    xferchan->readformat = transferee->readformat;
02862    xferchan->writeformat = transferee->writeformat;
02863 
02864    if (ast_channel_masquerade(xferchan, transferee)) {
02865       ast_hangup(xferchan);
02866       ast_hangup(newchan);
02867       ast_party_connected_line_free(&connected_line);
02868       return -1;
02869    }
02870 
02871    dash = strrchr(xferto, '@');
02872    if (dash) {
02873       /* Trim off the context. */
02874       *dash = '\0';
02875    }
02876    ast_explicit_goto(xferchan, transferer_real_context, xferto, 1);
02877    xferchan->_state = AST_STATE_UP;
02878    ast_clear_flag(xferchan, AST_FLAGS_ALL);
02879 
02880    /* Do the masquerade manually to make sure that is is completed. */
02881    ast_do_masquerade(xferchan);
02882 
02883    newchan->_state = AST_STATE_UP;
02884    ast_clear_flag(newchan, AST_FLAGS_ALL);
02885    tobj = ast_calloc(1, sizeof(*tobj));
02886    if (!tobj) {
02887       ast_hangup(xferchan);
02888       ast_hangup(newchan);
02889       ast_party_connected_line_free(&connected_line);
02890       return -1;
02891    }
02892 
02893    tobj->chan = newchan;
02894    tobj->peer = xferchan;
02895    tobj->bconfig = *config;
02896 
02897    ast_channel_lock(newchan);
02898    features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL);
02899    if (features_datastore && (dialfeatures = features_datastore->data)) {
02900       ast_copy_flags(&tobj->bconfig.features_callee, &dialfeatures->my_features,
02901          AST_FLAGS_ALL);
02902    }
02903    ast_channel_unlock(newchan);
02904 
02905    ast_channel_lock(xferchan);
02906    features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL);
02907    if (features_datastore && (dialfeatures = features_datastore->data)) {
02908       ast_copy_flags(&tobj->bconfig.features_caller, &dialfeatures->my_features,
02909          AST_FLAGS_ALL);
02910    }
02911    ast_channel_unlock(xferchan);
02912 
02913    if (tobj->bconfig.end_bridge_callback_data_fixup) {
02914       tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
02915    }
02916 
02917    /*
02918     * xferchan is transferee, and newchan is the transfer target
02919     * So...in a transfer, who is the caller and who is the callee?
02920     *
02921     * When the call is originally made, it is clear who is caller and callee.
02922     * When a transfer occurs, it is my humble opinion that the transferee becomes
02923     * the caller, and the transfer target is the callee.
02924     *
02925     * The problem is that these macros were set with the intention of the original
02926     * caller and callee taking those roles.  A transfer can totally mess things up,
02927     * to be technical.  What sucks even more is that you can't effectively change
02928     * the macros in the dialplan during the call from the transferer to the transfer
02929     * target because the transferee is stuck with whatever role he originally had.
02930     *
02931     * I think the answer here is just to make sure that it is well documented that
02932     * during a transfer, the transferee is the "caller" and the transfer target
02933     * is the "callee."
02934     *
02935     * This means that if party B calls party A, and party B transfers party A to
02936     * party C, then A has switched roles for the call.  Now party A will have the
02937     * caller macro called on his channel instead of the callee macro.
02938     *
02939     * Luckily, the method by which the party B to party C bridge is
02940     * launched above ensures that the transferee is the "chan" on
02941     * the bridge and the transfer target is the "peer," so my idea
02942     * for the roles post-transfer does not require extensive code
02943     * changes.
02944     */
02945 
02946    /* Transfer party C connected line to party A */
02947    ast_channel_lock(transferer);
02948    /*
02949     * Due to a limitation regarding when callerID is set on a Local channel,
02950     * we use the transferer's connected line information here.
02951     */
02952    ast_party_connected_line_copy(&connected_line, &transferer->connected);
02953    ast_channel_unlock(transferer);
02954    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02955    if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
02956       ast_channel_update_connected_line(xferchan, &connected_line, NULL);
02957    }
02958 
02959    /* Transfer party A connected line to party C */
02960    ast_channel_lock(xferchan);
02961    ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller);
02962    ast_channel_unlock(xferchan);
02963    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02964    if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
02965       ast_channel_update_connected_line(newchan, &connected_line, NULL);
02966    }
02967 
02968    if (ast_stream_and_wait(newchan, xfersound, ""))
02969       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02970    bridge_call_thread_launch(tobj);
02971 
02972    ast_party_connected_line_free(&connected_line);
02973    return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */
02974 }

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

Definition at line 2200 of file features.c.

References args, ast_alloca, AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_unlock, AST_FEATURE_RETURN_SUCCESS, AST_FRAME_DTMF_END, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_COR, S_OR, set_peers(), stopmixmonitor_app, stopmixmonitor_ok, ast_party_number::str, and ast_party_number::valid.

02201 {
02202    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
02203    int x = 0;
02204    size_t len;
02205    struct ast_channel *caller_chan, *callee_chan;
02206    const char *mixmonitor_spy_type = "MixMonitor";
02207    const char *touch_format;
02208    const char *touch_monitor;
02209    int count = 0;
02210 
02211    if (!mixmonitor_ok) {
02212       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
02213       return -1;
02214    }
02215 
02216    if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
02217       mixmonitor_ok = 0;
02218       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
02219       return -1;
02220    }
02221 
02222    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
02223 
02224    if (!ast_strlen_zero(courtesytone)) {
02225       if (ast_autoservice_start(callee_chan))
02226          return -1;
02227       ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
02228       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
02229          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02230          ast_autoservice_stop(callee_chan);
02231          return -1;
02232       }
02233       if (ast_autoservice_stop(callee_chan))
02234          return -1;
02235    }
02236 
02237    ast_channel_lock(callee_chan);
02238    count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
02239    ast_channel_unlock(callee_chan);
02240 
02241    /* This means a mixmonitor is attached to the channel, running or not is unknown. */
02242    if (count > 0) {
02243       ast_verb(3, "User hit '%s' to stop recording call.\n", code);
02244 
02245       /* Make sure they are running */
02246       ast_channel_lock(callee_chan);
02247       count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
02248       ast_channel_unlock(callee_chan);
02249       if (count > 0) {
02250          if (!stopmixmonitor_ok) {
02251             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
02252             return -1;
02253          }
02254          if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
02255             stopmixmonitor_ok = 0;
02256             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
02257             return -1;
02258          } else {
02259             pbx_exec(callee_chan, stopmixmonitor_app, "");
02260             return AST_FEATURE_RETURN_SUCCESS;
02261          }
02262       }
02263       
02264       ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 
02265    }        
02266 
02267    touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
02268    touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
02269 
02270    if (!touch_format)
02271       touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
02272 
02273    if (!touch_monitor)
02274       touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
02275 
02276    if (touch_monitor) {
02277       len = strlen(touch_monitor) + 50;
02278       args = ast_alloca(len);
02279       touch_filename = ast_alloca(len);
02280       snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
02281       snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
02282    } else {
02283       caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
02284          caller_chan->caller.id.number.str, caller_chan->name));
02285       callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
02286          callee_chan->caller.id.number.str, callee_chan->name));
02287       len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
02288       args = ast_alloca(len);
02289       touch_filename = ast_alloca(len);
02290       snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
02291       snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
02292    }
02293 
02294    for( x = 0; x < strlen(args); x++) {
02295       if (args[x] == '/')
02296          args[x] = '-';
02297    }
02298 
02299    ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
02300 
02301    pbx_exec(callee_chan, mixmonitor_app, args);
02302    pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
02303    pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
02304    return AST_FEATURE_RETURN_SUCCESS;
02305 }

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

Monitor a channel by DTMF.

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 2098 of file features.c.

References args, ast_alloca, AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, EVENT_FLAG_USER, ast_party_caller::id, LOG_ERROR, manager_event, ast_channel::monitor, monitor_app, monitor_ok, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_COR, S_OR, set_peers(), ast_channel_monitor::stop, ast_party_number::str, and ast_party_number::valid.

02099 {
02100    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
02101    int x = 0;
02102    size_t len;
02103    struct ast_channel *caller_chan, *callee_chan;
02104    const char *automon_message_start = NULL;
02105    const char *automon_message_stop = NULL;
02106    const char *touch_format = NULL;
02107    const char *touch_monitor = NULL;
02108    const char *touch_monitor_prefix = NULL;
02109 
02110    if (!monitor_ok) {
02111       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
02112       return -1;
02113    }
02114 
02115    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
02116       monitor_ok = 0;
02117       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
02118       return -1;
02119    }
02120 
02121    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
02122 
02123    /* Find extra messages */
02124    automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
02125    automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
02126 
02127    if (!ast_strlen_zero(courtesytone)) {  /* Play courtesy tone if configured */
02128       if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
02129          return -1;
02130       }
02131    }
02132    
02133    if (callee_chan->monitor) {
02134       manager_event(EVENT_FLAG_USER, "UserEvent",
02135                            "UserEvent: StopRec\r\n"
02136                            "Uniqueid: %s\r\n",
02137                            caller_chan->uniqueid);
02138       ast_verb(4, "User hit '%s' to stop recording call.\n", code);
02139       if (!ast_strlen_zero(automon_message_stop)) {
02140          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
02141       }
02142       callee_chan->monitor->stop(callee_chan, 1);
02143       return AST_FEATURE_RETURN_SUCCESS;
02144    }
02145 
02146    touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
02147    touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
02148    touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
02149 
02150    if (!touch_format)
02151       touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
02152 
02153    if (!touch_monitor)
02154       touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
02155 
02156    if (!touch_monitor_prefix)
02157       touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
02158 
02159    if (touch_monitor) {
02160       len = strlen(touch_monitor) + 50;
02161       args = ast_alloca(len);
02162       touch_filename = ast_alloca(len);
02163       snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
02164       snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
02165    } else {
02166       caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
02167          caller_chan->caller.id.number.str, caller_chan->name));
02168       callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
02169          callee_chan->caller.id.number.str, callee_chan->name));
02170       len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
02171       args = ast_alloca(len);
02172       touch_filename = ast_alloca(len);
02173       snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
02174       snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
02175    }
02176 
02177    for(x = 0; x < strlen(args); x++) {
02178       if (args[x] == '/')
02179          args[x] = '-';
02180    }
02181    
02182    manager_event(EVENT_FLAG_USER, "UserEvent",
02183                         "UserEvent: Rec\r\n"
02184                         "Uniqueid: %s\r\n"
02185                         "FileName: %s\r\n",
02186                         caller_chan->uniqueid, touch_filename);
02187    ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
02188 
02189    pbx_exec(callee_chan, monitor_app, args);
02190    pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
02191    pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
02192 
02193    if (!ast_strlen_zero(automon_message_start)) {  /* Play start message for both channels */
02194       play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
02195    }
02196 
02197    return AST_FEATURE_RETURN_SUCCESS;
02198 }

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

Blind transfer user to another extension.

Parameters:
chan channel to be transferred
peer channel initiated blind transfer
config 
code 
data 
sense feature options

Place chan on hold, check if transferred to parkinglot extension, otherwise check extension exists and transfer caller.

Return values:
AST_FEATURE_RETURN_SUCCESS. 
-1 on failure.

Definition at line 2350 of file features.c.

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

02351 {
02352    struct ast_channel *transferer;
02353    struct ast_channel *transferee;
02354    struct ast_exten *park_exten;
02355    const char *transferer_real_context;
02356    char xferto[256] = "";
02357    int res;
02358 
02359    ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02360    set_peers(&transferer, &transferee, peer, chan, sense);
02361    transferer_real_context = real_ctx(transferer, transferee);
02362 
02363    /* Start autoservice on transferee while we talk to the transferer */
02364    ast_autoservice_start(transferee);
02365    ast_indicate(transferee, AST_CONTROL_HOLD);
02366 
02367    /* Transfer */
02368    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02369    if (res < 0) {
02370       finishup(transferee);
02371       return -1; /* error ? */
02372    }
02373    if (res > 0) { /* If they've typed a digit already, handle it */
02374       xferto[0] = (char) res;
02375    }
02376 
02377    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02378    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
02379       finishup(transferee);
02380       return -1;
02381    }
02382    if (res == 0) {
02383       if (xferto[0]) {
02384          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02385             xferto, transferer_real_context);
02386       } else {
02387          /* Does anyone care about this case? */
02388          ast_log(LOG_WARNING, "No digits dialed.\n");
02389       }
02390       ast_stream_and_wait(transferer, "pbx-invalid", "");
02391       finishup(transferee);
02392       return AST_FEATURE_RETURN_SUCCESS;
02393    }
02394 
02395    park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
02396    if (park_exten) {
02397       /* We are transfering the transferee to a parking lot. */
02398       return xfer_park_call_helper(transferee, transferer, park_exten);
02399    }
02400 
02401    /* Do blind transfer. */
02402    ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n",
02403       transferee->name, xferto, transferer_real_context);
02404    ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
02405    pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
02406    pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
02407    finishup(transferee);
02408    ast_channel_lock(transferer);
02409    if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
02410       transferer->cdr = ast_cdr_alloc();
02411       if (transferer->cdr) {
02412          ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */
02413          ast_cdr_start(transferer->cdr);
02414       }
02415    }
02416    ast_channel_unlock(transferer);
02417    if (transferer->cdr) {
02418       struct ast_cdr *swap = transferer->cdr;
02419 
02420       ast_debug(1,
02421          "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
02422          transferer->name, transferee->name, transferer->cdr->lastapp,
02423          transferer->cdr->lastdata, transferer->cdr->channel,
02424          transferer->cdr->dstchannel);
02425       ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
02426          transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel,
02427          transferee->cdr->dstchannel);
02428       ast_debug(1, "transferer_real_context=%s; xferto=%s\n",
02429          transferer_real_context, xferto);
02430       /* swap cdrs-- it will save us some time & work */
02431       transferer->cdr = transferee->cdr;
02432       transferee->cdr = swap;
02433    }
02434    if (!transferee->pbx) {
02435       /* Doh!  Use our handy async_goto functions */
02436       ast_debug(1, "About to ast_async_goto %s.\n", transferee->name);
02437       if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) {
02438          ast_log(LOG_WARNING, "Async goto failed :-(\n");
02439       }
02440 
02441       /* The transferee is masqueraded and the original bridged channels can be hungup. */
02442       res = -1;
02443    } else {
02444       /* Set the transferee's new extension, since it exists, using transferer context */
02445       ast_debug(1, "About to explicit goto %s, it has a PBX.\n", transferee->name);
02446       ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
02447       set_c_e_p(transferee, transferer_real_context, xferto, 0);
02448 
02449       /*
02450        * Break the bridge.  The transferee needs to resume executing
02451        * dialplan at the xferto location.
02452        */
02453       res = AST_FEATURE_RETURN_SUCCESSBREAK;
02454    }
02455    check_goto_on_transfer(transferer);
02456    return res;
02457 }

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

Definition at line 2307 of file features.c.

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

02308 {
02309    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
02310    return AST_FEATURE_RETURN_HANGUP;
02311 }

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

support routing for one touch call parking

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 1976 of file features.c.

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

01977 {
01978    struct ast_channel *parker;
01979    struct ast_channel *parkee;
01980    struct ast_park_call_args args = { 0, };
01981 
01982    /*
01983     * We used to set chan's exten and priority to "s" and 1 here,
01984     * but this generates (in some cases) an invalid extension, and
01985     * if "s" exists, could errantly cause execution of extensions
01986     * you don't expect.  It makes more sense to let nature take its
01987     * course when chan finishes, and let the pbx do its thing and
01988     * hang up when the park is over.
01989     */
01990 
01991    /* Answer if call is not up */
01992    if (chan->_state != AST_STATE_UP) {
01993       /*
01994        * XXX Why are we doing this?  Both of the channels should be up
01995        * since you cannot do DTMF features unless you are bridged.
01996        */
01997       if (ast_answer(chan)) {
01998          return -1;
01999       }
02000 
02001       /* Sleep to allow VoIP streams to settle down */
02002       if (ast_safe_sleep(chan, 1000)) {
02003          return -1;
02004       }
02005    }
02006 
02007    /* one direction used to call park_call.... */
02008    set_peers(&parker, &parkee, peer, chan, sense);
02009    return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1;
02010 }

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

Definition at line 4651 of file features.c.

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

Referenced by manage_parked_call().

04652 {
04653    int i = 0;
04654    enum {
04655       OPT_CALLEE_REDIRECT   = 't',
04656       OPT_CALLER_REDIRECT   = 'T',
04657       OPT_CALLEE_AUTOMON    = 'w',
04658       OPT_CALLER_AUTOMON    = 'W',
04659       OPT_CALLEE_DISCONNECT = 'h',
04660       OPT_CALLER_DISCONNECT = 'H',
04661       OPT_CALLEE_PARKCALL   = 'k',
04662       OPT_CALLER_PARKCALL   = 'K',
04663    };
04664 
04665    memset(options, 0, len);
04666    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
04667       options[i++] = OPT_CALLER_REDIRECT;
04668    }
04669    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
04670       options[i++] = OPT_CALLER_AUTOMON;
04671    }
04672    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
04673       options[i++] = OPT_CALLER_DISCONNECT;
04674    }
04675    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
04676       options[i++] = OPT_CALLER_PARKCALL;
04677    }
04678 
04679    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
04680       options[i++] = OPT_CALLEE_REDIRECT;
04681    }
04682    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
04683       options[i++] = OPT_CALLEE_AUTOMON;
04684    }
04685    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
04686       options[i++] = OPT_CALLEE_DISCONNECT;
04687    }
04688    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
04689       options[i++] = OPT_CALLEE_PARKCALL;
04690    }
04691 
04692    return options;
04693 }

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

make channels compatible

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

Definition at line 2466 of file features.c.

References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING.

Referenced by builtin_atxfer().

02467 {
02468    if (ast_channel_make_compatible(c, newchan) < 0) {
02469       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
02470          c->name, newchan->name);
02471       ast_hangup(newchan);
02472       return -1;
02473    }
02474    return 0;
02475 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Check goto on transfer.

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 896 of file features.c.

References ast_channel::_state, ast_channel_alloc, ast_channel_clear_softhangup(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_clear_flag, ast_debug, ast_do_masquerade(), AST_FLAGS_ALL, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), AST_SOFTHANGUP_ALL, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.

Referenced by builtin_blindtransfer().

00897 {
00898    struct ast_channel *xferchan;
00899    const char *val;
00900    char *goto_on_transfer;
00901    char *x;
00902 
00903    ast_channel_lock(chan);
00904    val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00905    if (ast_strlen_zero(val)) {
00906       ast_channel_unlock(chan);
00907       return;
00908    }
00909    goto_on_transfer = ast_strdupa(val);
00910    ast_channel_unlock(chan);
00911 
00912    ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, chan->name);
00913 
00914    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0,
00915       "%s", chan->name);
00916    if (!xferchan) {
00917       return;
00918    }
00919 
00920    /* Make formats okay */
00921    xferchan->readformat = chan->readformat;
00922    xferchan->writeformat = chan->writeformat;
00923 
00924    if (ast_channel_masquerade(xferchan, chan)) {
00925       /* Failed to setup masquerade. */
00926       ast_hangup(xferchan);
00927       return;
00928    }
00929 
00930    for (x = goto_on_transfer; *x; ++x) {
00931       if (*x == '^') {
00932          *x = ',';
00933       }
00934    }
00935    ast_parseable_goto(xferchan, goto_on_transfer);
00936    xferchan->_state = AST_STATE_UP;
00937    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00938    ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
00939 
00940    ast_do_masquerade(xferchan);
00941    if (ast_pbx_start(xferchan)) {
00942       /* Failed to start PBX. */
00943       ast_hangup(xferchan);
00944    }
00945 }

static void clear_dialed_interfaces ( struct ast_channel chan  )  [static]

Definition at line 3911 of file features.c.

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

Referenced by ast_bridge_call().

03912 {
03913    struct ast_datastore *di_datastore;
03914 
03915    ast_channel_lock(chan);
03916    if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
03917       if (option_debug) {
03918          ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name);
03919       }
03920       if (!ast_channel_datastore_remove(chan, di_datastore)) {
03921          ast_datastore_free(di_datastore);
03922       }
03923    }
03924    ast_channel_unlock(chan);
03925 }

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

Copy parkinglot and store it with new name.

Definition at line 5034 of file features.c.

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

Referenced by create_dynamic_parkinglot().

05035 {
05036    struct ast_parkinglot *copylot;
05037 
05038    if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
05039       ao2_ref(copylot, -1);
05040       return NULL;
05041    }
05042 
05043    copylot = create_parkinglot(name);
05044    if (!copylot) {
05045       return NULL;
05046    }
05047 
05048    ast_debug(1, "Building parking lot %s\n", name);
05049 
05050    /* Copy the source parking lot configuration. */
05051    copylot->cfg = parkinglot->cfg;
05052 
05053    return copylot;
05054 }

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

Definition at line 1165 of file features.c.

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

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

01166 {
01167    const char *dyn_context;
01168    const char *dyn_exten;
01169    const char *dyn_range;
01170    const char *template_name;
01171    struct ast_parkinglot *template_parkinglot = NULL;
01172    struct ast_parkinglot *parkinglot;
01173    int dyn_start;
01174    int dyn_end;
01175 
01176    ast_channel_lock(chan);
01177    template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
01178    dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
01179    dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), ""));
01180    dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
01181    ast_channel_unlock(chan);
01182 
01183    if (!ast_strlen_zero(template_name)) {
01184       template_parkinglot = find_parkinglot(template_name);
01185       if (!template_parkinglot) {
01186          ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n",
01187             template_name);
01188       } else if (template_parkinglot->cfg.is_invalid) {
01189          ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n",
01190             template_name);
01191          parkinglot_unref(template_parkinglot);
01192          template_parkinglot = NULL;
01193       }
01194    }
01195    if (!template_parkinglot) {
01196       template_parkinglot = parkinglot_addref(default_parkinglot);
01197       ast_debug(1, "Using default parking lot for template\n");
01198    }
01199 
01200    parkinglot = copy_parkinglot(name, template_parkinglot);
01201    if (!parkinglot) {
01202       ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
01203    } else {
01204       /* Configure the dynamic parking lot. */
01205       if (!ast_strlen_zero(dyn_context)) {
01206          ast_copy_string(parkinglot->cfg.parking_con, dyn_context,
01207             sizeof(parkinglot->cfg.parking_con));
01208       }
01209       if (!ast_strlen_zero(dyn_exten)) {
01210          ast_copy_string(parkinglot->cfg.parkext, dyn_exten,
01211             sizeof(parkinglot->cfg.parkext));
01212       }
01213       if (!ast_strlen_zero(dyn_range)) {
01214          if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
01215             ast_log(LOG_WARNING,
01216                "Format for parking positions is a-b, where a and b are numbers\n");
01217          } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) {
01218             ast_log(LOG_WARNING,
01219                "Format for parking positions is a-b, where a <= b\n");
01220          } else {
01221             parkinglot->cfg.parking_start = dyn_start;
01222             parkinglot->cfg.parking_stop = dyn_end;
01223          }
01224       }
01225 
01226       /*
01227        * Sanity check for dynamic parking lot configuration.
01228        *
01229        * XXX It may be desirable to instead check if the dynamic
01230        * parking lot overlaps any existing lots like what is done for
01231        * a reload.
01232        */
01233       if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) {
01234          if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext)
01235             && parkinglot->cfg.parkext_exclusive) {
01236             ast_log(LOG_WARNING,
01237                "Parking lot '%s' conflicts with template parking lot '%s'!\n"
01238                "Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n",
01239                parkinglot->name, template_parkinglot->name);
01240          }
01241          if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start
01242                && parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop)
01243             || (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop
01244                && parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop)
01245             || (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start
01246                && template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) {
01247             ast_log(LOG_WARNING,
01248                "Parking lot '%s' parking spaces overlap template parking lot '%s'!\n"
01249                "Change PARKINGDYNPOS.\n",
01250                parkinglot->name, template_parkinglot->name);
01251          }
01252       }
01253 
01254       parkinglot_activate(parkinglot);
01255       ao2_link(parkinglots, parkinglot);
01256    }
01257    parkinglot_unref(template_parkinglot);
01258 
01259    return parkinglot;
01260 }

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

Allocate parking lot structure.

Definition at line 5459 of file features.c.

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

Referenced by build_parkinglot(), and copy_parkinglot().

05460 {
05461    struct ast_parkinglot *newlot;
05462 
05463    if (ast_strlen_zero(name)) { /* No name specified */
05464       return NULL;
05465    }
05466 
05467    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
05468    if (!newlot)
05469       return NULL;
05470    
05471    ast_copy_string(newlot->name, name, sizeof(newlot->name));
05472    newlot->cfg.is_invalid = 1;/* No config is set yet. */
05473    AST_LIST_HEAD_INIT(&newlot->parkings);
05474 
05475    return newlot;
05476 }

static void destroy_dialplan_usage_context ( struct parking_dp_context doomed  )  [static]

Definition at line 6043 of file features.c.

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

Referenced by build_dialplan_useage_context(), and destroy_dialplan_usage_map().

06044 {
06045    struct parking_dp_ramp *ramp;
06046    struct parking_dp_spaces *spaces;
06047 
06048    while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) {
06049       ast_free(ramp);
06050    }
06051    while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) {
06052       ast_free(spaces);
06053    }
06054    while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) {
06055       ast_free(spaces);
06056    }
06057    ast_free(doomed);
06058 }

static void destroy_dialplan_usage_map ( struct parking_dp_map doomed  )  [static]

Definition at line 6068 of file features.c.

References AST_LIST_REMOVE_HEAD, and destroy_dialplan_usage_context().

Referenced by load_config().

06069 {
06070    struct parking_dp_context *item;
06071 
06072    while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) {
06073       destroy_dialplan_usage_context(item);
06074    }
06075 }

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

Definition at line 6498 of file features.c.

References AST_MAX_EXTENSION, PRIORITY_HINT, and remove_exten_if_exist().

Referenced by remove_dead_context_usage(), and remove_dead_spaces_usage().

06499 {
06500    char exten[AST_MAX_EXTENSION];
06501 
06502    /* Destroy priorities of the parking space that we registered. */
06503    snprintf(exten, sizeof(exten), "%d", space);
06504    remove_exten_if_exist(context, exten, PRIORITY_HINT);
06505    remove_exten_if_exist(context, exten, 1);
06506 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 744 of file features.c.

References ast_free.

00745 {
00746    struct ast_dial_features *df = data;
00747    if (df) {
00748       ast_free(df);
00749    }
00750 }

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

Definition at line 731 of file features.c.

References ast_calloc.

00732 {
00733    struct ast_dial_features *df = data, *df_copy;
00734  
00735    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00736       return NULL;
00737    }
00738  
00739    memcpy(df_copy, df, sizeof(*df));
00740  
00741    return df_copy;
00742 }

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

Definition at line 6351 of file features.c.

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

Referenced by build_dialplan_useage_map().

06352 {
06353    struct parking_dp_context *cur_ctx;
06354    struct parking_dp_context *new_ctx;
06355    int cmp;
06356 
06357    AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) {
06358       cmp = strcmp(lot->cfg.parking_con, cur_ctx->context);
06359       if (cmp > 0) {
06360          /* The parking lot context goes after this node. */
06361          continue;
06362       }
06363       if (cmp == 0) {
06364          /* This is the node we will add parking lot spaces to the map. */
06365          return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain);
06366       }
06367       /* The new parking lot context goes before this node. */
06368       new_ctx = build_dialplan_useage_context(lot);
06369       if (!new_ctx) {
06370          return -1;
06371       }
06372       AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node);
06373       return 0;
06374    }
06375    AST_LIST_TRAVERSE_SAFE_END;
06376 
06377    /* New parking lot context goes on the end. */
06378    new_ctx = build_dialplan_useage_context(lot);
06379    if (!new_ctx) {
06380       return -1;
06381    }
06382    AST_LIST_INSERT_TAIL(usage_map, new_ctx, node);
06383    return 0;
06384 }

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

Definition at line 6297 of file features.c.

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

Referenced by build_dialplan_useage_context(), and dialplan_usage_add_parkinglot().

06298 {
06299    if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext,
06300       lot->cfg.parkext_exclusive, lot, complain)) {
06301       return -1;
06302    }
06303    if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start,
06304       lot->cfg.parking_stop, lot, complain)) {
06305       return -1;
06306    }
06307    if (lot->cfg.parkaddhints
06308       && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start,
06309          lot->cfg.parking_stop, lot, 0)) {
06310       return -1;
06311    }
06312    return 0;
06313 }

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

Actual bridge.

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 6933 of file features.c.

References ast_channel::_state, ast_channel_lock_both, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_explicit_goto(), ast_moh_stop(), ast_setstate(), ast_strdupa, ast_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

Referenced by action_bridge(), and bridge_exec().

06934 {
06935    const char *context;
06936    const char *exten;
06937    int priority;
06938 
06939    ast_moh_stop(chan);
06940    ast_channel_lock_both(chan, tmpchan);
06941    context = ast_strdupa(chan->context);
06942    exten = ast_strdupa(chan->exten);
06943    priority = chan->priority;
06944    ast_setstate(tmpchan, chan->_state);
06945    tmpchan->readformat = chan->readformat;
06946    tmpchan->writeformat = chan->writeformat;
06947    ast_channel_unlock(chan);
06948    ast_channel_unlock(tmpchan);
06949 
06950    /* Masquerade setup and execution must be done without any channel locks held */
06951    if (ast_channel_masquerade(tmpchan, chan)) {
06952       return -1;
06953    }
06954    ast_do_masquerade(tmpchan);
06955 
06956    /* when returning from bridge, the channel will continue at the next priority */
06957    ast_explicit_goto(tmpchan, context, exten, priority + 1);
06958 
06959    return 0;
06960 }

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

Take care of parked calls and unpark them if needed.

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 4984 of file features.c.

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

Referenced by ast_features_init().

04985 {
04986    struct pollfd *pfds = NULL, *new_pfds = NULL;
04987    int nfds = 0, new_nfds = 0;
04988 
04989    for (;;) {
04990       struct ao2_iterator iter;
04991       struct ast_parkinglot *curlot;
04992       int ms = -1;   /* poll2 timeout, uninitialized */
04993 
04994       iter = ao2_iterator_init(parkinglots, 0);
04995       while ((curlot = ao2_iterator_next(&iter))) {
04996          manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
04997          ao2_ref(curlot, -1);
04998       }
04999       ao2_iterator_destroy(&iter);
05000 
05001       /* Recycle */
05002       ast_free(pfds);
05003       pfds = new_pfds;
05004       nfds = new_nfds;
05005       new_pfds = NULL;
05006       new_nfds = 0;
05007 
05008       /* Wait for something to happen */
05009       ast_poll(pfds, nfds, ms);
05010       pthread_testcancel();
05011    }
05012    /* If this WERE reached, we'd need to free(pfds) */
05013    return NULL;   /* Never reached */
05014 }

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

Check if a feature exists.

Definition at line 3440 of file features.c.

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

Referenced by ast_bridge_call().

03440                                                                                            {
03441    char *chan_dynamic_features;
03442    ast_channel_lock(chan);
03443    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03444    ast_channel_unlock(chan);
03445 
03446    return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL);
03447 }

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

exec an app by feature

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 3179 of file features.c.

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

Referenced by process_applicationmap_line().

03180 {
03181    struct ast_app *app;
03182    struct ast_call_feature *feature = data;
03183    struct ast_channel *work, *idle;
03184    int res;
03185 
03186    if (!feature) { /* shouldn't ever happen! */
03187       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
03188       return -1; 
03189    }
03190 
03191    if (sense == FEATURE_SENSE_CHAN) {
03192       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
03193          return AST_FEATURE_RETURN_KEEPTRYING;
03194       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03195          work = chan;
03196          idle = peer;
03197       } else {
03198          work = peer;
03199          idle = chan;
03200       }
03201    } else {
03202       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
03203          return AST_FEATURE_RETURN_KEEPTRYING;
03204       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03205          work = peer;
03206          idle = chan;
03207       } else {
03208          work = chan;
03209          idle = peer;
03210       }
03211    }
03212 
03213    if (!(app = pbx_findapp(feature->app))) {
03214       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
03215       return -2;
03216    }
03217 
03218    ast_autoservice_start(idle);
03219    ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
03220    
03221    pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name);
03222    pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name);
03223    pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
03224    pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
03225 
03226    if (!ast_strlen_zero(feature->moh_class))
03227       ast_moh_start(idle, feature->moh_class, NULL);
03228 
03229    if (!strcasecmp("Gosub", feature->app)) {
03230       res = ast_app_exec_sub(NULL, work, feature->app_args, 0);
03231    } else if (!strcasecmp("Macro", feature->app)) {
03232       res = ast_app_exec_macro(NULL, work, feature->app_args);
03233    } else {
03234       res = pbx_exec(work, app, feature->app_args);
03235    }
03236 
03237    if (!ast_strlen_zero(feature->moh_class))
03238       ast_moh_stop(idle);
03239 
03240    ast_autoservice_stop(idle);
03241 
03242    if (res) {
03243       return AST_FEATURE_RETURN_SUCCESSBREAK;
03244    }
03245    return AST_FEATURE_RETURN_SUCCESS;  /*! \todo XXX should probably return res */
03246 }

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

Check the dynamic features.

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

Definition at line 3403 of file features.c.

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

Referenced by ast_bridge_call().

03403                                                                                                                                                 {
03404 
03405    char dynamic_features_buf[128];
03406    const char *peer_dynamic_features, *chan_dynamic_features;
03407    struct ast_flags features;
03408    struct ast_call_feature feature;
03409    if (sense == FEATURE_SENSE_CHAN) {
03410       /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
03411       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
03412    }
03413    else {
03414       /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
03415       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
03416    }
03417 
03418    ast_channel_lock(peer);
03419    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
03420    ast_channel_unlock(peer);
03421 
03422    ast_channel_lock(chan);
03423    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03424    ast_channel_unlock(chan);
03425 
03426    snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,""));
03427 
03428    ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%u, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf);
03429 
03430    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
03431 }

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

Helper function for feature_interpret and ast_feature_detect.

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 3286 of file features.c.

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

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

03289 {
03290    int x;
03291    struct feature_group *fg = NULL;
03292    struct feature_group_exten *fge;
03293    struct ast_call_feature *tmpfeature;
03294    char *tmp, *tok;
03295    int res = AST_FEATURE_RETURN_PASSDIGITS;
03296    int feature_detected = 0;
03297 
03298    if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) {
03299       return -1; /* can not run feature operation */
03300    }
03301 
03302    ast_rwlock_rdlock(&features_lock);
03303    for (x = 0; x < FEATURES_COUNT; x++) {
03304       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
03305           !ast_strlen_zero(builtin_features[x].exten)) {
03306          /* Feature is up for consideration */
03307          if (!strcmp(builtin_features[x].exten, code)) {
03308             ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
03309             if (operation == FEATURE_INTERPRET_CHECK) {
03310                res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
03311             } else if (operation == FEATURE_INTERPRET_DO) {
03312                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
03313             }
03314             if (feature) {
03315                memcpy(feature, &builtin_features[x], sizeof(*feature));
03316             }
03317             feature_detected = 1;
03318             break;
03319          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
03320             if (res == AST_FEATURE_RETURN_PASSDIGITS) {
03321                res = AST_FEATURE_RETURN_STOREDIGITS;
03322             }
03323          }
03324       }
03325    }
03326    ast_rwlock_unlock(&features_lock);
03327 
03328    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
03329       return res;
03330    }
03331 
03332    tmp = dynamic_features_buf;
03333 
03334    while ((tok = strsep(&tmp, "#"))) {
03335       AST_RWLIST_RDLOCK(&feature_groups);
03336 
03337       fg = find_group(tok);
03338 
03339       if (fg) {
03340          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03341             if (!strcmp(fge->exten, code)) {
03342                if (operation) {
03343                   res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
03344                }
03345                if (feature) {
03346                   memcpy(feature, fge->feature, sizeof(*feature));
03347                }
03348                if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03349                   AST_RWLIST_UNLOCK(&feature_groups);
03350                   break;
03351                }
03352                res = AST_FEATURE_RETURN_PASSDIGITS;
03353             } else if (!strncmp(fge->exten, code, strlen(code))) {
03354                res = AST_FEATURE_RETURN_STOREDIGITS;
03355             }
03356          }
03357          if (fge) {
03358             break;
03359          }
03360       }
03361 
03362       AST_RWLIST_UNLOCK(&feature_groups);
03363 
03364       AST_RWLIST_RDLOCK(&feature_list);
03365 
03366       if (!(tmpfeature = find_dynamic_feature(tok))) {
03367          AST_RWLIST_UNLOCK(&feature_list);
03368          continue;
03369       }
03370 
03371       /* Feature is up for consideration */
03372       if (!strcmp(tmpfeature->exten, code)) {
03373          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
03374          if (operation == FEATURE_INTERPRET_CHECK) {
03375             res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
03376          } else if (operation == FEATURE_INTERPRET_DO) {
03377             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
03378          }
03379          if (feature) {
03380             memcpy(feature, tmpfeature, sizeof(*feature));
03381          }
03382          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03383             AST_RWLIST_UNLOCK(&feature_list);
03384             break;
03385          }
03386          res = AST_FEATURE_RETURN_PASSDIGITS;
03387       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
03388          res = AST_FEATURE_RETURN_STOREDIGITS;
03389 
03390       AST_RWLIST_UNLOCK(&feature_list);
03391    }
03392 
03393    return res;
03394 }

static struct ast_channel * feature_request_and_dial ( struct ast_channel caller,
const char *  caller_name,
struct ast_channel requestor,
struct ast_channel transferee,
const char *  type,
format_t  format,
void *  data,
int  timeout,
int *  outstate,
const char *  language 
) [static, read]

Definition at line 3544 of file features.c.

References ast_channel::_state, ast_alloca, ast_autoservice_start(), ast_autoservice_stop(), ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_connected_line_macro(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_redirecting_macro(), ast_channel_set_connected_line(), ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), ast_connected_line_parse_data(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_INCOMPLETE, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_frisolate(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_is_deferrable_frame(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_party_connected_line_free(), ast_party_connected_line_set_init(), ast_poll_channel_add(), ast_poll_channel_del(), ast_queue_frame_head(), ast_read(), ast_request(), ast_rwlock_rdlock, ast_rwlock_unlock, AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), ast_channel::caller, ast_channel::connected, ast_frame::data, ast_frame::datalen, ast_channel::exten, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_frame::frametype, ast_channel::hangupcause, ast_frame_subclass::integer, LOG_NOTICE, pbx_builtin_setvar_helper(), ast_frame::ptr, and ast_frame::subclass.

Referenced by builtin_atxfer().

03548 {
03549    int state = 0;
03550    int cause = 0;
03551    int to;
03552    int caller_hungup;
03553    int transferee_hungup;
03554    struct ast_channel *chan;
03555    struct ast_channel *monitor_chans[3];
03556    struct ast_channel *active_channel;
03557    int res;
03558    int ready = 0;
03559    struct timeval started;
03560    int x, len = 0;
03561    char *disconnect_code = NULL, *dialed_code = NULL;
03562    struct ast_frame *f;
03563    AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
03564 
03565    caller_hungup = ast_check_hangup(caller);
03566 
03567    if (!(chan = ast_request(type, format, requestor, data, &cause))) {
03568       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
03569       switch (cause) {
03570       case AST_CAUSE_BUSY:
03571          state = AST_CONTROL_BUSY;
03572          break;
03573       case AST_CAUSE_CONGESTION:
03574          state = AST_CONTROL_CONGESTION;
03575          break;
03576       default:
03577          state = 0;
03578          break;
03579       }
03580       goto done;
03581    }
03582 
03583    ast_string_field_set(chan, language, language);
03584    ast_channel_inherit_variables(caller, chan);
03585    pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
03586 
03587    ast_channel_lock(chan);
03588    ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller);
03589    ast_channel_unlock(chan);
03590 
03591    if (ast_call(chan, data, timeout)) {
03592       ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
03593       switch (chan->hangupcause) {
03594       case AST_CAUSE_BUSY:
03595          state = AST_CONTROL_BUSY;
03596          break;
03597       case AST_CAUSE_CONGESTION:
03598          state = AST_CONTROL_CONGESTION;
03599          break;
03600       default:
03601          state = 0;
03602          break;
03603       }
03604       goto done;
03605    }
03606 
03607    /* support dialing of the featuremap disconnect code while performing an attended tranfer */
03608    ast_rwlock_rdlock(&features_lock);
03609    for (x = 0; x < FEATURES_COUNT; x++) {
03610       if (strcasecmp(builtin_features[x].sname, "disconnect"))
03611          continue;
03612 
03613       disconnect_code = builtin_features[x].exten;
03614       len = strlen(disconnect_code) + 1;
03615       dialed_code = ast_alloca(len);
03616       memset(dialed_code, 0, len);
03617       break;
03618    }
03619    ast_rwlock_unlock(&features_lock);
03620    x = 0;
03621    started = ast_tvnow();
03622    to = timeout;
03623    AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
03624 
03625    ast_poll_channel_add(caller, chan);
03626 
03627    transferee_hungup = 0;
03628    while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) {
03629       int num_chans = 0;
03630 
03631       monitor_chans[num_chans++] = transferee;
03632       monitor_chans[num_chans++] = chan;
03633       if (!caller_hungup) {
03634          if (ast_check_hangup(caller)) {
03635             caller_hungup = 1;
03636 
03637 #if defined(ATXFER_NULL_TECH)
03638             /* Change caller's name to ensure that it will remain unique. */
03639             set_new_chan_name(caller);
03640 
03641             /*
03642              * Get rid of caller's physical technology so it is free for
03643              * other calls.
03644              */
03645             set_kill_chan_tech(caller);
03646 #endif   /* defined(ATXFER_NULL_TECH) */
03647          } else {
03648             /* caller is not hungup so monitor it. */
03649             monitor_chans[num_chans++] = caller;
03650          }
03651       }
03652 
03653       /* see if the timeout has been violated */
03654       if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
03655          state = AST_CONTROL_UNHOLD;
03656          ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name);
03657          break; /*doh! timeout*/
03658       }
03659 
03660       active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
03661       if (!active_channel)
03662          continue;
03663 
03664       f = NULL;
03665       if (transferee == active_channel) {
03666          struct ast_frame *dup_f;
03667 
03668          f = ast_read(transferee);
03669          if (f == NULL) { /*doh! where'd he go?*/
03670             transferee_hungup = 1;
03671             state = 0;
03672             break;
03673          }
03674          if (ast_is_deferrable_frame(f)) {
03675             dup_f = ast_frisolate(f);
03676             if (dup_f) {
03677                if (dup_f == f) {
03678                   f = NULL;
03679                }
03680                AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
03681             }
03682          }
03683       } else if (chan == active_channel) {
03684          if (!ast_strlen_zero(chan->call_forward)) {
03685             state = 0;
03686             ast_autoservice_start(transferee);
03687             chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
03688             ast_autoservice_stop(transferee);
03689             if (!chan) {
03690                break;
03691             }
03692             continue;
03693          }
03694          f = ast_read(chan);
03695          if (f == NULL) { /*doh! where'd he go?*/
03696             switch (chan->hangupcause) {
03697             case AST_CAUSE_BUSY:
03698                state = AST_CONTROL_BUSY;
03699                break;
03700             case AST_CAUSE_CONGESTION:
03701                state = AST_CONTROL_CONGESTION;
03702                break;
03703             default:
03704                state = 0;
03705                break;
03706             }
03707             break;
03708          }
03709 
03710          if (f->frametype == AST_FRAME_CONTROL) {
03711             if (f->subclass.integer == AST_CONTROL_RINGING) {
03712                ast_verb(3, "%s is ringing\n", chan->name);
03713                ast_indicate(caller, AST_CONTROL_RINGING);
03714             } else if (f->subclass.integer == AST_CONTROL_BUSY) {
03715                state = f->subclass.integer;
03716                ast_verb(3, "%s is busy\n", chan->name);
03717                ast_indicate(caller, AST_CONTROL_BUSY);
03718                ast_frfree(f);
03719                break;
03720             } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) {
03721                ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", chan->name, chan->exten);
03722             } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
03723                state = f->subclass.integer;
03724                ast_verb(3, "%s is congested\n", chan->name);
03725                ast_indicate(caller, AST_CONTROL_CONGESTION);
03726                ast_frfree(f);
03727                break;
03728             } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
03729                /* This is what we are hoping for */
03730                state = f->subclass.integer;
03731                ast_frfree(f);
03732                ready=1;
03733                break;
03734             } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
03735                if (caller_hungup) {
03736                   struct ast_party_connected_line connected;
03737 
03738                   /* Just save it for the transfer. */
03739                   ast_party_connected_line_set_init(&connected, &caller->connected);
03740                   res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
03741                      &connected);
03742                   if (!res) {
03743                      ast_channel_set_connected_line(caller, &connected, NULL);
03744                   }
03745                   ast_party_connected_line_free(&connected);
03746                } else {
03747                   ast_autoservice_start(transferee);
03748                   if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
03749                      ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
03750                         f->data.ptr, f->datalen);
03751                   }
03752                   ast_autoservice_stop(transferee);
03753                }
03754             } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
03755                if (!caller_hungup) {
03756                   ast_autoservice_start(transferee);
03757                   if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
03758                      ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
03759                         f->data.ptr, f->datalen);
03760                   }
03761                   ast_autoservice_stop(transferee);
03762                }
03763             } else if (f->subclass.integer != -1
03764                && f->subclass.integer != AST_CONTROL_PROGRESS
03765                && f->subclass.integer != AST_CONTROL_PROCEEDING) {
03766                ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
03767             }
03768             /* else who cares */
03769          } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03770             ast_write(caller, f);
03771          }
03772       } else if (caller == active_channel) {
03773          f = ast_read(caller);
03774          if (f) {
03775             if (f->frametype == AST_FRAME_DTMF) {
03776                dialed_code[x++] = f->subclass.integer;
03777                dialed_code[x] = '\0';
03778                if (strlen(dialed_code) == len) {
03779                   x = 0;
03780                } else if (x && strncmp(dialed_code, disconnect_code, x)) {
03781                   x = 0;
03782                   dialed_code[x] = '\0';
03783                }
03784                if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
03785                   /* Caller Canceled the call */
03786                   state = AST_CONTROL_UNHOLD;
03787                   ast_frfree(f);
03788                   break;
03789                }
03790             } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03791                ast_write(chan, f);
03792             }
03793          }
03794       }
03795       if (f)
03796          ast_frfree(f);
03797    } /* end while */
03798 
03799    ast_poll_channel_del(caller, chan);
03800 
03801    /*
03802     * We need to free all the deferred frames, but we only need to
03803     * queue the deferred frames if no hangup was received.
03804     */
03805    ast_channel_lock(transferee);
03806    transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
03807    while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
03808       if (!transferee_hungup) {
03809          ast_queue_frame_head(transferee, f);
03810       }
03811       ast_frfree(f);
03812    }
03813    ast_channel_unlock(transferee);
03814 
03815 done:
03816    ast_indicate(caller, -1);
03817    if (chan && (ready || chan->_state == AST_STATE_UP)) {
03818       state = AST_CONTROL_ANSWER;
03819    } else if (chan) {
03820       ast_hangup(chan);
03821       chan = NULL;
03822    }
03823 
03824    if (outstate)
03825       *outstate = state;
03826 
03827    return chan;
03828 }

static void features_shutdown ( void   )  [static]

Definition at line 8314 of file features.c.

References ao2_ref, ARRAY_LEN, ast_cli_unregister_multiple(), ast_context_destroy(), ast_devstate_prov_del(), ast_manager_unregister(), AST_TEST_UNREGISTER, ast_unregister_application(), parkcall, parking_thread, parkinglots, and registrar.

Referenced by ast_features_init().

08315 {
08316    ast_cli_unregister_multiple(cli_features, ARRAY_LEN(cli_features));
08317    ast_devstate_prov_del("Park");
08318    ast_manager_unregister("Bridge");
08319    ast_manager_unregister("Park");
08320    ast_manager_unregister("Parkinglots");
08321    ast_manager_unregister("ParkedCalls");
08322    ast_unregister_application(parkcall);
08323    ast_unregister_application(parkedcall);
08324    ast_unregister_application(app_bridge);
08325 #if defined(TEST_FRAMEWORK)
08326    AST_TEST_UNREGISTER(features_test);
08327 #endif   /* defined(TEST_FRAMEWORK) */
08328 
08329    pthread_cancel(parking_thread);
08330    pthread_kill(parking_thread, SIGURG);
08331    pthread_join(parking_thread, NULL);
08332    ast_context_destroy(NULL, registrar);
08333    ao2_ref(parkinglots, -1);
08334 }

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

< Potential pickup target

< Channel wanting to pickup call

Definition at line 7356 of file features.c.

References ast_can_pickup(), ast_channel_lock, ast_channel_unlock, ast_channel::callgroup, CMP_MATCH, CMP_STOP, and ast_channel::pickupgroup.

Referenced by ast_pickup_call().

07357 {
07358    struct ast_channel *target = obj;/*!< Potential pickup target */
07359    struct ast_channel *chan = data;/*!< Channel wanting to pickup call */
07360 
07361    ast_channel_lock(target);
07362    if (chan != target && (chan->pickupgroup & target->callgroup)
07363       && ast_can_pickup(target)) {
07364       /* Return with the channel still locked on purpose */
07365       return CMP_MATCH | CMP_STOP;
07366    }
07367    ast_channel_unlock(target);
07368 
07369    return 0;
07370 }

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

find a call feature by name

Definition at line 3100 of file features.c.

References AST_RWLIST_TRAVERSE, and ast_call_feature::sname.

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

03101 {
03102    struct ast_call_feature *tmp;
03103 
03104    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
03105       if (!strcasecmp(tmp->sname, name)) {
03106          break;
03107       }
03108    }
03109 
03110    return tmp;
03111 }

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

Find a group by name.

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

Definition at line 3138 of file features.c.

References AST_LIST_TRAVERSE, and feature_group::gname.

Referenced by feature_interpret_helper().

03139 {
03140    struct feature_group *fg = NULL;
03141 
03142    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
03143       if (!strcasecmp(fg->gname, name))
03144          break;
03145    }
03146 
03147    return fg;
03148 }

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

Find parkinglot by name.

Definition at line 5017 of file features.c.

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

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

05018 {
05019    struct ast_parkinglot *parkinglot;
05020 
05021    if (ast_strlen_zero(name)) {
05022       return NULL;
05023    }
05024 
05025    parkinglot = ao2_find(parkinglots, (void *) name, 0);
05026    if (parkinglot) {
05027       ast_debug(1, "Found Parking lot: %s\n", parkinglot->name);
05028    }
05029 
05030    return parkinglot;
05031 }

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

Find parking lot name from channel.

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

Definition at line 1082 of file features.c.

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

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

01083 {
01084    const char *name;
01085 
01086    /* The channel variable overrides everything */
01087    name = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
01088    if (!name && !ast_strlen_zero(chan->parkinglot)) {
01089       /* Use the channel's parking lot. */
01090       name = chan->parkinglot;
01091    }
01092    return name;
01093 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 1870 of file features.c.

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

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

01871 {
01872    ast_indicate(chan, AST_CONTROL_UNHOLD);
01873 
01874    return ast_autoservice_stop(chan);
01875 }

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

Definition at line 823 of file features.c.

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

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

00824 {
00825    struct ast_exten *exten;
00826    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
00827    const char *app_at_exten;
00828 
00829    ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context);
00830    exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
00831       E_MATCH);
00832    if (!exten) {
00833       return NULL;
00834    }
00835 
00836    app_at_exten = ast_get_extension_app(exten);
00837    if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) {
00838       return NULL;
00839    }
00840 
00841    return exten;
00842 }

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

CLI command to list configured features.

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

Definition at line 6799 of file features.c.

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

06800 {
06801    int i;
06802    struct ast_call_feature *feature;
06803    struct ao2_iterator iter;
06804    struct ast_parkinglot *curlot;
06805 #define HFS_FORMAT "%-25s %-7s %-7s\n"
06806 
06807    switch (cmd) {
06808    
06809    case CLI_INIT:
06810       e->command = "features show";
06811       e->usage =
06812          "Usage: features show\n"
06813          "       Lists configured features\n";
06814       return NULL;
06815    case CLI_GENERATE:
06816       return NULL;
06817    }
06818 
06819    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
06820    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06821 
06822    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
06823 
06824    ast_rwlock_rdlock(&features_lock);
06825    for (i = 0; i < FEATURES_COUNT; i++)
06826       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
06827    ast_rwlock_unlock(&features_lock);
06828 
06829    ast_cli(a->fd, "\n");
06830    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
06831    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06832    if (AST_RWLIST_EMPTY(&feature_list)) {
06833       ast_cli(a->fd, "(none)\n");
06834    } else {
06835       AST_RWLIST_RDLOCK(&feature_list);
06836       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
06837          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
06838       }
06839       AST_RWLIST_UNLOCK(&feature_list);
06840    }
06841 
06842    ast_cli(a->fd, "\nFeature Groups:\n");
06843    ast_cli(a->fd, "---------------\n");
06844    if (AST_RWLIST_EMPTY(&feature_groups)) {
06845       ast_cli(a->fd, "(none)\n");
06846    } else {
06847       struct feature_group *fg;
06848       struct feature_group_exten *fge;
06849 
06850       AST_RWLIST_RDLOCK(&feature_groups);
06851       AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
06852          ast_cli(a->fd, "===> Group: %s\n", fg->gname);
06853          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
06854             ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
06855          }
06856       }
06857       AST_RWLIST_UNLOCK(&feature_groups);
06858    }
06859 
06860    iter = ao2_iterator_init(parkinglots, 0);
06861    while ((curlot = ao2_iterator_next(&iter))) {
06862       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
06863       ast_cli(a->fd, "------------\n");
06864       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", curlot->cfg.parkext);
06865       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->cfg.parking_con);
06866       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions",
06867          curlot->cfg.parking_start, curlot->cfg.parking_stop);
06868       ast_cli(a->fd,"%-22s:      %d ms\n", "Parkingtime", curlot->cfg.parkingtime);
06869       ast_cli(a->fd,"%-22s:      %s\n", "MusicOnHold class", curlot->cfg.mohclass);
06870       ast_cli(a->fd,"%-22s:      %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled));
06871       ast_cli(a->fd,"\n");
06872       ao2_ref(curlot, -1);
06873    }
06874    ao2_iterator_destroy(&iter);
06875 
06876    return CLI_SUCCESS;
06877 }

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

Definition at line 6905 of file features.c.

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

06906 {
06907    switch (cmd) { 
06908    case CLI_INIT:
06909       e->command = "features reload";
06910       e->usage =
06911          "Usage: features reload\n"
06912          "       Reloads configured call features from features.conf\n";
06913       return NULL;
06914    case CLI_GENERATE:
06915       return NULL;
06916    }
06917    ast_features_reload();
06918 
06919    return CLI_SUCCESS;
06920 }

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

CLI command to list parked calls.

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 7109 of file features.c.

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

07110 {
07111    struct parkeduser *cur;
07112    int numparked = 0;
07113    struct ao2_iterator iter;
07114    struct ast_parkinglot *curlot;
07115 
07116    switch (cmd) {
07117    case CLI_INIT:
07118       e->command = "parkedcalls show";
07119       e->usage =
07120          "Usage: parkedcalls show\n"
07121          "       List currently parked calls\n";
07122       return NULL;
07123    case CLI_GENERATE:
07124       return NULL;
07125    }
07126 
07127    if (a->argc > e->args)
07128       return CLI_SHOWUSAGE;
07129 
07130    ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel",
07131       "Context", "Extension", "Pri", "Timeout");
07132 
07133    iter = ao2_iterator_init(parkinglots, 0);
07134    while ((curlot = ao2_iterator_next(&iter))) {
07135       int lotparked = 0;
07136 
07137       /* subtract ref for iterator and for configured parking lot */
07138       ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name,
07139          ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot));
07140 
07141       AST_LIST_LOCK(&curlot->parkings);
07142       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
07143          ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n",
07144             cur->parkingexten, cur->chan->name, cur->context, cur->exten,
07145             cur->priority,
07146             (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL)));
07147          ++lotparked;
07148       }
07149       AST_LIST_UNLOCK(&curlot->parkings);
07150       if (lotparked) {
07151          numparked += lotparked;
07152          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked,
07153             ESS(lotparked), curlot->name);
07154       }
07155 
07156       ao2_ref(curlot, -1);
07157    }
07158    ao2_iterator_destroy(&iter);
07159 
07160    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
07161 
07162    return CLI_SUCCESS;
07163 }

static int load_config ( int  reload  )  [static]

Definition at line 6717 of file features.c.

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

Referenced by ast_features_init(), and ast_features_reload().

06718 {
06719    struct ast_flags config_flags = {
06720       reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06721    struct ast_config *cfg;
06722    struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06723    struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06724 
06725    /* We are reloading now and have already determined if we will force the reload. */
06726    force_reload_load = 0;
06727 
06728    if (!default_parkinglot) {
06729       /* Must create the default default parking lot */
06730       default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
06731       if (!default_parkinglot) {
06732          ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n");
06733          return -1;
06734       }
06735       ast_debug(1, "Configuration of default default parking lot done.\n");
06736    }
06737 
06738    cfg = ast_config_load2("features.conf", "features", config_flags);
06739    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06740       /* No sense in asking for reload trouble if nothing changed. */
06741       ast_debug(1, "features.conf did not change.\n");
06742       return 0;
06743    }
06744    if (cfg == CONFIG_STATUS_FILEMISSING
06745       || cfg == CONFIG_STATUS_FILEINVALID) {
06746       ast_log(LOG_WARNING, "Could not load features.conf\n");
06747       return 0;
06748    }
06749 
06750    /* Save current parking lot dialplan needs. */
06751    if (build_dialplan_useage_map(&old_usage_map, 0)) {
06752       destroy_dialplan_usage_map(&old_usage_map);
06753 
06754       /* Allow reloading later to see if conditions have improved. */
06755       force_reload_load = 1;
06756       return -1;
06757    }
06758 
06759    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL,
06760       "callback to mark all parking lots");
06761    process_config(cfg);
06762    ast_config_destroy(cfg);
06763    ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL,
06764       "callback to remove marked parking lots");
06765 
06766    /* Save updated parking lot dialplan needs. */
06767    if (build_dialplan_useage_map(&new_usage_map, 1)) {
06768       /*
06769        * Yuck, if this failure caused any parking lot dialplan items
06770        * to be lost, they will likely remain lost until Asterisk is
06771        * restarted.
06772        */
06773       destroy_dialplan_usage_map(&old_usage_map);
06774       destroy_dialplan_usage_map(&new_usage_map);
06775       return -1;
06776    }
06777 
06778    /* Remove no longer needed parking lot dialplan usage. */
06779    remove_dead_dialplan_useage(&old_usage_map, &new_usage_map);
06780 
06781    destroy_dialplan_usage_map(&old_usage_map);
06782    destroy_dialplan_usage_map(&new_usage_map);
06783 
06784    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL,
06785       "callback to activate all parking lots");
06786 
06787    return 0;
06788 }

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

Definition at line 4703 of file features.c.

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

Referenced by manage_parkinglot().

04704 {
04705    struct ast_channel *chan = pu->chan;   /* shorthand */
04706    int tms;        /* timeout for this item */
04707    int x;          /* fd index in channel */
04708 
04709    tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04710    if (tms > pu->parkingtime) {
04711       /*
04712        * Call has been parked too long.
04713        * Stop entertaining the caller.
04714        */
04715       switch (pu->hold_method) {
04716       case AST_CONTROL_HOLD:
04717          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04718          break;
04719       case AST_CONTROL_RINGING:
04720          ast_indicate(pu->chan, -1);
04721          break;
04722       default:
04723          break;
04724       }
04725       pu->hold_method = 0;
04726 
04727       /* Get chan, exten from derived kludge */
04728       if (pu->peername[0]) {
04729          char *peername;
04730          char *dash;
04731          char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
04732          int i;
04733 
04734          peername = ast_strdupa(pu->peername);
04735          dash = strrchr(peername, '-');
04736          if (dash) {
04737             *dash = '\0';
04738          }
04739 
04740          peername_flat = ast_strdupa(peername);
04741          for (i = 0; peername_flat[i]; i++) {
04742             if (peername_flat[i] == '/') {
04743                peername_flat[i] = '_';
04744             }
04745          }
04746 
04747          if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) {
04748             ast_log(LOG_ERROR,
04749                "Parking dial context '%s' does not exist and unable to create\n",
04750                parking_con_dial);
04751          } else {
04752             char returnexten[AST_MAX_EXTENSION];
04753             struct ast_datastore *features_datastore;
04754             struct ast_dial_features *dialfeatures;
04755 
04756             if (!strncmp(peername, "Parked/", 7)) {
04757                peername += 7;
04758             }
04759             /* If dahdi channel, add a ring cadence DAHDI/NNr3 (if parkingretdahdiring defined) */
04760             if (!ast_strlen_zero(parkingretdahdiring) && !strncasecmp(peername, "dahdi", 5))
04761                   strncat(peername, parkingretdahdiring, 2);
04762 
04763             ast_channel_lock(chan);
04764             features_datastore = ast_channel_datastore_find(chan, &dial_features_info,
04765                NULL);
04766             if (features_datastore && (dialfeatures = features_datastore->data)) {
04767                char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
04768 
04769                snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername,
04770                   callback_dialoptions(&dialfeatures->peer_features,
04771                      &dialfeatures->my_features, buf, sizeof(buf)));
04772             } else { /* Existing default */
04773                ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n",
04774                   chan->name);
04775                snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
04776             }
04777             ast_channel_unlock(chan);
04778 
04779 
04780             int parkdialprio = 1;
04781             char parkciddata[512];
04782             char parkalertinfodata[512];
04783             /* alter CALLERID(name) and add AlertInfo header if requested */
04784             if (!ast_strlen_zero(parkingretcidname)) {
04785                snprintf(parkciddata, sizeof(parkciddata), "CALLERID(name)=%s", parkingretcidname);
04786                if (ast_add_extension(parking_con_dial, 1, peername_flat, parkdialprio++, NULL, NULL, "Set", strdup(parkciddata), ast_free_ptr, registrar))
04787                   ast_log(LOG_ERROR, "Could not create parking return dial exten: %s@%s\n",  peername_flat, parking_con_dial);
04788             }
04789             if (!ast_strlen_zero(parkingretalertinfo)) {
04790                snprintf(parkalertinfodata, sizeof(parkalertinfodata), "Alert-Info: %s", parkingretalertinfo);
04791                if (ast_add_extension(parking_con_dial, 1, peername_flat, parkdialprio++, NULL, NULL, "SIPAddHeader", strdup(parkalertinfodata), ast_free_ptr, registrar))
04792                      ast_log(LOG_ERROR, "Could not create parking return dial exten: %s@%s\n",  peername_flat, parking_con_dial);
04793             }
04794             if (ast_add_extension(parking_con_dial, 1, peername_flat, parkdialprio, NULL, NULL,
04795                "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) {
04796                ast_log(LOG_ERROR,
04797                   "Could not create parking return dial exten: %s@%s\n",
04798                   peername_flat, parking_con_dial);
04799             }
04800          }
04801          if (pu->options_specified) {
04802             /*
04803              * Park() was called with overriding return arguments, respect
04804              * those arguments.
04805              */
04806             set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04807          } else if (comebacktoorigin) {
04808             set_c_e_p(chan, parking_con_dial, peername_flat, 1);
04809          } else {
04810             char parkingslot[AST_MAX_EXTENSION];
04811 
04812             snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
04813             pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
04814             set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
04815          }
04816       } else {
04817          /*
04818           * They've been waiting too long, send them back to where they
04819           * came.  Theoretically they should have their original
04820           * extensions and such, but we copy to be on the safe side.
04821           */
04822          set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04823       }
04824       post_manager_event("ParkedCallTimeOut", pu);
04825       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
04826 
04827       ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n",
04828          pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context,
04829          pu->chan->exten, pu->chan->priority);
04830 
04831       /* Start up the PBX, or hang them up */
04832       if (ast_pbx_start(chan))  {
04833          ast_log(LOG_WARNING,
04834             "Unable to restart the PBX for user on '%s', hanging them up...\n",
04835             pu->chan->name);
04836          ast_hangup(chan);
04837       }
04838 
04839       /* And take them out of the parking lot */
04840       return 1;
04841    }
04842 
04843    /* still within parking time, process descriptors */
04844    if (pfds) {
04845       for (x = 0; x < AST_MAX_FDS; x++) {
04846          struct ast_frame *f;
04847          int y;
04848 
04849          if (chan->fds[x] == -1) {
04850             continue;   /* nothing on this descriptor */
04851          }
04852 
04853          for (y = 0; y < nfds; y++) {
04854             if (pfds[y].fd == chan->fds[x]) {
04855                /* Found poll record! */
04856                break;
04857             }
04858          }
04859          if (y == nfds) {
04860             /* Not found */
04861             continue;
04862          }
04863 
04864          if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
04865             /* Next x */
04866             continue;
04867          }
04868 
04869          if (pfds[y].revents & POLLPRI) {
04870             ast_set_flag(chan, AST_FLAG_EXCEPTION);
04871          } else {
04872             ast_clear_flag(chan, AST_FLAG_EXCEPTION);
04873          }
04874          chan->fdno = x;
04875 
04876          /* See if they need servicing */
04877          f = ast_read(pu->chan);
04878          /* Hangup? */
04879          if (!f || (f->frametype == AST_FRAME_CONTROL
04880             && f->subclass.integer == AST_CONTROL_HANGUP)) {
04881             if (f) {
04882                ast_frfree(f);
04883             }
04884             post_manager_event("ParkedCallGiveUp", pu);
04885             ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp",
04886                NULL);
04887 
04888             /* There's a problem, hang them up */
04889             ast_verb(2, "%s got tired of being parked\n", chan->name);
04890             ast_hangup(chan);
04891 
04892             /* And take them out of the parking lot */
04893             return 1;
04894          } else {
04895             /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
04896             ast_frfree(f);
04897             if (pu->hold_method == AST_CONTROL_HOLD
04898                && pu->moh_trys < 3
04899                && !chan->generatordata) {
04900                ast_debug(1,
04901                   "MOH on parked call stopped by outside source.  Restarting on channel %s.\n",
04902                   chan->name);
04903                ast_indicate_data(chan, AST_CONTROL_HOLD,
04904                   S_OR(pu->parkinglot->cfg.mohclass, NULL),
04905                   (!ast_strlen_zero(pu->parkinglot->cfg.mohclass)
04906                      ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0));
04907                pu->moh_trys++;
04908             }
04909             break;
04910          }
04911       } /* End for */
04912    }
04913 
04914    /* mark fds for next round */
04915    for (x = 0; x < AST_MAX_FDS; x++) {
04916       if (chan->fds[x] > -1) {
04917          void *tmp = ast_realloc(*new_pfds,
04918             (*new_nfds + 1) * sizeof(struct pollfd));
04919 
04920          if (!tmp) {
04921             continue;
04922          }
04923          *new_pfds = tmp;
04924          (*new_pfds)[*new_nfds].fd = chan->fds[x];
04925          (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
04926          (*new_pfds)[*new_nfds].revents = 0;
04927          (*new_nfds)++;
04928       }
04929    }
04930    /* Keep track of our shortest wait */
04931    if (tms < *ms || *ms < 0) {
04932       *ms = tms;
04933    }
04934 
04935    /* Stay in the parking lot. */
04936    return 0;
04937 }

static void manage_parkinglot ( struct ast_parkinglot curlot,
const struct pollfd *  pfds,
int  nfds,
struct pollfd **  new_pfds,
int *  new_nfds,
int *  ms 
) [static]

Run management on parkinglots, called once per parkinglot.

Definition at line 4940 of file features.c.

References ast_context_find(), ast_context_remove_extension2(), AST_DEVICE_NOT_INUSE, ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_parkinglot::cfg, LOG_WARNING, manage_parked_call(), ast_parkinglot::name, notify_metermaids(), parkeduser::notquiteyet, parkinglot_cfg::parking_con, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_unref(), and ast_parkinglot::parkings.

Referenced by do_parking_thread().

04941 {
04942    struct parkeduser *pu;
04943    struct ast_context *con;
04944 
04945    /* Lock parkings list */
04946    AST_LIST_LOCK(&curlot->parkings);
04947    AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
04948       if (pu->notquiteyet) { /* Pretend this one isn't here yet */
04949          continue;
04950       }
04951       if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) {
04952          /* Parking is complete for this call so remove it from the parking lot. */
04953          con = ast_context_find(pu->parkinglot->cfg.parking_con);
04954          if (con) {
04955             if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
04956                ast_log(LOG_WARNING,
04957                   "Whoa, failed to remove the parking extension %s@%s!\n",
04958                   pu->parkingexten, pu->parkinglot->cfg.parking_con);
04959             }
04960             notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con,
04961                AST_DEVICE_NOT_INUSE);
04962          } else {
04963             ast_log(LOG_WARNING,
04964                "Whoa, parking lot '%s' context '%s' does not exist.\n",
04965                pu->parkinglot->name, pu->parkinglot->cfg.parking_con);
04966          }
04967          AST_LIST_REMOVE_CURRENT(list);
04968          parkinglot_unref(pu->parkinglot);
04969          ast_free(pu);
04970       }
04971    }
04972    AST_LIST_TRAVERSE_SAFE_END;
04973    AST_LIST_UNLOCK(&curlot->parkings);
04974 }

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

Create manager event for parked calls.

Parameters:
s 
m Get channels involved in park, create event.
Returns:
Always 0
Note:
ADSI is not compatible with this AMI action for the same reason ch2 can no longer announce the parking space.

Definition at line 7245 of file features.c.

References ast_channel_get_by_name(), ast_channel_unref, AST_PARK_OPT_SILENCE, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), find_parkinglot(), ast_park_call_args::flags, masq_park_call(), ast_park_call_args::parkinglot, parkinglot_unref(), and ast_park_call_args::timeout.

Referenced by ast_features_init().

07246 {
07247    const char *channel = astman_get_header(m, "Channel");
07248    const char *channel2 = astman_get_header(m, "Channel2");
07249    const char *timeout = astman_get_header(m, "Timeout");
07250    const char *parkinglotname = astman_get_header(m, "Parkinglot");
07251    char buf[BUFSIZ];
07252    int res = 0;
07253    struct ast_channel *ch1, *ch2;
07254    struct ast_park_call_args args = {
07255          /*
07256           * Don't say anything to ch2 since AMI is a third party parking
07257           * a call and we will likely crash if we do.
07258           *
07259           * XXX When the AMI action was originally implemented, the
07260           * parking space was announced to ch2.  Unfortunately, grabbing
07261           * the ch2 lock and holding it while the announcement is played
07262           * was not really a good thing to do to begin with since it
07263           * could hold up the system.  Also holding the lock is no longer
07264           * possible with a masquerade.
07265           *
07266           * Restoring the announcement to ch2 is not easily doable for
07267           * the following reasons:
07268           *
07269           * 1) The AMI manager is not the thread processing ch2.
07270           *
07271           * 2) ch2 could be the same as ch1, bridged to ch1, or some
07272           * random uninvolved channel.
07273           */
07274          .flags = AST_PARK_OPT_SILENCE,
07275       };
07276 
07277    if (ast_strlen_zero(channel)) {
07278       astman_send_error(s, m, "Channel not specified");
07279       return 0;
07280    }
07281 
07282    if (ast_strlen_zero(channel2)) {
07283       astman_send_error(s, m, "Channel2 not specified");
07284       return 0;
07285    }
07286 
07287    if (!ast_strlen_zero(timeout)) {
07288       if (sscanf(timeout, "%30d", &args.timeout) != 1) {
07289          astman_send_error(s, m, "Invalid timeout value.");
07290          return 0;
07291       }
07292    }
07293 
07294    if (!(ch1 = ast_channel_get_by_name(channel))) {
07295       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
07296       astman_send_error(s, m, buf);
07297       return 0;
07298    }
07299 
07300    if (!(ch2 = ast_channel_get_by_name(channel2))) {
07301       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
07302       astman_send_error(s, m, buf);
07303       ast_channel_unref(ch1);
07304       return 0;
07305    }
07306 
07307    if (!ast_strlen_zero(parkinglotname)) {
07308       args.parkinglot = find_parkinglot(parkinglotname);
07309    }
07310 
07311    res = masq_park_call(ch1, ch2, &args);
07312    if (!res) {
07313       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
07314       astman_send_ack(s, m, "Park successful");
07315    } else {
07316       astman_send_error(s, m, "Park failure");
07317    }
07318 
07319    if (args.parkinglot) {
07320       parkinglot_unref(args.parkinglot);
07321    }
07322    ch1 = ast_channel_unref(ch1);
07323    ch2 = ast_channel_unref(ch2);
07324 
07325    return 0;
07326 }

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

Dump parking lot status.

Parameters:
s 
m Lock parking lot, iterate list and append parked calls status, unlock parking lot.
Returns:
Always RESULT_SUCCESS

Definition at line 7179 of file features.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::caller, parkeduser::chan, ast_channel::connected, ast_party_connected_line::id, ast_party_caller::id, ast_party_id::name, ast_parkinglot::name, ast_party_id::number, parkinglots, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, S_COR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.

Referenced by ast_features_init().

07180 {
07181    struct parkeduser *cur;
07182    const char *id = astman_get_header(m, "ActionID");
07183    char idText[256] = "";
07184    struct ao2_iterator iter;
07185    struct ast_parkinglot *curlot;
07186    int numparked = 0;
07187 
07188    if (!ast_strlen_zero(id))
07189       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
07190 
07191    astman_send_ack(s, m, "Parked calls will follow");
07192 
07193    iter = ao2_iterator_init(parkinglots, 0);
07194    while ((curlot = ao2_iterator_next(&iter))) {
07195       AST_LIST_LOCK(&curlot->parkings);
07196       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
07197          astman_append(s, "Event: ParkedCall\r\n"
07198             "Parkinglot: %s\r\n"
07199             "Exten: %d\r\n"
07200             "Channel: %s\r\n"
07201             "From: %s\r\n"
07202             "Timeout: %ld\r\n"
07203             "CallerIDNum: %s\r\n"
07204             "CallerIDName: %s\r\n"
07205             "ConnectedLineNum: %s\r\n"
07206             "ConnectedLineName: %s\r\n"
07207             "%s"
07208             "\r\n",
07209             curlot->name,
07210             cur->parkingnum, cur->chan->name, cur->peername,
07211             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
07212             S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""),   /* XXX in other places it is <unknown> */
07213             S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
07214             S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""),   /* XXX in other places it is <unknown> */
07215             S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""),
07216             idText);
07217          ++numparked;
07218       }
07219       AST_LIST_UNLOCK(&curlot->parkings);
07220       ao2_ref(curlot, -1);
07221    }
07222    ao2_iterator_destroy(&iter);
07223 
07224    astman_append(s,
07225       "Event: ParkedCallsComplete\r\n"
07226       "Total: %d\r\n"
07227       "%s"
07228       "\r\n",
07229       numparked, idText);
07230 
07231    return RESULT_SUCCESS;
07232 }

static int masq_park_call ( struct ast_channel rchan,
struct ast_channel peer,
struct ast_park_call_args args 
) [static]

Park call via masqueraded channel and announce parking spot on peer channel.

Parameters:
rchan the real channel to be parked
peer the channel to have the parking read to.
args Additional parking options when parking a call.
Return values:
0 on success.
-1 on failure.

Definition at line 1726 of file features.c.

References ast_channel::amaflags, ast_channel_alloc, ast_channel_masquerade(), ast_copy_string(), ast_do_masquerade(), ast_hangup(), ast_log(), AST_PARK_OPT_SILENCE, AST_STATE_DOWN, ast_stream_and_wait(), ast_test_flag, ast_channel::context, ast_channel::exten, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, park_call_full(), park_space_abort(), park_space_reserve(), play_message_on_chan(), ast_channel::priority, ast_park_call_args::pu, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

Referenced by ast_masq_park_call(), ast_masq_park_call_exten(), builtin_parkcall(), manager_park(), park_call_exec(), and xfer_park_call_helper().

01727 {
01728    struct ast_channel *chan;
01729 
01730    /* Make a new, channel that we'll use to masquerade in the real one */
01731    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten,
01732       rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s", rchan->name);
01733    if (!chan) {
01734       ast_log(LOG_WARNING, "Unable to create parked channel\n");
01735       if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
01736          if (peer == rchan) {
01737             /* Only have one channel to worry about. */
01738             ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01739          } else if (peer) {
01740             /* Have two different channels to worry about. */
01741             play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
01742          }
01743       }
01744       return -1;
01745    }
01746 
01747    args->pu = park_space_reserve(rchan, peer, args);
01748    if (!args->pu) {
01749       ast_hangup(chan);
01750       if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
01751          if (peer == rchan) {
01752             /* Only have one channel to worry about. */
01753             ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01754          } else if (peer) {
01755             /* Have two different channels to worry about. */
01756             play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
01757          }
01758       }
01759       return -1;
01760    }
01761 
01762    /* Make formats okay */
01763    chan->readformat = rchan->readformat;
01764    chan->writeformat = rchan->writeformat;
01765 
01766    if (ast_channel_masquerade(chan, rchan)) {
01767       park_space_abort(args->pu);
01768       args->pu = NULL;
01769       ast_hangup(chan);
01770       if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
01771          if (peer == rchan) {
01772             /* Only have one channel to worry about. */
01773             ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01774          } else if (peer) {
01775             /* Have two different channels to worry about. */
01776             play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
01777          }
01778       }
01779       return -1;
01780    }
01781 
01782    /* Setup the extensions and such */
01783    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
01784 
01785    /* Setup the macro extension and such */
01786    ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext));
01787    ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten));
01788    chan->macropriority = rchan->macropriority;
01789 
01790    /* Manually do the masquerade to make sure it is complete. */
01791    ast_do_masquerade(chan);
01792 
01793    if (peer == rchan) {
01794       peer = chan;
01795    }
01796 
01797    /* parking space reserved, return code check unnecessary */
01798    park_call_full(chan, peer, args);
01799 
01800    return 0;
01801 }

static enum ast_device_state metermaidstate ( const char *  data  )  [static]

metermaids callback from devicestate.c

Definition at line 1105 of file features.c.

References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), and ast_strdupa.

Referenced by ast_features_init().

01106 {
01107    char *context;
01108    char *exten;
01109 
01110    context = ast_strdupa(data);
01111 
01112    exten = strsep(&context, "@");
01113    if (!context)
01114       return AST_DEVICE_INVALID;
01115    
01116    ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
01117 
01118    if (!ast_exists_extension(NULL, context, exten, 1, NULL))
01119       return AST_DEVICE_NOT_INUSE;
01120 
01121    return AST_DEVICE_INUSE;
01122 }

static void notify_metermaids ( const char *  exten,
char *  context,
enum ast_device_state  state 
) [static]

Notify metermaids that we've changed an extension.

Definition at line 1096 of file features.c.

References ast_debug, ast_devstate2str(), AST_DEVSTATE_CACHABLE, and ast_devstate_changed().

Referenced by manage_parkinglot(), park_call_full(), parked_call_exec(), and parkinglot_activate().

01097 {
01098    ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
01099       exten, context, ast_devstate2str(state));
01100 
01101    ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "park:%s@%s", exten, context);
01102 }

static void park_add_hints ( const char *  context,
int  start,
int  stop 
) [static]

Add parking hints for all defined parking spaces.

Parameters:
context Dialplan context to add the hints.
start Starting space in parkinglot.
stop Ending space in parkinglot.

Definition at line 5484 of file features.c.

References ast_add_extension(), AST_MAX_EXTENSION, PRIORITY_HINT, and registrar.

Referenced by parkinglot_activate().

05485 {
05486    int numext;
05487    char device[AST_MAX_EXTENSION];
05488    char exten[10];
05489 
05490    for (numext = start; numext <= stop; numext++) {
05491       snprintf(exten, sizeof(exten), "%d", numext);
05492       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
05493       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
05494    }
05495 }

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

Park a call.

Definition at line 5063 of file features.c.

References ast_channel::_state, ast_answer(), ast_app_parse_options(), ast_copy_string(), ast_log(), AST_MAX_EXTENSION, AST_PARK_OPT_SILENCE, ast_safe_sleep(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, create_dynamic_parkinglot(), default_parkinglot, ast_channel::exten, find_parkinglot(), findparkinglotname(), ast_flags::flags, ast_park_call_args::flags, LOG_WARNING, masq_park_call(), park_app_args::options, ast_park_call_args::orig_chan_name, orig_exten(), park_call_options, parkeddynamic, ast_park_call_args::parkinglot, parkinglot_addref(), parkinglot_unref(), parse(), pbx_builtin_getvar_helper(), park_app_args::pl_name, ast_channel::priority, ast_park_call_args::return_con, park_app_args::return_con, ast_park_call_args::return_ext, park_app_args::return_ext, ast_park_call_args::return_pri, park_app_args::return_pri, S_OR, ast_park_call_args::timeout, and park_app_args::timeout.

Referenced by ast_features_init().

05064 {
05065    struct ast_park_call_args args = { 0, };
05066    struct ast_flags flags = { 0 };
05067    char orig_exten[AST_MAX_EXTENSION];
05068    int orig_priority;
05069    int res;
05070    const char *pl_name;
05071    char *parse;
05072    struct park_app_args app_args;
05073 
05074    /*
05075     * Cache the original channel name because we are going to
05076     * masquerade the channel.  Prefer the BLINDTRANSFER channel
05077     * name over this channel name.  BLINDTRANSFER could be set if
05078     * the parking access extension did not get detected and we are
05079     * executing the Park application from the dialplan.
05080     *
05081     * The orig_chan_name is used to return the call to the
05082     * originator on parking timeout.
05083     */
05084    args.orig_chan_name = ast_strdupa(S_OR(
05085       pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name));
05086 
05087    /* Answer if call is not up */
05088    if (chan->_state != AST_STATE_UP) {
05089       if (ast_answer(chan)) {
05090          return -1;
05091       }
05092 
05093       /* Sleep to allow VoIP streams to settle down */
05094       if (ast_safe_sleep(chan, 1000)) {
05095          return -1;
05096       }
05097    }
05098 
05099    /* Process the dialplan application options. */
05100    parse = ast_strdupa(data);
05101    AST_STANDARD_APP_ARGS(app_args, parse);
05102 
05103    if (!ast_strlen_zero(app_args.timeout)) {
05104       if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
05105          ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
05106          args.timeout = 0;
05107       }
05108    }
05109    if (!ast_strlen_zero(app_args.return_con)) {
05110       args.return_con = app_args.return_con;
05111    }
05112    if (!ast_strlen_zero(app_args.return_ext)) {
05113       args.return_ext = app_args.return_ext;
05114    }
05115    if (!ast_strlen_zero(app_args.return_pri)) {
05116       if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
05117          ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
05118          args.return_pri = 0;
05119       }
05120    }
05121 
05122    ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
05123    args.flags = flags.flags;
05124 
05125    /*
05126     * Setup the exten/priority to be s/1 since we don't know where
05127     * this call should return.
05128     */
05129    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
05130    orig_priority = chan->priority;
05131    strcpy(chan->exten, "s");
05132    chan->priority = 1;
05133 
05134    /* Park the call */
05135    if (!ast_strlen_zero(app_args.pl_name)) {
05136       pl_name = app_args.pl_name;
05137    } else {
05138       pl_name = findparkinglotname(chan);
05139    }
05140    if (ast_strlen_zero(pl_name)) {
05141       /* Parking lot is not specified, so use the default parking lot. */
05142       args.parkinglot = parkinglot_addref(default_parkinglot);
05143    } else {
05144       args.parkinglot = find_parkinglot(pl_name);
05145       if (!args.parkinglot && parkeddynamic) {
05146          args.parkinglot = create_dynamic_parkinglot(pl_name, chan);
05147       }
05148    }
05149    if (args.parkinglot) {
05150       res = masq_park_call(chan, chan, &args);
05151       parkinglot_unref(args.parkinglot);
05152    } else {
05153       /* Parking failed because the parking lot does not exist. */
05154       if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
05155          ast_stream_and_wait(chan, "pbx-parkingfailed", "");
05156       }
05157       res = -1;
05158    }
05159    if (res) {
05160       /* Park failed, try to continue in the dialplan. */
05161       ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
05162       chan->priority = orig_priority;
05163       res = 0;
05164    } else {
05165       /* Park succeeded. */
05166       res = -1;
05167    }
05168 
05169    return res;
05170 }

static int park_call_full ( struct ast_channel chan,
struct ast_channel peer,
struct ast_park_call_args args 
) [static]

< Channel name that is parking the call.

Definition at line 1470 of file features.c.

References adsi_announce_park(), adsipark, ast_channel::appl, ast_add_extension(), ast_adsi_available(), ast_adsi_unload_session(), ast_bridged_channel(), AST_CEL_PARK_START, ast_cel_report_event(), ast_channel_get_by_name(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_unlock, ast_channel_unref, ast_clear_flag, AST_CONTROL_HOLD, AST_CONTROL_RINGING, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr(), ast_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), ast_manager_event, AST_MAX_CONTEXT, AST_MAX_EXTENSION, AST_PARK_OPT_RINGING, AST_PARK_OPT_SILENCE, ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, ast_channel::caller, ast_parkinglot::cfg, parkeduser::chan, ast_channel::connected, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, ast_park_call_args::extout, parkeduser::hold_method, ast_party_connected_line::id, ast_party_caller::id, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, parkinglot_cfg::mohclass, ast_party_id::name, ast_parkinglot::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkeduser::options_specified, ast_park_call_args::orig_chan_name, park_space_reserve(), parkinglot_cfg::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, parkinglot_cfg::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, ast_park_call_args::pu, registrar, ast_park_call_args::return_con, ast_park_call_args::return_ext, ast_park_call_args::return_pri, S_COR, S_OR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_channel::tech, ast_park_call_args::timeout, ast_channel_tech::type, ast_party_name::valid, and ast_party_number::valid.

Referenced by ast_park_call(), ast_park_call_exten(), and masq_park_call().

01471 {
01472    struct parkeduser *pu = args->pu;
01473    const char *event_from;    /*!< Channel name that is parking the call. */
01474    char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT];
01475 
01476    if (pu == NULL) {
01477       args->pu = pu = park_space_reserve(chan, peer, args);
01478       if (pu == NULL) {
01479          return -1;
01480       }
01481    }
01482 
01483    chan->appl = "Parked Call";
01484    chan->data = NULL;
01485 
01486    pu->chan = chan;
01487 
01488    /* Put the parked channel on hold if we have two different channels */
01489    if (chan != peer) {
01490       if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
01491          pu->hold_method = AST_CONTROL_RINGING;
01492          ast_indicate(chan, AST_CONTROL_RINGING);
01493       } else {
01494          pu->hold_method = AST_CONTROL_HOLD;
01495          ast_indicate_data(chan, AST_CONTROL_HOLD,
01496             S_OR(pu->parkinglot->cfg.mohclass, NULL),
01497             !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
01498       }
01499    }
01500    
01501    pu->start = ast_tvnow();
01502    pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->cfg.parkingtime;
01503    if (args->extout)
01504       *(args->extout) = pu->parkingnum;
01505 
01506    if (peer) {
01507       event_from = S_OR(args->orig_chan_name, peer->name);
01508 
01509       /*
01510        * This is so ugly that it hurts, but implementing
01511        * get_base_channel() on local channels could have ugly side
01512        * effects.  We could have
01513        * transferer<->local,1<->local,2<->parking and we need the
01514        * callback name to be that of transferer.  Since local,1/2 have
01515        * the same name we can be tricky and just grab the bridged
01516        * channel from the other side of the local.
01517        */
01518       if (!strcasecmp(peer->tech->type, "Local")) {
01519          struct ast_channel *tmpchan, *base_peer;
01520          char other_side[AST_CHANNEL_NAME];
01521          char *c;
01522 
01523          ast_copy_string(other_side, event_from, sizeof(other_side));
01524          if ((c = strrchr(other_side, ';'))) {
01525             *++c = '1';
01526          }
01527          if ((tmpchan = ast_channel_get_by_name(other_side))) {
01528             ast_channel_lock(tmpchan);
01529             if ((base_peer = ast_bridged_channel(tmpchan))) {
01530                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
01531             }
01532             ast_channel_unlock(tmpchan);
01533             tmpchan = ast_channel_unref(tmpchan);
01534          }
01535       } else {
01536          ast_copy_string(pu->peername, event_from, sizeof(pu->peername));
01537       }
01538    } else {
01539       event_from = S_OR(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name);
01540    }
01541 
01542    /*
01543     * Remember what had been dialed, so that if the parking
01544     * expires, we try to come back to the same place
01545     */
01546    pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
01547 
01548    /*
01549     * If extension has options specified, they override all other
01550     * possibilities such as the returntoorigin flag and transferred
01551     * context.  Information on extension options is lost here, so
01552     * we set a flag
01553     */
01554    ast_copy_string(pu->context, 
01555       S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 
01556       sizeof(pu->context));
01557    ast_copy_string(pu->exten, 
01558       S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 
01559       sizeof(pu->exten));
01560    pu->priority = args->return_pri ? args->return_pri : 
01561       (chan->macropriority ? chan->macropriority : chan->priority);
01562 
01563    /* Mark channel as parked */
01564    pbx_builtin_setvar_helper(pu->chan, "PARKED_CALL", "1");
01565 
01566    /*
01567     * If parking a channel directly, don't quite yet get parking
01568     * running on it.  All parking lot entries are put into the
01569     * parking lot with notquiteyet on.
01570     */
01571    if (peer != chan) {
01572       pu->notquiteyet = 0;
01573    }
01574 
01575    /* Wake up the (presumably select()ing) thread */
01576    pthread_kill(parking_thread, SIGURG);
01577    ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n",
01578       chan->name, pu->parkingnum, pu->parkinglot->name,
01579       pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000));
01580 
01581    ast_cel_report_event(chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
01582 
01583    ast_manager_event(chan, EVENT_FLAG_CALL, "ParkedCall",
01584       "Exten: %s\r\n"
01585       "Channel: %s\r\n"
01586       "Parkinglot: %s\r\n"
01587       "From: %s\r\n"
01588       "Timeout: %ld\r\n"
01589       "CallerIDNum: %s\r\n"
01590       "CallerIDName: %s\r\n"
01591       "ConnectedLineNum: %s\r\n"
01592       "ConnectedLineName: %s\r\n"
01593       "Uniqueid: %s\r\n",
01594       pu->parkingexten, chan->name, pu->parkinglot->name, event_from,
01595       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
01596       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<unknown>"),
01597       S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>"),
01598       S_COR(chan->connected.id.number.valid, chan->connected.id.number.str, "<unknown>"),
01599       S_COR(chan->connected.id.name.valid, chan->connected.id.name.str, "<unknown>"),
01600       chan->uniqueid
01601       );
01602    ast_debug(4, "peer->name: %s\n", peer ? peer->name : "-No peer-");
01603    ast_debug(4, "args->orig_chan_name: %s\n", args->orig_chan_name ? args->orig_chan_name : "-none-");
01604    ast_debug(4, "pu->peername: %s\n", pu->peername);
01605    ast_debug(4, "AMI ParkedCall Channel: %s\n", chan->name);
01606    ast_debug(4, "AMI ParkedCall From: %s\n", event_from);
01607 
01608    if (peer && adsipark && ast_adsi_available(peer)) {
01609       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
01610       ast_adsi_unload_session(peer);
01611    }
01612 
01613    snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten,
01614       pu->parkinglot->name);
01615    if (ast_add_extension(pu->parkinglot->cfg.parking_con, 1, pu->parkingexten, 1,
01616       NULL, NULL, parkedcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
01617       ast_log(LOG_ERROR, "Could not create parked call exten: %s@%s\n",
01618          pu->parkingexten, pu->parkinglot->cfg.parking_con);
01619    } else {
01620       notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE);
01621    }
01622 
01623    AST_LIST_UNLOCK(&pu->parkinglot->parkings);
01624 
01625    /* Only say number if it's a number and the channel hasn't been masqueraded away */
01626    if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE)
01627       && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
01628       /*
01629        * If a channel is masqueraded into peer while playing back the
01630        * parking space number do not continue playing it back.  This
01631        * is the case if an attended transfer occurs.
01632        */
01633       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01634       /* Tell the peer channel the number of the parking space */
01635       ast_say_digits(peer, pu->parkingnum, "", peer->language);
01636       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01637    }
01638    if (peer == chan) { /* pu->notquiteyet = 1 */
01639       /* Wake up parking thread if we're really done */
01640       if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
01641          pu->hold_method = AST_CONTROL_RINGING;
01642          ast_indicate(chan, AST_CONTROL_RINGING);
01643       } else {
01644          pu->hold_method = AST_CONTROL_HOLD;
01645          ast_indicate_data(chan, AST_CONTROL_HOLD,
01646             S_OR(pu->parkinglot->cfg.mohclass, NULL),
01647             !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
01648       }
01649       pu->notquiteyet = 0;
01650       pthread_kill(parking_thread, SIGURG);
01651    }
01652    return 0;
01653 }

static void park_space_abort ( struct parkeduser pu  )  [static]

Definition at line 1272 of file features.c.

References ast_free, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_parkinglot::next_parking_space, parkeduser::parkinglot, parkinglot_unref(), and ast_parkinglot::parkings.

Referenced by masq_park_call().

01273 {
01274    struct ast_parkinglot *parkinglot;
01275 
01276    parkinglot = pu->parkinglot;
01277 
01278    /* Put back the parking space just allocated. */
01279    --parkinglot->next_parking_space;
01280 
01281    AST_LIST_REMOVE(&parkinglot->parkings, pu, list);
01282 
01283    AST_LIST_UNLOCK(&parkinglot->parkings);
01284    parkinglot_unref(parkinglot);
01285    ast_free(pu);
01286 }

static struct parkeduser* park_space_reserve ( struct ast_channel park_me,
struct ast_channel parker,
struct ast_park_call_args args 
) [static, read]

Note:
The API forces us to specify a numeric parking slot, even though the architecture would tend to support non-numeric extensions (as are possible with SIP, for example). Hence, we enforce that limitation here. If extout was not numeric, we could permit arbitrary non-numeric extensions.

Definition at line 1299 of file features.c.

References ast_calloc, ast_debug, ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_parkinglot::cfg, create_dynamic_parkinglot(), default_parkinglot, ast_parkinglot::disabled, find_parkinglot(), findparkinglotname(), parkinglot_cfg::is_invalid, LOG_WARNING, ast_parkinglot::name, ast_parkinglot::next_parking_space, parkeduser::notquiteyet, parkeddynamic, parkinglot_cfg::parkfindnext, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkeduser::parkingexten, parkeduser::parkinglot, ast_park_call_args::parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, ast_parkinglot::parkings, pbx_builtin_getvar_helper(), and S_OR.

Referenced by masq_park_call(), and park_call_full().

01300 {
01301    struct parkeduser *pu;
01302    int i;
01303    int parking_space = -1;
01304    const char *parkinglotname;
01305    const char *parkingexten;
01306    struct parkeduser *cur;
01307    struct ast_parkinglot *parkinglot = NULL;
01308 
01309    if (args->parkinglot) {
01310       parkinglot = parkinglot_addref(args->parkinglot);
01311       parkinglotname = parkinglot->name;
01312    } else {
01313       if (parker) {
01314          parkinglotname = findparkinglotname(parker);
01315       } else { /* parker was NULL, check park_me (ParkAndAnnounce / res_agi) */
01316          parkinglotname = findparkinglotname(park_me);
01317       }
01318       if (!ast_strlen_zero(parkinglotname)) {
01319          parkinglot = find_parkinglot(parkinglotname);
01320       } else {
01321          /* Parking lot is not specified, so use the default parking lot. */
01322          ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
01323          parkinglot = parkinglot_addref(default_parkinglot);
01324       }
01325    }
01326 
01327    /* Dynamically create parkinglot */
01328    if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
01329       parkinglot = create_dynamic_parkinglot(parkinglotname, park_me);
01330    }
01331 
01332    if (!parkinglot) {
01333       ast_log(LOG_WARNING, "Parking lot not available to park %s.\n", park_me->name);
01334       return NULL;
01335    }
01336 
01337    ast_debug(1, "Parking lot: %s\n", parkinglot->name);
01338    if (parkinglot->disabled || parkinglot->cfg.is_invalid) {
01339       ast_log(LOG_WARNING, "Parking lot %s is not in a useable state.\n",
01340          parkinglot->name);
01341       parkinglot_unref(parkinglot);
01342       return NULL;
01343    }
01344 
01345    /* Allocate memory for parking data */
01346    if (!(pu = ast_calloc(1, sizeof(*pu)))) {
01347       parkinglot_unref(parkinglot);
01348       return NULL;
01349    }
01350 
01351    /* Lock parking list */
01352    AST_LIST_LOCK(&parkinglot->parkings);
01353 
01354    /* Check for channel variable PARKINGEXTEN */
01355    parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(park_me, "PARKINGEXTEN"), ""));
01356    if (!ast_strlen_zero(parkingexten)) {
01357       /*!
01358        * \note The API forces us to specify a numeric parking slot, even
01359        * though the architecture would tend to support non-numeric extensions
01360        * (as are possible with SIP, for example).  Hence, we enforce that
01361        * limitation here.  If extout was not numeric, we could permit
01362        * arbitrary non-numeric extensions.
01363        */
01364       if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space <= 0) {
01365          ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n",
01366             parkingexten);
01367          AST_LIST_UNLOCK(&parkinglot->parkings);
01368          parkinglot_unref(parkinglot);
01369          ast_free(pu);
01370          return NULL;
01371       }
01372 
01373       if (parking_space < parkinglot->cfg.parking_start
01374          || parkinglot->cfg.parking_stop < parking_space) {
01375          /*
01376           * Cannot allow park because parking lots are not setup for
01377           * spaces outside of the lot.  (Things like dialplan hints don't
01378           * exist for outside lot space.)
01379           */
01380          ast_log(LOG_WARNING, "PARKINGEXTEN=%d is not in %s (%d-%d).\n",
01381             parking_space, parkinglot->name, parkinglot->cfg.parking_start,
01382             parkinglot->cfg.parking_stop);
01383          AST_LIST_UNLOCK(&parkinglot->parkings);
01384          parkinglot_unref(parkinglot);
01385          ast_free(pu);
01386          return NULL;
01387       }
01388 
01389       /* Check if requested parking space is in use. */
01390       AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
01391          if (cur->parkingnum == parking_space) {
01392             ast_log(LOG_WARNING, "PARKINGEXTEN=%d is already in use in %s\n",
01393                parking_space, parkinglot->name);
01394             AST_LIST_UNLOCK(&parkinglot->parkings);
01395             parkinglot_unref(parkinglot);
01396             ast_free(pu);
01397             return NULL;
01398          }
01399       }
01400    } else {
01401       /* PARKINGEXTEN is empty, so find a usable extension in the lot to park the call */
01402       int start; /* The first slot we look in the parkinglot. It can be randomized. */
01403       int start_checked = 0; /* flag raised once the first slot is checked */
01404 
01405       /* If using randomize mode, set start to random position on parking range */
01406       if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
01407          start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1);
01408          start += parkinglot->cfg.parking_start;
01409       } else if (parkinglot->cfg.parkfindnext
01410          && parkinglot->cfg.parking_start <= parkinglot->next_parking_space
01411          && parkinglot->next_parking_space <= parkinglot->cfg.parking_stop) {
01412          /* Start looking with the next parking space in the lot. */
01413          start = parkinglot->next_parking_space;
01414       } else {
01415          /* Otherwise, just set it to the start position. */
01416          start = parkinglot->cfg.parking_start;
01417       }
01418 
01419       /* free parking extension linear search: O(n^2) */
01420       for (i = start; ; i++) {
01421          /* If we are past the end, wrap around to the first parking slot*/
01422          if (i == parkinglot->cfg.parking_stop + 1) {
01423             i = parkinglot->cfg.parking_start;
01424          }
01425 
01426          if (i == start) {
01427             /* At this point, if start_checked, we've exhausted all the possible slots. */
01428             if (start_checked) {
01429                break;
01430             } else {
01431                start_checked = 1;
01432             }
01433          }
01434 
01435          /* Search the list of parked calls already in use for i. If we find it, it's in use. */
01436          AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
01437             if (cur->parkingnum == i) {
01438                break;
01439             }
01440          }
01441          if (!cur) {
01442             /* We found a parking space. */
01443             parking_space = i;
01444             break;
01445          }
01446       }
01447       if (parking_space == -1) {
01448          /* We did not find a parking space.  Lot is full. */
01449          ast_log(LOG_WARNING, "No more parking spaces in %s\n", parkinglot->name);
01450          AST_LIST_UNLOCK(&parkinglot->parkings);
01451          parkinglot_unref(parkinglot);
01452          ast_free(pu);
01453          return NULL;
01454       }
01455    }
01456 
01457    /* Prepare for next parking space search. */
01458    parkinglot->next_parking_space = parking_space + 1;
01459 
01460    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
01461    pu->notquiteyet = 1;
01462    pu->parkingnum = parking_space;
01463    pu->parkinglot = parkinglot;
01464    AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
01465 
01466    return pu;
01467 }

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

Pickup parked call.

< Parking lot space to retrieve if present.

< Parking lot name to use if present.

< Place to put any remaining args string.

Definition at line 5173 of file features.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_bridge_call(), ast_cdr_setdestchan(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_flags, AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_free, ast_hangup(), ast_indicate(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_manager_event, ast_party_connected_line_free(), ast_party_connected_line_init(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, ast_channel::caller, ast_channel::cdr, ast_parkinglot::cfg, parkeduser::chan, ast_channel::connected, courtesytone, ast_datastore::data, default_parkinglot, dial_features_info, EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, find_parkinglot(), findparkinglotname(), parkeduser::hold_method, ast_party_connected_line::id, ast_party_caller::id, LOG_WARNING, ast_dial_features::my_features, ast_party_id::name, ast_parkinglot::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkinglot_cfg::parkedcallhangup, parkinglot_cfg::parkedcallrecording, parkinglot_cfg::parkedcallreparking, parkinglot_cfg::parkedcalltransfers, parkedplay, parkinglot_cfg::parking_con, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, ast_parkinglot::parkings, parse(), ast_channel::pbx, pbx_builtin_setvar_helper(), play_message_to_chans(), S_COR, ast_party_connected_line::source, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.

Referenced by ast_features_init().

05174 {
05175    int res;
05176    struct ast_channel *peer = NULL;
05177    struct parkeduser *pu;
05178    struct ast_context *con;
05179    char *parse;
05180    const char *pl_name;
05181    unsigned int park = 0;
05182    struct ast_bridge_config config;
05183    struct ast_parkinglot *parkinglot;
05184    AST_DECLARE_APP_ARGS(app_args,
05185       AST_APP_ARG(pl_space);  /*!< Parking lot space to retrieve if present. */
05186       AST_APP_ARG(pl_name);   /*!< Parking lot name to use if present. */
05187       AST_APP_ARG(dummy);     /*!< Place to put any remaining args string. */
05188    );
05189 
05190    parse = ast_strdupa(data);
05191    AST_STANDARD_APP_ARGS(app_args, parse);
05192 
05193    if (!ast_strlen_zero(app_args.pl_space)) {
05194       if (sscanf(app_args.pl_space, "%30u", &park) != 1) {
05195          ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n",
05196             app_args.pl_space);
05197          park = -1;
05198       }
05199    }
05200 
05201    if (!ast_strlen_zero(app_args.pl_name)) {
05202       pl_name = app_args.pl_name;
05203    } else {
05204       pl_name = findparkinglotname(chan);
05205    }
05206    if (ast_strlen_zero(pl_name)) {
05207       /* Parking lot is not specified, so use the default parking lot. */
05208       parkinglot = parkinglot_addref(default_parkinglot);
05209    } else {
05210       parkinglot = find_parkinglot(pl_name);
05211       if (!parkinglot) {
05212          /* It helps to answer the channel if not already up. :) */
05213          if (chan->_state != AST_STATE_UP) {
05214             ast_answer(chan);
05215          }
05216          if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05217             ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n",
05218                "pbx-invalidpark", chan->name);
05219          }
05220          ast_log(LOG_WARNING,
05221             "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
05222             chan->name, pl_name);
05223          return -1;
05224       }
05225    }
05226 
05227    AST_LIST_LOCK(&parkinglot->parkings);
05228    AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
05229       if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
05230          && !pu->notquiteyet && !pu->chan->pbx) {
05231          /* The parking space has a call and can be picked up now. */
05232          AST_LIST_REMOVE_CURRENT(list);
05233          break;
05234       }
05235    }
05236    AST_LIST_TRAVERSE_SAFE_END;
05237    if (pu) {
05238       /* Found a parked call to pickup. */
05239       peer = pu->chan;
05240       con = ast_context_find(parkinglot->cfg.parking_con);
05241       if (con) {
05242          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
05243             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
05244          } else {
05245             notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
05246          }
05247       } else {
05248          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
05249       }
05250 
05251       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
05252       ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
05253          "Exten: %s\r\n"
05254          "Channel: %s\r\n"
05255          "Parkinglot: %s\r\n"
05256          "From: %s\r\n"
05257          "CallerIDNum: %s\r\n"
05258          "CallerIDName: %s\r\n"
05259          "ConnectedLineNum: %s\r\n"
05260          "ConnectedLineName: %s\r\n"
05261          "Uniqueid: %s\r\n",
05262          pu->parkingexten, pu->chan->name, pu->parkinglot->name, chan->name,
05263          S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
05264          S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
05265          S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
05266          S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
05267          pu->chan->uniqueid
05268          );
05269 
05270       /* Stop entertaining the caller. */
05271       switch (pu->hold_method) {
05272       case AST_CONTROL_HOLD:
05273          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
05274          break;
05275       case AST_CONTROL_RINGING:
05276          ast_indicate(pu->chan, -1);
05277          break;
05278       default:
05279          break;
05280       }
05281       pu->hold_method = 0;
05282 
05283       parkinglot_unref(pu->parkinglot);
05284       ast_free(pu);
05285    }
05286    AST_LIST_UNLOCK(&parkinglot->parkings);
05287 
05288    if (peer) {
05289       /* Update connected line between retrieving call and parked call. */
05290       struct ast_party_connected_line connected;
05291 
05292       ast_party_connected_line_init(&connected);
05293 
05294       /* Send our caller-id to peer. */
05295       ast_channel_lock(chan);
05296       ast_connected_line_copy_from_caller(&connected, &chan->caller);
05297       ast_channel_unlock(chan);
05298       connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05299       if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) {
05300          ast_channel_update_connected_line(peer, &connected, NULL);
05301       }
05302 
05303       /*
05304        * Get caller-id from peer.
05305        *
05306        * Update the retrieving call before it is answered if possible
05307        * for best results.  Some phones do not support updating the
05308        * connected line information after connection.
05309        */
05310       ast_channel_lock(peer);
05311       ast_connected_line_copy_from_caller(&connected, &peer->caller);
05312       ast_channel_unlock(peer);
05313       connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05314       if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) {
05315          ast_channel_update_connected_line(chan, &connected, NULL);
05316       }
05317 
05318       ast_party_connected_line_free(&connected);
05319    }
05320 
05321    /* JK02: it helps to answer the channel if not already up */
05322    if (chan->_state != AST_STATE_UP) {
05323       ast_answer(chan);
05324    }
05325 
05326    if (peer) {
05327       struct ast_datastore *features_datastore;
05328       struct ast_dial_features *dialfeatures;
05329 
05330       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
05331       if (!ast_strlen_zero(courtesytone)) {
05332          static const char msg[] = "courtesy tone";
05333 
05334          switch (parkedplay) {
05335          case 0:/* Courtesy tone to pickup chan */
05336             res = play_message_to_chans(chan, peer, -1, msg, courtesytone);
05337             break;
05338          case 1:/* Courtesy tone to parked chan */
05339             res = play_message_to_chans(chan, peer, 1, msg, courtesytone);
05340             break;
05341          case 2:/* Courtesy tone to both chans */
05342             res = play_message_to_chans(chan, peer, 0, msg, courtesytone);
05343             break;
05344          default:
05345             res = 0;
05346             break;
05347          }
05348          if (res) {
05349             ast_hangup(peer);
05350             parkinglot_unref(parkinglot);
05351             return -1;
05352          }
05353       }
05354 
05355       res = ast_channel_make_compatible(chan, peer);
05356       if (res < 0) {
05357          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
05358          ast_hangup(peer);
05359          parkinglot_unref(parkinglot);
05360          return -1;
05361       }
05362       /* This runs sorta backwards, since we give the incoming channel control, as if it
05363          were the person called. */
05364       ast_verb(3, "Channel %s connected to parked call %u\n", chan->name, park);
05365 
05366       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05367       ast_cdr_setdestchan(chan->cdr, peer->name);
05368       memset(&config, 0, sizeof(struct ast_bridge_config));
05369 
05370       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
05371       ast_channel_lock(peer);
05372       features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL);
05373       if (features_datastore && (dialfeatures = features_datastore->data)) {
05374          ast_copy_flags(&config.features_callee, &dialfeatures->my_features,
05375             AST_FLAGS_ALL);
05376       }
05377       ast_channel_unlock(peer);
05378 
05379       if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05380          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
05381       }
05382       if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05383          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
05384       }
05385       if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05386          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
05387       }
05388       if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05389          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
05390       }
05391       if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05392          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
05393       }
05394       if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05395          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
05396       }
05397       if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05398          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
05399       }
05400       if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05401          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
05402       }
05403 
05404       res = ast_bridge_call(chan, peer, &config);
05405 
05406       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05407       ast_cdr_setdestchan(chan->cdr, peer->name);
05408 
05409       /* Simulate the PBX hanging up */
05410       ast_hangup(peer);
05411    } else {
05412       if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05413          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
05414             chan->name);
05415       }
05416       ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %u\n",
05417          chan->name, park);
05418       res = -1;
05419    }
05420 
05421    parkinglot_unref(parkinglot);
05422    return res;
05423 }

static int parkinglot_activate ( struct ast_parkinglot parkinglot  )  [static]

Definition at line 5640 of file features.c.

References ast_add_extension(), ast_context_find_or_create(), AST_DEVICE_INUSE, ast_free_ptr(), ast_log(), AST_MAX_CONTEXT, ast_strdup, ast_parkinglot::cfg, ast_parkinglot::disabled, LOG_ERROR, ast_parkinglot::name, notify_metermaids(), park_add_hints(), parkinglot_cfg::parkaddhints, parkcall, parkinglot_cfg::parkext, parkinglot_cfg::parkext_exclusive, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, and registrar.

Referenced by create_dynamic_parkinglot(), and parkinglot_activate_cb().

05641 {
05642    int disabled = 0;
05643    char app_data[5 + AST_MAX_CONTEXT];
05644 
05645    /* Create Park option list.  Must match with struct park_app_args options. */
05646    if (parkinglot->cfg.parkext_exclusive) {
05647       /* Specify the parking lot this parking extension parks calls. */
05648       snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name);
05649    } else {
05650       /* The dialplan must specify which parking lot to use. */
05651       app_data[0] = '\0';
05652    }
05653 
05654    /* Create context */
05655    if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) {
05656       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n",
05657          parkinglot->cfg.parking_con);
05658       disabled = 1;
05659 
05660    /* Add a parking extension into the context */
05661    } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext,
05662       1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
05663       ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n",
05664          parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con);
05665       disabled = 1;
05666    } else {
05667       /* Add parking hints */
05668       if (parkinglot->cfg.parkaddhints) {
05669          park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start,
05670             parkinglot->cfg.parking_stop);
05671       }
05672 
05673       /*
05674        * XXX Not sure why we should need to notify the metermaids for
05675        * this exten.  It was originally done for the default parking
05676        * lot entry exten only but should be done for all entry extens
05677        * if we do it for one.
05678        */
05679       /* Notify metermaids about parking lot entry exten state. */
05680       notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con,
05681          AST_DEVICE_INUSE);
05682    }
05683 
05684    parkinglot->disabled = disabled;
05685    return disabled ? -1 : 0;
05686 }

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

Definition at line 6689 of file features.c.

References ast_debug, ast_log(), ast_parkinglot::cfg, force_reload_load, LOG_WARNING, ast_parkinglot::name, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglot_activate(), and ast_parkinglot::the_mark.

Referenced by load_config().

06690 {
06691    struct ast_parkinglot *parkinglot = obj;
06692 
06693    if (parkinglot->the_mark) {
06694       /*
06695        * Don't activate a parking lot that still bears the_mark since
06696        * it is effectively deleted.
06697        */
06698       return 0;
06699    }
06700 
06701    if (parkinglot_activate(parkinglot)) {
06702       /*
06703        * The parking lot failed to activate.  Allow reloading later to
06704        * see if that fixes it.
06705        */
06706       force_reload_load = 1;
06707       ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name);
06708    } else {
06709       ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n",
06710          parkinglot->name, parkinglot->cfg.parking_start,
06711          parkinglot->cfg.parking_stop);
06712    }
06713 
06714    return 0;
06715 }

static struct ast_parkinglot * parkinglot_addref ( struct ast_parkinglot parkinglot  )  [static, read]

Definition at line 5435 of file features.c.

References ao2_ref, ast_debug, and ast_parkinglot::name.

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

05436 {
05437    int refcount;
05438 
05439    refcount = ao2_ref(parkinglot, +1);
05440    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
05441    return parkinglot;
05442 }

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

Definition at line 869 of file features.c.

References CMP_MATCH, CMP_STOP, and ast_parkinglot::name.

Referenced by ast_features_init().

00870 {
00871    struct ast_parkinglot *parkinglot = obj;
00872    struct ast_parkinglot *parkinglot2 = arg;
00873 
00874    return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00875 }

static int parkinglot_config_read ( const char *  pl_name,
struct parkinglot_cfg cfg,
struct ast_variable var 
) [static]

Definition at line 5546 of file features.c.

References ast_copy_string(), ast_log(), ast_strlen_zero(), ast_true(), ast_variable::file, parkinglot_cfg::is_invalid, ast_variable::lineno, LOG_WARNING, parkinglot_cfg::mohclass, ast_variable::name, ast_variable::next, parkinglot_cfg::parkaddhints, parkinglot_cfg::parkedcallhangup, parkinglot_cfg::parkedcallrecording, parkinglot_cfg::parkedcallreparking, parkinglot_cfg::parkedcalltransfers, parkinglot_cfg::parkext, parkinglot_cfg::parkext_exclusive, parkinglot_cfg::parkfindnext, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglot_feature_flag_cfg(), parkingretalertinfo, parkingretcidname, parkingretdahdiring, parkinglot_cfg::parkingtime, and ast_variable::value.

Referenced by build_parkinglot().

05547 {
05548    int error = 0;
05549 
05550    while (var) {
05551       if (!strcasecmp(var->name, "context")) {
05552          ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con));
05553       } else if (!strcasecmp(var->name, "parkext")) {
05554          ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext));
05555       } else if (!strcasecmp(var->name, "parkext_exclusive")) {
05556          cfg->parkext_exclusive = ast_true(var->value);
05557       } else if (!strcasecmp(var->name, "parkinghints")) {
05558          cfg->parkaddhints = ast_true(var->value);
05559       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
05560          ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass));
05561       } else if (!strcasecmp(var->name, "parkingtime")) {
05562          int parkingtime = 0;
05563 
05564          if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) {
05565             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
05566             error = -1;
05567          } else {
05568             cfg->parkingtime = parkingtime * 1000;
05569          }
05570       } else if (!strcasecmp(var->name, "parkpos")) {
05571          int start = 0;
05572          int end = 0;
05573 
05574          if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
05575             ast_log(LOG_WARNING,
05576                "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n",
05577                var->lineno, var->file);
05578             error = -1;
05579          } else if (end < start || start <= 0 || end <= 0) {
05580             ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n",
05581                var->lineno, var->file);
05582             error = -1;
05583          } else {
05584             cfg->parking_start = start;
05585             cfg->parking_stop = end;
05586          }
05587       } else if (!strcasecmp(var->name, "findslot")) {
05588          cfg->parkfindnext = (!strcasecmp(var->value, "next"));
05589       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
05590          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var);
05591       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
05592          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var);
05593       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
05594          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var);
05595       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
05596          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var);
05597       } else if (!strcasecmp(var->name, "parkingretcidname")) {
05598          ast_copy_string(parkingretcidname, var->value, sizeof(parkingretcidname));
05599       } else if (!strcasecmp(var->name, "parkingretdahdiring")) {
05600          ast_copy_string(parkingretdahdiring, var->value, sizeof(parkingretdahdiring));
05601       } else if (!strcasecmp(var->name, "parkingretalertinfo")) {
05602          ast_copy_string(parkingretalertinfo, var->value, sizeof(parkingretalertinfo));
05603       }
05604       var = var->next;
05605    }
05606 
05607    /* Check for configuration errors */
05608    if (ast_strlen_zero(cfg->parking_con)) {
05609       ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name);
05610       error = -1;
05611    }
05612    if (ast_strlen_zero(cfg->parkext)) {
05613       ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name);
05614       error = -1;
05615    }
05616    if (!cfg->parking_start) {
05617       ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name);
05618       error = -1;
05619    }
05620    if (error) {
05621       cfg->is_invalid = 1;
05622    }
05623 
05624    return error;
05625 }

static void parkinglot_destroy ( void *  obj  )  [static]

Destroy a parking lot.

Definition at line 5445 of file features.c.

References ast_assert, AST_LIST_EMPTY, AST_LIST_HEAD_DESTROY, and ast_parkinglot::parkings.

Referenced by create_parkinglot().

05446 {
05447    struct ast_parkinglot *doomed = obj;
05448 
05449    /*
05450     * No need to destroy parked calls here because any parked call
05451     * holds a parking lot reference.  Therefore the parkings list
05452     * must be empty.
05453     */
05454    ast_assert(AST_LIST_EMPTY(&doomed->parkings));
05455    AST_LIST_HEAD_DESTROY(&doomed->parkings);
05456 }

static void parkinglot_feature_flag_cfg ( const char *  pl_name,
int *  param,
struct ast_variable var 
) [static]

Definition at line 5523 of file features.c.

References ast_debug, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, ast_variable::name, and ast_variable::value.

Referenced by parkinglot_config_read().

05524 {
05525    ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value);
05526    if (!strcasecmp(var->value, "both")) {
05527       *param = AST_FEATURE_FLAG_BYBOTH;
05528    } else if (!strcasecmp(var->value, "caller")) {
05529       *param = AST_FEATURE_FLAG_BYCALLER;
05530    } else if (!strcasecmp(var->value, "callee")) {
05531       *param = AST_FEATURE_FLAG_BYCALLEE;
05532    }
05533 }

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

Definition at line 862 of file features.c.

References ast_str_case_hash(), and ast_parkinglot::name.

Referenced by ast_features_init().

00863 {
00864    const struct ast_parkinglot *parkinglot = obj;
00865 
00866    return ast_str_case_hash(parkinglot->name);
00867 }

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

Definition at line 6669 of file features.c.

References AST_LIST_EMPTY, ast_log(), CMP_MATCH, ast_parkinglot::disabled, force_reload_load, LOG_WARNING, ast_parkinglot::name, ast_parkinglot::parkings, and ast_parkinglot::the_mark.

Referenced by load_config().

06670 {
06671    struct ast_parkinglot *parkinglot = obj;
06672 
06673    if (parkinglot->the_mark) {
06674       if (AST_LIST_EMPTY(&parkinglot->parkings)) {
06675          /* This parking lot can actually be deleted. */
06676          return CMP_MATCH;
06677       }
06678       /* Try reloading later when parking lot is empty. */
06679       ast_log(LOG_WARNING,
06680          "Parking lot %s has parked calls.  Could not remove.\n",
06681          parkinglot->name);
06682       parkinglot->disabled = 1;
06683       force_reload_load = 1;
06684    }
06685 
06686    return 0;
06687 }

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

Definition at line 6661 of file features.c.

References ast_parkinglot::the_mark.

Referenced by load_config().

06662 {
06663    struct ast_parkinglot *parkinglot = obj;
06664 
06665    parkinglot->the_mark = 1;
06666    return 0;
06667 }

static void parkinglot_unref ( struct ast_parkinglot parkinglot  )  [static]

Unreference parkinglot object.

Definition at line 5428 of file features.c.

References ao2_ref, ast_debug, and ast_parkinglot::name.

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

05429 {
05430    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name,
05431       ao2_ref(parkinglot, 0) - 1);
05432    ao2_ref(parkinglot, -1);
05433 }

static struct ast_cdr* pick_unlocked_cdr ( struct ast_cdr cdr  )  [static, read]

return the first unlocked cdr in a possible chain

Definition at line 3854 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

03855 {
03856    struct ast_cdr *cdr_orig = cdr;
03857    while (cdr) {
03858       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
03859          return cdr;
03860       cdr = cdr->next;
03861    }
03862    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
03863 }

static int play_message_in_bridged_call ( struct ast_channel caller_chan,
struct ast_channel callee_chan,
const char *  audiofile 
) [static]

Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages.

Definition at line 2078 of file features.c.

References play_message_to_chans().

Referenced by builtin_automonitor().

02079 {
02080    return play_message_to_chans(caller_chan, callee_chan, 0, "automon message",
02081       audiofile);
02082 }

static int play_message_on_chan ( struct ast_channel play_to,
struct ast_channel other,
const char *  msg,
const char *  audiofile 
) [static]

Definition at line 2024 of file features.c.

References ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_log(), ast_stream_and_wait(), and LOG_WARNING.

Referenced by masq_park_call(), and play_message_to_chans().

02025 {
02026    /* Put other channel in autoservice. */
02027    if (ast_autoservice_start(other)) {
02028       return -1;
02029    }
02030    ast_autoservice_ignore(other, AST_FRAME_DTMF_BEGIN);
02031    ast_autoservice_ignore(other, AST_FRAME_DTMF_END);
02032    if (ast_stream_and_wait(play_to, audiofile, "")) {
02033       ast_log(LOG_WARNING, "Failed to play %s '%s'!\n", msg, audiofile);
02034       ast_autoservice_stop(other);
02035       return -1;
02036    }
02037    if (ast_autoservice_stop(other)) {
02038       return -1;
02039    }
02040    return 0;
02041 }

static int play_message_to_chans ( struct ast_channel left,
struct ast_channel right,
int  which,
const char *  msg,
const char *  audiofile 
) [static]

Definition at line 2059 of file features.c.

References play_message_on_chan().

Referenced by parked_call_exec(), and play_message_in_bridged_call().

02060 {
02061    /* First play the file to the left channel if requested. */
02062    if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) {
02063       return -1;
02064    }
02065 
02066    /* Then play the file to the right channel if requested. */
02067    if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) {
02068       return -1;
02069    }
02070 
02071    return 0;
02072 }

static void post_manager_event ( const char *  s,
struct parkeduser pu 
) [static]

Output parking event to manager.

Definition at line 4629 of file features.c.

References ast_channel::caller, parkeduser::chan, ast_channel::connected, EVENT_FLAG_CALL, ast_party_connected_line::id, ast_party_caller::id, manager_event, ast_party_id::name, ast_parkinglot::name, ast_party_id::number, parkeduser::parkingexten, parkeduser::parkinglot, S_COR, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.

Referenced by manage_parked_call().

04630 {
04631    manager_event(EVENT_FLAG_CALL, s,
04632       "Exten: %s\r\n"
04633       "Channel: %s\r\n"
04634       "Parkinglot: %s\r\n"
04635       "CallerIDNum: %s\r\n"
04636       "CallerIDName: %s\r\n"
04637       "ConnectedLineNum: %s\r\n"
04638       "ConnectedLineName: %s\r\n"
04639       "UniqueID: %s\r\n",
04640       pu->parkingexten, 
04641       pu->chan->name,
04642       pu->parkinglot->name,
04643       S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
04644       S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
04645       S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
04646       S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
04647       pu->chan->uniqueid
04648       );
04649 }

static void process_applicationmap_line ( struct ast_variable var  )  [static]

Definition at line 5768 of file features.c.

References ast_call_feature::app, app, ast_call_feature::app_args, args, AST_APP_ARG, ast_calloc, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FEATURE_FLAG_ONPEER, AST_FEATURE_FLAG_ONSELF, ast_free, ast_log(), ast_register_feature(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_verb, ast_call_feature::exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_MOH_LEN, FEATURE_SNAME_LEN, find_dynamic_feature(), LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_variable::name, ast_call_feature::operation, ast_call_feature::sname, and ast_variable::value.

Referenced by process_config().

05769 {
05770    char *tmp_val = ast_strdupa(var->value);
05771    char *activateon, *new_syn;
05772    struct ast_call_feature *feature;
05773    AST_DECLARE_APP_ARGS(args,
05774       AST_APP_ARG(exten);
05775       AST_APP_ARG(activatedby);
05776       AST_APP_ARG(app);
05777       AST_APP_ARG(app_args);
05778       AST_APP_ARG(moh_class);
05779    );
05780 
05781    AST_STANDARD_APP_ARGS(args, tmp_val);
05782 
05783    activateon = strsep(&args.activatedby, "/");
05784 
05785    if (ast_strlen_zero(args.app)
05786       || ast_strlen_zero(args.exten)
05787       || ast_strlen_zero(activateon)
05788       || ast_strlen_zero(var->name)) {
05789       ast_log(LOG_NOTICE,
05790          "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
05791          args.app, args.exten, activateon, var->name);
05792       return;
05793    }
05794 
05795    if ((new_syn = strchr(args.app, '('))) {
05796       /* New syntax */
05797       args.moh_class = args.app_args;
05798       args.app_args = new_syn;
05799       *args.app_args++ = '\0';
05800       if (args.app_args[strlen(args.app_args) - 1] == ')') {
05801          args.app_args[strlen(args.app_args) - 1] = '\0';
05802       }
05803    }
05804    
05805    AST_RWLIST_RDLOCK(&feature_list);
05806    if (find_dynamic_feature(var->name)) {
05807       AST_RWLIST_UNLOCK(&feature_list);
05808       ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n",
05809          var->name);
05810       return;
05811    }
05812    AST_RWLIST_UNLOCK(&feature_list);
05813 
05814    if (!(feature = ast_calloc(1, sizeof(*feature)))) {
05815       return;
05816    }
05817 
05818    ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
05819    ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
05820    ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
05821 
05822    if (args.app_args) {
05823       ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
05824    }
05825 
05826    if (args.moh_class) {
05827       ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
05828    }
05829 
05830    ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
05831    feature->operation = feature_exec_app;
05832    ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
05833 
05834    /* Allow caller and callee to be specified for backwards compatability */
05835    if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) {
05836       ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
05837    } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) {
05838       ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
05839    } else {
05840       ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
05841          " must be 'self', or 'peer'\n", var->name);
05842       ast_free(feature);
05843       return;
05844    }
05845 
05846    if (ast_strlen_zero(args.activatedby)) {
05847       ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05848    } else if (!strcasecmp(args.activatedby, "caller")) {
05849       ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
05850    } else if (!strcasecmp(args.activatedby, "callee")) {
05851       ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
05852    } else if (!strcasecmp(args.activatedby, "both")) {
05853       ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05854    } else {
05855       ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
05856          " must be 'caller', or 'callee', or 'both'\n", var->name);
05857       ast_free(feature);
05858       return;
05859    }
05860 
05861    ast_register_feature(feature);
05862 
05863    ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n",
05864       var->name, args.app, args.app_args, args.exten);
05865 }

static int process_config ( struct ast_config cfg  )  [static]

Definition at line 5867 of file features.c.

References adsipark, ARRAY_LEN, ast_category_browse(), ast_copy_string(), ast_debug, ast_find_call_feature(), ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_true(), ast_unregister_features(), ast_unregister_groups(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARKINGLOT, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, find_dynamic_feature(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, parkeddynamic, parkedplay, pickupfailsound, pickupsound, process_applicationmap_line(), register_group(), register_group_feature(), remap_feature(), transferdigittimeout, unmap_features(), ast_variable::value, var, xferfailsound, and xfersound.

Referenced by load_config().

05868 {
05869    int i;
05870    struct ast_variable *var = NULL;
05871    struct feature_group *fg = NULL;
05872    char *ctg; 
05873    static const char * const categories[] = { 
05874       /* Categories in features.conf that are not
05875        * to be parsed as group categories
05876        */
05877       "general",
05878       "featuremap",
05879       "applicationmap"
05880    };
05881 
05882    /* Set general features global defaults. */
05883    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05884 
05885    /* Set global call pickup defaults. */
05886    strcpy(pickup_ext, "*8");
05887    pickupsound[0] = '\0';
05888    pickupfailsound[0] = '\0';
05889 
05890    /* Set global call transfer defaults. */
05891    strcpy(xfersound, "beep");
05892    strcpy(xferfailsound, "beeperr");
05893    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05894    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05895    atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05896    atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
05897    atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05898 
05899    /* Set global call parking defaults. */
05900    comebacktoorigin = 1;
05901    courtesytone[0] = '\0';
05902    parkedplay = 0;
05903    adsipark = 0;
05904    parkeddynamic = 0;
05905 
05906    var = ast_variable_browse(cfg, "general");
05907    build_parkinglot(DEFAULT_PARKINGLOT, var);
05908    for (; var; var = var->next) {
05909       if (!strcasecmp(var->name, "parkeddynamic")) {
05910          parkeddynamic = ast_true(var->value);
05911       } else if (!strcasecmp(var->name, "adsipark")) {
05912          adsipark = ast_true(var->value);
05913       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
05914          if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
05915             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
05916             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05917          } else {
05918             transferdigittimeout = transferdigittimeout * 1000;
05919          }
05920       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
05921          if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
05922             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
05923             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05924          }
05925       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
05926          if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
05927             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
05928             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05929          } else {
05930             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
05931          }
05932       } else if (!strcasecmp(var->name, "atxferloopdelay")) {
05933          if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
05934             ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
05935             atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05936          } else {
05937             atxferloopdelay *= 1000;
05938          }
05939       } else if (!strcasecmp(var->name, "atxferdropcall")) {
05940          atxferdropcall = ast_true(var->value);
05941       } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
05942          if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
05943             ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
05944             atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05945          }
05946       } else if (!strcasecmp(var->name, "courtesytone")) {
05947          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
05948       }  else if (!strcasecmp(var->name, "parkedplay")) {
05949          if (!strcasecmp(var->value, "both")) {
05950             parkedplay = 2;
05951          } else if (!strcasecmp(var->value, "parked")) {
05952             parkedplay = 1;
05953          } else {
05954             parkedplay = 0;
05955          }
05956       } else if (!strcasecmp(var->name, "xfersound")) {
05957          ast_copy_string(xfersound, var->value, sizeof(xfersound));
05958       } else if (!strcasecmp(var->name, "xferfailsound")) {
05959          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
05960       } else if (!strcasecmp(var->name, "pickupexten")) {
05961          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
05962       } else if (!strcasecmp(var->name, "pickupsound")) {
05963          ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
05964       } else if (!strcasecmp(var->name, "pickupfailsound")) {
05965          ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
05966       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
05967          comebacktoorigin = ast_true(var->value);
05968       }
05969    }
05970 
05971    unmap_features();
05972    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
05973       if (remap_feature(var->name, var->value)) {
05974          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
05975       }
05976    }
05977 
05978    /* Map a key combination to an application */
05979    ast_unregister_features();
05980    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
05981       process_applicationmap_line(var);
05982    }
05983 
05984    ast_unregister_groups();
05985    AST_RWLIST_WRLOCK(&feature_groups);
05986 
05987    ctg = NULL;
05988    while ((ctg = ast_category_browse(cfg, ctg))) {
05989       /* Is this a parkinglot definition ? */
05990       if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
05991          ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
05992          if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) {
05993             ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
05994          } else {
05995             ast_debug(1, "Configured parking context %s\n", ctg);
05996          }
05997          continue;   
05998       }
05999 
06000       /* No, check if it's a group */
06001       for (i = 0; i < ARRAY_LEN(categories); i++) {
06002          if (!strcasecmp(categories[i], ctg)) {
06003             break;
06004          }
06005       }
06006       if (i < ARRAY_LEN(categories)) {
06007          continue;
06008       }
06009 
06010       if (!(fg = register_group(ctg))) {
06011          continue;
06012       }
06013 
06014       for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
06015          struct ast_call_feature *feature;
06016 
06017          AST_RWLIST_RDLOCK(&feature_list);
06018          if (!(feature = find_dynamic_feature(var->name)) && 
06019              !(feature = ast_find_call_feature(var->name))) {
06020             AST_RWLIST_UNLOCK(&feature_list);
06021             ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
06022             continue;
06023          }
06024          AST_RWLIST_UNLOCK(&feature_list);
06025 
06026          register_group_feature(fg, var->value, feature);
06027       }
06028    }
06029 
06030    AST_RWLIST_UNLOCK(&feature_groups);
06031 
06032    return 0;
06033 }

static const char* real_ctx ( struct ast_channel transferer,
struct ast_channel transferee 
) [static]

Find the context for the transfer.

Parameters:
transferer 
transferee Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext.
Returns:
a context string

Definition at line 2321 of file features.c.

References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, and pbx_builtin_getvar_helper().

Referenced by builtin_atxfer(), and builtin_blindtransfer().

02322 {
02323    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
02324    if (ast_strlen_zero(s)) {
02325       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
02326    }
02327    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
02328       s = transferer->macrocontext;
02329    }
02330    if (ast_strlen_zero(s)) {
02331       s = transferer->context;
02332    }
02333    return s;  
02334 }

static struct feature_group* register_group ( const char *  fgname  )  [static, read]

Add new feature group.

Parameters:
fgname feature group name.

Add new feature group to the feature group list insert at head of list.

Note:
This function MUST be called while feature_groups is locked.

Definition at line 3015 of file features.c.

References ast_calloc_with_stringfields, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_set, ast_verb, feature_group::gname, and LOG_NOTICE.

Referenced by process_config().

03016 {
03017    struct feature_group *fg;
03018 
03019    if (!fgname) {
03020       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
03021       return NULL;
03022    }
03023 
03024    if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) {
03025       return NULL;
03026    }
03027 
03028    ast_string_field_set(fg, gname, fgname);
03029 
03030    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
03031 
03032    ast_verb(2, "Registered group '%s'\n", fg->gname);
03033 
03034    return fg;
03035 }

static void register_group_feature ( struct feature_group fg,
const char *  exten,
struct ast_call_feature feature 
) [static]

Add feature to group.

Parameters:
fg feature group
exten 
feature feature to add.

Check fg and feature specified, add feature to list

Note:
This function MUST be called while feature_groups is locked.

Definition at line 3046 of file features.c.

References ast_calloc_with_stringfields, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_set, ast_verb, feature_group_exten::exten, ast_call_feature::exten, feature_group_exten::feature, feature_group::features, feature_group::gname, LOG_NOTICE, S_OR, and ast_call_feature::sname.

Referenced by process_config().

03047 {
03048    struct feature_group_exten *fge;
03049 
03050    if (!fg) {
03051       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
03052       return;
03053    }
03054 
03055    if (!feature) {
03056       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
03057       return;
03058    }
03059 
03060    if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) {
03061       return;
03062    }
03063 
03064    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
03065 
03066    fge->feature = feature;
03067 
03068    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
03069 
03070    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
03071                feature->sname, fg->gname, fge->exten);
03072 }

static int remap_feature ( const char *  name,
const char *  value 
) [static]

Definition at line 3258 of file features.c.

References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, FEATURES_COUNT, and features_lock.

Referenced by process_config().

03259 {
03260    int x, res = -1;
03261 
03262    ast_rwlock_wrlock(&features_lock);
03263    for (x = 0; x < FEATURES_COUNT; x++) {
03264       if (strcasecmp(builtin_features[x].sname, name))
03265          continue;
03266 
03267       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
03268       res = 0;
03269       break;
03270    }
03271    ast_rwlock_unlock(&features_lock);
03272 
03273    return res;
03274 }

static void remove_dead_context_usage ( const char *  context,
struct parking_dp_context old_ctx,
struct parking_dp_context new_ctx 
) [static]

Definition at line 6594 of file features.c.

References parking_dp_context::access_extens, destroy_space(), parking_dp_context::hints, remove_dead_ramp_usage(), remove_dead_spaces_usage(), and parking_dp_context::spaces.

Referenced by remove_dead_dialplan_useage().

06595 {
06596    remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens);
06597    remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space);
06598 #if 0
06599    /* I don't think we should destroy hints if the parking space still exists. */
06600    remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint);
06601 #endif
06602 }

static void remove_dead_dialplan_useage ( struct parking_dp_map old_map,
struct parking_dp_map new_map 
) [static]

Definition at line 6617 of file features.c.

References ast_context_destroy(), ast_context_find(), AST_LIST_FIRST, AST_LIST_NEXT, parking_dp_context::context, registrar, and remove_dead_context_usage().

Referenced by load_config().

06618 {
06619    struct parking_dp_context *old_ctx;
06620    struct parking_dp_context *new_ctx;
06621    struct ast_context *con;
06622    int cmp;
06623 
06624    old_ctx = AST_LIST_FIRST(old_map);
06625    new_ctx = AST_LIST_FIRST(new_map);
06626 
06627    while (new_ctx) {
06628       if (!old_ctx) {
06629          /* No old contexts left, so no dead stuff can remain. */
06630          return;
06631       }
06632       cmp = strcmp(old_ctx->context, new_ctx->context);
06633       if (cmp < 0) {
06634          /* New map does not have old map context. */
06635          con = ast_context_find(old_ctx->context);
06636          if (con) {
06637             ast_context_destroy(con, registrar);
06638          }
06639          old_ctx = AST_LIST_NEXT(old_ctx, node);
06640          continue;
06641       }
06642       if (cmp == 0) {
06643          /* Old and new map have this context. */
06644          remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx);
06645          old_ctx = AST_LIST_NEXT(old_ctx, node);
06646       } else {
06647          /* Old map does not have new map context. */
06648       }
06649       new_ctx = AST_LIST_NEXT(new_ctx, node);
06650    }
06651 
06652    /* Any old contexts left must be dead. */
06653    for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) {
06654       con = ast_context_find(old_ctx->context);
06655       if (con) {
06656          ast_context_destroy(con, registrar);
06657       }
06658    }
06659 }

static void remove_dead_ramp_usage ( const char *  context,
struct parking_dp_ramp_map old_ramps,
struct parking_dp_ramp_map new_ramps 
) [static]

Definition at line 6453 of file features.c.

References AST_LIST_FIRST, AST_LIST_NEXT, parking_dp_ramp::exten, and remove_exten_if_exist().

Referenced by remove_dead_context_usage().

06454 {
06455    struct parking_dp_ramp *old_ramp;
06456    struct parking_dp_ramp *new_ramp;
06457    int cmp;
06458 
06459    old_ramp = AST_LIST_FIRST(old_ramps);
06460    new_ramp = AST_LIST_FIRST(new_ramps);
06461 
06462    while (new_ramp) {
06463       if (!old_ramp) {
06464          /* No old ramps left, so no dead ramps can remain. */
06465          return;
06466       }
06467       cmp = strcmp(old_ramp->exten, new_ramp->exten);
06468       if (cmp < 0) {
06469          /* New map does not have old ramp. */
06470          remove_exten_if_exist(context, old_ramp->exten, 1);
06471          old_ramp = AST_LIST_NEXT(old_ramp, node);
06472          continue;
06473       }
06474       if (cmp == 0) {
06475          /* Old and new map have this ramp. */
06476          old_ramp = AST_LIST_NEXT(old_ramp, node);
06477       } else {
06478          /* Old map does not have new ramp. */
06479       }
06480       new_ramp = AST_LIST_NEXT(new_ramp, node);
06481    }
06482 
06483    /* Any old ramps left must be dead. */
06484    for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) {
06485       remove_exten_if_exist(context, old_ramp->exten, 1);
06486    }
06487 }

static void remove_dead_spaces_usage ( const char *  context,
struct parking_dp_space_map old_spaces,
struct parking_dp_space_map new_spaces,
void(*)(const char *context, int space)  destroy_space 
) [static]

< Current position in the current old range.

Definition at line 6523 of file features.c.

References AST_LIST_FIRST, AST_LIST_NEXT, destroy_space(), parking_dp_spaces::start, and parking_dp_spaces::stop.

Referenced by remove_dead_context_usage().

06526 {
06527    struct parking_dp_spaces *old_range;
06528    struct parking_dp_spaces *new_range;
06529    int space;/*!< Current position in the current old range. */
06530    int stop;
06531 
06532    old_range = AST_LIST_FIRST(old_spaces);
06533    new_range = AST_LIST_FIRST(new_spaces);
06534    space = -1;
06535 
06536    while (old_range) {
06537       if (space < old_range->start) {
06538          space = old_range->start;
06539       }
06540       if (new_range) {
06541          if (space < new_range->start) {
06542             /* Current position in old range starts before new range. */
06543             if (old_range->stop < new_range->start) {
06544                /* Old range ends before new range. */
06545                stop = old_range->stop;
06546                old_range = AST_LIST_NEXT(old_range, node);
06547             } else {
06548                /* Tail of old range overlaps new range. */
06549                stop = new_range->start - 1;
06550             }
06551          } else if (/* new_range->start <= space && */ space <= new_range->stop) {
06552             /* Current position in old range overlaps new range. */
06553             if (old_range->stop <= new_range->stop) {
06554                /* Old range ends at or before new range. */
06555                old_range = AST_LIST_NEXT(old_range, node);
06556             } else {
06557                /* Old range extends beyond end of new range. */
06558                space = new_range->stop + 1;
06559                new_range = AST_LIST_NEXT(new_range, node);
06560             }
06561             continue;
06562          } else /* if (new_range->stop < space) */ {
06563             /* Current position in old range starts after new range. */
06564             new_range = AST_LIST_NEXT(new_range, node);
06565             continue;
06566          }
06567       } else {
06568          /* No more new ranges.  All remaining old spaces are dead. */
06569          stop = old_range->stop;
06570          old_range = AST_LIST_NEXT(old_range, node);
06571       }
06572 
06573       /* Destroy dead parking spaces. */
06574       for (; space <= stop; ++space) {
06575          destroy_space(context, space);
06576       }
06577    }
06578 }

static void remove_exten_if_exist ( const char *  context,
const char *  exten,
int  priority 
) [static]

Definition at line 6427 of file features.c.

References ast_context_remove_extension(), ast_debug, E_MATCH, pbx_find_extension(), registrar, and pbx_find_info::stacklen.

Referenced by destroy_space(), and remove_dead_ramp_usage().

06428 {
06429    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
06430 
06431    if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL,
06432       E_MATCH)) {
06433       ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n",
06434          context, exten, priority);
06435       ast_context_remove_extension(context, exten, priority, registrar);
06436    }
06437 }

static void set_bridge_features_on_config ( struct ast_bridge_config config,
const char *  features 
) [static]

Definition at line 3865 of file features.c.

References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), ast_bridge_config::features_caller, and LOG_WARNING.

Referenced by ast_bridge_call().

03866 {
03867    const char *feature;
03868 
03869    if (ast_strlen_zero(features)) {
03870       return;
03871    }
03872 
03873    for (feature = features; *feature; feature++) {
03874       switch (*feature) {
03875       case 'T' :
03876       case 't' :
03877          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
03878          break;
03879       case 'K' :
03880       case 'k' :
03881          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
03882          break;
03883       case 'H' :
03884       case 'h' :
03885          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
03886          break;
03887       case 'W' :
03888       case 'w' :
03889          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
03890          break;
03891       default :
03892          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
03893       }
03894    }
03895 }

static void set_c_e_p ( struct ast_channel chan,
const char *  context,
const char *  ext,
int  pri 
) [static]

store context, extension and priority

Parameters:
chan,context,ext,pri 

Definition at line 881 of file features.c.

References ast_copy_string(), ast_channel::context, ast_channel::exten, and ast_channel::priority.

Referenced by builtin_blindtransfer(), manage_parked_call(), and masq_park_call().

00882 {
00883    ast_copy_string(chan->context, context, sizeof(chan->context));
00884    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00885    chan->priority = pri;
00886 }

static int set_chan_app_data ( struct ast_channel chan,
const char *  src_app_data 
) [static]

Definition at line 957 of file features.c.

References ast_channel_datastore_add(), ast_datastore_alloc, ast_datastore_free(), ast_malloc, channel_app_data_datastore, ast_datastore::data, and ast_channel::data.

Referenced by bridge_call_thread().

00958 {
00959    struct ast_datastore *datastore;
00960    char *dst_app_data;
00961 
00962    datastore = ast_datastore_alloc(&channel_app_data_datastore, NULL);
00963    if (!datastore) {
00964       return -1;
00965    }
00966 
00967    dst_app_data = ast_malloc(strlen(src_app_data) + 1);
00968    if (!dst_app_data) {
00969       ast_datastore_free(datastore);
00970       return -1;
00971    }
00972 
00973    chan->data = strcpy(dst_app_data, src_app_data);
00974    datastore->data = dst_app_data;
00975    ast_channel_datastore_add(chan, datastore);
00976    return 0;
00977 }

static void set_config_flags ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config 
) [static]

Definition at line 3449 of file features.c.

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_set_flag, ast_strdupa, ast_test_flag, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, features_lock, find_dynamic_feature(), and pbx_builtin_getvar_helper().

Referenced by ast_bridge_call().

03450 {
03451    int x;
03452 
03453    ast_clear_flag(config, AST_FLAGS_ALL);
03454 
03455    ast_rwlock_rdlock(&features_lock);
03456    for (x = 0; x < FEATURES_COUNT; x++) {
03457       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
03458          continue;
03459 
03460       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
03461          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03462 
03463       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
03464          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03465    }
03466    ast_rwlock_unlock(&features_lock);
03467 
03468    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
03469       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
03470 
03471       if (dynamic_features) {
03472          char *tmp = ast_strdupa(dynamic_features);
03473          char *tok;
03474          struct ast_call_feature *feature;
03475 
03476          /* while we have a feature */
03477          while ((tok = strsep(&tmp, "#"))) {
03478             struct feature_group *fg;
03479 
03480             AST_RWLIST_RDLOCK(&feature_groups);
03481             AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
03482                struct feature_group_exten *fge;
03483 
03484                AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03485                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
03486                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03487                   }
03488                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
03489                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03490                   }
03491                }
03492             }
03493             AST_RWLIST_UNLOCK(&feature_groups);
03494 
03495             AST_RWLIST_RDLOCK(&feature_list);
03496             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
03497                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
03498                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03499                }
03500                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
03501                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03502                }
03503             }
03504             AST_RWLIST_UNLOCK(&feature_list);
03505          }
03506       }
03507    }
03508 }

static void set_peers ( struct ast_channel **  caller,
struct ast_channel **  callee,
struct ast_channel peer,
struct ast_channel chan,
int  sense 
) [static]

set caller and callee according to the direction

Parameters:
caller,callee,peer,chan,sense Detect who triggered feature and set callee/caller variables accordingly

Definition at line 1951 of file features.c.

References FEATURE_SENSE_PEER.

Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().

01953 {
01954    if (sense == FEATURE_SENSE_PEER) {
01955       *caller = peer;
01956       *callee = chan;
01957    } else {
01958       *callee = peer;
01959       *caller = chan;
01960    }
01961 }

static void unmap_features ( void   )  [static]

Definition at line 3248 of file features.c.

References ast_rwlock_unlock, ast_rwlock_wrlock, FEATURES_COUNT, and features_lock.

Referenced by process_config().

03249 {
03250    int x;
03251 
03252    ast_rwlock_wrlock(&features_lock);
03253    for (x = 0; x < FEATURES_COUNT; x++)
03254       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
03255    ast_rwlock_unlock(&features_lock);
03256 }

static int usage_context_add_ramp ( struct parking_dp_ramp_map ramp_map,
const char *  exten,
int  exclusive,
struct ast_parkinglot lot,
int  complain 
) [static]

Definition at line 6113 of file features.c.

References AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), build_dialplan_useage_ramp(), ast_parkinglot::cfg, parking_dp_ramp::exclusive, parking_dp_ramp::exten, LOG_WARNING, ast_parkinglot::name, and parkinglot_cfg::parking_con.

Referenced by dialplan_usage_add_parkinglot_data().

06114 {
06115    struct parking_dp_ramp *cur_ramp;
06116    struct parking_dp_ramp *new_ramp;
06117    int cmp;
06118 
06119    /* Make sure that exclusive is only 0 or 1 */
06120    if (exclusive) {
06121       exclusive = 1;
06122    }
06123 
06124    AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) {
06125       cmp = strcmp(exten, cur_ramp->exten);
06126       if (cmp > 0) {
06127          /* The parking lot ramp goes after this node. */
06128          continue;
06129       }
06130       if (cmp == 0) {
06131          /* The ramp is already in the map. */
06132          if (complain && (cur_ramp->exclusive || exclusive)) {
06133             ast_log(LOG_WARNING,
06134                "Parking lot '%s' parkext %s@%s used by another parking lot.\n",
06135                lot->name, exten, lot->cfg.parking_con);
06136          }
06137          return 0;
06138       }
06139       /* The new parking lot ramp goes before this node. */
06140       new_ramp = build_dialplan_useage_ramp(exten, exclusive);
06141       if (!new_ramp) {
06142          return -1;
06143       }
06144       AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node);
06145       return 0;
06146    }
06147    AST_LIST_TRAVERSE_SAFE_END;
06148 
06149    /* New parking lot access ramp goes on the end. */
06150    new_ramp = build_dialplan_useage_ramp(exten, exclusive);
06151    if (!new_ramp) {
06152       return -1;
06153    }
06154    AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node);
06155    return 0;
06156 }

static int usage_context_add_spaces ( struct parking_dp_space_map space_map,
int  start,
int  stop,
struct ast_parkinglot lot,
int  complain 
) [static]

Definition at line 6194 of file features.c.

References ast_free, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), build_dialplan_useage_spaces(), ast_parkinglot::cfg, LOG_WARNING, ast_parkinglot::name, parkinglot_cfg::parking_con, parking_dp_spaces::start, and parking_dp_spaces::stop.

Referenced by dialplan_usage_add_parkinglot_data().

06195 {
06196    struct parking_dp_spaces *cur_node;
06197    struct parking_dp_spaces *expand_node;
06198    struct parking_dp_spaces *new_node;
06199 
06200    expand_node = NULL;
06201    AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) {
06202       /* NOTE: stop + 1 to combine immediately adjacent nodes into one. */
06203       if (expand_node) {
06204          /* The previous node is expanding to possibly eat following nodes. */
06205          if (expand_node->stop + 1 < cur_node->start) {
06206             /* Current node is completely after expanding node. */
06207             return 0;
06208          }
06209 
06210          if (complain
06211             && ((cur_node->start <= start && start <= cur_node->stop)
06212                || (cur_node->start <= stop && stop <= cur_node->stop)
06213                || (start < cur_node->start && cur_node->stop < stop))) {
06214             /* Only complain once per range add. */
06215             complain = 0;
06216             ast_log(LOG_WARNING,
06217                "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06218                lot->name, start, stop, lot->cfg.parking_con);
06219          }
06220 
06221          /* Current node is eaten by the expanding node. */
06222          if (expand_node->stop < cur_node->stop) {
06223             expand_node->stop = cur_node->stop;
06224          }
06225          AST_LIST_REMOVE_CURRENT(node);
06226          ast_free(cur_node);
06227          continue;
06228       }
06229 
06230       if (cur_node->stop + 1 < start) {
06231          /* New range is completely after current node. */
06232          continue;
06233       }
06234       if (stop + 1 < cur_node->start) {
06235          /* New range is completely before current node. */
06236          new_node = build_dialplan_useage_spaces(start, stop);
06237          if (!new_node) {
06238             return -1;
06239          }
06240          AST_LIST_INSERT_BEFORE_CURRENT(new_node, node);
06241          return 0;
06242       }
06243 
06244       if (complain
06245          && ((cur_node->start <= start && start <= cur_node->stop)
06246             || (cur_node->start <= stop && stop <= cur_node->stop)
06247             || (start < cur_node->start && cur_node->stop < stop))) {
06248          /* Only complain once per range add. */
06249          complain = 0;
06250          ast_log(LOG_WARNING,
06251             "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06252             lot->name, start, stop, lot->cfg.parking_con);
06253       }
06254 
06255       /* Current node range overlaps or is immediately adjacent to new range. */
06256       if (start < cur_node->start) {
06257          /* Expand the current node in the front. */
06258          cur_node->start = start;
06259       }
06260       if (stop <= cur_node->stop) {
06261          /* Current node is not expanding in the rear. */
06262          return 0;
06263       }
06264       cur_node->stop = stop;
06265       expand_node = cur_node;
06266    }
06267    AST_LIST_TRAVERSE_SAFE_END;
06268 
06269    if (expand_node) {
06270       /*
06271        * The previous node expanded and either ate all following nodes
06272        * or it was the last node.
06273        */
06274       return 0;
06275    }
06276 
06277    /* New range goes on the end. */
06278    new_node = build_dialplan_useage_spaces(start, stop);
06279    if (!new_node) {
06280       return -1;
06281    }
06282    AST_LIST_INSERT_TAIL(space_map, new_node, node);
06283    return 0;
06284 }

static int xfer_park_call_helper ( struct ast_channel park_me,
struct ast_channel parker,
struct ast_exten park_exten 
) [static]

Definition at line 1891 of file features.c.

References AST_FEATURE_RETURN_SUCCESS, ast_get_extension_app_data(), AST_PARK_OPT_SILENCE, AST_STANDARD_APP_ARGS, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, create_dynamic_parkinglot(), default_parkinglot, find_parkinglot(), findparkinglotname(), finishup(), masq_park_call(), parkeddynamic, ast_park_call_args::parkinglot, parkinglot_addref(), parkinglot_unref(), parse(), and park_app_args::pl_name.

Referenced by builtin_atxfer(), and builtin_blindtransfer().

01892 {
01893    char *parse;
01894    const char *app_data;
01895    const char *pl_name;
01896    struct ast_park_call_args args = { 0, };
01897    struct park_app_args app_args;
01898    int res;
01899 
01900    app_data = ast_get_extension_app_data(park_exten);
01901    if (!app_data) {
01902       app_data = "";
01903    }
01904    parse = ast_strdupa(app_data);
01905    AST_STANDARD_APP_ARGS(app_args, parse);
01906 
01907    /* Find the parking lot */
01908    if (!ast_strlen_zero(app_args.pl_name)) {
01909       pl_name = app_args.pl_name;
01910    } else {
01911       pl_name = findparkinglotname(parker);
01912    }
01913    if (ast_strlen_zero(pl_name)) {
01914       /* Parking lot is not specified, so use the default parking lot. */
01915       args.parkinglot = parkinglot_addref(default_parkinglot);
01916    } else {
01917       args.parkinglot = find_parkinglot(pl_name);
01918       if (!args.parkinglot && parkeddynamic) {
01919          args.parkinglot = create_dynamic_parkinglot(pl_name, park_me);
01920       }
01921    }
01922 
01923    if (args.parkinglot) {
01924       /* Park the call */
01925       res = finishup(park_me);
01926       if (res) {
01927          /* park_me hungup on us. */
01928          parkinglot_unref(args.parkinglot);
01929          return -1;
01930       }
01931       res = masq_park_call(park_me, parker, &args);
01932       parkinglot_unref(args.parkinglot);
01933    } else {
01934       /* Parking failed because parking lot does not exist. */
01935       if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
01936          ast_stream_and_wait(parker, "pbx-parkingfailed", "");
01937       }
01938       finishup(park_me);
01939       res = -1;
01940    }
01941 
01942    return res ? AST_FEATURE_RETURN_SUCCESS : -1;
01943 }


Variable Documentation

int adsipark [static]

Definition at line 612 of file features.c.

Referenced by park_call_full(), and process_config().

char* app_bridge = "Bridge" [static]

Definition at line 7493 of file features.c.

unsigned int atxfercallbackretries [static]

Definition at line 621 of file features.c.

Referenced by builtin_atxfer(), and process_config().

unsigned int atxferdropcall [static]

Definition at line 619 of file features.c.

Referenced by builtin_atxfer(), and process_config().

unsigned int atxferloopdelay [static]

Definition at line 620 of file features.c.

Referenced by builtin_atxfer(), and process_config().

int atxfernoanswertimeout [static]

Definition at line 618 of file features.c.

Referenced by builtin_atxfer(), and process_config().

struct ast_app_option bridge_exec_options[128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, } [static]

Definition at line 7530 of file features.c.

Referenced by bridge_exec().

Definition at line 2981 of file features.c.

Initial value:
 {
   .type = "Channel appdata datastore",
   .destroy = ast_free_ptr,
}

Definition at line 952 of file features.c.

Referenced by set_chan_app_data().

struct ast_cli_entry cli_features[] [static]
Initial value:
 {
   AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
   AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
   AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
}

Definition at line 7165 of file features.c.

int comebacktoorigin = 1 [static]

Definition at line 616 of file features.c.

Referenced by manage_parked_call(), and process_config().

char courtesytone[256] [static]

Courtesy tone used to pickup parked calls and on-touch-record

Definition at line 589 of file features.c.

Referenced by builtin_automixmonitor(), builtin_automonitor(), parked_call_exec(), and process_config().

Default parking lot.

Note:
Holds a parkinglot reference.
Will not be NULL while running.

Definition at line 582 of file features.c.

Referenced by create_dynamic_parkinglot(), handle_parkedcalls(), load_config(), park_call_exec(), park_space_reserve(), parked_call_exec(), and xfer_park_call_helper().

Initial value:
 {
   .type = "dial-features",
   .destroy = dial_features_destroy,
   .duplicate = dial_features_duplicate,
}

Definition at line 752 of file features.c.

Referenced by add_features_datastore(), builtin_atxfer(), manage_parked_call(), and parked_call_exec().

int featuredigittimeout [static]

Definition at line 615 of file features.c.

Referenced by ast_bridge_call(), and process_config().

ast_rwlock_t features_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } [static]
ast_mutex_t features_reload_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]

Ensure that features.conf reloads on one thread at a time.

Definition at line 610 of file features.c.

Referenced by ast_features_reload().

int force_reload_load [static]

Force a config reload to reload regardless of config file timestamp.

Definition at line 585 of file features.c.

Referenced by build_parkinglot(), load_config(), parkinglot_activate_cb(), and parkinglot_is_marked_cb().

struct ast_app* mixmonitor_app = NULL [static]

Definition at line 642 of file features.c.

Referenced by builtin_automixmonitor().

int mixmonitor_ok = 1 [static]

Definition at line 643 of file features.c.

Referenced by builtin_automixmonitor().

struct ast_app* monitor_app = NULL [static]

Definition at line 639 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 640 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

struct ast_app_option park_call_options[128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } [static]

Definition at line 5060 of file features.c.

Referenced by park_call_exec().

const char* parkcall = "Park" [static]
const char* parkedcall = "ParkedCall" [static]

Definition at line 419 of file features.c.

int parkeddynamic = 0 [static]

Enable creation of parkinglots dynamically

Definition at line 588 of file features.c.

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

int parkedplay = 0 [static]

Who to play courtesytone to when someone picks up a parked call.

Definition at line 587 of file features.c.

Referenced by parked_call_exec(), and process_config().

char parking_con_dial[] = "park-dial" [static]

Context for parking dialback to parker.

Note:
The need for the context is a KLUDGE.
Todo:
Might be able to eliminate the parking_con_dial context kludge by running app_dial directly in its own thread to simulate a PBX.

Definition at line 607 of file features.c.

Referenced by ast_features_reload(), and manage_parked_call().

pthread_t parking_thread [static]

Definition at line 648 of file features.c.

Referenced by ast_features_init(), features_shutdown(), and park_call_full().

Initial value:
 {
   .parkext = DEFAULT_PARK_EXTENSION,
   .parkingtime = DEFAULT_PARK_TIME,
}

Default configuration for normal parking lots.

Definition at line 5508 of file features.c.

Default configuration for default parking lot.

Definition at line 5498 of file features.c.

struct ao2_container* parkinglots [static]
char parkingretalertinfo[256] [static]

Distinctive ring if chantech = SIP (adds a SIP AlertInfo header)

Definition at line 597 of file features.c.

Referenced by manage_parked_call(), and parkinglot_config_read().

char parkingretcidname[256] [static]

Callerid name of returned parked call

Definition at line 595 of file features.c.

Referenced by manage_parked_call(), and parkinglot_config_read().

char parkingretdahdiring[3] [static]

Distinctive ring if chantech = DAHDI

Definition at line 596 of file features.c.

Referenced by manage_parked_call(), and parkinglot_config_read().

Initial value:
 {
   .type = "pickup-active",
}

The presence of this datastore on the channel indicates that someone is attemting to pickup or has picked up the channel. The purpose is to prevent a race between two channels attempting to pickup the same channel.

Definition at line 7334 of file features.c.

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 421 of file features.c.

Referenced by analog_canmatch_featurecode(), and canmatch_featurecode().

char pickupfailsound[256] [static]

Pickup failure sound

Definition at line 593 of file features.c.

Referenced by ast_pickup_call(), and process_config().

char pickupsound[256] [static]

Pickup sound

Definition at line 592 of file features.c.

Referenced by ast_pickup_call(), and process_config().

char* registrar = "features" [static]
struct ast_app* stopmixmonitor_app = NULL [static]

Definition at line 645 of file features.c.

Referenced by builtin_automixmonitor().

int stopmixmonitor_ok = 1 [static]

Definition at line 646 of file features.c.

Referenced by builtin_automixmonitor().

int transferdigittimeout [static]

Definition at line 614 of file features.c.

Referenced by builtin_atxfer(), builtin_blindtransfer(), and process_config().

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 591 of file features.c.

Referenced by builtin_atxfer(), and process_config().

char xfersound[256] [static]

Call transfer sound

Definition at line 590 of file features.c.

Referenced by action_bridge(), bridge_exec(), builtin_atxfer(), local_attended_transfer(), and process_config().


Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1