Mon Oct 8 12:39:22 2012

Asterisk developer's documentation


features.c File Reference

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

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

Go to the source code of this file.

Data Structures

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

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_ATXFER_CALLBACK_RETRIES   2
#define DEFAULT_ATXFER_DROP_CALL   0
#define DEFAULT_ATXFER_LOOP_DELAY   10000
#define DEFAULT_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 a call, optionally allowing redirection.
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.
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_set
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 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 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)

Definition at line 2950 of file features.c.

Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().

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

Referenced by handle_feature_show().

#define MAX_DIAL_FEATURE_OPTIONS   30

Definition at line 393 of file features.c.

Referenced by manage_parked_call().


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

07407      {
07408    BRIDGE_OPT_PLAYTONE = (1 << 0),
07409    OPT_CALLEE_HANGUP =  (1 << 1),
07410    OPT_CALLER_HANGUP =  (1 << 2),
07411    OPT_DURATION_LIMIT = (1 << 3),
07412    OPT_DURATION_STOP =  (1 << 4),
07413    OPT_CALLEE_TRANSFER = (1 << 5),
07414    OPT_CALLER_TRANSFER = (1 << 6),
07415    OPT_CALLEE_MONITOR = (1 << 7),
07416    OPT_CALLER_MONITOR = (1 << 8),
07417    OPT_CALLEE_PARK = (1 << 9),
07418    OPT_CALLER_PARK = (1 << 10),
07419    OPT_CALLEE_KILL = (1 << 11),
07420 };

anonymous enum

Enumerator:
OPT_ARG_DURATION_LIMIT 
OPT_ARG_DURATION_STOP 
OPT_ARG_ARRAY_SIZE 

Definition at line 7422 of file features.c.

07422      {
07423    OPT_ARG_DURATION_LIMIT = 0,
07424    OPT_ARG_DURATION_STOP,
07425    /* note: this entry _MUST_ be the last one in the enum */
07426    OPT_ARG_ARRAY_SIZE,
07427 };

enum ast_park_call_options

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

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

enum feature_interpret_op

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 6887 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(), do_bridge_masquerade(), errno, EVENT_FLAG_CALL, LOG_WARNING, ast_channel::name, playtone(), and xfersound.

Referenced by ast_features_init().

06888 {
06889    const char *channela = astman_get_header(m, "Channel1");
06890    const char *channelb = astman_get_header(m, "Channel2");
06891    const char *playtone = astman_get_header(m, "Tone");
06892    struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
06893    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
06894    struct ast_bridge_thread_obj *tobj = NULL;
06895    char buf[256];
06896 
06897    /* make sure valid channels were specified */
06898    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
06899       astman_send_error(s, m, "Missing channel parameter in request");
06900       return 0;
06901    }
06902 
06903    /* Start with chana */
06904    chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
06905    if (!chana) {
06906       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
06907       astman_send_error(s, m, buf);
06908       return 0;
06909    }
06910 
06911    /* Answer the channels if needed */
06912    if (chana->_state != AST_STATE_UP)
06913       ast_answer(chana);
06914 
06915    /* create the placeholder channels and grab the other channels */
06916    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
06917       NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
06918       astman_send_error(s, m, "Unable to create temporary channel!");
06919       chana = ast_channel_unref(chana);
06920       return 0;
06921    }
06922 
06923    if (do_bridge_masquerade(chana, tmpchana)) {
06924       snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela);
06925       astman_send_error(s, m, buf);
06926       ast_hangup(tmpchana);
06927       chana = ast_channel_unref(chana);
06928       return 0;
06929    }
06930 
06931    chana = ast_channel_unref(chana);
06932 
06933    /* now do chanb */
06934    chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
06935    if (!chanb) {
06936       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
06937       astman_send_error(s, m, buf);
06938       ast_hangup(tmpchana);
06939       return 0;
06940    }
06941 
06942    /* Answer the channels if needed */
06943    if (chanb->_state != AST_STATE_UP)
06944       ast_answer(chanb);
06945 
06946    /* create the placeholder channels and grab the other channels */
06947    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
06948       NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
06949       astman_send_error(s, m, "Unable to create temporary channels!");
06950       ast_hangup(tmpchana);
06951       chanb = ast_channel_unref(chanb);
06952       return 0;
06953    }
06954 
06955    if (do_bridge_masquerade(chanb, tmpchanb)) {
06956       snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb);
06957       astman_send_error(s, m, buf);
06958       ast_hangup(tmpchana);
06959       ast_hangup(tmpchanb);
06960       chanb = ast_channel_unref(chanb);
06961       return 0;
06962    }
06963 
06964    chanb = ast_channel_unref(chanb);
06965 
06966    /* make the channels compatible, send error if we fail doing so */
06967    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
06968       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
06969       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
06970       ast_hangup(tmpchana);
06971       ast_hangup(tmpchanb);
06972       return 0;
06973    }
06974 
06975    /* setup the bridge thread object and start the bridge */
06976    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
06977       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
06978       astman_send_error(s, m, "Unable to spawn a new bridge thread");
06979       ast_hangup(tmpchana);
06980       ast_hangup(tmpchanb);
06981       return 0;
06982    }
06983 
06984    tobj->chan = tmpchana;
06985    tobj->peer = tmpchanb;
06986    tobj->return_to_pbx = 1;
06987 
06988    if (ast_true(playtone)) {
06989       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
06990          if (ast_waitstream(tmpchanb, "") < 0)
06991             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
06992       }
06993    }
06994 
06995    chans[0] = tmpchana;
06996    chans[1] = tmpchanb;
06997 
06998    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
06999             "Response: Success\r\n"
07000             "Channel1: %s\r\n"
07001             "Channel2: %s\r\n", tmpchana->name, tmpchanb->name);
07002 
07003    bridge_call_thread_launch(tobj);
07004 
07005    astman_send_ack(s, m, "Launched bridge thread with success");
07006 
07007    return 0;
07008 }

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

Definition at line 764 of file features.c.

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

Referenced by add_features_datastores(), and builtin_atxfer().

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

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

Definition at line 3864 of file features.c.

References add_features_datastore(), and config.

Referenced by ast_bridge_call().

03865 {
03866    if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) {
03867       /*
03868        * If we don't return here, then when we do a builtin_atxfer we
03869        * will copy the disconnect flags over from the atxfer to the
03870        * callee (Party C).
03871        */
03872       return;
03873    }
03874 
03875    add_features_datastore(callee, &config->features_callee, &config->features_caller);
03876 }

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

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

Referenced by park_call_full().

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

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

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

References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_cdr::answer, 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_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(), config, ast_channel::context, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_party_caller::id, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, monitor_app, monitor_ok, ast_channel::name, 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, S_COR, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_party_number::str, 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(), and parked_call_exec().

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

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 7444 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, config, LOG_WARNING, pbx_builtin_getvar_helper(), S_OR, strsep(), and var.

Referenced by bridge_exec(), and dial_exec_full().

07446 {
07447    char *stringp = ast_strdupa(parse);
07448    char *limit_str, *warning_str, *warnfreq_str;
07449    const char *var;
07450    int play_to_caller = 0, play_to_callee = 0;
07451    int delta;
07452 
07453    limit_str = strsep(&stringp, ":");
07454    warning_str = strsep(&stringp, ":");
07455    warnfreq_str = strsep(&stringp, ":");
07456 
07457    config->timelimit = atol(limit_str);
07458    if (warning_str)
07459       config->play_warning = atol(warning_str);
07460    if (warnfreq_str)
07461       config->warning_freq = atol(warnfreq_str);
07462 
07463    if (!config->timelimit) {
07464       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07465       config->timelimit = config->play_warning = config->warning_freq = 0;
07466       config->warning_sound = NULL;
07467       return -1; /* error */
07468    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07469       int w = config->warning_freq;
07470 
07471       /*
07472        * If the first warning is requested _after_ the entire call
07473        * would end, and no warning frequency is requested, then turn
07474        * off the warning. If a warning frequency is requested, reduce
07475        * the 'first warning' time by that frequency until it falls
07476        * within the call's total time limit.
07477        *
07478        * Graphically:
07479        *                timelim->|    delta        |<-playwarning
07480        *      0__________________|_________________|
07481        *                       | w  |    |    |    |
07482        *
07483        * so the number of intervals to cut is 1+(delta-1)/w
07484        */
07485       if (w == 0) {
07486          config->play_warning = 0;
07487       } else {
07488          config->play_warning -= w * ( 1 + (delta-1)/w );
07489          if (config->play_warning < 1)
07490             config->play_warning = config->warning_freq = 0;
07491       }
07492    }
07493    
07494    ast_channel_lock(chan);
07495 
07496    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07497    play_to_caller = var ? ast_true(var) : 1;
07498 
07499    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07500    play_to_callee = var ? ast_true(var) : 0;
07501 
07502    if (!play_to_caller && !play_to_callee)
07503       play_to_caller = 1;
07504 
07505    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07506    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07507 
07508    /* The code looking at config wants a NULL, not just "", to decide
07509     * that the message should not be played, so we replace "" with NULL.
07510     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
07511     * not found.
07512     */
07513 
07514    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07515    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07516 
07517    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07518    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07519 
07520    ast_channel_unlock(chan);
07521 
07522    /* undo effect of S(x) in case they are both used */
07523    calldurationlimit->tv_sec = 0;
07524    calldurationlimit->tv_usec = 0;
07525 
07526    /* more efficient to do it like S(x) does since no advanced opts */
07527    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07528       calldurationlimit->tv_sec = config->timelimit / 1000;
07529       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07530       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07531          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07532       config->timelimit = play_to_caller = play_to_callee =
07533       config->play_warning = config->warning_freq = 0;
07534    } else {
07535       ast_verb(4, "Limit Data for this call:\n");
07536       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07537       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07538       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07539       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07540       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07541       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
07542       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
07543       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
07544    }
07545    if (play_to_caller)
07546       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07547    if (play_to_callee)
07548       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07549    return 0;
07550 }

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 7250 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, ast_channel::pbx, and pickup_active.

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

07251 {
07252    if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07253       && (chan->_state == AST_STATE_RINGING
07254          || chan->_state == AST_STATE_RING
07255          /*
07256           * Check the down state as well because some SIP devices do not
07257           * give 180 ringing when they can just give 183 session progress
07258           * instead.  Issue 14005.  (Some ISDN switches as well for that
07259           * matter.)
07260           */
07261          || chan->_state == AST_STATE_DOWN)
07262       && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07263       return 1;
07264    }
07265    return 0;
07266 }

void ast_channel_log ( char *  title,
struct ast_channel chan 
)

Definition at line 3799 of file features.c.

References ast_log(), and LOG_NOTICE.

Referenced by ast_bridge_call().

03800 {
03801        ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
03802        ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
03803                        chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
03804        ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
03805                        chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
03806        ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
03807                        chan->masq, chan->masqr,
03808                        chan->_bridge, chan->uniqueid, chan->linkedid);
03809        if (chan->masqr)
03810                ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
03811                                chan->masqr->name, chan->masqr->cdr);
03812        if (chan->_bridge)
03813                ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
03814 
03815    ast_log(LOG_NOTICE, "===== done ====\n");
03816 }

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 7326 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, EVENT_FLAG_CALL, LOG_WARNING, ast_channel::name, pickup_active, 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().

07327 {
07328    struct ast_party_connected_line connected_caller;
07329    struct ast_channel *chans[2] = { chan, target };
07330    struct ast_datastore *ds_pickup;
07331    const char *chan_name;/*!< A masquerade changes channel names. */
07332    const char *target_name;/*!< A masquerade changes channel names. */
07333    int res = -1;
07334 
07335    target_name = ast_strdupa(target->name);
07336    ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name);
07337 
07338    /* Mark the target to block any call pickup race. */
07339    ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07340    if (!ds_pickup) {
07341       ast_log(LOG_WARNING,
07342          "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07343       return -1;
07344    }
07345    ast_channel_datastore_add(target, ds_pickup);
07346 
07347    ast_party_connected_line_init(&connected_caller);
07348    ast_party_connected_line_copy(&connected_caller, &target->connected);
07349    ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
07350    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07351    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07352       ast_channel_update_connected_line(chan, &connected_caller, NULL);
07353    }
07354    ast_party_connected_line_free(&connected_caller);
07355 
07356    ast_channel_lock(chan);
07357    chan_name = ast_strdupa(chan->name);
07358    ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07359    ast_channel_unlock(chan);
07360    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07361 
07362    ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07363 
07364    if (ast_answer(chan)) {
07365       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07366       goto pickup_failed;
07367    }
07368 
07369    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07370       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07371       goto pickup_failed;
07372    }
07373    
07374    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07375 
07376    /* setting this flag to generate a reason header in the cancel message to the ringing channel */
07377    ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07378 
07379    if (ast_channel_masquerade(target, chan)) {
07380       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07381          target_name);
07382       goto pickup_failed;
07383    }
07384 
07385    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
07386    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07387       "Channel: %s\r\n"
07388       "TargetChannel: %s\r\n",
07389       chan_name, target_name);
07390 
07391    /* Do the masquerade manually to make sure that it is completed. */
07392    ast_do_masquerade(target);
07393    res = 0;
07394 
07395 pickup_failed:
07396    ast_channel_lock(target);
07397    if (!ast_channel_datastore_remove(target, ds_pickup)) {
07398       ast_datastore_free(ds_pickup);
07399    }
07400    ast_party_connected_line_free(&connected_caller);
07401 
07402    return res;
07403 }

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

References feature_group_exten::feature, FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

03401                                                                                                                                  {
03402 
03403    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03404 }

int ast_features_init ( void   ) 

Provided by features.c

Definition at line 8224 of file features.c.

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

Referenced by main().

08225 {
08226    int res;
08227 
08228    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
08229    if (!parkinglots) {
08230       return -1;
08231    }
08232 
08233    res = load_config(0);
08234    if (res) {
08235       return res;
08236    }
08237    ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
08238    if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) {
08239       return -1;
08240    }
08241    ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
08242    res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL);
08243    if (!res)
08244       res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
08245    if (!res) {
08246       ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
08247       ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
08248       ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
08249    }
08250 
08251    res |= ast_devstate_prov_add("Park", metermaidstate);
08252 #if defined(TEST_FRAMEWORK)
08253    res |= AST_TEST_REGISTER(features_test);
08254 #endif   /* defined(TEST_FRAMEWORK) */
08255 
08256    return res;
08257 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 6791 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().

06792 {
06793    struct ast_context *con;
06794    int res;
06795 
06796    ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
06797 
06798    /*
06799     * Always destroy the parking_con_dial context to remove buildup
06800     * of recalled extensions in the context.  At worst, the parked
06801     * call gets hungup attempting to run an invalid extension when
06802     * we are trying to callback the parker or the preset return
06803     * extension.  This is a small window of opportunity on an
06804     * execution chain that is not expected to happen very often.
06805     */
06806    con = ast_context_find(parking_con_dial);
06807    if (con) {
06808       ast_context_destroy(con, registrar);
06809    }
06810 
06811    res = load_config(1);
06812    ast_mutex_unlock(&features_reload_lock);
06813 
06814    return res;
06815 }

struct ast_call_feature* ast_find_call_feature ( const char *  name  ) 

look for a call feature entry by its sname

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

Definition at line 3133 of file features.c.

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

03134 {
03135    int x;
03136    for (x = 0; x < FEATURES_COUNT; x++) {
03137       if (!strcasecmp(name, builtin_features[x].sname))
03138          return &builtin_features[x];
03139    }
03140    return NULL;
03141 }

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

References args, ast_strdupa, masq_park_call(), and ast_channel::name.

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

01846 {
01847    struct ast_park_call_args args = {
01848       .timeout = timeout,
01849       .extout = extout,
01850    };
01851 
01852    if (peer) {
01853       args.orig_chan_name = ast_strdupa(peer->name);
01854    }
01855    return masq_park_call(rchan, peer, &args);
01856 }

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

References args, ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), feature_group_exten::exten, find_parkinglot(), get_parking_exten(), masq_park_call(), ast_channel::name, parkeddynamic, parkinglot_unref(), parse(), and park_app_args::pl_name.

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

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

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

References args, and park_call_full().

01695 {
01696    struct ast_park_call_args args = {
01697       .timeout = timeout,
01698       .extout = extout,
01699    };
01700 
01701    return park_call_full(park_me, parker, &args);
01702 }

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

References args, ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), feature_group_exten::exten, find_parkinglot(), get_parking_exten(), park_call_full(), parkeddynamic, parkinglot_unref(), parse(), and park_app_args::pl_name.

Referenced by iax_park_thread(), and sip_park_thread().

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

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

References get_parking_exten().

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

00841 {
00842    return get_parking_exten(exten_str, chan, context) ? 1 : 0;
00843 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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 7292 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, ast_channel::name, pbx_builtin_setvar_helper(), pickupfailsound, and pickupsound.

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

07293 {
07294    struct ast_channel *target;/*!< Potential pickup target */
07295    int res = -1;
07296    ast_debug(1, "pickup attempt by %s\n", chan->name);
07297 
07298    /* The found channel is already locked. */
07299    target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07300    if (target) {
07301       ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
07302 
07303       res = ast_do_pickup(chan, target);
07304       ast_channel_unlock(target);
07305       if (!res) {
07306          if (!ast_strlen_zero(pickupsound)) {
07307             pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07308          }
07309       } else {
07310          ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name);
07311       }
07312       target = ast_channel_unref(target);
07313    }
07314 
07315    if (res < 0) {
07316       ast_debug(1, "No call pickup possible... for %s\n", chan->name);
07317       if (!ast_strlen_zero(pickupfailsound)) {
07318          ast_answer(chan);
07319          ast_stream_and_wait(chan, pickupfailsound, "");
07320       }
07321    }
07322 
07323    return res;
07324 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 845 of file features.c.

Referenced by __analog_ss_thread(), analog_canmatch_featurecode(), analog_ss_thread(), canmatch_featurecode(), cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), and mgcp_ss().

00846 {
00847    return pickup_ext;
00848 }

void ast_rdlock_call_features ( void   ) 

Definition at line 3123 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

03124 {
03125    ast_rwlock_rdlock(&features_lock);
03126 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_set

Parameters:
feature an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call.

Definition at line 2967 of file features.c.

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

Referenced by process_applicationmap_line().

02968 {
02969    if (!feature) {
02970       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02971       return;
02972    }
02973   
02974    AST_RWLIST_WRLOCK(&feature_list);
02975    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02976    AST_RWLIST_UNLOCK(&feature_list);
02977 
02978    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02979 }

void ast_unlock_call_features ( void   ) 

Definition at line 3128 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

03129 {
03130    ast_rwlock_unlock(&features_lock);
03131 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.

03048 {
03049    if (!feature) {
03050       return;
03051    }
03052 
03053    AST_RWLIST_WRLOCK(&feature_list);
03054    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
03055    AST_RWLIST_UNLOCK(&feature_list);
03056 
03057    ast_free(feature);
03058 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 3061 of file features.c.

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

03062 {
03063    struct ast_call_feature *feature;
03064 
03065    AST_RWLIST_WRLOCK(&feature_list);
03066    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
03067       ast_free(feature);
03068    }
03069    AST_RWLIST_UNLOCK(&feature_list);
03070 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

Definition at line 3087 of file features.c.

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

03088 {
03089    struct feature_group *fg;
03090    struct feature_group_exten *fge;
03091 
03092    AST_RWLIST_WRLOCK(&feature_groups);
03093    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
03094       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
03095          ast_string_field_free_memory(fge);
03096          ast_free(fge);
03097       }
03098 
03099       ast_string_field_free_memory(fg);
03100       ast_free(fg);
03101    }
03102    AST_RWLIST_UNLOCK(&feature_groups);
03103 }

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

Definition at line 2469 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().

02470 {
02471    finishup(transferee);
02472 
02473    /*
02474     * Restore party B connected line info about party A.
02475     *
02476     * Party B was the caller to party C and is the last known mode
02477     * for party B.
02478     */
02479    if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
02480       ast_channel_update_connected_line(transferer, connected_line, NULL);
02481    }
02482    ast_party_connected_line_free(connected_line);
02483 }

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

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

Referenced by bridge_call_thread_launch().

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

static void bridge_call_thread_launch ( struct ast_bridge_thread_obj data  )  [static]

create thread for the parked call

Parameters:
data Create thread and attributes, call bridge_call_thread

Definition at line 1033 of file features.c.

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

Referenced by action_bridge(), and builtin_atxfer().

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

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

Bridge channels.

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

Definition at line 7562 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, ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_channel::name, 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().

07563 {
07564    struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
07565    char *tmp_data  = NULL;
07566    struct ast_flags opts = { 0, };
07567    struct ast_bridge_config bconfig = { { 0, }, };
07568    char *opt_args[OPT_ARG_ARRAY_SIZE];
07569    struct timeval calldurationlimit = { 0, };
07570 
07571    AST_DECLARE_APP_ARGS(args,
07572       AST_APP_ARG(dest_chan);
07573       AST_APP_ARG(options);
07574    );
07575 
07576    if (ast_strlen_zero(data)) {
07577       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
07578       return -1;
07579    }
07580 
07581    tmp_data = ast_strdupa(data);
07582    AST_STANDARD_APP_ARGS(args, tmp_data);
07583    if (!ast_strlen_zero(args.options))
07584       ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
07585 
07586    /* avoid bridge with ourselves */
07587    if (!strcmp(chan->name, args.dest_chan)) {
07588       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
07589       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07590          "Response: Failed\r\n"
07591          "Reason: Unable to bridge channel to itself\r\n"
07592          "Channel1: %s\r\n"
07593          "Channel2: %s\r\n",
07594          chan->name, args.dest_chan);
07595       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
07596       return 0;
07597    }
07598 
07599    /* make sure we have a valid end point */
07600    if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
07601          strlen(args.dest_chan)))) {
07602       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
07603          args.dest_chan);
07604       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07605          "Response: Failed\r\n"
07606          "Reason: Channel2 does not exist\r\n"
07607          "Channel1: %s\r\n"
07608          "Channel2: %s\r\n", chan->name, args.dest_chan);
07609       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
07610       return 0;
07611    }
07612 
07613    /* try to allocate a place holder where current_dest_chan will be placed */
07614    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
07615       NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
07616       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
07617       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07618          "Response: Failed\r\n"
07619          "Reason: Cannot create placeholder channel\r\n"
07620          "Channel1: %s\r\n"
07621          "Channel2: %s\r\n", chan->name, args.dest_chan);
07622       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07623       ast_channel_unref(current_dest_chan);
07624       return 0;
07625    }
07626 
07627    if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
07628       && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
07629       && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
07630       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07631          "Response: Failed\r\n"
07632          "Reason: Cannot setup bridge time limit\r\n"
07633          "Channel1: %s\r\n"
07634          "Channel2: %s\r\n", chan->name, args.dest_chan);
07635       ast_hangup(final_dest_chan);
07636       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07637       current_dest_chan = ast_channel_unref(current_dest_chan);
07638       goto done;
07639    }
07640 
07641    if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) {
07642       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07643          "Response: Failed\r\n"
07644          "Reason: Cannot masquerade channels\r\n"
07645          "Channel1: %s\r\n"
07646          "Channel2: %s\r\n", chan->name, args.dest_chan);
07647       ast_hangup(final_dest_chan);
07648       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
07649       current_dest_chan = ast_channel_unref(current_dest_chan);
07650       goto done;
07651    }
07652 
07653    /* answer the channel if needed */
07654    if (final_dest_chan->_state != AST_STATE_UP) {
07655       ast_answer(final_dest_chan);
07656    }
07657 
07658    chans[0] = current_dest_chan;
07659    chans[1] = final_dest_chan;
07660 
07661    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
07662    /* try to make compatible, send error if we fail */
07663    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
07664       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
07665       ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07666          "Response: Failed\r\n"
07667          "Reason: Could not make channels compatible for bridge\r\n"
07668          "Channel1: %s\r\n"
07669          "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07670 
07671       /* Maybe we should return this channel to the PBX? */
07672       ast_hangup(final_dest_chan);
07673 
07674       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
07675       current_dest_chan = ast_channel_unref(current_dest_chan);
07676       goto done;
07677    }
07678 
07679    /* Report that the bridge will be successfull */
07680    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07681       "Response: Success\r\n"
07682       "Channel1: %s\r\n"
07683       "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07684 
07685    current_dest_chan = ast_channel_unref(current_dest_chan);
07686 
07687    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
07688    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
07689       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
07690          if (ast_waitstream(final_dest_chan, "") < 0)
07691             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
07692       }
07693    }
07694 
07695    if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
07696       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
07697    if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
07698       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
07699    if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
07700       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
07701    if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
07702       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
07703    if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
07704       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
07705    if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
07706       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
07707    if (ast_test_flag(&opts, OPT_CALLEE_PARK))
07708       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
07709    if (ast_test_flag(&opts, OPT_CALLER_PARK))
07710       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
07711 
07712    /*
07713     * Don't let the after-bridge code run the h-exten.  We want to
07714     * continue in the dialplan.
07715     */
07716    ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
07717    ast_bridge_call(chan, final_dest_chan, &bconfig);
07718 
07719    /* The bridge has ended, set BRIDGERESULT to SUCCESS. */
07720    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
07721 
07722    /* If the other channel has not been hung up, return it to the PBX */
07723    if (!ast_check_hangup(final_dest_chan)) {
07724       if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
07725          ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
07726             final_dest_chan->context, final_dest_chan->exten,
07727             final_dest_chan->priority, final_dest_chan->name);
07728 
07729          if (ast_pbx_start(final_dest_chan)) {
07730             ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
07731             ast_hangup(final_dest_chan);
07732          } else {
07733             ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
07734          }
07735       } else {
07736          ast_hangup(final_dest_chan);
07737       }
07738    } else {
07739       ast_debug(1, "chan %s was hungup\n", final_dest_chan->name);
07740       ast_hangup(final_dest_chan);
07741    }
07742 done:
07743    ast_free((char *) bconfig.warning_sound);
07744    ast_free((char *) bconfig.end_sound);
07745    ast_free((char *) bconfig.start_sound);
07746 
07747    return 0;
07748 }

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

Definition at line 6235 of file features.c.

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

Referenced by dialplan_usage_add_parkinglot().

06236 {
06237    struct parking_dp_context *ctx_node;
06238 
06239    ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con));
06240    if (!ctx_node) {
06241       return NULL;
06242    }
06243    if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) {
06244       destroy_dialplan_usage_context(ctx_node);
06245       return NULL;
06246    }
06247    strcpy(ctx_node->context, lot->cfg.parking_con);
06248    return ctx_node;
06249 }

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

Definition at line 6307 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().

06308 {
06309    int status = 0;
06310    struct ao2_iterator iter;
06311    struct ast_parkinglot *curlot;
06312 
06313    /* For all parking lots */
06314    iter = ao2_iterator_init(parkinglots, 0);
06315    for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) {
06316       /* Add the parking lot to the map. */
06317       if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) {
06318          ao2_ref(curlot, -1);
06319          status = -1;
06320          break;
06321       }
06322    }
06323    ao2_iterator_destroy(&iter);
06324 
06325    return status;
06326 }

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

Definition at line 5998 of file features.c.

References ast_calloc.

Referenced by usage_context_add_ramp().

05999 {
06000    struct parking_dp_ramp *ramp_node;
06001 
06002    ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten));
06003    if (!ramp_node) {
06004       return NULL;
06005    }
06006    ramp_node->exclusive = exclusive;
06007    strcpy(ramp_node->exten, exten);
06008    return ramp_node;
06009 }

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

Definition at line 6079 of file features.c.

References ast_calloc.

Referenced by usage_context_add_spaces().

06080 {
06081    struct parking_dp_spaces *spaces_node;
06082 
06083    spaces_node = ast_calloc(1, sizeof(*spaces_node));
06084    if (!spaces_node) {
06085       return NULL;
06086    }
06087    spaces_node->start = start;
06088    spaces_node->stop = stop;
06089    return spaces_node;
06090 }

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

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

Definition at line 5600 of file features.c.

References ao2_link, ao2_lock, ao2_unlock, ast_debug, AST_LIST_EMPTY, ast_log(), create_parkinglot(), DEFAULT_PARKINGLOT, find_parkinglot(), force_reload_load, LOG_WARNING, parkinglot, parkinglot_cfg_default, parkinglot_cfg_default_default, parkinglot_config_read(), parkinglot_unref(), parkinglots, and var.

Referenced by load_config(), and process_config().

05601 {
05602    struct ast_parkinglot *parkinglot;
05603    const struct parkinglot_cfg *cfg_defaults;
05604    struct parkinglot_cfg new_cfg;
05605    int cfg_error;
05606    int oldparkinglot = 0;
05607 
05608    parkinglot = find_parkinglot(pl_name);
05609    if (parkinglot) {
05610       oldparkinglot = 1;
05611    } else {
05612       parkinglot = create_parkinglot(pl_name);
05613       if (!parkinglot) {
05614          return NULL;
05615       }
05616    }
05617    if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) {
05618       cfg_defaults = &parkinglot_cfg_default_default;
05619    } else {
05620       cfg_defaults = &parkinglot_cfg_default;
05621    }
05622    new_cfg = *cfg_defaults;
05623 
05624    ast_debug(1, "Building parking lot %s\n", parkinglot->name);
05625 
05626    ao2_lock(parkinglot);
05627 
05628    /* Do some config stuff */
05629    cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var);
05630    if (oldparkinglot) {
05631       if (cfg_error) {
05632          /* Bad configuration read.  Keep using the original config. */
05633          ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n",
05634             parkinglot->name);
05635          cfg_error = 0;
05636       } else if (!AST_LIST_EMPTY(&parkinglot->parkings)
05637          && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) {
05638          /* Try reloading later when parking lot is empty. */
05639          ast_log(LOG_WARNING,
05640             "Parking lot %s has parked calls.  Parking lot changes discarded.\n",
05641             parkinglot->name);
05642          force_reload_load = 1;
05643       } else {
05644          /* Accept the new config */
05645          parkinglot->cfg = new_cfg;
05646       }
05647    } else {
05648       /* Load the initial parking lot config. */
05649       parkinglot->cfg = new_cfg;
05650    }
05651    parkinglot->the_mark = 0;
05652 
05653    ao2_unlock(parkinglot);
05654 
05655    if (cfg_error) {
05656       /* Only new parking lots could have config errors here. */
05657       ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name);
05658       parkinglot_unref(parkinglot);
05659       return NULL;
05660    }
05661 
05662    /* Move it into the list, if it wasn't already there */
05663    if (!oldparkinglot) {
05664       ao2_link(parkinglots, parkinglot);
05665    }
05666    parkinglot_unref(parkinglot);
05667 
05668    return parkinglot;
05669 }

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

Attended transfer.

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

Definition at line 2500 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, bridge_call_thread_launch(), ast_channel::caller, check_compat(), config, ast_channel::connected, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, feature_request_and_dial(), ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), get_parking_exten(), ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_dial_features::my_features, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_dial_features::peer_features, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_party_connected_line::source, strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xfer_park_call_helper(), xferfailsound, and xfersound.

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

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

References args, AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_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_channel::name, 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.

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

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

References args, AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, ast_channel::monitor, monitor_app, monitor_ok, ast_channel::name, 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.

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

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

Blind transfer user to another extension.

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

Definition at line 2329 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::name, ast_channel::pbx, pbx_builtin_setvar_helper(), ast_exten::peer, real_ctx(), set_c_e_p(), set_peers(), transferdigittimeout, and xfer_park_call_helper().

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

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

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

02287 {
02288    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
02289    return AST_FEATURE_RETURN_HANGUP;
02290 }

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

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

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

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

Definition at line 4586 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().

04587 {
04588    int i = 0;
04589    enum {
04590       OPT_CALLEE_REDIRECT   = 't',
04591       OPT_CALLER_REDIRECT   = 'T',
04592       OPT_CALLEE_AUTOMON    = 'w',
04593       OPT_CALLER_AUTOMON    = 'W',
04594       OPT_CALLEE_DISCONNECT = 'h',
04595       OPT_CALLER_DISCONNECT = 'H',
04596       OPT_CALLEE_PARKCALL   = 'k',
04597       OPT_CALLER_PARKCALL   = 'K',
04598    };
04599 
04600    memset(options, 0, len);
04601    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
04602       options[i++] = OPT_CALLER_REDIRECT;
04603    }
04604    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
04605       options[i++] = OPT_CALLER_AUTOMON;
04606    }
04607    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
04608       options[i++] = OPT_CALLER_DISCONNECT;
04609    }
04610    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
04611       options[i++] = OPT_CALLER_PARKCALL;
04612    }
04613 
04614    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
04615       options[i++] = OPT_CALLEE_REDIRECT;
04616    }
04617    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
04618       options[i++] = OPT_CALLEE_AUTOMON;
04619    }
04620    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
04621       options[i++] = OPT_CALLEE_DISCONNECT;
04622    }
04623    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
04624       options[i++] = OPT_CALLEE_PARKCALL;
04625    }
04626 
04627    return options;
04628 }

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

References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.

Referenced by builtin_atxfer().

02446 {
02447    if (ast_channel_make_compatible(c, newchan) < 0) {
02448       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
02449          c->name, newchan->name);
02450       ast_hangup(newchan);
02451       return -1;
02452    }
02453    return 0;
02454 }

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

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

Referenced by builtin_blindtransfer().

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

static void clear_dialed_interfaces ( struct ast_channel chan  )  [static]

Definition at line 3878 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, ast_channel::name, and option_debug.

Referenced by ast_bridge_call().

03879 {
03880    struct ast_datastore *di_datastore;
03881 
03882    ast_channel_lock(chan);
03883    if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
03884       if (option_debug) {
03885          ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name);
03886       }
03887       if (!ast_channel_datastore_remove(chan, di_datastore)) {
03888          ast_datastore_free(di_datastore);
03889       }
03890    }
03891    ast_channel_unlock(chan);
03892 }

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

Copy parkinglot and store it with new name.

Definition at line 4951 of file features.c.

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

Referenced by create_dynamic_parkinglot().

04952 {
04953    struct ast_parkinglot *copylot;
04954 
04955    if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
04956       ao2_ref(copylot, -1);
04957       return NULL;
04958    }
04959 
04960    copylot = create_parkinglot(name);
04961    if (!copylot) {
04962       return NULL;
04963    }
04964 
04965    ast_debug(1, "Building parking lot %s\n", name);
04966 
04967    /* Copy the source parking lot configuration. */
04968    copylot->cfg = parkinglot->cfg;
04969 
04970    return copylot;
04971 }

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

Definition at line 1161 of file features.c.

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

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

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

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

Allocate parking lot structure.

Definition at line 5376 of file features.c.

References ao2_alloc, ast_copy_string(), AST_LIST_HEAD_INIT, ast_strlen_zero(), and parkinglot_destroy().

Referenced by build_parkinglot(), and copy_parkinglot().

05377 {
05378    struct ast_parkinglot *newlot;
05379 
05380    if (ast_strlen_zero(name)) { /* No name specified */
05381       return NULL;
05382    }
05383 
05384    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
05385    if (!newlot)
05386       return NULL;
05387    
05388    ast_copy_string(newlot->name, name, sizeof(newlot->name));
05389    newlot->cfg.is_invalid = 1;/* No config is set yet. */
05390    AST_LIST_HEAD_INIT(&newlot->parkings);
05391 
05392    return newlot;
05393 }

static void destroy_dialplan_usage_context ( struct parking_dp_context doomed  )  [static]

Definition at line 5954 of file features.c.

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

Referenced by build_dialplan_useage_context(), and destroy_dialplan_usage_map().

05955 {
05956    struct parking_dp_ramp *ramp;
05957    struct parking_dp_spaces *spaces;
05958 
05959    while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) {
05960       ast_free(ramp);
05961    }
05962    while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) {
05963       ast_free(spaces);
05964    }
05965    while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) {
05966       ast_free(spaces);
05967    }
05968    ast_free(doomed);
05969 }

static void destroy_dialplan_usage_map ( struct parking_dp_map doomed  )  [static]

Definition at line 5979 of file features.c.

References AST_LIST_REMOVE_HEAD, destroy_dialplan_usage_context(), and parking_dp_context::node.

Referenced by load_config().

05980 {
05981    struct parking_dp_context *item;
05982 
05983    while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) {
05984       destroy_dialplan_usage_context(item);
05985    }
05986 }

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

Definition at line 6409 of file features.c.

References AST_MAX_EXTENSION, PRIORITY_HINT, and remove_exten_if_exist().

Referenced by remove_dead_spaces_usage().

06410 {
06411    char exten[AST_MAX_EXTENSION];
06412 
06413    /* Destroy priorities of the parking space that we registered. */
06414    snprintf(exten, sizeof(exten), "%d", space);
06415    remove_exten_if_exist(context, exten, PRIORITY_HINT);
06416    remove_exten_if_exist(context, exten, 1);
06417 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 740 of file features.c.

References ast_free.

00741 {
00742    struct ast_dial_features *df = data;
00743    if (df) {
00744       ast_free(df);
00745    }
00746 }

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

Definition at line 727 of file features.c.

References ast_calloc.

00728 {
00729    struct ast_dial_features *df = data, *df_copy;
00730  
00731    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00732       return NULL;
00733    }
00734  
00735    memcpy(df_copy, df, sizeof(*df));
00736  
00737    return df_copy;
00738 }

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

Definition at line 6262 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(), parking_dp_context::node, and parkinglot_cfg::parking_con.

Referenced by build_dialplan_useage_map().

06263 {
06264    struct parking_dp_context *cur_ctx;
06265    struct parking_dp_context *new_ctx;
06266    int cmp;
06267 
06268    AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) {
06269       cmp = strcmp(lot->cfg.parking_con, cur_ctx->context);
06270       if (cmp > 0) {
06271          /* The parking lot context goes after this node. */
06272          continue;
06273       }
06274       if (cmp == 0) {
06275          /* This is the node we will add parking lot spaces to the map. */
06276          return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain);
06277       }
06278       /* The new parking lot context goes before this node. */
06279       new_ctx = build_dialplan_useage_context(lot);
06280       if (!new_ctx) {
06281          return -1;
06282       }
06283       AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node);
06284       return 0;
06285    }
06286    AST_LIST_TRAVERSE_SAFE_END;
06287 
06288    /* New parking lot context goes on the end. */
06289    new_ctx = build_dialplan_useage_context(lot);
06290    if (!new_ctx) {
06291       return -1;
06292    }
06293    AST_LIST_INSERT_TAIL(usage_map, new_ctx, node);
06294    return 0;
06295 }

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

Definition at line 6208 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().

06209 {
06210    if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext,
06211       lot->cfg.parkext_exclusive, lot, complain)) {
06212       return -1;
06213    }
06214    if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start,
06215       lot->cfg.parking_stop, lot, complain)) {
06216       return -1;
06217    }
06218    if (lot->cfg.parkaddhints
06219       && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start,
06220          lot->cfg.parking_stop, lot, 0)) {
06221       return -1;
06222    }
06223    return 0;
06224 }

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 6845 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().

06846 {
06847    const char *context;
06848    const char *exten;
06849    int priority;
06850 
06851    ast_moh_stop(chan);
06852    ast_channel_lock_both(chan, tmpchan);
06853    context = ast_strdupa(chan->context);
06854    exten = ast_strdupa(chan->exten);
06855    priority = chan->priority;
06856    ast_setstate(tmpchan, chan->_state);
06857    tmpchan->readformat = chan->readformat;
06858    tmpchan->writeformat = chan->writeformat;
06859    ast_channel_unlock(chan);
06860    ast_channel_unlock(tmpchan);
06861 
06862    /* Masquerade setup and execution must be done without any channel locks held */
06863    if (ast_channel_masquerade(tmpchan, chan)) {
06864       return -1;
06865    }
06866    ast_do_masquerade(tmpchan);
06867 
06868    /* when returning from bridge, the channel will continue at the next priority */
06869    ast_explicit_goto(tmpchan, context, exten, priority + 1);
06870 
06871    return 0;
06872 }

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 4901 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().

04902 {
04903    struct pollfd *pfds = NULL, *new_pfds = NULL;
04904    int nfds = 0, new_nfds = 0;
04905 
04906    for (;;) {
04907       struct ao2_iterator iter;
04908       struct ast_parkinglot *curlot;
04909       int ms = -1;   /* poll2 timeout, uninitialized */
04910 
04911       iter = ao2_iterator_init(parkinglots, 0);
04912       while ((curlot = ao2_iterator_next(&iter))) {
04913          manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
04914          ao2_ref(curlot, -1);
04915       }
04916       ao2_iterator_destroy(&iter);
04917 
04918       /* Recycle */
04919       ast_free(pfds);
04920       pfds = new_pfds;
04921       nfds = new_nfds;
04922       new_pfds = NULL;
04923       new_nfds = 0;
04924 
04925       /* Wait for something to happen */
04926       ast_poll(pfds, nfds, ms);
04927       pthread_testcancel();
04928    }
04929    /* If this WERE reached, we'd need to free(pfds) */
04930    return NULL;   /* Never reached */
04931 }

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

Check if a feature exists.

Definition at line 3407 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().

03407                                                                                            {
03408    char *chan_dynamic_features;
03409    ast_channel_lock(chan);
03410    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03411    ast_channel_unlock(chan);
03412 
03413    return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL);
03414 }

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

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

Referenced by process_applicationmap_line().

03153 {
03154    struct ast_app *app;
03155    struct ast_call_feature *feature = data;
03156    struct ast_channel *work, *idle;
03157    int res;
03158 
03159    if (!feature) { /* shouldn't ever happen! */
03160       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
03161       return -1; 
03162    }
03163 
03164    if (sense == FEATURE_SENSE_CHAN) {
03165       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
03166          return AST_FEATURE_RETURN_KEEPTRYING;
03167       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03168          work = chan;
03169          idle = peer;
03170       } else {
03171          work = peer;
03172          idle = chan;
03173       }
03174    } else {
03175       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
03176          return AST_FEATURE_RETURN_KEEPTRYING;
03177       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03178          work = peer;
03179          idle = chan;
03180       } else {
03181          work = chan;
03182          idle = peer;
03183       }
03184    }
03185 
03186    if (!(app = pbx_findapp(feature->app))) {
03187       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
03188       return -2;
03189    }
03190 
03191    ast_autoservice_start(idle);
03192    ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
03193    
03194    pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name);
03195    pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name);
03196    pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
03197    pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
03198 
03199    if (!ast_strlen_zero(feature->moh_class))
03200       ast_moh_start(idle, feature->moh_class, NULL);
03201 
03202    res = pbx_exec(work, app, feature->app_args);
03203 
03204    if (!ast_strlen_zero(feature->moh_class))
03205       ast_moh_stop(idle);
03206 
03207    ast_autoservice_stop(idle);
03208 
03209    if (res) {
03210       return AST_FEATURE_RETURN_SUCCESSBREAK;
03211    }
03212    return AST_FEATURE_RETURN_SUCCESS;  /*! \todo XXX should probably return res */
03213 }

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

References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, config, feature_group_exten::feature, FEATURE_INTERPRET_DO, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

03370                                                                                                                                                 {
03371 
03372    char dynamic_features_buf[128];
03373    const char *peer_dynamic_features, *chan_dynamic_features;
03374    struct ast_flags features;
03375    struct ast_call_feature feature;
03376    if (sense == FEATURE_SENSE_CHAN) {
03377       /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
03378       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
03379    }
03380    else {
03381       /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
03382       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
03383    }
03384 
03385    ast_channel_lock(peer);
03386    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
03387    ast_channel_unlock(peer);
03388 
03389    ast_channel_lock(chan);
03390    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03391    ast_channel_unlock(chan);
03392 
03393    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,""));
03394 
03395    ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf);
03396 
03397    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
03398 }

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

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

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

03256 {
03257    int x;
03258    struct feature_group *fg = NULL;
03259    struct feature_group_exten *fge;
03260    struct ast_call_feature *tmpfeature;
03261    char *tmp, *tok;
03262    int res = AST_FEATURE_RETURN_PASSDIGITS;
03263    int feature_detected = 0;
03264 
03265    if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) {
03266       return -1; /* can not run feature operation */
03267    }
03268 
03269    ast_rwlock_rdlock(&features_lock);
03270    for (x = 0; x < FEATURES_COUNT; x++) {
03271       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
03272           !ast_strlen_zero(builtin_features[x].exten)) {
03273          /* Feature is up for consideration */
03274          if (!strcmp(builtin_features[x].exten, code)) {
03275             ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
03276             if (operation == FEATURE_INTERPRET_CHECK) {
03277                res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
03278             } else if (operation == FEATURE_INTERPRET_DO) {
03279                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
03280             }
03281             if (feature) {
03282                memcpy(feature, &builtin_features[x], sizeof(*feature));
03283             }
03284             feature_detected = 1;
03285             break;
03286          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
03287             if (res == AST_FEATURE_RETURN_PASSDIGITS) {
03288                res = AST_FEATURE_RETURN_STOREDIGITS;
03289             }
03290          }
03291       }
03292    }
03293    ast_rwlock_unlock(&features_lock);
03294 
03295    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
03296       return res;
03297    }
03298 
03299    tmp = dynamic_features_buf;
03300 
03301    while ((tok = strsep(&tmp, "#"))) {
03302       AST_RWLIST_RDLOCK(&feature_groups);
03303 
03304       fg = find_group(tok);
03305 
03306       if (fg) {
03307          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03308             if (!strcmp(fge->exten, code)) {
03309                if (operation) {
03310                   res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
03311                }
03312                if (feature) {
03313                   memcpy(feature, fge->feature, sizeof(*feature));
03314                }
03315                if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03316                   AST_RWLIST_UNLOCK(&feature_groups);
03317                   break;
03318                }
03319                res = AST_FEATURE_RETURN_PASSDIGITS;
03320             } else if (!strncmp(fge->exten, code, strlen(code))) {
03321                res = AST_FEATURE_RETURN_STOREDIGITS;
03322             }
03323          }
03324          if (fge) {
03325             break;
03326          }
03327       }
03328 
03329       AST_RWLIST_UNLOCK(&feature_groups);
03330 
03331       AST_RWLIST_RDLOCK(&feature_list);
03332 
03333       if (!(tmpfeature = find_dynamic_feature(tok))) {
03334          AST_RWLIST_UNLOCK(&feature_list);
03335          continue;
03336       }
03337 
03338       /* Feature is up for consideration */
03339       if (!strcmp(tmpfeature->exten, code)) {
03340          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
03341          if (operation == FEATURE_INTERPRET_CHECK) {
03342             res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
03343          } else if (operation == FEATURE_INTERPRET_DO) {
03344             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
03345          }
03346          if (feature) {
03347             memcpy(feature, tmpfeature, sizeof(*feature));
03348          }
03349          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03350             AST_RWLIST_UNLOCK(&feature_list);
03351             break;
03352          }
03353          res = AST_FEATURE_RETURN_PASSDIGITS;
03354       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
03355          res = AST_FEATURE_RETURN_STOREDIGITS;
03356 
03357       AST_RWLIST_UNLOCK(&feature_list);
03358    }
03359 
03360    return res;
03361 }

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]

Definition at line 3511 of file features.c.

References ast_channel::_state, 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(), builtin_features, ast_channel::call_forward, ast_channel::caller, cause, connected, ast_channel::connected, ast_channel::exten, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_channel::hangupcause, LOG_NOTICE, ast_channel::name, and pbx_builtin_setvar_helper().

Referenced by builtin_atxfer().

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

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

Definition at line 7268 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.

07269 {
07270    struct ast_channel *target = obj;/*!< Potential pickup target */
07271    struct ast_channel *chan = data;/*!< Channel wanting to pickup call */
07272 
07273    ast_channel_lock(target);
07274    if (chan != target && (chan->pickupgroup & target->callgroup)
07275       && ast_can_pickup(target)) {
07276       /* Return with the channel still locked on purpose */
07277       return CMP_MATCH | CMP_STOP;
07278    }
07279    ast_channel_unlock(target);
07280 
07281    return 0;
07282 }

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

find a call feature by name

Definition at line 3073 of file features.c.

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

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

03074 {
03075    struct ast_call_feature *tmp;
03076 
03077    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
03078       if (!strcasecmp(tmp->sname, name)) {
03079          break;
03080       }
03081    }
03082 
03083    return tmp;
03084 }

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

Find a group by name.

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

Definition at line 3111 of file features.c.

References AST_LIST_TRAVERSE, feature_group_exten::entry, and feature_group::gname.

Referenced by feature_interpret_helper().

03112 {
03113    struct feature_group *fg = NULL;
03114 
03115    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
03116       if (!strcasecmp(fg->gname, name))
03117          break;
03118    }
03119 
03120    return fg;
03121 }

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

Find parkinglot by name.

Definition at line 4934 of file features.c.

References ao2_find, ast_debug, ast_strlen_zero(), parkinglot, 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().

04935 {
04936    struct ast_parkinglot *parkinglot;
04937 
04938    if (ast_strlen_zero(name)) {
04939       return NULL;
04940    }
04941 
04942    parkinglot = ao2_find(parkinglots, (void *) name, 0);
04943    if (parkinglot) {
04944       ast_debug(1, "Found Parking lot: %s\n", parkinglot->name);
04945    }
04946 
04947    return parkinglot;
04948 }

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

References ast_strlen_zero(), name, ast_channel::parkinglot, and pbx_builtin_getvar_helper().

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

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

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 1858 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().

01859 {
01860    ast_indicate(chan, AST_CONTROL_UNHOLD);
01861 
01862    return ast_autoservice_stop(chan);
01863 }

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

Definition at line 819 of file features.c.

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

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

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

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

CLI command to list configured features.

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

Definition at line 6711 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, builtin_features, ast_parkinglot::cfg, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, ast_parkinglot::disabled, feature_group_exten::entry, 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.

06712 {
06713    int i;
06714    struct ast_call_feature *feature;
06715    struct ao2_iterator iter;
06716    struct ast_parkinglot *curlot;
06717 #define HFS_FORMAT "%-25s %-7s %-7s\n"
06718 
06719    switch (cmd) {
06720    
06721    case CLI_INIT:
06722       e->command = "features show";
06723       e->usage =
06724          "Usage: features show\n"
06725          "       Lists configured features\n";
06726       return NULL;
06727    case CLI_GENERATE:
06728       return NULL;
06729    }
06730 
06731    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
06732    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06733 
06734    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
06735 
06736    ast_rwlock_rdlock(&features_lock);
06737    for (i = 0; i < FEATURES_COUNT; i++)
06738       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
06739    ast_rwlock_unlock(&features_lock);
06740 
06741    ast_cli(a->fd, "\n");
06742    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
06743    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06744    if (AST_RWLIST_EMPTY(&feature_list)) {
06745       ast_cli(a->fd, "(none)\n");
06746    } else {
06747       AST_RWLIST_RDLOCK(&feature_list);
06748       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
06749          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
06750       }
06751       AST_RWLIST_UNLOCK(&feature_list);
06752    }
06753 
06754    ast_cli(a->fd, "\nFeature Groups:\n");
06755    ast_cli(a->fd, "---------------\n");
06756    if (AST_RWLIST_EMPTY(&feature_groups)) {
06757       ast_cli(a->fd, "(none)\n");
06758    } else {
06759       struct feature_group *fg;
06760       struct feature_group_exten *fge;
06761 
06762       AST_RWLIST_RDLOCK(&feature_groups);
06763       AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
06764          ast_cli(a->fd, "===> Group: %s\n", fg->gname);
06765          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
06766             ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
06767          }
06768       }
06769       AST_RWLIST_UNLOCK(&feature_groups);
06770    }
06771 
06772    iter = ao2_iterator_init(parkinglots, 0);
06773    while ((curlot = ao2_iterator_next(&iter))) {
06774       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
06775       ast_cli(a->fd, "------------\n");
06776       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", curlot->cfg.parkext);
06777       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->cfg.parking_con);
06778       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions",
06779          curlot->cfg.parking_start, curlot->cfg.parking_stop);
06780       ast_cli(a->fd,"%-22s:      %d ms\n", "Parkingtime", curlot->cfg.parkingtime);
06781       ast_cli(a->fd,"%-22s:      %s\n", "MusicOnHold class", curlot->cfg.mohclass);
06782       ast_cli(a->fd,"%-22s:      %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled));
06783       ast_cli(a->fd,"\n");
06784       ao2_ref(curlot, -1);
06785    }
06786    ao2_iterator_destroy(&iter);
06787 
06788    return CLI_SUCCESS;
06789 }

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

Definition at line 6817 of file features.c.

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

06818 {
06819    switch (cmd) { 
06820    case CLI_INIT:
06821       e->command = "features reload";
06822       e->usage =
06823          "Usage: features reload\n"
06824          "       Reloads configured call features from features.conf\n";
06825       return NULL;
06826    case CLI_GENERATE:
06827       return NULL;
06828    }
06829    ast_features_reload();
06830 
06831    return CLI_SUCCESS;
06832 }

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 7021 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_channel::name, ast_parkinglot::name, parkeduser::parkingexten, parkinglots, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.

07022 {
07023    struct parkeduser *cur;
07024    int numparked = 0;
07025    struct ao2_iterator iter;
07026    struct ast_parkinglot *curlot;
07027 
07028    switch (cmd) {
07029    case CLI_INIT:
07030       e->command = "parkedcalls show";
07031       e->usage =
07032          "Usage: parkedcalls show\n"
07033          "       List currently parked calls\n";
07034       return NULL;
07035    case CLI_GENERATE:
07036       return NULL;
07037    }
07038 
07039    if (a->argc > e->args)
07040       return CLI_SHOWUSAGE;
07041 
07042    ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel",
07043       "Context", "Extension", "Pri", "Timeout");
07044 
07045    iter = ao2_iterator_init(parkinglots, 0);
07046    while ((curlot = ao2_iterator_next(&iter))) {
07047       int lotparked = 0;
07048 
07049       /* subtract ref for iterator and for configured parking lot */
07050       ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name,
07051          ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot));
07052 
07053       AST_LIST_LOCK(&curlot->parkings);
07054       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
07055          ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n",
07056             cur->parkingexten, cur->chan->name, cur->context, cur->exten,
07057             cur->priority,
07058             (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL)));
07059          ++lotparked;
07060       }
07061       AST_LIST_UNLOCK(&curlot->parkings);
07062       if (lotparked) {
07063          numparked += lotparked;
07064          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked,
07065             ESS(lotparked), curlot->name);
07066       }
07067 
07068       ao2_ref(curlot, -1);
07069    }
07070    ao2_iterator_destroy(&iter);
07071 
07072    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
07073 
07074    return CLI_SUCCESS;
07075 }

static int load_config ( int  reload  )  [static]

Definition at line 6628 of file features.c.

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

06629 {
06630    struct ast_flags config_flags = {
06631       reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06632    struct ast_config *cfg;
06633    struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06634    struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06635 
06636    /* We are reloading now and have already determined if we will force the reload. */
06637    force_reload_load = 0;
06638 
06639    if (!default_parkinglot) {
06640       /* Must create the default default parking lot */
06641       default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
06642       if (!default_parkinglot) {
06643          ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n");
06644          return -1;
06645       }
06646       ast_debug(1, "Configuration of default default parking lot done.\n");
06647       parkinglot_addref(default_parkinglot);
06648    }
06649 
06650    cfg = ast_config_load2("features.conf", "features", config_flags);
06651    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06652       /* No sense in asking for reload trouble if nothing changed. */
06653       ast_debug(1, "features.conf did not change.\n");
06654       return 0;
06655    }
06656    if (cfg == CONFIG_STATUS_FILEMISSING
06657       || cfg == CONFIG_STATUS_FILEINVALID) {
06658       ast_log(LOG_WARNING, "Could not load features.conf\n");
06659       return 0;
06660    }
06661 
06662    /* Save current parking lot dialplan needs. */
06663    if (build_dialplan_useage_map(&old_usage_map, 0)) {
06664       destroy_dialplan_usage_map(&old_usage_map);
06665 
06666       /* Allow reloading later to see if conditions have improved. */
06667       force_reload_load = 1;
06668       return -1;
06669    }
06670 
06671    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL,
06672       "callback to mark all parking lots");
06673    process_config(cfg);
06674    ast_config_destroy(cfg);
06675    ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL,
06676       "callback to remove marked parking lots");
06677 
06678    /* Save updated parking lot dialplan needs. */
06679    if (build_dialplan_useage_map(&new_usage_map, 1)) {
06680       /*
06681        * Yuck, if this failure caused any parking lot dialplan items
06682        * to be lost, they will likely remain lost until Asterisk is
06683        * restarted.
06684        */
06685       destroy_dialplan_usage_map(&old_usage_map);
06686       destroy_dialplan_usage_map(&new_usage_map);
06687       return -1;
06688    }
06689 
06690    /* Remove no longer needed parking lot dialplan usage. */
06691    remove_dead_dialplan_useage(&old_usage_map, &new_usage_map);
06692 
06693    destroy_dialplan_usage_map(&old_usage_map);
06694    destroy_dialplan_usage_map(&new_usage_map);
06695 
06696    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL,
06697       "callback to activate all parking lots");
06698 
06699    return 0;
06700 }

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 4638 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_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_channel::generatordata, parkeduser::hold_method, LOG_ERROR, LOG_NOTICE, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, parkinglot_cfg::mohclass, ast_dial_features::my_features, ast_parkinglot::name, ast_channel::name, parkeduser::options_specified, parking_con_dial, parkeduser::parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_setvar_helper(), ast_dial_features::peer_features, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), and parkeduser::start.

Referenced by manage_parkinglot().

04639 {
04640    struct ast_channel *chan = pu->chan;   /* shorthand */
04641    int tms;        /* timeout for this item */
04642    int x;          /* fd index in channel */
04643 
04644    tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04645    if (tms > pu->parkingtime) {
04646       /*
04647        * Call has been parked too long.
04648        * Stop entertaining the caller.
04649        */
04650       switch (pu->hold_method) {
04651       case AST_CONTROL_HOLD:
04652          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04653          break;
04654       case AST_CONTROL_RINGING:
04655          ast_indicate(pu->chan, -1);
04656          break;
04657       default:
04658          break;
04659       }
04660       pu->hold_method = 0;
04661 
04662       /* Get chan, exten from derived kludge */
04663       if (pu->peername[0]) {
04664          char *peername;
04665          char *dash;
04666          char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
04667          int i;
04668 
04669          peername = ast_strdupa(pu->peername);
04670          dash = strrchr(peername, '-');
04671          if (dash) {
04672             *dash = '\0';
04673          }
04674 
04675          peername_flat = ast_strdupa(peername);
04676          for (i = 0; peername_flat[i]; i++) {
04677             if (peername_flat[i] == '/') {
04678                peername_flat[i] = '_';
04679             }
04680          }
04681 
04682          if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) {
04683             ast_log(LOG_ERROR,
04684                "Parking dial context '%s' does not exist and unable to create\n",
04685                parking_con_dial);
04686          } else {
04687             char returnexten[AST_MAX_EXTENSION];
04688             struct ast_datastore *features_datastore;
04689             struct ast_dial_features *dialfeatures;
04690 
04691             if (!strncmp(peername, "Parked/", 7)) {
04692                peername += 7;
04693             }
04694 
04695             ast_channel_lock(chan);
04696             features_datastore = ast_channel_datastore_find(chan, &dial_features_info,
04697                NULL);
04698             if (features_datastore && (dialfeatures = features_datastore->data)) {
04699                char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
04700 
04701                snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername,
04702                   callback_dialoptions(&dialfeatures->peer_features,
04703                      &dialfeatures->my_features, buf, sizeof(buf)));
04704             } else { /* Existing default */
04705                ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n",
04706                   chan->name);
04707                snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
04708             }
04709             ast_channel_unlock(chan);
04710 
04711             if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL,
04712                "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) {
04713                ast_log(LOG_ERROR,
04714                   "Could not create parking return dial exten: %s@%s\n",
04715                   peername_flat, parking_con_dial);
04716             }
04717          }
04718          if (pu->options_specified) {
04719             /*
04720              * Park() was called with overriding return arguments, respect
04721              * those arguments.
04722              */
04723             set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04724          } else if (comebacktoorigin) {
04725             set_c_e_p(chan, parking_con_dial, peername_flat, 1);
04726          } else {
04727             char parkingslot[AST_MAX_EXTENSION];
04728 
04729             snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
04730             pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
04731             set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
04732          }
04733       } else {
04734          /*
04735           * They've been waiting too long, send them back to where they
04736           * came.  Theoretically they should have their original
04737           * extensions and such, but we copy to be on the safe side.
04738           */
04739          set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04740       }
04741       post_manager_event("ParkedCallTimeOut", pu);
04742       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
04743 
04744       ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n",
04745          pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context,
04746          pu->chan->exten, pu->chan->priority);
04747 
04748       /* Start up the PBX, or hang them up */
04749       if (ast_pbx_start(chan))  {
04750          ast_log(LOG_WARNING,
04751             "Unable to restart the PBX for user on '%s', hanging them up...\n",
04752             pu->chan->name);
04753          ast_hangup(chan);
04754       }
04755 
04756       /* And take them out of the parking lot */
04757       return 1;
04758    }
04759 
04760    /* still within parking time, process descriptors */
04761    if (pfds) {
04762       for (x = 0; x < AST_MAX_FDS; x++) {
04763          struct ast_frame *f;
04764          int y;
04765 
04766          if (chan->fds[x] == -1) {
04767             continue;   /* nothing on this descriptor */
04768          }
04769 
04770          for (y = 0; y < nfds; y++) {
04771             if (pfds[y].fd == chan->fds[x]) {
04772                /* Found poll record! */
04773                break;
04774             }
04775          }
04776          if (y == nfds) {
04777             /* Not found */
04778             continue;
04779          }
04780 
04781          if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
04782             /* Next x */
04783             continue;
04784          }
04785 
04786          if (pfds[y].revents & POLLPRI) {
04787             ast_set_flag(chan, AST_FLAG_EXCEPTION);
04788          } else {
04789             ast_clear_flag(chan, AST_FLAG_EXCEPTION);
04790          }
04791          chan->fdno = x;
04792 
04793          /* See if they need servicing */
04794          f = ast_read(pu->chan);
04795          /* Hangup? */
04796          if (!f || (f->frametype == AST_FRAME_CONTROL
04797             && f->subclass.integer == AST_CONTROL_HANGUP)) {
04798             if (f) {
04799                ast_frfree(f);
04800             }
04801             post_manager_event("ParkedCallGiveUp", pu);
04802             ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp",
04803                NULL);
04804 
04805             /* There's a problem, hang them up */
04806             ast_verb(2, "%s got tired of being parked\n", chan->name);
04807             ast_hangup(chan);
04808 
04809             /* And take them out of the parking lot */
04810             return 1;
04811          } else {
04812             /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
04813             ast_frfree(f);
04814             if (pu->hold_method == AST_CONTROL_HOLD
04815                && pu->moh_trys < 3
04816                && !chan->generatordata) {
04817                ast_debug(1,
04818                   "MOH on parked call stopped by outside source.  Restarting on channel %s.\n",
04819                   chan->name);
04820                ast_indicate_data(chan, AST_CONTROL_HOLD,
04821                   S_OR(pu->parkinglot->cfg.mohclass, NULL),
04822                   (!ast_strlen_zero(pu->parkinglot->cfg.mohclass)
04823                      ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0));
04824                pu->moh_trys++;
04825             }
04826             break;
04827          }
04828       } /* End for */
04829    }
04830 
04831    /* mark fds for next round */
04832    for (x = 0; x < AST_MAX_FDS; x++) {
04833       if (chan->fds[x] > -1) {
04834          void *tmp = ast_realloc(*new_pfds,
04835             (*new_nfds + 1) * sizeof(struct pollfd));
04836 
04837          if (!tmp) {
04838             continue;
04839          }
04840          *new_pfds = tmp;
04841          (*new_pfds)[*new_nfds].fd = chan->fds[x];
04842          (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
04843          (*new_pfds)[*new_nfds].revents = 0;
04844          (*new_nfds)++;
04845       }
04846    }
04847    /* Keep track of our shortest wait */
04848    if (tms < *ms || *ms < 0) {
04849       *ms = tms;
04850    }
04851 
04852    /* Stay in the parking lot. */
04853    return 0;
04854 }

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 4857 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().

04858 {
04859    struct parkeduser *pu;
04860    struct ast_context *con;
04861 
04862    /* Lock parkings list */
04863    AST_LIST_LOCK(&curlot->parkings);
04864    AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
04865       if (pu->notquiteyet) { /* Pretend this one isn't here yet */
04866          continue;
04867       }
04868       if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) {
04869          /* Parking is complete for this call so remove it from the parking lot. */
04870          con = ast_context_find(pu->parkinglot->cfg.parking_con);
04871          if (con) {
04872             if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
04873                ast_log(LOG_WARNING,
04874                   "Whoa, failed to remove the parking extension %s@%s!\n",
04875                   pu->parkingexten, pu->parkinglot->cfg.parking_con);
04876             }
04877             notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con,
04878                AST_DEVICE_NOT_INUSE);
04879          } else {
04880             ast_log(LOG_WARNING,
04881                "Whoa, parking lot '%s' context '%s' does not exist.\n",
04882                pu->parkinglot->name, pu->parkinglot->cfg.parking_con);
04883          }
04884          AST_LIST_REMOVE_CURRENT(list);
04885          parkinglot_unref(pu->parkinglot);
04886          ast_free(pu);
04887       }
04888    }
04889    AST_LIST_TRAVERSE_SAFE_END;
04890    AST_LIST_UNLOCK(&curlot->parkings);
04891 }

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

References args, 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(), masq_park_call(), and parkinglot_unref().

Referenced by ast_features_init().

07158 {
07159    const char *channel = astman_get_header(m, "Channel");
07160    const char *channel2 = astman_get_header(m, "Channel2");
07161    const char *timeout = astman_get_header(m, "Timeout");
07162    const char *parkinglotname = astman_get_header(m, "Parkinglot");
07163    char buf[BUFSIZ];
07164    int res = 0;
07165    struct ast_channel *ch1, *ch2;
07166    struct ast_park_call_args args = {
07167          /*
07168           * Don't say anything to ch2 since AMI is a third party parking
07169           * a call and we will likely crash if we do.
07170           *
07171           * XXX When the AMI action was originally implemented, the
07172           * parking space was announced to ch2.  Unfortunately, grabbing
07173           * the ch2 lock and holding it while the announcement is played
07174           * was not really a good thing to do to begin with since it
07175           * could hold up the system.  Also holding the lock is no longer
07176           * possible with a masquerade.
07177           *
07178           * Restoring the announcement to ch2 is not easily doable for
07179           * the following reasons:
07180           *
07181           * 1) The AMI manager is not the thread processing ch2.
07182           *
07183           * 2) ch2 could be the same as ch1, bridged to ch1, or some
07184           * random uninvolved channel.
07185           */
07186          .flags = AST_PARK_OPT_SILENCE,
07187       };
07188 
07189    if (ast_strlen_zero(channel)) {
07190       astman_send_error(s, m, "Channel not specified");
07191       return 0;
07192    }
07193 
07194    if (ast_strlen_zero(channel2)) {
07195       astman_send_error(s, m, "Channel2 not specified");
07196       return 0;
07197    }
07198 
07199    if (!ast_strlen_zero(timeout)) {
07200       if (sscanf(timeout, "%30d", &args.timeout) != 1) {
07201          astman_send_error(s, m, "Invalid timeout value.");
07202          return 0;
07203       }
07204    }
07205 
07206    if (!(ch1 = ast_channel_get_by_name(channel))) {
07207       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
07208       astman_send_error(s, m, buf);
07209       return 0;
07210    }
07211 
07212    if (!(ch2 = ast_channel_get_by_name(channel2))) {
07213       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
07214       astman_send_error(s, m, buf);
07215       ast_channel_unref(ch1);
07216       return 0;
07217    }
07218 
07219    if (!ast_strlen_zero(parkinglotname)) {
07220       args.parkinglot = find_parkinglot(parkinglotname);
07221    }
07222 
07223    res = masq_park_call(ch1, ch2, &args);
07224    if (!res) {
07225       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
07226       astman_send_ack(s, m, "Park successful");
07227    } else {
07228       astman_send_error(s, m, "Park failure");
07229    }
07230 
07231    if (args.parkinglot) {
07232       parkinglot_unref(args.parkinglot);
07233    }
07234    ch1 = ast_channel_unref(ch1);
07235    ch2 = ast_channel_unref(ch2);
07236 
07237    return 0;
07238 }

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 7091 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_channel::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().

07092 {
07093    struct parkeduser *cur;
07094    const char *id = astman_get_header(m, "ActionID");
07095    char idText[256] = "";
07096    struct ao2_iterator iter;
07097    struct ast_parkinglot *curlot;
07098    int numparked = 0;
07099 
07100    if (!ast_strlen_zero(id))
07101       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
07102 
07103    astman_send_ack(s, m, "Parked calls will follow");
07104 
07105    iter = ao2_iterator_init(parkinglots, 0);
07106    while ((curlot = ao2_iterator_next(&iter))) {
07107       AST_LIST_LOCK(&curlot->parkings);
07108       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
07109          astman_append(s, "Event: ParkedCall\r\n"
07110             "Parkinglot: %s\r\n"
07111             "Exten: %d\r\n"
07112             "Channel: %s\r\n"
07113             "From: %s\r\n"
07114             "Timeout: %ld\r\n"
07115             "CallerIDNum: %s\r\n"
07116             "CallerIDName: %s\r\n"
07117             "ConnectedLineNum: %s\r\n"
07118             "ConnectedLineName: %s\r\n"
07119             "%s"
07120             "\r\n",
07121             curlot->name,
07122             cur->parkingnum, cur->chan->name, cur->peername,
07123             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
07124             S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""),   /* XXX in other places it is <unknown> */
07125             S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
07126             S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""),   /* XXX in other places it is <unknown> */
07127             S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""),
07128             idText);
07129          ++numparked;
07130       }
07131       AST_LIST_UNLOCK(&curlot->parkings);
07132       ao2_ref(curlot, -1);
07133    }
07134    ao2_iterator_destroy(&iter);
07135 
07136    astman_append(s,
07137       "Event: ParkedCallsComplete\r\n"
07138       "Total: %d\r\n"
07139       "%s"
07140       "\r\n",
07141       numparked, idText);
07142 
07143    return RESULT_SUCCESS;
07144 }

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

References ast_channel::accountcode, ast_channel::amaflags, args, 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, ast_channel::linkedid, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, ast_channel::name, park_call_full(), park_space_abort(), park_space_reserve(), play_message_on_chan(), ast_channel::priority, 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().

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

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

metermaids callback from devicestate.c

Definition at line 1101 of file features.c.

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

Referenced by ast_features_init().

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

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

Notify metermaids that we've changed an extension.

Definition at line 1092 of file features.c.

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

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

01093 {
01094    ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
01095       exten, context, ast_devstate2str(state));
01096 
01097    ast_devstate_changed(state, "park:%s@%s", exten, context);
01098 }

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

Add parking hints for all defined parking spaces.

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

Definition at line 5401 of file features.c.

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

Referenced by parkinglot_activate().

05402 {
05403    int numext;
05404    char device[AST_MAX_EXTENSION];
05405    char exten[10];
05406 
05407    for (numext = start; numext <= stop; numext++) {
05408       snprintf(exten, sizeof(exten), "%d", numext);
05409       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
05410       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
05411    }
05412 }

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

Park a call.

Definition at line 4980 of file features.c.

References ast_channel::_state, args, 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, LOG_WARNING, masq_park_call(), ast_channel::name, park_app_args::options, orig_exten(), park_call_options, parkeddynamic, parkinglot_addref(), parkinglot_unref(), parse(), pbx_builtin_getvar_helper(), park_app_args::pl_name, ast_channel::priority, park_app_args::return_con, park_app_args::return_ext, park_app_args::return_pri, S_OR, and park_app_args::timeout.

Referenced by ast_features_init().

04981 {
04982    struct ast_park_call_args args = { 0, };
04983    struct ast_flags flags = { 0 };
04984    char orig_exten[AST_MAX_EXTENSION];
04985    int orig_priority;
04986    int res;
04987    const char *pl_name;
04988    char *parse;
04989    struct park_app_args app_args;
04990 
04991    /*
04992     * Cache the original channel name because we are going to
04993     * masquerade the channel.  Prefer the BLINDTRANSFER channel
04994     * name over this channel name.  BLINDTRANSFER could be set if
04995     * the parking access extension did not get detected and we are
04996     * executing the Park application from the dialplan.
04997     *
04998     * The orig_chan_name is used to return the call to the
04999     * originator on parking timeout.
05000     */
05001    args.orig_chan_name = ast_strdupa(S_OR(
05002       pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), chan->name));
05003 
05004    /* Answer if call is not up */
05005    if (chan->_state != AST_STATE_UP) {
05006       if (ast_answer(chan)) {
05007          return -1;
05008       }
05009 
05010       /* Sleep to allow VoIP streams to settle down */
05011       if (ast_safe_sleep(chan, 1000)) {
05012          return -1;
05013       }
05014    }
05015 
05016    /* Process the dialplan application options. */
05017    parse = ast_strdupa(data);
05018    AST_STANDARD_APP_ARGS(app_args, parse);
05019 
05020    if (!ast_strlen_zero(app_args.timeout)) {
05021       if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
05022          ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
05023          args.timeout = 0;
05024       }
05025    }
05026    if (!ast_strlen_zero(app_args.return_con)) {
05027       args.return_con = app_args.return_con;
05028    }
05029    if (!ast_strlen_zero(app_args.return_ext)) {
05030       args.return_ext = app_args.return_ext;
05031    }
05032    if (!ast_strlen_zero(app_args.return_pri)) {
05033       if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
05034          ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
05035          args.return_pri = 0;
05036       }
05037    }
05038 
05039    ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
05040    args.flags = flags.flags;
05041 
05042    /*
05043     * Setup the exten/priority to be s/1 since we don't know where
05044     * this call should return.
05045     */
05046    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
05047    orig_priority = chan->priority;
05048    strcpy(chan->exten, "s");
05049    chan->priority = 1;
05050 
05051    /* Park the call */
05052    if (!ast_strlen_zero(app_args.pl_name)) {
05053       pl_name = app_args.pl_name;
05054    } else {
05055       pl_name = findparkinglotname(chan);
05056    }
05057    if (ast_strlen_zero(pl_name)) {
05058       /* Parking lot is not specified, so use the default parking lot. */
05059       args.parkinglot = parkinglot_addref(default_parkinglot);
05060    } else {
05061       args.parkinglot = find_parkinglot(pl_name);
05062       if (!args.parkinglot && parkeddynamic) {
05063          args.parkinglot = create_dynamic_parkinglot(pl_name, chan);
05064       }
05065    }
05066    if (args.parkinglot) {
05067       res = masq_park_call(chan, chan, &args);
05068       parkinglot_unref(args.parkinglot);
05069    } else {
05070       /* Parking failed because the parking lot does not exist. */
05071       if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
05072          ast_stream_and_wait(chan, "pbx-parkingfailed", "");
05073       }
05074       res = -1;
05075    }
05076    if (res) {
05077       /* Park failed, try to continue in the dialplan. */
05078       ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
05079       chan->priority = orig_priority;
05080       res = 0;
05081    } else {
05082       /* Park succeeded. */
05083       res = -1;
05084    }
05085 
05086    return res;
05087 }

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

Definition at line 1466 of file features.c.

References adsi_announce_park(), adsipark, ast_channel::appl, args, 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, parkeduser::hold_method, ast_party_connected_line::id, ast_party_caller::id, ast_channel::language, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, parkinglot_cfg::mohclass, ast_party_id::name, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkeduser::options_specified, park_space_reserve(), parkinglot_cfg::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, parkinglot_cfg::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, registrar, S_COR, S_OR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_channel::tech, ast_channel_tech::type, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.

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

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

static void park_space_abort ( struct parkeduser pu  )  [static]

Definition at line 1268 of file features.c.

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

Referenced by masq_park_call().

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

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

Definition at line 1295 of file features.c.

References args, ast_calloc, ast_debug, ast_free, 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, find_parkinglot(), findparkinglotname(), LOG_WARNING, ast_channel::name, parkeddynamic, parkinglot_cfg::parking_start, parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, pbx_builtin_getvar_helper(), and S_OR.

Referenced by masq_park_call(), and park_call_full().

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

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

Pickup parked call.

< Parking lot space to retrieve if present.

< Parking lot name to use if present.

< Place to put any remaining args string.

Definition at line 5090 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, parkeduser::chan, config, connected, ast_channel::connected, courtesytone, ast_datastore::data, default_parkinglot, dial_features_info, dummy(), EVENT_FLAG_CALL, 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, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkedplay, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, parse(), ast_channel::pbx, pbx_builtin_setvar_helper(), play_message_to_chans(), S_COR, ast_party_name::str, ast_party_number::str, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.

Referenced by ast_features_init().

05091 {
05092    int res;
05093    struct ast_channel *peer = NULL;
05094    struct parkeduser *pu;
05095    struct ast_context *con;
05096    char *parse;
05097    const char *pl_name;
05098    int park = 0;
05099    struct ast_bridge_config config;
05100    struct ast_parkinglot *parkinglot;
05101    AST_DECLARE_APP_ARGS(app_args,
05102       AST_APP_ARG(pl_space);  /*!< Parking lot space to retrieve if present. */
05103       AST_APP_ARG(pl_name);   /*!< Parking lot name to use if present. */
05104       AST_APP_ARG(dummy);     /*!< Place to put any remaining args string. */
05105    );
05106 
05107    parse = ast_strdupa(data);
05108    AST_STANDARD_APP_ARGS(app_args, parse);
05109 
05110    if (!ast_strlen_zero(app_args.pl_space)) {
05111       if (sscanf(app_args.pl_space, "%30u", &park) != 1) {
05112          ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n",
05113             app_args.pl_space);
05114          park = -1;
05115       }
05116    }
05117 
05118    if (!ast_strlen_zero(app_args.pl_name)) {
05119       pl_name = app_args.pl_name;
05120    } else {
05121       pl_name = findparkinglotname(chan);
05122    }
05123    if (ast_strlen_zero(pl_name)) {
05124       /* Parking lot is not specified, so use the default parking lot. */
05125       parkinglot = parkinglot_addref(default_parkinglot);
05126    } else {
05127       parkinglot = find_parkinglot(pl_name);
05128       if (!parkinglot) {
05129          /* It helps to answer the channel if not already up. :) */
05130          if (chan->_state != AST_STATE_UP) {
05131             ast_answer(chan);
05132          }
05133          if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05134             ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n",
05135                "pbx-invalidpark", chan->name);
05136          }
05137          ast_log(LOG_WARNING,
05138             "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
05139             chan->name, pl_name);
05140          return -1;
05141       }
05142    }
05143 
05144    AST_LIST_LOCK(&parkinglot->parkings);
05145    AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
05146       if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
05147          && !pu->notquiteyet && !pu->chan->pbx) {
05148          /* The parking space has a call and can be picked up now. */
05149          AST_LIST_REMOVE_CURRENT(list);
05150          break;
05151       }
05152    }
05153    AST_LIST_TRAVERSE_SAFE_END;
05154    if (pu) {
05155       /* Found a parked call to pickup. */
05156       peer = pu->chan;
05157       con = ast_context_find(parkinglot->cfg.parking_con);
05158       if (con) {
05159          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
05160             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
05161          } else {
05162             notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
05163          }
05164       } else {
05165          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
05166       }
05167 
05168       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
05169       ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
05170          "Exten: %s\r\n"
05171          "Channel: %s\r\n"
05172          "Parkinglot: %s\r\n"
05173          "From: %s\r\n"
05174          "CallerIDNum: %s\r\n"
05175          "CallerIDName: %s\r\n"
05176          "ConnectedLineNum: %s\r\n"
05177          "ConnectedLineName: %s\r\n"
05178          "Uniqueid: %s\r\n",
05179          pu->parkingexten, pu->chan->name, pu->parkinglot->name, chan->name,
05180          S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
05181          S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
05182          S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
05183          S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
05184          pu->chan->uniqueid
05185          );
05186 
05187       /* Stop entertaining the caller. */
05188       switch (pu->hold_method) {
05189       case AST_CONTROL_HOLD:
05190          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
05191          break;
05192       case AST_CONTROL_RINGING:
05193          ast_indicate(pu->chan, -1);
05194          break;
05195       default:
05196          break;
05197       }
05198       pu->hold_method = 0;
05199 
05200       parkinglot_unref(pu->parkinglot);
05201       ast_free(pu);
05202    }
05203    AST_LIST_UNLOCK(&parkinglot->parkings);
05204 
05205    if (peer) {
05206       /* Update connected line between retrieving call and parked call. */
05207       struct ast_party_connected_line connected;
05208 
05209       ast_party_connected_line_init(&connected);
05210 
05211       /* Send our caller-id to peer. */
05212       ast_channel_lock(chan);
05213       ast_connected_line_copy_from_caller(&connected, &chan->caller);
05214       ast_channel_unlock(chan);
05215       connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05216       if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) {
05217          ast_channel_update_connected_line(peer, &connected, NULL);
05218       }
05219 
05220       /*
05221        * Get caller-id from peer.
05222        *
05223        * Update the retrieving call before it is answered if possible
05224        * for best results.  Some phones do not support updating the
05225        * connected line information after connection.
05226        */
05227       ast_channel_lock(peer);
05228       ast_connected_line_copy_from_caller(&connected, &peer->caller);
05229       ast_channel_unlock(peer);
05230       connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05231       if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) {
05232          ast_channel_update_connected_line(chan, &connected, NULL);
05233       }
05234 
05235       ast_party_connected_line_free(&connected);
05236    }
05237 
05238    /* JK02: it helps to answer the channel if not already up */
05239    if (chan->_state != AST_STATE_UP) {
05240       ast_answer(chan);
05241    }
05242 
05243    if (peer) {
05244       struct ast_datastore *features_datastore;
05245       struct ast_dial_features *dialfeatures;
05246 
05247       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
05248       if (!ast_strlen_zero(courtesytone)) {
05249          static const char msg[] = "courtesy tone";
05250 
05251          switch (parkedplay) {
05252          case 0:/* Courtesy tone to pickup chan */
05253             res = play_message_to_chans(chan, peer, -1, msg, courtesytone);
05254             break;
05255          case 1:/* Courtesy tone to parked chan */
05256             res = play_message_to_chans(chan, peer, 1, msg, courtesytone);
05257             break;
05258          case 2:/* Courtesy tone to both chans */
05259             res = play_message_to_chans(chan, peer, 0, msg, courtesytone);
05260             break;
05261          default:
05262             res = 0;
05263             break;
05264          }
05265          if (res) {
05266             ast_hangup(peer);
05267             parkinglot_unref(parkinglot);
05268             return -1;
05269          }
05270       }
05271 
05272       res = ast_channel_make_compatible(chan, peer);
05273       if (res < 0) {
05274          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
05275          ast_hangup(peer);
05276          parkinglot_unref(parkinglot);
05277          return -1;
05278       }
05279       /* This runs sorta backwards, since we give the incoming channel control, as if it
05280          were the person called. */
05281       ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
05282 
05283       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05284       ast_cdr_setdestchan(chan->cdr, peer->name);
05285       memset(&config, 0, sizeof(struct ast_bridge_config));
05286 
05287       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
05288       ast_channel_lock(peer);
05289       features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL);
05290       if (features_datastore && (dialfeatures = features_datastore->data)) {
05291          ast_copy_flags(&config.features_callee, &dialfeatures->my_features,
05292             AST_FLAGS_ALL);
05293       }
05294       ast_channel_unlock(peer);
05295 
05296       if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05297          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
05298       }
05299       if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05300          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
05301       }
05302       if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05303          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
05304       }
05305       if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05306          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
05307       }
05308       if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05309          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
05310       }
05311       if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05312          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
05313       }
05314       if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05315          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
05316       }
05317       if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05318          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
05319       }
05320 
05321       res = ast_bridge_call(chan, peer, &config);
05322 
05323       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05324       ast_cdr_setdestchan(chan->cdr, peer->name);
05325 
05326       /* Simulate the PBX hanging up */
05327       ast_hangup(peer);
05328    } else {
05329       if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05330          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
05331             chan->name);
05332       }
05333       ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n",
05334          chan->name, park);
05335       res = -1;
05336    }
05337 
05338    parkinglot_unref(parkinglot);
05339    return res;
05340 }

static int parkinglot_activate ( struct ast_parkinglot parkinglot  )  [static]

Definition at line 5551 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, LOG_ERROR, notify_metermaids(), park_add_hints(), parkcall, parkinglot, and registrar.

Referenced by create_dynamic_parkinglot(), and parkinglot_activate_cb().

05552 {
05553    int disabled = 0;
05554    char app_data[5 + AST_MAX_CONTEXT];
05555 
05556    /* Create Park option list.  Must match with struct park_app_args options. */
05557    if (parkinglot->cfg.parkext_exclusive) {
05558       /* Specify the parking lot this parking extension parks calls. */
05559       snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name);
05560    } else {
05561       /* The dialplan must specify which parking lot to use. */
05562       app_data[0] = '\0';
05563    }
05564 
05565    /* Create context */
05566    if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) {
05567       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n",
05568          parkinglot->cfg.parking_con);
05569       disabled = 1;
05570 
05571    /* Add a parking extension into the context */
05572    } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext,
05573       1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
05574       ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n",
05575          parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con);
05576       disabled = 1;
05577    } else {
05578       /* Add parking hints */
05579       if (parkinglot->cfg.parkaddhints) {
05580          park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start,
05581             parkinglot->cfg.parking_stop);
05582       }
05583 
05584       /*
05585        * XXX Not sure why we should need to notify the metermaids for
05586        * this exten.  It was originally done for the default parking
05587        * lot entry exten only but should be done for all entry extens
05588        * if we do it for one.
05589        */
05590       /* Notify metermaids about parking lot entry exten state. */
05591       notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con,
05592          AST_DEVICE_INUSE);
05593    }
05594 
05595    parkinglot->disabled = disabled;
05596    return disabled ? -1 : 0;
05597 }

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

Definition at line 6600 of file features.c.

References ast_debug, ast_log(), force_reload_load, LOG_WARNING, parkinglot, and parkinglot_activate().

Referenced by load_config().

06601 {
06602    struct ast_parkinglot *parkinglot = obj;
06603 
06604    if (parkinglot->the_mark) {
06605       /*
06606        * Don't activate a parking lot that still bears the_mark since
06607        * it is effectively deleted.
06608        */
06609       return 0;
06610    }
06611 
06612    if (parkinglot_activate(parkinglot)) {
06613       /*
06614        * The parking lot failed to activate.  Allow reloading later to
06615        * see if that fixes it.
06616        */
06617       force_reload_load = 1;
06618       ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name);
06619    } else {
06620       ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n",
06621          parkinglot->name, parkinglot->cfg.parking_start,
06622          parkinglot->cfg.parking_stop);
06623    }
06624 
06625    return 0;
06626 }

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

Definition at line 5352 of file features.c.

References ao2_ref, ast_debug, and parkinglot.

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

05353 {
05354    int refcount;
05355 
05356    refcount = ao2_ref(parkinglot, +1);
05357    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
05358    return parkinglot;
05359 }

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

Definition at line 865 of file features.c.

References CMP_MATCH, CMP_STOP, ast_parkinglot::name, and parkinglot.

Referenced by ast_features_init().

00866 {
00867    struct ast_parkinglot *parkinglot = obj;
00868    struct ast_parkinglot *parkinglot2 = arg;
00869 
00870    return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00871 }

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

Definition at line 5463 of file features.c.

References ast_copy_string(), ast_log(), ast_strlen_zero(), ast_true(), parkinglot_cfg::is_invalid, LOG_WARNING, parkinglot_cfg::mohclass, parkinglot_cfg::parkaddhints, parkinglot_cfg::parkedcallhangup, parkinglot_cfg::parkedcallrecording, parkinglot_cfg::parkedcallreparking, parkinglot_cfg::parkedcalltransfers, parkinglot_cfg::parkext, parkinglot_cfg::parkext_exclusive, parkinglot_cfg::parkfindnext, parkinglot_cfg::parking_con, parkinglot_cfg::parking_start, parkinglot_cfg::parking_stop, parkinglot_feature_flag_cfg(), parkinglot_cfg::parkingtime, and var.

Referenced by build_parkinglot().

05464 {
05465    int error = 0;
05466 
05467    while (var) {
05468       if (!strcasecmp(var->name, "context")) {
05469          ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con));
05470       } else if (!strcasecmp(var->name, "parkext")) {
05471          ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext));
05472       } else if (!strcasecmp(var->name, "parkext_exclusive")) {
05473          cfg->parkext_exclusive = ast_true(var->value);
05474       } else if (!strcasecmp(var->name, "parkinghints")) {
05475          cfg->parkaddhints = ast_true(var->value);
05476       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
05477          ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass));
05478       } else if (!strcasecmp(var->name, "parkingtime")) {
05479          int parkingtime = 0;
05480 
05481          if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) {
05482             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
05483             error = -1;
05484          } else {
05485             cfg->parkingtime = parkingtime * 1000;
05486          }
05487       } else if (!strcasecmp(var->name, "parkpos")) {
05488          int start = 0;
05489          int end = 0;
05490 
05491          if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
05492             ast_log(LOG_WARNING,
05493                "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n",
05494                var->lineno, var->file);
05495             error = -1;
05496          } else if (end < start || start <= 0 || end <= 0) {
05497             ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n",
05498                var->lineno, var->file);
05499             error = -1;
05500          } else {
05501             cfg->parking_start = start;
05502             cfg->parking_stop = end;
05503          }
05504       } else if (!strcasecmp(var->name, "findslot")) {
05505          cfg->parkfindnext = (!strcasecmp(var->value, "next"));
05506       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
05507          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var);
05508       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
05509          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var);
05510       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
05511          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var);
05512       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
05513          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var);
05514       }
05515       var = var->next;
05516    }
05517 
05518    /* Check for configuration errors */
05519    if (ast_strlen_zero(cfg->parking_con)) {
05520       ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name);
05521       error = -1;
05522    }
05523    if (ast_strlen_zero(cfg->parkext)) {
05524       ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name);
05525       error = -1;
05526    }
05527    if (!cfg->parking_start) {
05528       ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name);
05529       error = -1;
05530    }
05531    if (error) {
05532       cfg->is_invalid = 1;
05533    }
05534 
05535    return error;
05536 }

static void parkinglot_destroy ( void *  obj  )  [static]

Destroy a parking lot.

Definition at line 5362 of file features.c.

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

Referenced by create_parkinglot().

05363 {
05364    struct ast_parkinglot *doomed = obj;
05365 
05366    /*
05367     * No need to destroy parked calls here because any parked call
05368     * holds a parking lot reference.  Therefore the parkings list
05369     * must be empty.
05370     */
05371    ast_assert(AST_LIST_EMPTY(&doomed->parkings));
05372    AST_LIST_HEAD_DESTROY(&doomed->parkings);
05373 }

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

Definition at line 5440 of file features.c.

References ast_debug, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, and var.

Referenced by parkinglot_config_read().

05441 {
05442    ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value);
05443    if (!strcasecmp(var->value, "both")) {
05444       *param = AST_FEATURE_FLAG_BYBOTH;
05445    } else if (!strcasecmp(var->value, "caller")) {
05446       *param = AST_FEATURE_FLAG_BYCALLER;
05447    } else if (!strcasecmp(var->value, "callee")) {
05448       *param = AST_FEATURE_FLAG_BYCALLEE;
05449    }
05450 }

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

Definition at line 858 of file features.c.

References ast_str_case_hash(), and parkinglot.

Referenced by ast_features_init().

00859 {
00860    const struct ast_parkinglot *parkinglot = obj;
00861 
00862    return ast_str_case_hash(parkinglot->name);
00863 }

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

Definition at line 6580 of file features.c.

References AST_LIST_EMPTY, ast_log(), CMP_MATCH, force_reload_load, LOG_WARNING, and parkinglot.

Referenced by load_config().

06581 {
06582    struct ast_parkinglot *parkinglot = obj;
06583 
06584    if (parkinglot->the_mark) {
06585       if (AST_LIST_EMPTY(&parkinglot->parkings)) {
06586          /* This parking lot can actually be deleted. */
06587          return CMP_MATCH;
06588       }
06589       /* Try reloading later when parking lot is empty. */
06590       ast_log(LOG_WARNING,
06591          "Parking lot %s has parked calls.  Could not remove.\n",
06592          parkinglot->name);
06593       parkinglot->disabled = 1;
06594       force_reload_load = 1;
06595    }
06596 
06597    return 0;
06598 }

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

Definition at line 6572 of file features.c.

References parkinglot.

Referenced by load_config().

06573 {
06574    struct ast_parkinglot *parkinglot = obj;
06575 
06576    parkinglot->the_mark = 1;
06577    return 0;
06578 }

static void parkinglot_unref ( struct ast_parkinglot parkinglot  )  [static]

Unreference parkinglot object.

Definition at line 5345 of file features.c.

References ao2_ref, ast_debug, and parkinglot.

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().

05346 {
05347    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name,
05348       ao2_ref(parkinglot, 0) - 1);
05349    ao2_ref(parkinglot, -1);
05350 }

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

return the first unlocked cdr in a possible chain

Definition at line 3821 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

03822 {
03823    struct ast_cdr *cdr_orig = cdr;
03824    while (cdr) {
03825       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
03826          return cdr;
03827       cdr = cdr->next;
03828    }
03829    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
03830 }

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

References play_message_to_chans().

Referenced by builtin_automonitor().

02067 {
02068    return play_message_to_chans(caller_chan, callee_chan, 0, "automon message",
02069       audiofile);
02070 }

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 2012 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().

02013 {
02014    /* Put other channel in autoservice. */
02015    if (ast_autoservice_start(other)) {
02016       return -1;
02017    }
02018    ast_autoservice_ignore(other, AST_FRAME_DTMF_BEGIN);
02019    ast_autoservice_ignore(other, AST_FRAME_DTMF_END);
02020    if (ast_stream_and_wait(play_to, audiofile, "")) {
02021       ast_log(LOG_WARNING, "Failed to play %s '%s'!\n", msg, audiofile);
02022       ast_autoservice_stop(other);
02023       return -1;
02024    }
02025    if (ast_autoservice_stop(other)) {
02026       return -1;
02027    }
02028    return 0;
02029 }

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

References play_message_on_chan().

Referenced by parked_call_exec(), and play_message_in_bridged_call().

02048 {
02049    /* First play the file to the left channel if requested. */
02050    if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) {
02051       return -1;
02052    }
02053 
02054    /* Then play the file to the right channel if requested. */
02055    if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) {
02056       return -1;
02057    }
02058 
02059    return 0;
02060 }

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

Output parking event to manager.

Definition at line 4564 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_channel::name, ast_party_id::number, parkeduser::parkingexten, parkeduser::parkinglot, S_COR, ast_party_name::str, ast_party_number::str, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.

Referenced by manage_parked_call().

04565 {
04566    manager_event(EVENT_FLAG_CALL, s,
04567       "Exten: %s\r\n"
04568       "Channel: %s\r\n"
04569       "Parkinglot: %s\r\n"
04570       "CallerIDNum: %s\r\n"
04571       "CallerIDName: %s\r\n"
04572       "ConnectedLineNum: %s\r\n"
04573       "ConnectedLineName: %s\r\n"
04574       "UniqueID: %s\r\n",
04575       pu->parkingexten, 
04576       pu->chan->name,
04577       pu->parkinglot->name,
04578       S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
04579       S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
04580       S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
04581       S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
04582       pu->chan->uniqueid
04583       );
04584 }

static void process_applicationmap_line ( struct ast_variable var  )  [static]

Definition at line 5679 of file features.c.

References 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, feature_group_exten::feature, 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, strsep(), and var.

05680 {
05681    char *tmp_val = ast_strdupa(var->value);
05682    char *activateon, *new_syn;
05683    struct ast_call_feature *feature;
05684    AST_DECLARE_APP_ARGS(args,
05685       AST_APP_ARG(exten);
05686       AST_APP_ARG(activatedby);
05687       AST_APP_ARG(app);
05688       AST_APP_ARG(app_args);
05689       AST_APP_ARG(moh_class);
05690    );
05691 
05692    AST_STANDARD_APP_ARGS(args, tmp_val);
05693    if ((new_syn = strchr(args.app, '('))) {
05694       /* New syntax */
05695       args.moh_class = args.app_args;
05696       args.app_args = new_syn;
05697       *args.app_args++ = '\0';
05698       if (args.app_args[strlen(args.app_args) - 1] == ')') {
05699          args.app_args[strlen(args.app_args) - 1] = '\0';
05700       }
05701    }
05702 
05703    activateon = strsep(&args.activatedby, "/");
05704 
05705    /*! \todo XXX var_name or app_args ? */
05706    if (ast_strlen_zero(args.app)
05707       || ast_strlen_zero(args.exten)
05708       || ast_strlen_zero(activateon)
05709       || ast_strlen_zero(var->name)) {
05710       ast_log(LOG_NOTICE,
05711          "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
05712          args.app, args.exten, activateon, var->name);
05713       return;
05714    }
05715 
05716    AST_RWLIST_RDLOCK(&feature_list);
05717    if (find_dynamic_feature(var->name)) {
05718       AST_RWLIST_UNLOCK(&feature_list);
05719       ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n",
05720          var->name);
05721       return;
05722    }
05723    AST_RWLIST_UNLOCK(&feature_list);
05724 
05725    if (!(feature = ast_calloc(1, sizeof(*feature)))) {
05726       return;
05727    }
05728 
05729    ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
05730    ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
05731    ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
05732 
05733    if (args.app_args) {
05734       ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
05735    }
05736 
05737    if (args.moh_class) {
05738       ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
05739    }
05740 
05741    ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
05742    feature->operation = feature_exec_app;
05743    ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
05744 
05745    /* Allow caller and callee to be specified for backwards compatability */
05746    if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) {
05747       ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
05748    } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) {
05749       ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
05750    } else {
05751       ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
05752          " must be 'self', or 'peer'\n", var->name);
05753       ast_free(feature);
05754       return;
05755    }
05756 
05757    if (ast_strlen_zero(args.activatedby)) {
05758       ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05759    } else if (!strcasecmp(args.activatedby, "caller")) {
05760       ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
05761    } else if (!strcasecmp(args.activatedby, "callee")) {
05762       ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
05763    } else if (!strcasecmp(args.activatedby, "both")) {
05764       ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05765    } else {
05766       ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
05767          " must be 'caller', or 'callee', or 'both'\n", var->name);
05768       ast_free(feature);
05769       return;
05770    }
05771 
05772    ast_register_feature(feature);
05773 
05774    ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n",
05775       var->name, args.app, args.app_args, args.exten);
05776 }

static int process_config ( struct ast_config cfg  )  [static]

Definition at line 5778 of file features.c.

References adsipark, ast_true(), 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, parkeddynamic, parkedplay, pickupfailsound, pickupsound, transferdigittimeout, var, xferfailsound, and xfersound.

Referenced by load_config().

05779 {
05780    int i;
05781    struct ast_variable *var = NULL;
05782    struct feature_group *fg = NULL;
05783    char *ctg; 
05784    static const char * const categories[] = { 
05785       /* Categories in features.conf that are not
05786        * to be parsed as group categories
05787        */
05788       "general",
05789       "featuremap",
05790       "applicationmap"
05791    };
05792 
05793    /* Set general features global defaults. */
05794    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05795 
05796    /* Set global call pickup defaults. */
05797    strcpy(pickup_ext, "*8");
05798    pickupsound[0] = '\0';
05799    pickupfailsound[0] = '\0';
05800 
05801    /* Set global call transfer defaults. */
05802    strcpy(xfersound, "beep");
05803    strcpy(xferfailsound, "beeperr");
05804    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05805    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05806    atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05807    atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
05808    atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05809 
05810    /* Set global call parking defaults. */
05811    comebacktoorigin = 1;
05812    courtesytone[0] = '\0';
05813    parkedplay = 0;
05814    adsipark = 0;
05815    parkeddynamic = 0;
05816 
05817    var = ast_variable_browse(cfg, "general");
05818    build_parkinglot(DEFAULT_PARKINGLOT, var);
05819    for (; var; var = var->next) {
05820       if (!strcasecmp(var->name, "parkeddynamic")) {
05821          parkeddynamic = ast_true(var->value);
05822       } else if (!strcasecmp(var->name, "adsipark")) {
05823          adsipark = ast_true(var->value);
05824       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
05825          if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
05826             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
05827             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05828          } else {
05829             transferdigittimeout = transferdigittimeout * 1000;
05830          }
05831       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
05832          if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
05833             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
05834             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05835          }
05836       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
05837          if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
05838             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
05839             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05840          } else {
05841             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
05842          }
05843       } else if (!strcasecmp(var->name, "atxferloopdelay")) {
05844          if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
05845             ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
05846             atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05847          } else {
05848             atxferloopdelay *= 1000;
05849          }
05850       } else if (!strcasecmp(var->name, "atxferdropcall")) {
05851          atxferdropcall = ast_true(var->value);
05852       } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
05853          if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
05854             ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
05855             atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05856          }
05857       } else if (!strcasecmp(var->name, "courtesytone")) {
05858          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
05859       }  else if (!strcasecmp(var->name, "parkedplay")) {
05860          if (!strcasecmp(var->value, "both")) {
05861             parkedplay = 2;
05862          } else if (!strcasecmp(var->value, "parked")) {
05863             parkedplay = 1;
05864          } else {
05865             parkedplay = 0;
05866          }
05867       } else if (!strcasecmp(var->name, "xfersound")) {
05868          ast_copy_string(xfersound, var->value, sizeof(xfersound));
05869       } else if (!strcasecmp(var->name, "xferfailsound")) {
05870          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
05871       } else if (!strcasecmp(var->name, "pickupexten")) {
05872          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
05873       } else if (!strcasecmp(var->name, "pickupsound")) {
05874          ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
05875       } else if (!strcasecmp(var->name, "pickupfailsound")) {
05876          ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
05877       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
05878          comebacktoorigin = ast_true(var->value);
05879       }
05880    }
05881 
05882    unmap_features();
05883    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
05884       if (remap_feature(var->name, var->value)) {
05885          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
05886       }
05887    }
05888 
05889    /* Map a key combination to an application */
05890    ast_unregister_features();
05891    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
05892       process_applicationmap_line(var);
05893    }
05894 
05895    ast_unregister_groups();
05896    AST_RWLIST_WRLOCK(&feature_groups);
05897 
05898    ctg = NULL;
05899    while ((ctg = ast_category_browse(cfg, ctg))) {
05900       /* Is this a parkinglot definition ? */
05901       if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
05902          ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
05903          if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) {
05904             ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
05905          } else {
05906             ast_debug(1, "Configured parking context %s\n", ctg);
05907          }
05908          continue;   
05909       }
05910 
05911       /* No, check if it's a group */
05912       for (i = 0; i < ARRAY_LEN(categories); i++) {
05913          if (!strcasecmp(categories[i], ctg)) {
05914             break;
05915          }
05916       }
05917       if (i < ARRAY_LEN(categories)) {
05918          continue;
05919       }
05920 
05921       if (!(fg = register_group(ctg))) {
05922          continue;
05923       }
05924 
05925       for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
05926          struct ast_call_feature *feature;
05927 
05928          AST_RWLIST_RDLOCK(&feature_list);
05929          if (!(feature = find_dynamic_feature(var->name)) && 
05930              !(feature = ast_find_call_feature(var->name))) {
05931             AST_RWLIST_UNLOCK(&feature_list);
05932             ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
05933             continue;
05934          }
05935          AST_RWLIST_UNLOCK(&feature_list);
05936 
05937          register_group_feature(fg, var->value, feature);
05938       }
05939    }
05940 
05941    AST_RWLIST_UNLOCK(&feature_groups);
05942 
05943    return 0;
05944 }

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 2300 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().

02301 {
02302    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
02303    if (ast_strlen_zero(s)) {
02304       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
02305    }
02306    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
02307       s = transferer->macrocontext;
02308    }
02309    if (ast_strlen_zero(s)) {
02310       s = transferer->context;
02311    }
02312    return s;  
02313 }

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

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

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

02989 {
02990    struct feature_group *fg;
02991 
02992    if (!fgname) {
02993       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
02994       return NULL;
02995    }
02996 
02997    if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) {
02998       return NULL;
02999    }
03000 
03001    ast_string_field_set(fg, gname, fgname);
03002 
03003    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
03004 
03005    ast_verb(2, "Registered group '%s'\n", fg->gname);
03006 
03007    return fg;
03008 }

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

References ast_calloc_with_stringfields, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_set, ast_verb, feature_group_exten::entry, 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.

03020 {
03021    struct feature_group_exten *fge;
03022 
03023    if (!fg) {
03024       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
03025       return;
03026    }
03027 
03028    if (!feature) {
03029       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
03030       return;
03031    }
03032 
03033    if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) {
03034       return;
03035    }
03036 
03037    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
03038 
03039    fge->feature = feature;
03040 
03041    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
03042 
03043    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
03044                feature->sname, fg->gname, fge->exten);
03045 }

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

Definition at line 3225 of file features.c.

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

03226 {
03227    int x, res = -1;
03228 
03229    ast_rwlock_wrlock(&features_lock);
03230    for (x = 0; x < FEATURES_COUNT; x++) {
03231       if (strcasecmp(builtin_features[x].sname, name))
03232          continue;
03233 
03234       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
03235       res = 0;
03236       break;
03237    }
03238    ast_rwlock_unlock(&features_lock);
03239 
03240    return res;
03241 }

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

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

Referenced by remove_dead_dialplan_useage().

06506 {
06507    remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens);
06508    remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space);
06509 #if 0
06510    /* I don't think we should destroy hints if the parking space still exists. */
06511    remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint);
06512 #endif
06513 }

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

Definition at line 6528 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().

06529 {
06530    struct parking_dp_context *old_ctx;
06531    struct parking_dp_context *new_ctx;
06532    struct ast_context *con;
06533    int cmp;
06534 
06535    old_ctx = AST_LIST_FIRST(old_map);
06536    new_ctx = AST_LIST_FIRST(new_map);
06537 
06538    while (new_ctx) {
06539       if (!old_ctx) {
06540          /* No old contexts left, so no dead stuff can remain. */
06541          return;
06542       }
06543       cmp = strcmp(old_ctx->context, new_ctx->context);
06544       if (cmp < 0) {
06545          /* New map does not have old map context. */
06546          con = ast_context_find(old_ctx->context);
06547          if (con) {
06548             ast_context_destroy(con, registrar);
06549          }
06550          old_ctx = AST_LIST_NEXT(old_ctx, node);
06551          continue;
06552       }
06553       if (cmp == 0) {
06554          /* Old and new map have this context. */
06555          remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx);
06556          old_ctx = AST_LIST_NEXT(old_ctx, node);
06557       } else {
06558          /* Old map does not have new map context. */
06559       }
06560       new_ctx = AST_LIST_NEXT(new_ctx, node);
06561    }
06562 
06563    /* Any old contexts left must be dead. */
06564    for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) {
06565       con = ast_context_find(old_ctx->context);
06566       if (con) {
06567          ast_context_destroy(con, registrar);
06568       }
06569    }
06570 }

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

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

Referenced by remove_dead_context_usage().

06365 {
06366    struct parking_dp_ramp *old_ramp;
06367    struct parking_dp_ramp *new_ramp;
06368    int cmp;
06369 
06370    old_ramp = AST_LIST_FIRST(old_ramps);
06371    new_ramp = AST_LIST_FIRST(new_ramps);
06372 
06373    while (new_ramp) {
06374       if (!old_ramp) {
06375          /* No old ramps left, so no dead ramps can remain. */
06376          return;
06377       }
06378       cmp = strcmp(old_ramp->exten, new_ramp->exten);
06379       if (cmp < 0) {
06380          /* New map does not have old ramp. */
06381          remove_exten_if_exist(context, old_ramp->exten, 1);
06382          old_ramp = AST_LIST_NEXT(old_ramp, node);
06383          continue;
06384       }
06385       if (cmp == 0) {
06386          /* Old and new map have this ramp. */
06387          old_ramp = AST_LIST_NEXT(old_ramp, node);
06388       } else {
06389          /* Old map does not have new ramp. */
06390       }
06391       new_ramp = AST_LIST_NEXT(new_ramp, node);
06392    }
06393 
06394    /* Any old ramps left must be dead. */
06395    for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) {
06396       remove_exten_if_exist(context, old_ramp->exten, 1);
06397    }
06398 }

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]

Definition at line 6434 of file features.c.

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

Referenced by remove_dead_context_usage().

06437 {
06438    struct parking_dp_spaces *old_range;
06439    struct parking_dp_spaces *new_range;
06440    int space;/*!< Current position in the current old range. */
06441    int stop;
06442 
06443    old_range = AST_LIST_FIRST(old_spaces);
06444    new_range = AST_LIST_FIRST(new_spaces);
06445    space = -1;
06446 
06447    while (old_range) {
06448       if (space < old_range->start) {
06449          space = old_range->start;
06450       }
06451       if (new_range) {
06452          if (space < new_range->start) {
06453             /* Current position in old range starts before new range. */
06454             if (old_range->stop < new_range->start) {
06455                /* Old range ends before new range. */
06456                stop = old_range->stop;
06457                old_range = AST_LIST_NEXT(old_range, node);
06458             } else {
06459                /* Tail of old range overlaps new range. */
06460                stop = new_range->start - 1;
06461             }
06462          } else if (/* new_range->start <= space && */ space <= new_range->stop) {
06463             /* Current position in old range overlaps new range. */
06464             if (old_range->stop <= new_range->stop) {
06465                /* Old range ends at or before new range. */
06466                old_range = AST_LIST_NEXT(old_range, node);
06467             } else {
06468                /* Old range extends beyond end of new range. */
06469                space = new_range->stop + 1;
06470                new_range = AST_LIST_NEXT(new_range, node);
06471             }
06472             continue;
06473          } else /* if (new_range->stop < space) */ {
06474             /* Current position in old range starts after new range. */
06475             new_range = AST_LIST_NEXT(new_range, node);
06476             continue;
06477          }
06478       } else {
06479          /* No more new ranges.  All remaining old spaces are dead. */
06480          stop = old_range->stop;
06481          old_range = AST_LIST_NEXT(old_range, node);
06482       }
06483 
06484       /* Destroy dead parking spaces. */
06485       for (; space <= stop; ++space) {
06486          destroy_space(context, space);
06487       }
06488    }
06489 }

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

Definition at line 6338 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().

06339 {
06340    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
06341 
06342    if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL,
06343       E_MATCH)) {
06344       ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n",
06345          context, exten, priority);
06346       ast_context_remove_extension(context, exten, priority, registrar);
06347    }
06348 }

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

Definition at line 3832 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(), config, feature_group_exten::feature, and LOG_WARNING.

Referenced by ast_bridge_call().

03833 {
03834    const char *feature;
03835 
03836    if (ast_strlen_zero(features)) {
03837       return;
03838    }
03839 
03840    for (feature = features; *feature; feature++) {
03841       switch (*feature) {
03842       case 'T' :
03843       case 't' :
03844          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
03845          break;
03846       case 'K' :
03847       case 'k' :
03848          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
03849          break;
03850       case 'H' :
03851       case 'h' :
03852          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
03853          break;
03854       case 'W' :
03855       case 'w' :
03856          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
03857          break;
03858       default :
03859          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
03860       }
03861    }
03862 }

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

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

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

00878 {
00879    ast_copy_string(chan->context, context, sizeof(chan->context));
00880    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00881    chan->priority = pri;
00882 }

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

Definition at line 953 of file features.c.

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

Referenced by bridge_call_thread().

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

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

Definition at line 3416 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, builtin_features, config, feature_group_exten::entry, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

03417 {
03418    int x;
03419 
03420    ast_clear_flag(config, AST_FLAGS_ALL);
03421 
03422    ast_rwlock_rdlock(&features_lock);
03423    for (x = 0; x < FEATURES_COUNT; x++) {
03424       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
03425          continue;
03426 
03427       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
03428          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03429 
03430       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
03431          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03432    }
03433    ast_rwlock_unlock(&features_lock);
03434 
03435    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
03436       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
03437 
03438       if (dynamic_features) {
03439          char *tmp = ast_strdupa(dynamic_features);
03440          char *tok;
03441          struct ast_call_feature *feature;
03442 
03443          /* while we have a feature */
03444          while ((tok = strsep(&tmp, "#"))) {
03445             struct feature_group *fg;
03446 
03447             AST_RWLIST_RDLOCK(&feature_groups);
03448             AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
03449                struct feature_group_exten *fge;
03450 
03451                AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03452                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
03453                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03454                   }
03455                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
03456                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03457                   }
03458                }
03459             }
03460             AST_RWLIST_UNLOCK(&feature_groups);
03461 
03462             AST_RWLIST_RDLOCK(&feature_list);
03463             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
03464                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
03465                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03466                }
03467                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
03468                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03469                }
03470             }
03471             AST_RWLIST_UNLOCK(&feature_list);
03472          }
03473       }
03474    }
03475 }

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

References FEATURE_SENSE_PEER.

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

01941 {
01942    if (sense == FEATURE_SENSE_PEER) {
01943       *caller = peer;
01944       *callee = chan;
01945    } else {
01946       *callee = peer;
01947       *caller = chan;
01948    }
01949 }

static void unmap_features ( void   )  [static]

Definition at line 3215 of file features.c.

References ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, FEATURES_COUNT, and features_lock.

03216 {
03217    int x;
03218 
03219    ast_rwlock_wrlock(&features_lock);
03220    for (x = 0; x < FEATURES_COUNT; x++)
03221       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
03222    ast_rwlock_unlock(&features_lock);
03223 }

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 6024 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, parking_dp_ramp::node, and parkinglot_cfg::parking_con.

Referenced by dialplan_usage_add_parkinglot_data().

06025 {
06026    struct parking_dp_ramp *cur_ramp;
06027    struct parking_dp_ramp *new_ramp;
06028    int cmp;
06029 
06030    /* Make sure that exclusive is only 0 or 1 */
06031    if (exclusive) {
06032       exclusive = 1;
06033    }
06034 
06035    AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) {
06036       cmp = strcmp(exten, cur_ramp->exten);
06037       if (cmp > 0) {
06038          /* The parking lot ramp goes after this node. */
06039          continue;
06040       }
06041       if (cmp == 0) {
06042          /* The ramp is already in the map. */
06043          if (complain && (cur_ramp->exclusive || exclusive)) {
06044             ast_log(LOG_WARNING,
06045                "Parking lot '%s' parkext %s@%s used by another parking lot.\n",
06046                lot->name, exten, lot->cfg.parking_con);
06047          }
06048          return 0;
06049       }
06050       /* The new parking lot ramp goes before this node. */
06051       new_ramp = build_dialplan_useage_ramp(exten, exclusive);
06052       if (!new_ramp) {
06053          return -1;
06054       }
06055       AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node);
06056       return 0;
06057    }
06058    AST_LIST_TRAVERSE_SAFE_END;
06059 
06060    /* New parking lot access ramp goes on the end. */
06061    new_ramp = build_dialplan_useage_ramp(exten, exclusive);
06062    if (!new_ramp) {
06063       return -1;
06064    }
06065    AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node);
06066    return 0;
06067 }

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 6105 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, parking_dp_spaces::node, parkinglot_cfg::parking_con, parking_dp_spaces::start, and parking_dp_spaces::stop.

Referenced by dialplan_usage_add_parkinglot_data().

06106 {
06107    struct parking_dp_spaces *cur_node;
06108    struct parking_dp_spaces *expand_node;
06109    struct parking_dp_spaces *new_node;
06110 
06111    expand_node = NULL;
06112    AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) {
06113       /* NOTE: stop + 1 to combine immediately adjacent nodes into one. */
06114       if (expand_node) {
06115          /* The previous node is expanding to possibly eat following nodes. */
06116          if (expand_node->stop + 1 < cur_node->start) {
06117             /* Current node is completely after expanding node. */
06118             return 0;
06119          }
06120 
06121          if (complain
06122             && ((cur_node->start <= start && start <= cur_node->stop)
06123                || (cur_node->start <= stop && stop <= cur_node->stop)
06124                || (start < cur_node->start && cur_node->stop < stop))) {
06125             /* Only complain once per range add. */
06126             complain = 0;
06127             ast_log(LOG_WARNING,
06128                "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06129                lot->name, start, stop, lot->cfg.parking_con);
06130          }
06131 
06132          /* Current node is eaten by the expanding node. */
06133          if (expand_node->stop < cur_node->stop) {
06134             expand_node->stop = cur_node->stop;
06135          }
06136          AST_LIST_REMOVE_CURRENT(node);
06137          ast_free(cur_node);
06138          continue;
06139       }
06140 
06141       if (cur_node->stop + 1 < start) {
06142          /* New range is completely after current node. */
06143          continue;
06144       }
06145       if (stop + 1 < cur_node->start) {
06146          /* New range is completely before current node. */
06147          new_node = build_dialplan_useage_spaces(start, stop);
06148          if (!new_node) {
06149             return -1;
06150          }
06151          AST_LIST_INSERT_BEFORE_CURRENT(new_node, node);
06152          return 0;
06153       }
06154 
06155       if (complain
06156          && ((cur_node->start <= start && start <= cur_node->stop)
06157             || (cur_node->start <= stop && stop <= cur_node->stop)
06158             || (start < cur_node->start && cur_node->stop < stop))) {
06159          /* Only complain once per range add. */
06160          complain = 0;
06161          ast_log(LOG_WARNING,
06162             "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06163             lot->name, start, stop, lot->cfg.parking_con);
06164       }
06165 
06166       /* Current node range overlaps or is immediately adjacent to new range. */
06167       if (start < cur_node->start) {
06168          /* Expand the current node in the front. */
06169          cur_node->start = start;
06170       }
06171       if (stop <= cur_node->stop) {
06172          /* Current node is not expanding in the rear. */
06173          return 0;
06174       }
06175       cur_node->stop = stop;
06176       expand_node = cur_node;
06177    }
06178    AST_LIST_TRAVERSE_SAFE_END;
06179 
06180    if (expand_node) {
06181       /*
06182        * The previous node expanded and either ate all following nodes
06183        * or it was the last node.
06184        */
06185       return 0;
06186    }
06187 
06188    /* New range goes on the end. */
06189    new_node = build_dialplan_useage_spaces(start, stop);
06190    if (!new_node) {
06191       return -1;
06192    }
06193    AST_LIST_INSERT_TAIL(space_map, new_node, node);
06194    return 0;
06195 }

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

Definition at line 1879 of file features.c.

References args, 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, parkinglot_addref(), parkinglot_unref(), parse(), and park_app_args::pl_name.

Referenced by builtin_atxfer(), and builtin_blindtransfer().

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


Variable Documentation

int adsipark [static]

Definition at line 608 of file features.c.

Referenced by park_call_full(), and process_config().

char* app_bridge = "Bridge" [static]

Definition at line 7405 of file features.c.

unsigned int atxfercallbackretries [static]

Definition at line 617 of file features.c.

Referenced by builtin_atxfer(), and process_config().

unsigned int atxferdropcall [static]

Definition at line 615 of file features.c.

Referenced by builtin_atxfer(), and process_config().

unsigned int atxferloopdelay [static]

Definition at line 616 of file features.c.

Referenced by builtin_atxfer(), and process_config().

int atxfernoanswertimeout [static]

Definition at line 614 of file features.c.

Referenced by builtin_atxfer(), and process_config().

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

Definition at line 7442 of file features.c.

Referenced by bridge_exec().

struct ast_call_feature builtin_features[] [static]

Definition at line 2954 of file features.c.

Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().

struct ast_datastore_info channel_app_data_datastore [static]

Initial value:

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

Definition at line 948 of file features.c.

Referenced by set_chan_app_data().

struct ast_cli_entry cli_features[] [static]

Initial value:

 {
   { .handler =  handle_feature_show , .summary =  "Lists configured features" ,__VA_ARGS__ },
   { .handler =  handle_features_reload , .summary =  "Reloads configured features" ,__VA_ARGS__ },
   { .handler =  handle_parkedcalls , .summary =  "List currently parked calls" ,__VA_ARGS__ },
}

Definition at line 7077 of file features.c.

Referenced by ast_features_init().

int comebacktoorigin = 1 [static]

Definition at line 612 of file features.c.

Referenced by manage_parked_call(), and process_config().

char courtesytone[256] [static]

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

Definition at line 589 of file features.c.

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

struct ast_parkinglot* default_parkinglot [static]

Default parking lot.

Note:
Holds a parkinglot reference.

Will not be NULL while running.

Definition at line 582 of file features.c.

struct ast_datastore_info dial_features_info [static]

Initial value:

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

Definition at line 748 of file features.c.

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

int featuredigittimeout [static]

Definition at line 611 of file features.c.

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

Definition at line 2952 of file features.c.

Referenced by ast_rdlock_call_features(), ast_unlock_call_features(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().

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

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

Definition at line 606 of file features.c.

Referenced by ast_features_reload().

int force_reload_load [static]

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

Definition at line 585 of file features.c.

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

struct ast_app* mixmonitor_app = NULL [static]

Definition at line 638 of file features.c.

Referenced by builtin_automixmonitor().

int mixmonitor_ok = 1 [static]

Definition at line 639 of file features.c.

Referenced by builtin_automixmonitor().

struct ast_app* monitor_app = NULL [static]

Definition at line 635 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 636 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

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

Definition at line 4977 of file features.c.

Referenced by park_call_exec().

const char* parkcall = "Park" [static]

Definition at line 633 of file features.c.

Referenced by ast_features_init(), get_parking_exten(), and parkinglot_activate().

const char* parkedcall = "ParkedCall" [static]

Definition at line 419 of file features.c.

int parkeddynamic = 0 [static]

Enable creation of parkinglots dynamically

Definition at line 588 of file features.c.

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

int parkedplay = 0 [static]

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

Definition at line 587 of file features.c.

Referenced by parked_call_exec(), and process_config().

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

Context for parking dialback to parker.

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

Referenced by ast_features_reload(), and manage_parked_call().

pthread_t parking_thread [static]

Definition at line 644 of file features.c.

Referenced by ast_features_init(), and park_call_full().

struct parkinglot_cfg parkinglot_cfg_default [static]

Initial value:

 {
   .parkext = DEFAULT_PARK_EXTENSION,
   .parkingtime = DEFAULT_PARK_TIME,
}
Default configuration for normal parking lots.

Definition at line 5425 of file features.c.

Referenced by build_parkinglot().

struct parkinglot_cfg parkinglot_cfg_default_default [static]

Default configuration for default parking lot.

Definition at line 5415 of file features.c.

Referenced by build_parkinglot().

struct ao2_container* parkinglots [static]

The configured parking lots container. Always at least one - the default parking lot.

Definition at line 575 of file features.c.

Referenced by ast_features_init(), build_dialplan_useage_map(), build_parkinglot(), create_dynamic_parkinglot(), do_parking_thread(), find_parkinglot(), handle_feature_show(), handle_parkedcalls(), load_config(), and manager_parking_status().

struct ast_datastore_info pickup_active [static]

Initial value:

 {
   .type = "pickup-active",
}
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 7246 of file features.c.

Referenced by ast_can_pickup(), and ast_do_pickup().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 421 of file features.c.

Referenced by analog_canmatch_featurecode(), and canmatch_featurecode().

char pickupfailsound[256] [static]

Pickup failure sound

Definition at line 593 of file features.c.

Referenced by ast_pickup_call(), and process_config().

char pickupsound[256] [static]

Pickup sound

Definition at line 592 of file features.c.

Referenced by ast_pickup_call(), and process_config().

char* registrar = "features" [static]

Registrar for operations

Definition at line 619 of file features.c.

Referenced by ast_features_reload(), manage_parked_call(), park_add_hints(), park_call_full(), parkinglot_activate(), remove_dead_dialplan_useage(), and remove_exten_if_exist().

struct ast_app* stopmixmonitor_app = NULL [static]

Definition at line 641 of file features.c.

Referenced by builtin_automixmonitor().

int stopmixmonitor_ok = 1 [static]

Definition at line 642 of file features.c.

Referenced by builtin_automixmonitor().

int transferdigittimeout [static]

Definition at line 610 of file features.c.

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

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 591 of file features.c.

Referenced by builtin_atxfer(), and process_config().

char xfersound[256] [static]

Call transfer sound

Definition at line 590 of file features.c.

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


Generated on Mon Oct 8 12:39:22 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7