Sat Mar 10 01:55: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 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 (void *data)
 create thread for the parked call
static int bridge_exec (struct ast_channel *chan, const char *data)
 Bridge channels.
static struct parking_dp_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 void do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan)
 Actual bridge.
static void * do_parking_thread (void *ignore)
 Take care of parked calls and unpark them if needed.
static int feature_check (struct ast_channel *chan, struct ast_flags *features, char *code)
 Check if a feature exists.
static int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 exec an app by feature
static int feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense)
 Check the dynamic features.
static int feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, feature_interpret_op operation, struct ast_call_feature *feature)
 Helper function for feature_interpret and ast_feature_detect.
static struct ast_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 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_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 2828 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 7290 of file features.c.

07290      {
07291    BRIDGE_OPT_PLAYTONE = (1 << 0),
07292    OPT_CALLEE_HANGUP =  (1 << 1),
07293    OPT_CALLER_HANGUP =  (1 << 2),
07294    OPT_DURATION_LIMIT = (1 << 3),
07295    OPT_DURATION_STOP =  (1 << 4),
07296    OPT_CALLEE_TRANSFER = (1 << 5),
07297    OPT_CALLER_TRANSFER = (1 << 6),
07298    OPT_CALLEE_MONITOR = (1 << 7),
07299    OPT_CALLER_MONITOR = (1 << 8),
07300    OPT_CALLEE_PARK = (1 << 9),
07301    OPT_CALLER_PARK = (1 << 10),
07302    OPT_CALLEE_KILL = (1 << 11),
07303 };

anonymous enum

Enumerator:
OPT_ARG_DURATION_LIMIT 
OPT_ARG_DURATION_STOP 
OPT_ARG_ARRAY_SIZE 

Definition at line 7305 of file features.c.

07305      {
07306    OPT_ARG_DURATION_LIMIT = 0,
07307    OPT_ARG_DURATION_STOP,
07308    /* note: this entry _MUST_ be the last one in the enum */
07309    OPT_ARG_ARRAY_SIZE,
07310 };

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

01035                            {
01036    /*! Provide ringing to the parked caller instead of music on hold */
01037    AST_PARK_OPT_RINGING =   (1 << 0),
01038    /*! Randomly choose a parking spot for the caller instead of choosing
01039     *  the first one that is available. */
01040    AST_PARK_OPT_RANDOMIZE = (1 << 1),
01041    /*! Do not announce the parking number */
01042    AST_PARK_OPT_SILENCE = (1 << 2),
01043 };

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 on success or on incorrect use.
1 on failure to bridge channels.

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

06781 {
06782    const char *channela = astman_get_header(m, "Channel1");
06783    const char *channelb = astman_get_header(m, "Channel2");
06784    const char *playtone = astman_get_header(m, "Tone");
06785    struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
06786    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
06787    struct ast_bridge_thread_obj *tobj = NULL;
06788 
06789    /* make sure valid channels were specified */
06790    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
06791       astman_send_error(s, m, "Missing channel parameter in request");
06792       return 0;
06793    }
06794 
06795    /* Start with chana */
06796    chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
06797 
06798    /* send errors if any of the channels could not be found/locked */
06799    if (!chana) {
06800       char buf[256];
06801       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
06802       astman_send_error(s, m, buf);
06803       return 0;
06804    }
06805 
06806    /* Answer the channels if needed */
06807    if (chana->_state != AST_STATE_UP)
06808       ast_answer(chana);
06809 
06810    /* create the placeholder channels and grab the other channels */
06811    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
06812       NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
06813       astman_send_error(s, m, "Unable to create temporary channel!");
06814       chana = ast_channel_unref(chana);
06815       return 1;
06816    }
06817 
06818    do_bridge_masquerade(chana, tmpchana);
06819 
06820    chana = ast_channel_unref(chana);
06821 
06822    /* now do chanb */
06823    chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
06824    /* send errors if any of the channels could not be found/locked */
06825    if (!chanb) {
06826       char buf[256];
06827       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
06828       ast_hangup(tmpchana);
06829       astman_send_error(s, m, buf);
06830       return 0;
06831    }
06832 
06833    /* Answer the channels if needed */
06834    if (chanb->_state != AST_STATE_UP)
06835       ast_answer(chanb);
06836 
06837    /* create the placeholder channels and grab the other channels */
06838    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
06839       NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
06840       astman_send_error(s, m, "Unable to create temporary channels!");
06841       ast_hangup(tmpchana);
06842       chanb = ast_channel_unref(chanb);
06843       return 1;
06844    }
06845 
06846    do_bridge_masquerade(chanb, tmpchanb);
06847 
06848    chanb = ast_channel_unref(chanb);
06849 
06850    /* make the channels compatible, send error if we fail doing so */
06851    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
06852       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
06853       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
06854       ast_hangup(tmpchana);
06855       ast_hangup(tmpchanb);
06856       return 1;
06857    }
06858 
06859    /* setup the bridge thread object and start the bridge */
06860    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
06861       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
06862       astman_send_error(s, m, "Unable to spawn a new bridge thread");
06863       ast_hangup(tmpchana);
06864       ast_hangup(tmpchanb);
06865       return 1;
06866    }
06867 
06868    tobj->chan = tmpchana;
06869    tobj->peer = tmpchanb;
06870    tobj->return_to_pbx = 1;
06871 
06872    if (ast_true(playtone)) {
06873       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
06874          if (ast_waitstream(tmpchanb, "") < 0)
06875             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
06876       }
06877    }
06878 
06879    chans[0] = tmpchana;
06880    chans[1] = tmpchanb;
06881 
06882    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
06883             "Response: Success\r\n"
06884             "Channel1: %s\r\n"
06885             "Channel2: %s\r\n", tmpchana->name, tmpchanb->name);
06886 
06887    bridge_call_thread_launch(tobj);
06888 
06889    astman_send_ack(s, m, "Launched bridge thread with success");
06890 
06891    return 0;
06892 }

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

Definition at line 3740 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(), config, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, and LOG_WARNING.

Referenced by ast_bridge_call().

03741 {
03742    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
03743    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
03744 
03745    ast_channel_lock(caller);
03746    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
03747    ast_channel_unlock(caller);
03748    if (!ds_caller_features) {
03749       if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03750          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
03751          return;
03752       }
03753       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
03754          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03755          ast_datastore_free(ds_caller_features);
03756          return;
03757       }
03758       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
03759       caller_features->is_caller = 1;
03760       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
03761       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
03762       ds_caller_features->data = caller_features;
03763       ast_channel_lock(caller);
03764       ast_channel_datastore_add(caller, ds_caller_features);
03765       ast_channel_unlock(caller);
03766    } else {
03767       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
03768        * flags over from the atxfer to the caller */
03769       return;
03770    }
03771 
03772    ast_channel_lock(callee);
03773    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
03774    ast_channel_unlock(callee);
03775    if (!ds_callee_features) {
03776       if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03777          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
03778          return;
03779       }
03780       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
03781          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03782          ast_datastore_free(ds_callee_features);
03783          return;
03784       }
03785       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
03786       callee_features->is_caller = 0;
03787       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
03788       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
03789       ds_callee_features->data = callee_features;
03790       ast_channel_lock(callee);
03791       ast_channel_datastore_add(callee, ds_callee_features);
03792       ast_channel_unlock(callee);
03793    }
03794 
03795    return;
03796 }

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

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

Referenced by park_call_full().

00974 {
00975    int res;
00976    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00977    char tmp[256];
00978    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00979 
00980    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00981    message[0] = tmp;
00982    res = ast_adsi_load_session(chan, NULL, 0, 1);
00983    if (res == -1)
00984       return res;
00985    return ast_adsi_print(chan, message, justify, 1);
00986 }

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

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

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

07329 {
07330    char *stringp = ast_strdupa(parse);
07331    char *limit_str, *warning_str, *warnfreq_str;
07332    const char *var;
07333    int play_to_caller = 0, play_to_callee = 0;
07334    int delta;
07335 
07336    limit_str = strsep(&stringp, ":");
07337    warning_str = strsep(&stringp, ":");
07338    warnfreq_str = strsep(&stringp, ":");
07339 
07340    config->timelimit = atol(limit_str);
07341    if (warning_str)
07342       config->play_warning = atol(warning_str);
07343    if (warnfreq_str)
07344       config->warning_freq = atol(warnfreq_str);
07345 
07346    if (!config->timelimit) {
07347       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07348       config->timelimit = config->play_warning = config->warning_freq = 0;
07349       config->warning_sound = NULL;
07350       return -1; /* error */
07351    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07352       int w = config->warning_freq;
07353 
07354       /*
07355        * If the first warning is requested _after_ the entire call
07356        * would end, and no warning frequency is requested, then turn
07357        * off the warning. If a warning frequency is requested, reduce
07358        * the 'first warning' time by that frequency until it falls
07359        * within the call's total time limit.
07360        *
07361        * Graphically:
07362        *                timelim->|    delta        |<-playwarning
07363        *      0__________________|_________________|
07364        *                       | w  |    |    |    |
07365        *
07366        * so the number of intervals to cut is 1+(delta-1)/w
07367        */
07368       if (w == 0) {
07369          config->play_warning = 0;
07370       } else {
07371          config->play_warning -= w * ( 1 + (delta-1)/w );
07372          if (config->play_warning < 1)
07373             config->play_warning = config->warning_freq = 0;
07374       }
07375    }
07376    
07377    ast_channel_lock(chan);
07378 
07379    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07380    play_to_caller = var ? ast_true(var) : 1;
07381 
07382    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07383    play_to_callee = var ? ast_true(var) : 0;
07384 
07385    if (!play_to_caller && !play_to_callee)
07386       play_to_caller = 1;
07387 
07388    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07389    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07390 
07391    /* The code looking at config wants a NULL, not just "", to decide
07392     * that the message should not be played, so we replace "" with NULL.
07393     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
07394     * not found.
07395     */
07396 
07397    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07398    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07399 
07400    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07401    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07402 
07403    ast_channel_unlock(chan);
07404 
07405    /* undo effect of S(x) in case they are both used */
07406    calldurationlimit->tv_sec = 0;
07407    calldurationlimit->tv_usec = 0;
07408 
07409    /* more efficient to do it like S(x) does since no advanced opts */
07410    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07411       calldurationlimit->tv_sec = config->timelimit / 1000;
07412       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07413       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07414          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07415       config->timelimit = play_to_caller = play_to_callee =
07416       config->play_warning = config->warning_freq = 0;
07417    } else {
07418       ast_verb(4, "Limit Data for this call:\n");
07419       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07420       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07421       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07422       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07423       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07424       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
07425       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
07426       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
07427    }
07428    if (play_to_caller)
07429       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07430    if (play_to_callee)
07431       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07432    return 0;
07433 }

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

07135 {
07136    if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07137       && (chan->_state == AST_STATE_RINGING
07138          || chan->_state == AST_STATE_RING
07139          /*
07140           * Check the down state as well because some SIP devices do not
07141           * give 180 ringing when they can just give 183 session progress
07142           * instead.  Issue 14005.  (Some ISDN switches as well for that
07143           * matter.)
07144           */
07145          || chan->_state == AST_STATE_DOWN)
07146       && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07147       return 1;
07148    }
07149    return 0;
07150 }

void ast_channel_log ( char *  title,
struct ast_channel chan 
)

Definition at line 3675 of file features.c.

References ast_log(), and LOG_NOTICE.

Referenced by ast_bridge_call().

03676 {
03677        ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
03678        ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
03679                        chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
03680        ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
03681                        chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
03682        ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
03683                        chan->masq, chan->masqr,
03684                        chan->_bridge, chan->uniqueid, chan->linkedid);
03685        if (chan->masqr)
03686                ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
03687                                chan->masqr->name, chan->masqr->cdr);
03688        if (chan->_bridge)
03689                ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
03690 
03691    ast_log(LOG_NOTICE, "===== done ====\n");
03692 }

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

07211 {
07212    struct ast_party_connected_line connected_caller;
07213    struct ast_channel *chans[2] = { chan, target };
07214    struct ast_datastore *ds_pickup;
07215    const char *chan_name;/*!< A masquerade changes channel names. */
07216    const char *target_name;/*!< A masquerade changes channel names. */
07217    int res = -1;
07218 
07219    target_name = ast_strdupa(target->name);
07220    ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name);
07221 
07222    /* Mark the target to block any call pickup race. */
07223    ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07224    if (!ds_pickup) {
07225       ast_log(LOG_WARNING,
07226          "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07227       return -1;
07228    }
07229    ast_channel_datastore_add(target, ds_pickup);
07230 
07231    ast_party_connected_line_init(&connected_caller);
07232    ast_party_connected_line_copy(&connected_caller, &target->connected);
07233    ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
07234    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07235    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07236       ast_channel_update_connected_line(chan, &connected_caller, NULL);
07237    }
07238    ast_party_connected_line_free(&connected_caller);
07239 
07240    ast_channel_lock(chan);
07241    chan_name = ast_strdupa(chan->name);
07242    ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07243    ast_channel_unlock(chan);
07244    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07245    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07246    ast_party_connected_line_free(&connected_caller);
07247 
07248    ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07249 
07250    if (ast_answer(chan)) {
07251       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07252       goto pickup_failed;
07253    }
07254 
07255    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07256       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07257       goto pickup_failed;
07258    }
07259    
07260    /* setting this flag to generate a reason header in the cancel message to the ringing channel */
07261    ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07262 
07263    if (ast_channel_masquerade(target, chan)) {
07264       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07265          target_name);
07266       goto pickup_failed;
07267    }
07268 
07269    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
07270    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07271       "Channel: %s\r\n"
07272       "TargetChannel: %s\r\n",
07273       chan_name, target_name);
07274 
07275    /* Do the masquerade manually to make sure that it is completed. */
07276    ast_do_masquerade(target);
07277    res = 0;
07278 
07279 pickup_failed:
07280    ast_channel_lock(target);
07281    if (!ast_channel_datastore_remove(target, ds_pickup)) {
07282       ast_datastore_free(ds_pickup);
07283    }
07284 
07285    return res;
07286 }

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

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

Referenced by detect_disconnect().

03277                                                                                                                                  {
03278 
03279    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03280 }

int ast_features_init ( void   ) 

Provided by features.c

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

08077 {
08078    int res;
08079 
08080    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
08081    if (!parkinglots) {
08082       return -1;
08083    }
08084 
08085    res = load_config(0);
08086    if (res) {
08087       return res;
08088    }
08089    ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
08090    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
08091    ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
08092    res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL);
08093    if (!res)
08094       res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
08095    if (!res) {
08096       ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
08097       ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
08098       ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
08099    }
08100 
08101    res |= ast_devstate_prov_add("Park", metermaidstate);
08102 #if defined(TEST_FRAMEWORK)
08103    res |= AST_TEST_REGISTER(features_test);
08104 #endif   /* defined(TEST_FRAMEWORK) */
08105 
08106    return res;
08107 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

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

06697 {
06698    struct ast_context *con;
06699    int res;
06700 
06701    ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
06702 
06703    /*
06704     * Always destroy the parking_con_dial context to remove buildup
06705     * of recalled extensions in the context.  At worst, the parked
06706     * call gets hungup attempting to run an invalid extension when
06707     * we are trying to callback the parker or the preset return
06708     * extension.  This is a small window of opportunity on an
06709     * execution chain that is not expected to happen very often.
06710     */
06711    con = ast_context_find(parking_con_dial);
06712    if (con) {
06713       ast_context_destroy(con, registrar);
06714    }
06715 
06716    res = load_config(1);
06717    ast_mutex_unlock(&features_reload_lock);
06718 
06719    return res;
06720 }

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

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

03012 {
03013    int x;
03014    for (x = 0; x < FEATURES_COUNT; x++) {
03015       if (!strcasecmp(name, builtin_features[x].sname))
03016          return &builtin_features[x];
03017    }
03018    return NULL;
03019 }

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 1756 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(), parkandannounce_exec(), and rpt_exec().

01757 {
01758    struct ast_park_call_args args = {
01759       .timeout = timeout,
01760       .extout = extout,
01761    };
01762 
01763    if (peer) {
01764       args.orig_chan_name = ast_strdupa(peer->name);
01765    }
01766    return masq_park_call(rchan, peer, &args);
01767 }

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

01703 {
01704    int res;
01705    char *parse;
01706    const char *app_data;
01707    struct ast_exten *exten;
01708    struct park_app_args app_args;
01709    struct ast_park_call_args args = {
01710       .timeout = timeout,
01711       .extout = extout,
01712    };
01713 
01714    if (parker) {
01715       args.orig_chan_name = ast_strdupa(parker->name);
01716    }
01717    if (!park_exten || !park_context) {
01718       return masq_park_call(park_me, parker, &args);
01719    }
01720 
01721    /*
01722     * Determiine if the specified park extension has an exclusive
01723     * parking lot to use.
01724     */
01725    if (parker && parker != park_me) {
01726       ast_autoservice_start(park_me);
01727    }
01728    exten = get_parking_exten(park_exten, parker, park_context);
01729    if (exten) {
01730       app_data = ast_get_extension_app_data(exten);
01731       if (!app_data) {
01732          app_data = "";
01733       }
01734       parse = ast_strdupa(app_data);
01735       AST_STANDARD_APP_ARGS(app_args, parse);
01736    
01737       if (!ast_strlen_zero(app_args.pl_name)) {
01738          /* Find the specified exclusive parking lot */
01739          args.parkinglot = find_parkinglot(app_args.pl_name);
01740          if (!args.parkinglot && parkeddynamic) {
01741             args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
01742          }
01743       }
01744    }
01745    if (parker && parker != park_me) {
01746       ast_autoservice_stop(park_me);
01747    }
01748 
01749    res = masq_park_call(park_me, parker, &args);
01750    if (args.parkinglot) {
01751       parkinglot_unref(args.parkinglot);
01752    }
01753    return res;
01754 }

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

References args, and park_call_full().

01606 {
01607    struct ast_park_call_args args = {
01608       .timeout = timeout,
01609       .extout = extout,
01610    };
01611 
01612    return park_call_full(park_me, parker, &args);
01613 }

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

01555 {
01556    int res;
01557    char *parse;
01558    const char *app_data;
01559    struct ast_exten *exten;
01560    struct park_app_args app_args;
01561    struct ast_park_call_args args = {
01562       .timeout = timeout,
01563       .extout = extout,
01564    };
01565 
01566    if (!park_exten || !park_context) {
01567       return park_call_full(park_me, parker, &args);
01568    }
01569 
01570    /*
01571     * Determiine if the specified park extension has an exclusive
01572     * parking lot to use.
01573     */
01574    if (parker && parker != park_me) {
01575       ast_autoservice_start(park_me);
01576    }
01577    exten = get_parking_exten(park_exten, parker, park_context);
01578    if (exten) {
01579       app_data = ast_get_extension_app_data(exten);
01580       if (!app_data) {
01581          app_data = "";
01582       }
01583       parse = ast_strdupa(app_data);
01584       AST_STANDARD_APP_ARGS(app_args, parse);
01585    
01586       if (!ast_strlen_zero(app_args.pl_name)) {
01587          /* Find the specified exclusive parking lot */
01588          args.parkinglot = find_parkinglot(app_args.pl_name);
01589          if (!args.parkinglot && parkeddynamic) {
01590             args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
01591          }
01592       }
01593    }
01594    if (parker && parker != park_me) {
01595       ast_autoservice_stop(park_me);
01596    }
01597 
01598    res = park_call_full(park_me, parker, &args);
01599    if (args.parkinglot) {
01600       parkinglot_unref(args.parkinglot);
01601    }
01602    return res;
01603 }

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

00794 {
00795    return get_parking_exten(exten_str, chan, context) ? 1 : 0;
00796 }

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

07177 {
07178    struct ast_channel *target;/*!< Potential pickup target */
07179    int res = -1;
07180    ast_debug(1, "pickup attempt by %s\n", chan->name);
07181 
07182    /* The found channel is already locked. */
07183    target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07184    if (target) {
07185       ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
07186 
07187       res = ast_do_pickup(chan, target);
07188       ast_channel_unlock(target);
07189       if (!res) {
07190          if (!ast_strlen_zero(pickupsound)) {
07191             pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07192          }
07193       } else {
07194          ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name);
07195       }
07196       target = ast_channel_unref(target);
07197    }
07198 
07199    if (res < 0) {
07200       ast_debug(1, "No call pickup possible... for %s\n", chan->name);
07201       if (!ast_strlen_zero(pickupfailsound)) {
07202          ast_answer(chan);
07203          ast_stream_and_wait(chan, pickupfailsound, "");
07204       }
07205    }
07206 
07207    return res;
07208 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

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

00799 {
00800    return pickup_ext;
00801 }

void ast_rdlock_call_features ( void   ) 

Definition at line 3001 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

03002 {
03003    ast_rwlock_rdlock(&features_lock);
03004 }

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

02846 {
02847    if (!feature) {
02848       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02849       return;
02850    }
02851   
02852    AST_RWLIST_WRLOCK(&feature_list);
02853    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02854    AST_RWLIST_UNLOCK(&feature_list);
02855 
02856    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02857 }

void ast_unlock_call_features ( void   ) 

Definition at line 3006 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

03007 {
03008    ast_rwlock_unlock(&features_lock);
03009 }

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

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

02926 {
02927    if (!feature) {
02928       return;
02929    }
02930 
02931    AST_RWLIST_WRLOCK(&feature_list);
02932    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02933    AST_RWLIST_UNLOCK(&feature_list);
02934 
02935    ast_free(feature);
02936 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

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

02940 {
02941    struct ast_call_feature *feature;
02942 
02943    AST_RWLIST_WRLOCK(&feature_list);
02944    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
02945       ast_free(feature);
02946    }
02947    AST_RWLIST_UNLOCK(&feature_list);
02948 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

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

02966 {
02967    struct feature_group *fg;
02968    struct feature_group_exten *fge;
02969 
02970    AST_RWLIST_WRLOCK(&feature_groups);
02971    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
02972       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
02973          ast_string_field_free_memory(fge);
02974          ast_free(fge);
02975       }
02976 
02977       ast_string_field_free_memory(fg);
02978       ast_free(fg);
02979    }
02980    AST_RWLIST_UNLOCK(&feature_groups);
02981 }

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

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

02389 {
02390    finishup(transferee);
02391 
02392    /*
02393     * Restore party B connected line info about party A.
02394     *
02395     * Party B was the caller to party C and is the last known mode
02396     * for party B.
02397     */
02398    if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
02399       ast_channel_update_connected_line(transferer, connected_line, NULL);
02400    }
02401    ast_party_connected_line_free(connected_line);
02402 }

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

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

Referenced by bridge_call_thread_launch().

00909 {
00910    struct ast_bridge_thread_obj *tobj = data;
00911    int res;
00912 
00913    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00914    tobj->chan->data = tobj->peer->name;
00915    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00916    tobj->peer->data = tobj->chan->name;
00917 
00918    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00919 
00920    if (tobj->return_to_pbx) {
00921       if (!ast_check_hangup(tobj->peer)) {
00922          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00923          res = ast_pbx_start(tobj->peer);
00924          if (res != AST_PBX_SUCCESS)
00925             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00926       } else
00927          ast_hangup(tobj->peer);
00928       if (!ast_check_hangup(tobj->chan)) {
00929          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00930          res = ast_pbx_start(tobj->chan);
00931          if (res != AST_PBX_SUCCESS)
00932             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00933       } else
00934          ast_hangup(tobj->chan);
00935    } else {
00936       ast_hangup(tobj->chan);
00937       ast_hangup(tobj->peer);
00938    }
00939 
00940    ast_free(tobj);
00941 
00942    return NULL;
00943 }

static void bridge_call_thread_launch ( void *  data  )  [static]

create thread for the parked call

Parameters:
data Create thread and attributes, call bridge_call_thread

Definition at line 951 of file features.c.

References ast_pthread_create, bridge_call_thread(), and thread.

Referenced by action_bridge(), and builtin_atxfer().

00952 {
00953    pthread_t thread;
00954    pthread_attr_t attr;
00955    struct sched_param sched;
00956 
00957    pthread_attr_init(&attr);
00958    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00959    ast_pthread_create(&thread, &attr, bridge_call_thread, data);
00960    pthread_attr_destroy(&attr);
00961    memset(&sched, 0, sizeof(sched));
00962    pthread_setschedparam(thread, SCHED_RR, &sched);
00963 }

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 7445 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_free, ast_hangup(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_pbx_start(), AST_PBX_SUCCESS, ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, ast_channel::context, do_bridge_masquerade(), ast_bridge_config::end_sound, EVENT_FLAG_CALL, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, 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().

07446 {
07447    struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
07448    char *tmp_data  = NULL;
07449    struct ast_flags opts = { 0, };
07450    struct ast_bridge_config bconfig = { { 0, }, };
07451    char *opt_args[OPT_ARG_ARRAY_SIZE];
07452    struct timeval calldurationlimit = { 0, };
07453 
07454    AST_DECLARE_APP_ARGS(args,
07455       AST_APP_ARG(dest_chan);
07456       AST_APP_ARG(options);
07457    );
07458    
07459    if (ast_strlen_zero(data)) {
07460       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
07461       return -1;
07462    }
07463 
07464    tmp_data = ast_strdupa(data);
07465    AST_STANDARD_APP_ARGS(args, tmp_data);
07466    if (!ast_strlen_zero(args.options))
07467       ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
07468 
07469    /* avoid bridge with ourselves */
07470    if (!strcmp(chan->name, args.dest_chan)) {
07471       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
07472       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07473                "Response: Failed\r\n"
07474                "Reason: Unable to bridge channel to itself\r\n"
07475                "Channel1: %s\r\n"
07476                "Channel2: %s\r\n",
07477                chan->name, args.dest_chan);
07478       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
07479       return 0;
07480    }
07481 
07482    /* make sure we have a valid end point */
07483    if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
07484          strlen(args.dest_chan)))) {
07485       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
07486          "cannot get its lock\n", args.dest_chan);
07487       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07488                "Response: Failed\r\n"
07489                "Reason: Cannot grab end point\r\n"
07490                "Channel1: %s\r\n"
07491                "Channel2: %s\r\n", chan->name, args.dest_chan);
07492       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
07493       return 0;
07494    }
07495 
07496    /* answer the channel if needed */
07497    if (current_dest_chan->_state != AST_STATE_UP) {
07498       ast_answer(current_dest_chan);
07499    }
07500 
07501    /* try to allocate a place holder where current_dest_chan will be placed */
07502    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
07503       NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
07504       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
07505       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
07506                "Response: Failed\r\n"
07507                "Reason: cannot create placeholder\r\n"
07508                "Channel1: %s\r\n"
07509                "Channel2: %s\r\n", chan->name, args.dest_chan);
07510    }
07511 
07512    do_bridge_masquerade(current_dest_chan, final_dest_chan);
07513 
07514    chans[0] = current_dest_chan;
07515    chans[1] = final_dest_chan;
07516 
07517    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
07518    /* try to make compatible, send error if we fail */
07519    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
07520       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
07521       ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07522                "Response: Failed\r\n"
07523                "Reason: Could not make channels compatible for bridge\r\n"
07524                "Channel1: %s\r\n"
07525                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07526       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
07527       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
07528       current_dest_chan = ast_channel_unref(current_dest_chan);
07529       return 0;
07530    }
07531 
07532    /* Report that the bridge will be successfull */
07533    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
07534             "Response: Success\r\n"
07535             "Channel1: %s\r\n"
07536             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
07537 
07538    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
07539    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
07540       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
07541          if (ast_waitstream(final_dest_chan, "") < 0)
07542             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
07543       }
07544    }
07545    
07546    current_dest_chan = ast_channel_unref(current_dest_chan);
07547    
07548    if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
07549       if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
07550          goto done;
07551    }
07552 
07553    if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
07554       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
07555    if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
07556       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
07557    if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
07558       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
07559    if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
07560       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
07561    if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
07562       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
07563    if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 
07564       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
07565    if (ast_test_flag(&opts, OPT_CALLEE_PARK))
07566       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
07567    if (ast_test_flag(&opts, OPT_CALLER_PARK))
07568       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
07569 
07570    ast_bridge_call(chan, final_dest_chan, &bconfig);
07571 
07572    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
07573    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
07574    if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) {
07575       ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 
07576          final_dest_chan->context, final_dest_chan->exten, 
07577          final_dest_chan->priority, final_dest_chan->name);
07578 
07579       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
07580          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
07581          ast_hangup(final_dest_chan);
07582       } else
07583          ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
07584    } else {
07585       ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name);
07586       ast_hangup(final_dest_chan);
07587    }
07588 done:
07589    if (bconfig.warning_sound) {
07590       ast_free((char *)bconfig.warning_sound);
07591    }
07592    if (bconfig.end_sound) {
07593       ast_free((char *)bconfig.end_sound);
07594    }
07595    if (bconfig.start_sound) {
07596       ast_free((char *)bconfig.start_sound);
07597    }
07598 
07599    return 0;
07600 }

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

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

06141 {
06142    struct parking_dp_context *ctx_node;
06143 
06144    ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con));
06145    if (!ctx_node) {
06146       return NULL;
06147    }
06148    if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) {
06149       destroy_dialplan_usage_context(ctx_node);
06150       return NULL;
06151    }
06152    strcpy(ctx_node->context, lot->cfg.parking_con);
06153    return ctx_node;
06154 }

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

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

06213 {
06214    int status = 0;
06215    struct ao2_iterator iter;
06216    struct ast_parkinglot *curlot;
06217 
06218    /* For all parking lots */
06219    iter = ao2_iterator_init(parkinglots, 0);
06220    for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) {
06221       /* Add the parking lot to the map. */
06222       if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) {
06223          ao2_ref(curlot, -1);
06224          status = -1;
06225          break;
06226       }
06227    }
06228    ao2_iterator_destroy(&iter);
06229 
06230    return status;
06231 }

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

Definition at line 5903 of file features.c.

References ast_calloc.

Referenced by usage_context_add_ramp().

05904 {
05905    struct parking_dp_ramp *ramp_node;
05906 
05907    ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten));
05908    if (!ramp_node) {
05909       return NULL;
05910    }
05911    ramp_node->exclusive = exclusive;
05912    strcpy(ramp_node->exten, exten);
05913    return ramp_node;
05914 }

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

Definition at line 5984 of file features.c.

References ast_calloc.

Referenced by usage_context_add_spaces().

05985 {
05986    struct parking_dp_spaces *spaces_node;
05987 
05988    spaces_node = ast_calloc(1, sizeof(*spaces_node));
05989    if (!spaces_node) {
05990       return NULL;
05991    }
05992    spaces_node->start = start;
05993    spaces_node->stop = stop;
05994    return spaces_node;
05995 }

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

05508 {
05509    struct ast_parkinglot *parkinglot;
05510    const struct parkinglot_cfg *cfg_defaults;
05511    struct parkinglot_cfg new_cfg;
05512    int cfg_error;
05513    int oldparkinglot = 0;
05514 
05515    parkinglot = find_parkinglot(pl_name);
05516    if (parkinglot) {
05517       oldparkinglot = 1;
05518    } else {
05519       parkinglot = create_parkinglot(pl_name);
05520       if (!parkinglot) {
05521          return NULL;
05522       }
05523    }
05524    if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) {
05525       cfg_defaults = &parkinglot_cfg_default_default;
05526    } else {
05527       cfg_defaults = &parkinglot_cfg_default;
05528    }
05529    new_cfg = *cfg_defaults;
05530 
05531    ast_debug(1, "Building parking lot %s\n", parkinglot->name);
05532 
05533    ao2_lock(parkinglot);
05534 
05535    /* Do some config stuff */
05536    cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var);
05537    if (oldparkinglot) {
05538       if (cfg_error) {
05539          /* Bad configuration read.  Keep using the original config. */
05540          ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n",
05541             parkinglot->name);
05542          cfg_error = 0;
05543       } else if (!AST_LIST_EMPTY(&parkinglot->parkings)
05544          && memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) {
05545          /* Try reloading later when parking lot is empty. */
05546          ast_log(LOG_WARNING,
05547             "Parking lot %s has parked calls.  Parking lot changes discarded.\n",
05548             parkinglot->name);
05549          force_reload_load = 1;
05550       } else {
05551          /* Accept the new config */
05552          parkinglot->cfg = new_cfg;
05553       }
05554    } else {
05555       /* Load the initial parking lot config. */
05556       parkinglot->cfg = new_cfg;
05557    }
05558    parkinglot->the_mark = 0;
05559 
05560    ao2_unlock(parkinglot);
05561 
05562    if (cfg_error) {
05563       /* Only new parking lots could have config errors here. */
05564       ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name);
05565       parkinglot_unref(parkinglot);
05566       return NULL;
05567    }
05568 
05569    /* Move it into the list, if it wasn't already there */
05570    if (!oldparkinglot) {
05571       ao2_link(parkinglots, parkinglot);
05572    }
05573    parkinglot_unref(parkinglot);
05574 
05575    return parkinglot;
05576 }

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

References ast_channel::_state, 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_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), get_parking_exten(), ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), 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.

02420 {
02421    struct ast_channel *transferer;/* Party B */
02422    struct ast_channel *transferee;/* Party A */
02423    struct ast_exten *park_exten;
02424    const char *transferer_real_context;
02425    char xferto[256] = "";
02426    int res;
02427    int outstate=0;
02428    struct ast_channel *newchan;
02429    struct ast_channel *xferchan;
02430    struct ast_bridge_thread_obj *tobj;
02431    struct ast_bridge_config bconfig;
02432    int l;
02433    struct ast_party_connected_line connected_line;
02434    struct ast_datastore *features_datastore;
02435    struct ast_dial_features *dialfeatures = NULL;
02436    char *transferer_tech;
02437    char *transferer_name;
02438    char *transferer_name_orig;
02439    char *dash;
02440 
02441    ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02442    set_peers(&transferer, &transferee, peer, chan, sense);
02443    transferer_real_context = real_ctx(transferer, transferee);
02444 
02445    /* Start autoservice on transferee while we talk to the transferer */
02446    ast_autoservice_start(transferee);
02447    ast_indicate(transferee, AST_CONTROL_HOLD);
02448 
02449    /* Transfer */
02450    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02451    if (res < 0) {
02452       finishup(transferee);
02453       return -1;
02454    }
02455    if (res > 0) { /* If they've typed a digit already, handle it */
02456       xferto[0] = (char) res;
02457    }
02458 
02459    /* this is specific of atxfer */
02460    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02461    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
02462       finishup(transferee);
02463       return -1;
02464    }
02465    l = strlen(xferto);
02466    if (res == 0) {
02467       if (l) {
02468          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02469             xferto, transferer_real_context);
02470       } else {
02471          /* Does anyone care about this case? */
02472          ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
02473       }
02474       ast_stream_and_wait(transferer, "pbx-invalid", "");
02475       finishup(transferee);
02476       return AST_FEATURE_RETURN_SUCCESS;
02477    }
02478 
02479    park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
02480    if (park_exten) {
02481       /* We are transfering the transferee to a parking lot. */
02482       return xfer_park_call_helper(transferee, transferer, park_exten);
02483    }
02484 
02485    /* Append context to dialed transfer number. */
02486    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
02487 
02488    /* If we are performing an attended transfer and we have two channels involved then
02489       copy sound file information to play upon attended transfer completion */
02490    if (transferee) {
02491       const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02492       const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02493 
02494       if (!ast_strlen_zero(chan1_attended_sound)) {
02495          pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
02496       }
02497       if (!ast_strlen_zero(chan2_attended_sound)) {
02498          pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
02499       }
02500    }
02501 
02502    /* Extract redial transferer information from the channel name. */
02503    transferer_name_orig = ast_strdupa(transferer->name);
02504    transferer_name = ast_strdupa(transferer_name_orig);
02505    transferer_tech = strsep(&transferer_name, "/");
02506    dash = strrchr(transferer_name, '-');
02507    if (dash) {
02508       /* Trim off channel name sequence/serial number. */
02509       *dash = '\0';
02510    }
02511 
02512    /* Stop autoservice so we can monitor all parties involved in the transfer. */
02513    if (ast_autoservice_stop(transferee) < 0) {
02514       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02515       return -1;
02516    }
02517 
02518    /* Save connected line info for party B about party A in case transfer fails. */
02519    ast_party_connected_line_init(&connected_line);
02520    ast_channel_lock(transferer);
02521    ast_party_connected_line_copy(&connected_line, &transferer->connected);
02522    ast_channel_unlock(transferer);
02523    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02524 
02525    /* Dial party C */
02526    newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
02527       transferee, "Local", ast_best_codec(transferer->nativeformats), xferto,
02528       atxfernoanswertimeout, &outstate, transferer->language);
02529    ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
02530 
02531    if (!ast_check_hangup(transferer)) {
02532       int hangup_dont = 0;
02533 
02534       /* Transferer (party B) is up */
02535       ast_debug(1, "Actually doing an attended transfer.\n");
02536 
02537       /* Start autoservice on transferee while the transferer deals with party C. */
02538       ast_autoservice_start(transferee);
02539 
02540       ast_indicate(transferer, -1);
02541       if (!newchan) {
02542          /* any reason besides user requested cancel and busy triggers the failed sound */
02543          switch (outstate) {
02544          case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */
02545          case AST_CONTROL_BUSY:
02546          case AST_CONTROL_CONGESTION:
02547             if (ast_stream_and_wait(transferer, xfersound, "")) {
02548                ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02549             }
02550             break;
02551          default:
02552             if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02553                ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02554             }
02555             break;
02556          }
02557          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02558          return AST_FEATURE_RETURN_SUCCESS;
02559       }
02560 
02561       if (check_compat(transferer, newchan)) {
02562          if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02563             ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02564          }
02565          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02566          return AST_FEATURE_RETURN_SUCCESS;
02567       }
02568       memset(&bconfig,0,sizeof(struct ast_bridge_config));
02569       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
02570       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
02571 
02572       /* ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we don't
02573          want that to happen here because we're also in another bridge already
02574        */
02575       if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) {
02576          hangup_dont = 1;
02577       }
02578       /* Let party B and party C talk as long as they want. */
02579       ast_bridge_call(transferer, newchan, &bconfig);
02580       if (hangup_dont) {
02581          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
02582       }
02583 
02584       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
02585          ast_hangup(newchan);
02586          if (ast_stream_and_wait(transferer, xfersound, "")) {
02587             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02588          }
02589          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02590          return AST_FEATURE_RETURN_SUCCESS;
02591       }
02592 
02593       /* Transferer (party B) is confirmed hung up at this point. */
02594       if (check_compat(transferee, newchan)) {
02595          finishup(transferee);
02596          ast_party_connected_line_free(&connected_line);
02597          return -1;
02598       }
02599 
02600       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02601       if ((ast_autoservice_stop(transferee) < 0)
02602          || (ast_waitfordigit(transferee, 100) < 0)
02603          || (ast_waitfordigit(newchan, 100) < 0)
02604          || ast_check_hangup(transferee)
02605          || ast_check_hangup(newchan)) {
02606          ast_hangup(newchan);
02607          ast_party_connected_line_free(&connected_line);
02608          return -1;
02609       }
02610    } else if (!ast_check_hangup(transferee)) {
02611       /* Transferer (party B) has hung up at this point.  Doing blonde transfer. */
02612       ast_debug(1, "Actually doing a blonde transfer.\n");
02613 
02614       if (!newchan && !atxferdropcall) {
02615          /* Party C is not available, try to call party B back. */
02616          unsigned int tries = 0;
02617 
02618          if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
02619             ast_log(LOG_WARNING,
02620                "Transferer channel name: '%s' cannot be used for callback.\n",
02621                transferer_name_orig);
02622             ast_indicate(transferee, AST_CONTROL_UNHOLD);
02623             ast_party_connected_line_free(&connected_line);
02624             return -1;
02625          }
02626 
02627          tries = 0;
02628          for (;;) {
02629             /* Try to get party B back. */
02630             ast_debug(1, "We're trying to callback %s/%s\n",
02631                transferer_tech, transferer_name);
02632             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02633                transferee, transferee, transferer_tech,
02634                ast_best_codec(transferee->nativeformats), transferer_name,
02635                atxfernoanswertimeout, &outstate, transferer->language);
02636             ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
02637                !!newchan, outstate);
02638             if (newchan || ast_check_hangup(transferee)) {
02639                break;
02640             }
02641 
02642             ++tries;
02643             if (atxfercallbackretries <= tries) {
02644                /* No more callback tries remaining. */
02645                break;
02646             }
02647 
02648             if (atxferloopdelay) {
02649                /* Transfer failed, sleeping */
02650                ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n",
02651                   atxferloopdelay);
02652                ast_safe_sleep(transferee, atxferloopdelay);
02653                if (ast_check_hangup(transferee)) {
02654                   ast_party_connected_line_free(&connected_line);
02655                   return -1;
02656                }
02657             }
02658 
02659             /* Retry dialing party C. */
02660             ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
02661             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02662                transferer, transferee, "Local",
02663                ast_best_codec(transferee->nativeformats), xferto,
02664                atxfernoanswertimeout, &outstate, transferer->language);
02665             ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
02666                !!newchan, outstate);
02667             if (newchan || ast_check_hangup(transferee)) {
02668                break;
02669             }
02670          }
02671       }
02672       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02673       if (!newchan) {
02674          /* No party C or could not callback party B. */
02675          ast_party_connected_line_free(&connected_line);
02676          return -1;
02677       }
02678 
02679       /* newchan is up, we should prepare transferee and bridge them */
02680       if (ast_check_hangup(newchan)) {
02681          ast_hangup(newchan);
02682          ast_party_connected_line_free(&connected_line);
02683          return -1;
02684       }
02685       if (check_compat(transferee, newchan)) {
02686          ast_party_connected_line_free(&connected_line);
02687          return -1;
02688       }
02689    } else {
02690       /*
02691        * Both the transferer and transferee have hungup.  If newchan
02692        * is up, hang it up as it has no one to talk to.
02693        */
02694       ast_debug(1, "Everyone is hungup.\n");
02695       if (newchan) {
02696          ast_hangup(newchan);
02697       }
02698       ast_party_connected_line_free(&connected_line);
02699       return -1;
02700    }
02701 
02702    /* Initiate the channel transfer of party A to party C (or recalled party B). */
02703    ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
02704 
02705    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name);
02706    if (!xferchan) {
02707       ast_hangup(newchan);
02708       ast_party_connected_line_free(&connected_line);
02709       return -1;
02710    }
02711 
02712    /* Give party A a momentary ringback tone during transfer. */
02713    xferchan->visible_indication = AST_CONTROL_RINGING;
02714 
02715    /* Make formats okay */
02716    xferchan->readformat = transferee->readformat;
02717    xferchan->writeformat = transferee->writeformat;
02718 
02719    ast_channel_masquerade(xferchan, transferee);
02720    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
02721    xferchan->_state = AST_STATE_UP;
02722    ast_clear_flag(xferchan, AST_FLAGS_ALL);
02723 
02724    /* Do the masquerade manually to make sure that is is completed. */
02725    ast_do_masquerade(xferchan);
02726 
02727    newchan->_state = AST_STATE_UP;
02728    ast_clear_flag(newchan, AST_FLAGS_ALL);
02729    tobj = ast_calloc(1, sizeof(*tobj));
02730    if (!tobj) {
02731       ast_hangup(xferchan);
02732       ast_hangup(newchan);
02733       ast_party_connected_line_free(&connected_line);
02734       return -1;
02735    }
02736 
02737    ast_channel_lock(newchan);
02738    if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
02739       dialfeatures = features_datastore->data;
02740    }
02741    ast_channel_unlock(newchan);
02742 
02743    if (dialfeatures) {
02744       /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
02745          I don't currently understand, the abilities of newchan seem to be stored on the caller side */
02746       ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02747       dialfeatures = NULL;
02748    }
02749 
02750    ast_channel_lock(xferchan);
02751    if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
02752       dialfeatures = features_datastore->data;
02753    }
02754    ast_channel_unlock(xferchan);
02755 
02756    if (dialfeatures) {
02757       ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02758    }
02759 
02760    tobj->chan = newchan;
02761    tobj->peer = xferchan;
02762    tobj->bconfig = *config;
02763 
02764    if (tobj->bconfig.end_bridge_callback_data_fixup) {
02765       tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
02766    }
02767 
02768    /*
02769     * xferchan is transferee, and newchan is the transfer target
02770     * So...in a transfer, who is the caller and who is the callee?
02771     *
02772     * When the call is originally made, it is clear who is caller and callee.
02773     * When a transfer occurs, it is my humble opinion that the transferee becomes
02774     * the caller, and the transfer target is the callee.
02775     *
02776     * The problem is that these macros were set with the intention of the original
02777     * caller and callee taking those roles.  A transfer can totally mess things up,
02778     * to be technical.  What sucks even more is that you can't effectively change
02779     * the macros in the dialplan during the call from the transferer to the transfer
02780     * target because the transferee is stuck with whatever role he originally had.
02781     *
02782     * I think the answer here is just to make sure that it is well documented that
02783     * during a transfer, the transferee is the "caller" and the transfer target
02784     * is the "callee."
02785     *
02786     * This means that if party B calls party A, and party B transfers party A to
02787     * party C, then A has switched roles for the call.  Now party A will have the
02788     * caller macro called on his channel instead of the callee macro.
02789     *
02790     * Luckily, the method by which the party B to party C bridge is
02791     * launched above ensures that the transferee is the "chan" on
02792     * the bridge and the transfer target is the "peer," so my idea
02793     * for the roles post-transfer does not require extensive code
02794     * changes.
02795     */
02796 
02797    /* Transfer party C connected line to party A */
02798    ast_channel_lock(transferer);
02799    /*
02800     * Due to a limitation regarding when callerID is set on a Local channel,
02801     * we use the transferer's connected line information here.
02802     */
02803    ast_party_connected_line_copy(&connected_line, &transferer->connected);
02804    ast_channel_unlock(transferer);
02805    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02806    if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
02807       ast_channel_update_connected_line(xferchan, &connected_line, NULL);
02808    }
02809 
02810    /* Transfer party A connected line to party C */
02811    ast_channel_lock(xferchan);
02812    ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller);
02813    ast_channel_unlock(xferchan);
02814    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02815    if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
02816       ast_channel_update_connected_line(newchan, &connected_line, NULL);
02817    }
02818 
02819    if (ast_stream_and_wait(newchan, xfersound, ""))
02820       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02821    bridge_call_thread_launch(tobj);
02822 
02823    ast_party_connected_line_free(&connected_line);
02824    return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */
02825 }

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 2092 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_NOTICE, 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.

02093 {
02094    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
02095    int x = 0;
02096    size_t len;
02097    struct ast_channel *caller_chan, *callee_chan;
02098    const char *mixmonitor_spy_type = "MixMonitor";
02099    int count = 0;
02100 
02101    if (!mixmonitor_ok) {
02102       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
02103       return -1;
02104    }
02105 
02106    if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
02107       mixmonitor_ok = 0;
02108       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
02109       return -1;
02110    }
02111 
02112    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
02113 
02114    if (!ast_strlen_zero(courtesytone)) {
02115       if (ast_autoservice_start(callee_chan))
02116          return -1;
02117       ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
02118       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
02119          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02120          ast_autoservice_stop(callee_chan);
02121          return -1;
02122       }
02123       if (ast_autoservice_stop(callee_chan))
02124          return -1;
02125    }
02126 
02127    ast_channel_lock(callee_chan);
02128    count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
02129    ast_channel_unlock(callee_chan);
02130 
02131    /* This means a mixmonitor is attached to the channel, running or not is unknown. */
02132    if (count > 0) {
02133       
02134       ast_verb(3, "User hit '%s' to stop recording call.\n", code);
02135 
02136       /* Make sure they are running */
02137       ast_channel_lock(callee_chan);
02138       count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
02139       ast_channel_unlock(callee_chan);
02140       if (count > 0) {
02141          if (!stopmixmonitor_ok) {
02142             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
02143             return -1;
02144          }
02145          if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
02146             stopmixmonitor_ok = 0;
02147             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
02148             return -1;
02149          } else {
02150             pbx_exec(callee_chan, stopmixmonitor_app, "");
02151             return AST_FEATURE_RETURN_SUCCESS;
02152          }
02153       }
02154       
02155       ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 
02156    }        
02157 
02158    if (caller_chan && callee_chan) {
02159       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
02160       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
02161 
02162       if (!touch_format)
02163          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
02164 
02165       if (!touch_monitor)
02166          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
02167 
02168       if (touch_monitor) {
02169          len = strlen(touch_monitor) + 50;
02170          args = alloca(len);
02171          touch_filename = alloca(len);
02172          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
02173          snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
02174       } else {
02175          caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
02176             caller_chan->caller.id.number.str, caller_chan->name));
02177          callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
02178             callee_chan->caller.id.number.str, callee_chan->name));
02179          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
02180          args = alloca(len);
02181          touch_filename = alloca(len);
02182          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
02183          snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
02184       }
02185 
02186       for( x = 0; x < strlen(args); x++) {
02187          if (args[x] == '/')
02188             args[x] = '-';
02189       }
02190 
02191       ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
02192 
02193       pbx_exec(callee_chan, mixmonitor_app, args);
02194       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
02195       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
02196       return AST_FEATURE_RETURN_SUCCESS;
02197    
02198    }
02199 
02200    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
02201    return -1;
02202 
02203 }

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 1997 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, LOG_NOTICE, 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.

01998 {
01999    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
02000    int x = 0;
02001    size_t len;
02002    struct ast_channel *caller_chan, *callee_chan;
02003    const char *automon_message_start = NULL;
02004    const char *automon_message_stop = NULL;
02005 
02006    if (!monitor_ok) {
02007       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
02008       return -1;
02009    }
02010 
02011    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
02012       monitor_ok = 0;
02013       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
02014       return -1;
02015    }
02016 
02017    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
02018    if (caller_chan) {   /* Find extra messages */
02019       automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
02020       automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
02021    }
02022 
02023    if (!ast_strlen_zero(courtesytone)) {  /* Play courtesy tone if configured */
02024       if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
02025          return -1;
02026       }
02027    }
02028    
02029    if (callee_chan->monitor) {
02030       ast_verb(4, "User hit '%s' to stop recording call.\n", code);
02031       if (!ast_strlen_zero(automon_message_stop)) {
02032          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
02033       }
02034       callee_chan->monitor->stop(callee_chan, 1);
02035       return AST_FEATURE_RETURN_SUCCESS;
02036    }
02037 
02038    if (caller_chan && callee_chan) {
02039       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
02040       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
02041       const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
02042 
02043       if (!touch_format)
02044          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
02045 
02046       if (!touch_monitor)
02047          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
02048    
02049       if (!touch_monitor_prefix)
02050          touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
02051    
02052       if (touch_monitor) {
02053          len = strlen(touch_monitor) + 50;
02054          args = alloca(len);
02055          touch_filename = alloca(len);
02056          snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
02057          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
02058       } else {
02059          caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
02060             caller_chan->caller.id.number.str, caller_chan->name));
02061          callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
02062             callee_chan->caller.id.number.str, callee_chan->name));
02063          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
02064          args = alloca(len);
02065          touch_filename = alloca(len);
02066          snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
02067          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
02068       }
02069 
02070       for(x = 0; x < strlen(args); x++) {
02071          if (args[x] == '/')
02072             args[x] = '-';
02073       }
02074       
02075       ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
02076 
02077       pbx_exec(callee_chan, monitor_app, args);
02078       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
02079       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
02080 
02081       if (!ast_strlen_zero(automon_message_start)) {  /* Play start message for both channels */
02082          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
02083       }
02084    
02085       return AST_FEATURE_RETURN_SUCCESS;
02086    }
02087    
02088    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
02089    return -1;
02090 }

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

02249 {
02250    struct ast_channel *transferer;
02251    struct ast_channel *transferee;
02252    struct ast_exten *park_exten;
02253    const char *transferer_real_context;
02254    char xferto[256] = "";
02255    int res;
02256 
02257    ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02258    set_peers(&transferer, &transferee, peer, chan, sense);
02259    transferer_real_context = real_ctx(transferer, transferee);
02260 
02261    /* Start autoservice on transferee while we talk to the transferer */
02262    ast_autoservice_start(transferee);
02263    ast_indicate(transferee, AST_CONTROL_HOLD);
02264 
02265    /* Transfer */
02266    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02267    if (res < 0) {
02268       finishup(transferee);
02269       return -1; /* error ? */
02270    }
02271    if (res > 0) { /* If they've typed a digit already, handle it */
02272       xferto[0] = (char) res;
02273    }
02274 
02275    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02276    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
02277       finishup(transferee);
02278       return -1;
02279    }
02280    if (res == 0) {
02281       if (xferto[0]) {
02282          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02283             xferto, transferer_real_context);
02284       } else {
02285          /* Does anyone care about this case? */
02286          ast_log(LOG_WARNING, "No digits dialed.\n");
02287       }
02288       ast_stream_and_wait(transferer, "pbx-invalid", "");
02289       finishup(transferee);
02290       return AST_FEATURE_RETURN_SUCCESS;
02291    }
02292 
02293    park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
02294    if (park_exten) {
02295       /* We are transfering the transferee to a parking lot. */
02296       return xfer_park_call_helper(transferee, transferer, park_exten);
02297    }
02298 
02299    /* Do blind transfer. */
02300    ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n",
02301       transferee->name, xferto, transferer_real_context);
02302    ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
02303    pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
02304    pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
02305    finishup(transferee);
02306    ast_channel_lock(transferer);
02307    if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
02308       transferer->cdr = ast_cdr_alloc();
02309       if (transferer->cdr) {
02310          ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */
02311          ast_cdr_start(transferer->cdr);
02312       }
02313    }
02314    ast_channel_unlock(transferer);
02315    if (transferer->cdr) {
02316       struct ast_cdr *swap = transferer->cdr;
02317 
02318       ast_debug(1,
02319          "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
02320          transferer->name, transferee->name, transferer->cdr->lastapp,
02321          transferer->cdr->lastdata, transferer->cdr->channel,
02322          transferer->cdr->dstchannel);
02323       ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
02324          transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel,
02325          transferee->cdr->dstchannel);
02326       ast_debug(1, "transferer_real_context=%s; xferto=%s\n",
02327          transferer_real_context, xferto);
02328       /* swap cdrs-- it will save us some time & work */
02329       transferer->cdr = transferee->cdr;
02330       transferee->cdr = swap;
02331    }
02332    if (!transferee->pbx) {
02333       /* Doh!  Use our handy async_goto functions */
02334       ast_debug(1, "About to ast_async_goto %s.\n", transferee->name);
02335       if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) {
02336          ast_log(LOG_WARNING, "Async goto failed :-(\n");
02337       }
02338 
02339       /* The transferee is masqueraded and the original bridged channels can be hungup. */
02340       res = -1;
02341    } else {
02342       /* Set the transferee's new extension, since it exists, using transferer context */
02343       ast_debug(1, "About to explicit goto %s, it has a PBX.\n", transferee->name);
02344       ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
02345       set_c_e_p(transferee, transferer_real_context, xferto, 0);
02346 
02347       /*
02348        * Break the bridge.  The transferee needs to resume executing
02349        * dialplan at the xferto location.
02350        */
02351       res = AST_FEATURE_RETURN_SUCCESSBREAK;
02352    }
02353    check_goto_on_transfer(transferer);
02354    return res;
02355 }

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

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

02206 {
02207    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
02208    return AST_FEATURE_RETURN_HANGUP;
02209 }

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

01876 {
01877    struct ast_channel *parker;
01878    struct ast_channel *parkee;
01879    struct ast_park_call_args args = { 0, };
01880 
01881    /*
01882     * We used to set chan's exten and priority to "s" and 1 here,
01883     * but this generates (in some cases) an invalid extension, and
01884     * if "s" exists, could errantly cause execution of extensions
01885     * you don't expect.  It makes more sense to let nature take its
01886     * course when chan finishes, and let the pbx do its thing and
01887     * hang up when the park is over.
01888     */
01889 
01890    /* Answer if call is not up */
01891    if (chan->_state != AST_STATE_UP) {
01892       /*
01893        * XXX Why are we doing this?  Both of the channels should be up
01894        * since you cannot do DTMF features unless you are bridged.
01895        */
01896       if (ast_answer(chan)) {
01897          return -1;
01898       }
01899 
01900       /* Sleep to allow VoIP streams to settle down */
01901       if (ast_safe_sleep(chan, 1000)) {
01902          return -1;
01903       }
01904    }
01905 
01906    /* one direction used to call park_call.... */
01907    set_peers(&parker, &parkee, peer, chan, sense);
01908    return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1;
01909 }

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

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

04497 {
04498    int i = 0;
04499    enum {
04500       OPT_CALLEE_REDIRECT   = 't',
04501       OPT_CALLER_REDIRECT   = 'T',
04502       OPT_CALLEE_AUTOMON    = 'w',
04503       OPT_CALLER_AUTOMON    = 'W',
04504       OPT_CALLEE_DISCONNECT = 'h',
04505       OPT_CALLER_DISCONNECT = 'H',
04506       OPT_CALLEE_PARKCALL   = 'k',
04507       OPT_CALLER_PARKCALL   = 'K',
04508    };
04509 
04510    memset(options, 0, len);
04511    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
04512       options[i++] = OPT_CALLER_REDIRECT;
04513    }
04514    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
04515       options[i++] = OPT_CALLER_AUTOMON;
04516    }
04517    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
04518       options[i++] = OPT_CALLER_DISCONNECT;
04519    }
04520    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
04521       options[i++] = OPT_CALLER_PARKCALL;
04522    }
04523 
04524    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
04525       options[i++] = OPT_CALLEE_REDIRECT;
04526    }
04527    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
04528       options[i++] = OPT_CALLEE_AUTOMON;
04529    }
04530    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
04531       options[i++] = OPT_CALLEE_DISCONNECT;
04532    }
04533    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
04534       options[i++] = OPT_CALLEE_PARKCALL;
04535    }
04536 
04537    return options;
04538 }

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

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

Referenced by builtin_atxfer().

02365 {
02366    if (ast_channel_make_compatible(c, newchan) < 0) {
02367       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
02368          c->name, newchan->name);
02369       ast_hangup(newchan);
02370       return -1;
02371    }
02372    return 0;
02373 }

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

00846 {
00847    struct ast_channel *xferchan;
00848    const char *val;
00849    char *goto_on_transfer;
00850    char *x;
00851 
00852    ast_channel_lock(chan);
00853    val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00854    if (ast_strlen_zero(val)) {
00855       ast_channel_unlock(chan);
00856       return;
00857    }
00858    goto_on_transfer = ast_strdupa(val);
00859    ast_channel_unlock(chan);
00860 
00861    ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, chan->name);
00862 
00863    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0,
00864       "%s", chan->name);
00865    if (!xferchan) {
00866       return;
00867    }
00868 
00869    /* Make formats okay */
00870    xferchan->readformat = chan->readformat;
00871    xferchan->writeformat = chan->writeformat;
00872 
00873    if (ast_channel_masquerade(xferchan, chan)) {
00874       /* Failed to setup masquerade. */
00875       ast_hangup(xferchan);
00876       return;
00877    }
00878 
00879    for (x = goto_on_transfer; *x; ++x) {
00880       if (*x == '^') {
00881          *x = ',';
00882       }
00883    }
00884    ast_parseable_goto(xferchan, goto_on_transfer);
00885    xferchan->_state = AST_STATE_UP;
00886    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00887    ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
00888 
00889    if (ast_do_masquerade(xferchan) || ast_pbx_start(xferchan)) {
00890       /* Failed to do masquerade or could not start PBX. */
00891       ast_hangup(xferchan);
00892    }
00893 }

static void clear_dialed_interfaces ( struct ast_channel chan  )  [static]

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

03799 {
03800    struct ast_datastore *di_datastore;
03801 
03802    ast_channel_lock(chan);
03803    if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
03804       if (option_debug) {
03805          ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name);
03806       }
03807       if (!ast_channel_datastore_remove(chan, di_datastore)) {
03808          ast_datastore_free(di_datastore);
03809       }
03810    }
03811    ast_channel_unlock(chan);
03812 }

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

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

Referenced by create_dynamic_parkinglot().

04860 {
04861    struct ast_parkinglot *copylot;
04862 
04863    if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
04864       ao2_ref(copylot, -1);
04865       return NULL;
04866    }
04867 
04868    copylot = create_parkinglot(name);
04869    if (!copylot) {
04870       return NULL;
04871    }
04872 
04873    ast_debug(1, "Building parking lot %s\n", name);
04874 
04875    /* Copy the source parking lot configuration. */
04876    copylot->cfg = parkinglot->cfg;
04877 
04878    return copylot;
04879 }

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

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

01076 {
01077    const char *dyn_context;
01078    const char *dyn_exten;
01079    const char *dyn_range;
01080    const char *template_name;
01081    struct ast_parkinglot *template_parkinglot = NULL;
01082    struct ast_parkinglot *parkinglot;
01083    int dyn_start;
01084    int dyn_end;
01085 
01086    ast_channel_lock(chan);
01087    template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
01088    dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
01089    dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), ""));
01090    dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
01091    ast_channel_unlock(chan);
01092 
01093    if (!ast_strlen_zero(template_name)) {
01094       template_parkinglot = find_parkinglot(template_name);
01095       if (!template_parkinglot) {
01096          ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n",
01097             template_name);
01098       } else if (template_parkinglot->cfg.is_invalid) {
01099          ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n",
01100             template_name);
01101          parkinglot_unref(template_parkinglot);
01102          template_parkinglot = NULL;
01103       }
01104    }
01105    if (!template_parkinglot) {
01106       template_parkinglot = parkinglot_addref(default_parkinglot);
01107       ast_debug(1, "Using default parking lot for template\n");
01108    }
01109 
01110    parkinglot = copy_parkinglot(name, template_parkinglot);
01111    if (!parkinglot) {
01112       ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
01113    } else {
01114       /* Configure the dynamic parking lot. */
01115       if (!ast_strlen_zero(dyn_context)) {
01116          ast_copy_string(parkinglot->cfg.parking_con, dyn_context,
01117             sizeof(parkinglot->cfg.parking_con));
01118       }
01119       if (!ast_strlen_zero(dyn_exten)) {
01120          ast_copy_string(parkinglot->cfg.parkext, dyn_exten,
01121             sizeof(parkinglot->cfg.parkext));
01122       }
01123       if (!ast_strlen_zero(dyn_range)) {
01124          if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
01125             ast_log(LOG_WARNING,
01126                "Format for parking positions is a-b, where a and b are numbers\n");
01127          } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) {
01128             ast_log(LOG_WARNING,
01129                "Format for parking positions is a-b, where a <= b\n");
01130          } else {
01131             parkinglot->cfg.parking_start = dyn_start;
01132             parkinglot->cfg.parking_stop = dyn_end;
01133          }
01134       }
01135 
01136       /*
01137        * Sanity check for dynamic parking lot configuration.
01138        *
01139        * XXX It may be desirable to instead check if the dynamic
01140        * parking lot overlaps any existing lots like what is done for
01141        * a reload.
01142        */
01143       if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) {
01144          if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext)
01145             && parkinglot->cfg.parkext_exclusive) {
01146             ast_log(LOG_WARNING,
01147                "Parking lot '%s' conflicts with template parking lot '%s'!\n"
01148                "Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n",
01149                parkinglot->name, template_parkinglot->name);
01150          }
01151          if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start
01152                && parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop)
01153             || (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop
01154                && parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop)
01155             || (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start
01156                && template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) {
01157             ast_log(LOG_WARNING,
01158                "Parking lot '%s' parking spaces overlap template parking lot '%s'!\n"
01159                "Change PARKINGDYNPOS.\n",
01160                parkinglot->name, template_parkinglot->name);
01161          }
01162       }
01163 
01164       parkinglot_activate(parkinglot);
01165       ao2_link(parkinglots, parkinglot);
01166    }
01167    parkinglot_unref(template_parkinglot);
01168 
01169    return parkinglot;
01170 }

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

Allocate parking lot structure.

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

05284 {
05285    struct ast_parkinglot *newlot;
05286 
05287    if (ast_strlen_zero(name)) { /* No name specified */
05288       return NULL;
05289    }
05290 
05291    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
05292    if (!newlot)
05293       return NULL;
05294    
05295    ast_copy_string(newlot->name, name, sizeof(newlot->name));
05296    newlot->cfg.is_invalid = 1;/* No config is set yet. */
05297    AST_LIST_HEAD_INIT(&newlot->parkings);
05298 
05299    return newlot;
05300 }

static void destroy_dialplan_usage_context ( struct parking_dp_context doomed  )  [static]

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

05860 {
05861    struct parking_dp_ramp *ramp;
05862    struct parking_dp_spaces *spaces;
05863 
05864    while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) {
05865       ast_free(ramp);
05866    }
05867    while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) {
05868       ast_free(spaces);
05869    }
05870    while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) {
05871       ast_free(spaces);
05872    }
05873    ast_free(doomed);
05874 }

static void destroy_dialplan_usage_map ( struct parking_dp_map doomed  )  [static]

Definition at line 5884 of file features.c.

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

Referenced by load_config().

05885 {
05886    struct parking_dp_context *item;
05887 
05888    while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) {
05889       destroy_dialplan_usage_context(item);
05890    }
05891 }

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

Definition at line 6314 of file features.c.

References AST_MAX_EXTENSION, PRIORITY_HINT, and remove_exten_if_exist().

Referenced by remove_dead_spaces_usage().

06315 {
06316    char exten[AST_MAX_EXTENSION];
06317 
06318    /* Destroy priorities of the parking space that we registered. */
06319    snprintf(exten, sizeof(exten), "%d", space);
06320    remove_exten_if_exist(context, exten, PRIORITY_HINT);
06321    remove_exten_if_exist(context, exten, 1);
06322 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 739 of file features.c.

References ast_free.

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

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

Definition at line 726 of file features.c.

References ast_calloc.

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

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

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

06168 {
06169    struct parking_dp_context *cur_ctx;
06170    struct parking_dp_context *new_ctx;
06171    int cmp;
06172 
06173    AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) {
06174       cmp = strcmp(lot->cfg.parking_con, cur_ctx->context);
06175       if (cmp > 0) {
06176          /* The parking lot context goes after this node. */
06177          continue;
06178       }
06179       if (cmp == 0) {
06180          /* This is the node we will add parking lot spaces to the map. */
06181          return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain);
06182       }
06183       /* The new parking lot context goes before this node. */
06184       new_ctx = build_dialplan_useage_context(lot);
06185       if (!new_ctx) {
06186          return -1;
06187       }
06188       AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node);
06189       return 0;
06190    }
06191    AST_LIST_TRAVERSE_SAFE_END;
06192 
06193    /* New parking lot context goes on the end. */
06194    new_ctx = build_dialplan_useage_context(lot);
06195    if (!new_ctx) {
06196       return -1;
06197    }
06198    AST_LIST_INSERT_TAIL(usage_map, new_ctx, node);
06199    return 0;
06200 }

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

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

06114 {
06115    if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext,
06116       lot->cfg.parkext_exclusive, lot, complain)) {
06117       return -1;
06118    }
06119    if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start,
06120       lot->cfg.parking_stop, lot, complain)) {
06121       return -1;
06122    }
06123    if (lot->cfg.parkaddhints
06124       && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start,
06125          lot->cfg.parking_stop, lot, 0)) {
06126       return -1;
06127    }
06128    return 0;
06129 }

static void 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.

Definition at line 6747 of file features.c.

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

Referenced by action_bridge(), and bridge_exec().

06748 {
06749    ast_moh_stop(chan);
06750    ast_channel_lock_both(chan, tmpchan);
06751    ast_setstate(tmpchan, chan->_state);
06752    tmpchan->readformat = chan->readformat;
06753    tmpchan->writeformat = chan->writeformat;
06754    ast_channel_unlock(chan);
06755    ast_channel_unlock(tmpchan);
06756 
06757    ast_channel_masquerade(tmpchan, chan);
06758 
06759    /* must be done without any channel locks held */
06760    ast_do_masquerade(tmpchan);
06761 
06762    /* when returning from bridge, the channel will continue at the next priority */
06763    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
06764 }

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

04810 {
04811    struct pollfd *pfds = NULL, *new_pfds = NULL;
04812    int nfds = 0, new_nfds = 0;
04813 
04814    for (;;) {
04815       struct ao2_iterator iter;
04816       struct ast_parkinglot *curlot;
04817       int ms = -1;   /* poll2 timeout, uninitialized */
04818 
04819       iter = ao2_iterator_init(parkinglots, 0);
04820       while ((curlot = ao2_iterator_next(&iter))) {
04821          manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
04822          ao2_ref(curlot, -1);
04823       }
04824       ao2_iterator_destroy(&iter);
04825 
04826       /* Recycle */
04827       ast_free(pfds);
04828       pfds = new_pfds;
04829       nfds = new_nfds;
04830       new_pfds = NULL;
04831       new_nfds = 0;
04832 
04833       /* Wait for something to happen */
04834       ast_poll(pfds, nfds, ms);
04835       pthread_testcancel();
04836    }
04837    /* If this WERE reached, we'd need to free(pfds) */
04838    return NULL;   /* Never reached */
04839 }

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

Check if a feature exists.

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

03283                                                                                            {
03284    char *chan_dynamic_features;
03285    ast_channel_lock(chan);
03286    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03287    ast_channel_unlock(chan);
03288 
03289    return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL);
03290 }

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

03031 {
03032    struct ast_app *app;
03033    struct ast_call_feature *feature = data;
03034    struct ast_channel *work, *idle;
03035    int res;
03036 
03037    if (!feature) { /* shouldn't ever happen! */
03038       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
03039       return -1; 
03040    }
03041 
03042    if (sense == FEATURE_SENSE_CHAN) {
03043       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
03044          return AST_FEATURE_RETURN_KEEPTRYING;
03045       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03046          work = chan;
03047          idle = peer;
03048       } else {
03049          work = peer;
03050          idle = chan;
03051       }
03052    } else {
03053       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
03054          return AST_FEATURE_RETURN_KEEPTRYING;
03055       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
03056          work = peer;
03057          idle = chan;
03058       } else {
03059          work = chan;
03060          idle = peer;
03061       }
03062    }
03063 
03064    if (!(app = pbx_findapp(feature->app))) {
03065       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
03066       return -2;
03067    }
03068 
03069    ast_autoservice_start(idle);
03070    ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
03071    
03072    if(work && idle) {
03073       pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name);
03074       pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name);
03075       pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
03076       pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
03077    }
03078 
03079    if (!ast_strlen_zero(feature->moh_class))
03080       ast_moh_start(idle, feature->moh_class, NULL);
03081 
03082    res = pbx_exec(work, app, feature->app_args);
03083 
03084    if (!ast_strlen_zero(feature->moh_class))
03085       ast_moh_stop(idle);
03086 
03087    ast_autoservice_stop(idle);
03088 
03089    if (res) {
03090       return AST_FEATURE_RETURN_SUCCESSBREAK;
03091    }
03092    return AST_FEATURE_RETURN_SUCCESS;  /*! \todo XXX should probably return res */
03093 }

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

03248                                                                                                                                                 {
03249 
03250    char dynamic_features_buf[128];
03251    const char *peer_dynamic_features, *chan_dynamic_features;
03252    struct ast_flags features;
03253    struct ast_call_feature feature;
03254    if (sense == FEATURE_SENSE_CHAN) {
03255       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
03256    }
03257    else {
03258       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
03259    }
03260 
03261    ast_channel_lock(peer);
03262    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
03263    ast_channel_unlock(peer);
03264 
03265    ast_channel_lock(chan);
03266    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
03267    ast_channel_unlock(chan);
03268 
03269    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,""));
03270 
03271    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);
03272 
03273    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
03274 }

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

03136 {
03137    int x;
03138    struct feature_group *fg = NULL;
03139    struct feature_group_exten *fge;
03140    struct ast_call_feature *tmpfeature;
03141    char *tmp, *tok;
03142    int res = AST_FEATURE_RETURN_PASSDIGITS;
03143    int feature_detected = 0;
03144 
03145    if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) {
03146       return -1; /* can not run feature operation */
03147    }
03148 
03149    ast_rwlock_rdlock(&features_lock);
03150    for (x = 0; x < FEATURES_COUNT; x++) {
03151       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
03152           !ast_strlen_zero(builtin_features[x].exten)) {
03153          /* Feature is up for consideration */
03154          if (!strcmp(builtin_features[x].exten, code)) {
03155             ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
03156             if (operation == FEATURE_INTERPRET_CHECK) {
03157                res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
03158             } else if (operation == FEATURE_INTERPRET_DO) {
03159                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
03160             }
03161             if (feature) {
03162                memcpy(feature, &builtin_features[x], sizeof(feature));
03163             }
03164             feature_detected = 1;
03165             break;
03166          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
03167             if (res == AST_FEATURE_RETURN_PASSDIGITS) {
03168                res = AST_FEATURE_RETURN_STOREDIGITS;
03169             }
03170          }
03171       }
03172    }
03173    ast_rwlock_unlock(&features_lock);
03174 
03175    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
03176       return res;
03177    }
03178 
03179    tmp = dynamic_features_buf;
03180 
03181    while ((tok = strsep(&tmp, "#"))) {
03182       AST_RWLIST_RDLOCK(&feature_groups);
03183 
03184       fg = find_group(tok);
03185 
03186       if (fg) {
03187          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03188             if (!strcmp(fge->exten, code)) {
03189                if (operation) {
03190                   res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
03191                }
03192                memcpy(feature, fge->feature, sizeof(feature));
03193                if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03194                   AST_RWLIST_UNLOCK(&feature_groups);
03195                   break;
03196                }
03197                res = AST_FEATURE_RETURN_PASSDIGITS;
03198             } else if (!strncmp(fge->exten, code, strlen(code))) {
03199                res = AST_FEATURE_RETURN_STOREDIGITS;
03200             }
03201          }
03202          if (fge) {
03203             break;
03204          }
03205       }
03206 
03207       AST_RWLIST_UNLOCK(&feature_groups);
03208 
03209       AST_RWLIST_RDLOCK(&feature_list);
03210 
03211       if (!(tmpfeature = find_dynamic_feature(tok))) {
03212          AST_RWLIST_UNLOCK(&feature_list);
03213          continue;
03214       }
03215 
03216       /* Feature is up for consideration */
03217       if (!strcmp(tmpfeature->exten, code)) {
03218          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
03219          if (operation == FEATURE_INTERPRET_CHECK) {
03220             res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
03221          } else if (operation == FEATURE_INTERPRET_DO) {
03222             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
03223          }
03224          if (feature) {
03225             memcpy(feature, tmpfeature, sizeof(feature));
03226          }
03227          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
03228             AST_RWLIST_UNLOCK(&feature_list);
03229             break;
03230          }
03231          res = AST_FEATURE_RETURN_PASSDIGITS;
03232       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
03233          res = AST_FEATURE_RETURN_STOREDIGITS;
03234 
03235       AST_RWLIST_UNLOCK(&feature_list);
03236    }
03237 
03238    return res;
03239 }

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

03391 {
03392    int state = 0;
03393    int cause = 0;
03394    int to;
03395    int caller_hungup;
03396    int transferee_hungup;
03397    struct ast_channel *chan;
03398    struct ast_channel *monitor_chans[3];
03399    struct ast_channel *active_channel;
03400    int res;
03401    int ready = 0;
03402    struct timeval started;
03403    int x, len = 0;
03404    char *disconnect_code = NULL, *dialed_code = NULL;
03405    struct ast_frame *f;
03406    AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
03407 
03408    caller_hungup = ast_check_hangup(caller);
03409 
03410    if (!(chan = ast_request(type, format, requestor, data, &cause))) {
03411       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
03412       switch (cause) {
03413       case AST_CAUSE_BUSY:
03414          state = AST_CONTROL_BUSY;
03415          break;
03416       case AST_CAUSE_CONGESTION:
03417          state = AST_CONTROL_CONGESTION;
03418          break;
03419       default:
03420          state = 0;
03421          break;
03422       }
03423       goto done;
03424    }
03425 
03426    ast_string_field_set(chan, language, language);
03427    ast_channel_inherit_variables(caller, chan);
03428    pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
03429 
03430    ast_channel_lock(chan);
03431    ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller);
03432    ast_channel_unlock(chan);
03433 
03434    if (ast_call(chan, data, timeout)) {
03435       ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
03436       switch (chan->hangupcause) {
03437       case AST_CAUSE_BUSY:
03438          state = AST_CONTROL_BUSY;
03439          break;
03440       case AST_CAUSE_CONGESTION:
03441          state = AST_CONTROL_CONGESTION;
03442          break;
03443       default:
03444          state = 0;
03445          break;
03446       }
03447       goto done;
03448    }
03449 
03450    /* support dialing of the featuremap disconnect code while performing an attended tranfer */
03451    ast_rwlock_rdlock(&features_lock);
03452    for (x = 0; x < FEATURES_COUNT; x++) {
03453       if (strcasecmp(builtin_features[x].sname, "disconnect"))
03454          continue;
03455 
03456       disconnect_code = builtin_features[x].exten;
03457       len = strlen(disconnect_code) + 1;
03458       dialed_code = alloca(len);
03459       memset(dialed_code, 0, len);
03460       break;
03461    }
03462    ast_rwlock_unlock(&features_lock);
03463    x = 0;
03464    started = ast_tvnow();
03465    to = timeout;
03466    AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
03467 
03468    ast_poll_channel_add(caller, chan);
03469 
03470    transferee_hungup = 0;
03471    while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) {
03472       int num_chans = 0;
03473 
03474       monitor_chans[num_chans++] = transferee;
03475       monitor_chans[num_chans++] = chan;
03476       if (!caller_hungup) {
03477          if (ast_check_hangup(caller)) {
03478             caller_hungup = 1;
03479 
03480 #if defined(ATXFER_NULL_TECH)
03481             /* Change caller's name to ensure that it will remain unique. */
03482             set_new_chan_name(caller);
03483 
03484             /*
03485              * Get rid of caller's physical technology so it is free for
03486              * other calls.
03487              */
03488             set_kill_chan_tech(caller);
03489 #endif   /* defined(ATXFER_NULL_TECH) */
03490          } else {
03491             /* caller is not hungup so monitor it. */
03492             monitor_chans[num_chans++] = caller;
03493          }
03494       }
03495 
03496       /* see if the timeout has been violated */
03497       if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
03498          state = AST_CONTROL_UNHOLD;
03499          ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name);
03500          break; /*doh! timeout*/
03501       }
03502 
03503       active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
03504       if (!active_channel)
03505          continue;
03506 
03507       f = NULL;
03508       if (transferee == active_channel) {
03509          struct ast_frame *dup_f;
03510 
03511          f = ast_read(transferee);
03512          if (f == NULL) { /*doh! where'd he go?*/
03513             transferee_hungup = 1;
03514             state = 0;
03515             break;
03516          }
03517          if (ast_is_deferrable_frame(f)) {
03518             dup_f = ast_frisolate(f);
03519             if (dup_f) {
03520                if (dup_f == f) {
03521                   f = NULL;
03522                }
03523                AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
03524             }
03525          }
03526       } else if (chan == active_channel) {
03527          if (!ast_strlen_zero(chan->call_forward)) {
03528             state = 0;
03529             ast_autoservice_start(transferee);
03530             chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
03531             ast_autoservice_stop(transferee);
03532             if (!chan) {
03533                break;
03534             }
03535             continue;
03536          }
03537          f = ast_read(chan);
03538          if (f == NULL) { /*doh! where'd he go?*/
03539             switch (chan->hangupcause) {
03540             case AST_CAUSE_BUSY:
03541                state = AST_CONTROL_BUSY;
03542                break;
03543             case AST_CAUSE_CONGESTION:
03544                state = AST_CONTROL_CONGESTION;
03545                break;
03546             default:
03547                state = 0;
03548                break;
03549             }
03550             break;
03551          }
03552 
03553          if (f->frametype == AST_FRAME_CONTROL) {
03554             if (f->subclass.integer == AST_CONTROL_RINGING) {
03555                ast_verb(3, "%s is ringing\n", chan->name);
03556                ast_indicate(caller, AST_CONTROL_RINGING);
03557             } else if (f->subclass.integer == AST_CONTROL_BUSY) {
03558                state = f->subclass.integer;
03559                ast_verb(3, "%s is busy\n", chan->name);
03560                ast_indicate(caller, AST_CONTROL_BUSY);
03561                ast_frfree(f);
03562                break;
03563             } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) {
03564                ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", chan->name, chan->exten);
03565             } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
03566                state = f->subclass.integer;
03567                ast_verb(3, "%s is congested\n", chan->name);
03568                ast_indicate(caller, AST_CONTROL_CONGESTION);
03569                ast_frfree(f);
03570                break;
03571             } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
03572                /* This is what we are hoping for */
03573                state = f->subclass.integer;
03574                ast_frfree(f);
03575                ready=1;
03576                break;
03577             } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
03578                if (caller_hungup) {
03579                   struct ast_party_connected_line connected;
03580 
03581                   /* Just save it for the transfer. */
03582                   ast_party_connected_line_set_init(&connected, &caller->connected);
03583                   res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
03584                      &connected);
03585                   if (!res) {
03586                      ast_channel_set_connected_line(caller, &connected, NULL);
03587                   }
03588                   ast_party_connected_line_free(&connected);
03589                } else {
03590                   ast_autoservice_start(transferee);
03591                   if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
03592                      ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
03593                         f->data.ptr, f->datalen);
03594                   }
03595                   ast_autoservice_stop(transferee);
03596                }
03597             } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
03598                if (!caller_hungup) {
03599                   ast_autoservice_start(transferee);
03600                   if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
03601                      ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
03602                         f->data.ptr, f->datalen);
03603                   }
03604                   ast_autoservice_stop(transferee);
03605                }
03606             } else if (f->subclass.integer != -1
03607                && f->subclass.integer != AST_CONTROL_PROGRESS
03608                && f->subclass.integer != AST_CONTROL_PROCEEDING) {
03609                ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
03610             }
03611             /* else who cares */
03612          } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03613             ast_write(caller, f);
03614          }
03615       } else if (caller == active_channel) {
03616          f = ast_read(caller);
03617          if (f) {
03618             if (f->frametype == AST_FRAME_DTMF) {
03619                dialed_code[x++] = f->subclass.integer;
03620                dialed_code[x] = '\0';
03621                if (strlen(dialed_code) == len) {
03622                   x = 0;
03623                } else if (x && strncmp(dialed_code, disconnect_code, x)) {
03624                   x = 0;
03625                   dialed_code[x] = '\0';
03626                }
03627                if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
03628                   /* Caller Canceled the call */
03629                   state = AST_CONTROL_UNHOLD;
03630                   ast_frfree(f);
03631                   break;
03632                }
03633             } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03634                ast_write(chan, f);
03635             }
03636          }
03637       }
03638       if (f)
03639          ast_frfree(f);
03640    } /* end while */
03641 
03642    ast_poll_channel_del(caller, chan);
03643 
03644    /*
03645     * We need to free all the deferred frames, but we only need to
03646     * queue the deferred frames if no hangup was received.
03647     */
03648    ast_channel_lock(transferee);
03649    transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
03650    while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
03651       if (!transferee_hungup) {
03652          ast_queue_frame_head(transferee, f);
03653       }
03654       ast_frfree(f);
03655    }
03656    ast_channel_unlock(transferee);
03657 
03658 done:
03659    ast_indicate(caller, -1);
03660    if (chan && (ready || chan->_state == AST_STATE_UP)) {
03661       state = AST_CONTROL_ANSWER;
03662    } else if (chan) {
03663       ast_hangup(chan);
03664       chan = NULL;
03665    }
03666 
03667    if (outstate)
03668       *outstate = state;
03669 
03670    return chan;
03671 }

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

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

07153 {
07154    struct ast_channel *target = obj;/*!< Potential pickup target */
07155    struct ast_channel *chan = data;/*!< Channel wanting to pickup call */
07156 
07157    ast_channel_lock(target);
07158    if (chan != target && (chan->pickupgroup & target->callgroup)
07159       && ast_can_pickup(target)) {
07160       /* Return with the channel still locked on purpose */
07161       return CMP_MATCH | CMP_STOP;
07162    }
07163    ast_channel_unlock(target);
07164 
07165    return 0;
07166 }

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

find a call feature by name

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

02952 {
02953    struct ast_call_feature *tmp;
02954 
02955    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
02956       if (!strcasecmp(tmp->sname, name)) {
02957          break;
02958       }
02959    }
02960 
02961    return tmp;
02962 }

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

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

Referenced by feature_interpret_helper().

02990 {
02991    struct feature_group *fg = NULL;
02992 
02993    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
02994       if (!strcasecmp(fg->gname, name))
02995          break;
02996    }
02997 
02998    return fg;
02999 }

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

Find parkinglot by name.

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

04843 {
04844    struct ast_parkinglot *parkinglot;
04845 
04846    if (ast_strlen_zero(name)) {
04847       return NULL;
04848    }
04849 
04850    parkinglot = ao2_find(parkinglots, (void *) name, 0);
04851    if (parkinglot) {
04852       ast_debug(1, "Found Parking lot: %s\n", parkinglot->name);
04853    }
04854 
04855    return parkinglot;
04856 }

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

00993 {
00994    const char *name;
00995 
00996    /* The channel variable overrides everything */
00997    name = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
00998    if (!name && !ast_strlen_zero(chan->parkinglot)) {
00999       /* Use the channel's parking lot. */
01000       name = chan->parkinglot;
01001    }
01002    return name;
01003 }

static int finishup ( struct ast_channel chan  )  [static]

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

01770 {
01771    ast_indicate(chan, AST_CONTROL_UNHOLD);
01772 
01773    return ast_autoservice_stop(chan);
01774 }

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

Definition at line 773 of file features.c.

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

00774 {
00775    struct ast_exten *exten;
00776    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
00777    const char *app_at_exten;
00778 
00779    exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
00780       E_MATCH);
00781    if (!exten) {
00782       return NULL;
00783    }
00784 
00785    app_at_exten = ast_get_extension_app(exten);
00786    if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) {
00787       return NULL;
00788    }
00789 
00790    return exten;
00791 }

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 6616 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.

06617 {
06618    int i;
06619    struct ast_call_feature *feature;
06620    struct ao2_iterator iter;
06621    struct ast_parkinglot *curlot;
06622 #define HFS_FORMAT "%-25s %-7s %-7s\n"
06623 
06624    switch (cmd) {
06625    
06626    case CLI_INIT:
06627       e->command = "features show";
06628       e->usage =
06629          "Usage: features show\n"
06630          "       Lists configured features\n";
06631       return NULL;
06632    case CLI_GENERATE:
06633       return NULL;
06634    }
06635 
06636    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
06637    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06638 
06639    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
06640 
06641    ast_rwlock_rdlock(&features_lock);
06642    for (i = 0; i < FEATURES_COUNT; i++)
06643       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
06644    ast_rwlock_unlock(&features_lock);
06645 
06646    ast_cli(a->fd, "\n");
06647    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
06648    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
06649    if (AST_RWLIST_EMPTY(&feature_list)) {
06650       ast_cli(a->fd, "(none)\n");
06651    } else {
06652       AST_RWLIST_RDLOCK(&feature_list);
06653       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
06654          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
06655       }
06656       AST_RWLIST_UNLOCK(&feature_list);
06657    }
06658 
06659    ast_cli(a->fd, "\nFeature Groups:\n");
06660    ast_cli(a->fd, "---------------\n");
06661    if (AST_RWLIST_EMPTY(&feature_groups)) {
06662       ast_cli(a->fd, "(none)\n");
06663    } else {
06664       struct feature_group *fg;
06665       struct feature_group_exten *fge;
06666 
06667       AST_RWLIST_RDLOCK(&feature_groups);
06668       AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
06669          ast_cli(a->fd, "===> Group: %s\n", fg->gname);
06670          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
06671             ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
06672          }
06673       }
06674       AST_RWLIST_UNLOCK(&feature_groups);
06675    }
06676 
06677    iter = ao2_iterator_init(parkinglots, 0);
06678    while ((curlot = ao2_iterator_next(&iter))) {
06679       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
06680       ast_cli(a->fd, "------------\n");
06681       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", curlot->cfg.parkext);
06682       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->cfg.parking_con);
06683       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions",
06684          curlot->cfg.parking_start, curlot->cfg.parking_stop);
06685       ast_cli(a->fd,"%-22s:      %d ms\n", "Parkingtime", curlot->cfg.parkingtime);
06686       ast_cli(a->fd,"%-22s:      %s\n", "MusicOnHold class", curlot->cfg.mohclass);
06687       ast_cli(a->fd,"%-22s:      %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled));
06688       ast_cli(a->fd,"\n");
06689       ao2_ref(curlot, -1);
06690    }
06691    ao2_iterator_destroy(&iter);
06692 
06693    return CLI_SUCCESS;
06694 }

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

Definition at line 6722 of file features.c.

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

06723 {
06724    switch (cmd) { 
06725    case CLI_INIT:
06726       e->command = "features reload";
06727       e->usage =
06728          "Usage: features reload\n"
06729          "       Reloads configured call features from features.conf\n";
06730       return NULL;
06731    case CLI_GENERATE:
06732       return NULL;
06733    }
06734    ast_features_reload();
06735 
06736    return CLI_SUCCESS;
06737 }

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 6905 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.

06906 {
06907    struct parkeduser *cur;
06908    int numparked = 0;
06909    struct ao2_iterator iter;
06910    struct ast_parkinglot *curlot;
06911 
06912    switch (cmd) {
06913    case CLI_INIT:
06914       e->command = "parkedcalls show";
06915       e->usage =
06916          "Usage: parkedcalls show\n"
06917          "       List currently parked calls\n";
06918       return NULL;
06919    case CLI_GENERATE:
06920       return NULL;
06921    }
06922 
06923    if (a->argc > e->args)
06924       return CLI_SHOWUSAGE;
06925 
06926    ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel",
06927       "Context", "Extension", "Pri", "Timeout");
06928 
06929    iter = ao2_iterator_init(parkinglots, 0);
06930    while ((curlot = ao2_iterator_next(&iter))) {
06931       int lotparked = 0;
06932 
06933       /* subtract ref for iterator and for configured parking lot */
06934       ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name,
06935          ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot));
06936 
06937       AST_LIST_LOCK(&curlot->parkings);
06938       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
06939          ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n",
06940             cur->parkingexten, cur->chan->name, cur->context, cur->exten,
06941             cur->priority,
06942             (long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL)));
06943          ++lotparked;
06944       }
06945       AST_LIST_UNLOCK(&curlot->parkings);
06946       if (lotparked) {
06947          numparked += lotparked;
06948          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked,
06949             ESS(lotparked), curlot->name);
06950       }
06951 
06952       ao2_ref(curlot, -1);
06953    }
06954    ao2_iterator_destroy(&iter);
06955 
06956    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
06957 
06958    return CLI_SUCCESS;
06959 }

static int load_config ( int  reload  )  [static]

Definition at line 6533 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_flags, 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().

06534 {
06535    struct ast_flags config_flags = {
06536       reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06537    struct ast_config *cfg;
06538    struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06539    struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
06540 
06541    /* We are reloading now and have already determined if we will force the reload. */
06542    force_reload_load = 0;
06543 
06544    if (!default_parkinglot) {
06545       /* Must create the default default parking lot */
06546       default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
06547       if (!default_parkinglot) {
06548          ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n");
06549          return -1;
06550       }
06551       ast_debug(1, "Configuration of default default parking lot done.\n");
06552       parkinglot_addref(default_parkinglot);
06553    }
06554 
06555    cfg = ast_config_load2("features.conf", "features", config_flags);
06556    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06557       /* No sense in asking for reload trouble if nothing changed. */
06558       ast_debug(1, "features.conf did not change.\n");
06559       return 0;
06560    }
06561    if (cfg == CONFIG_STATUS_FILEMISSING
06562       || cfg == CONFIG_STATUS_FILEINVALID) {
06563       ast_log(LOG_WARNING, "Could not load features.conf\n");
06564       return 0;
06565    }
06566 
06567    /* Save current parking lot dialplan needs. */
06568    if (build_dialplan_useage_map(&old_usage_map, 0)) {
06569       destroy_dialplan_usage_map(&old_usage_map);
06570 
06571       /* Allow reloading later to see if conditions have improved. */
06572       force_reload_load = 1;
06573       return -1;
06574    }
06575 
06576    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL,
06577       "callback to mark all parking lots");
06578    process_config(cfg);
06579    ast_config_destroy(cfg);
06580    ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL,
06581       "callback to remove marked parking lots");
06582 
06583    /* Save updated parking lot dialplan needs. */
06584    if (build_dialplan_useage_map(&new_usage_map, 1)) {
06585       /*
06586        * Yuck, if this failure caused any parking lot dialplan items
06587        * to be lost, they will likely remain lost until Asterisk is
06588        * restarted.
06589        */
06590       destroy_dialplan_usage_map(&old_usage_map);
06591       destroy_dialplan_usage_map(&new_usage_map);
06592       return -1;
06593    }
06594 
06595    /* Remove no longer needed parking lot dialplan usage. */
06596    remove_dead_dialplan_useage(&old_usage_map, &new_usage_map);
06597 
06598    destroy_dialplan_usage_map(&old_usage_map);
06599    destroy_dialplan_usage_map(&new_usage_map);
06600 
06601    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL,
06602       "callback to activate all parking lots");
06603 
06604    return 0;
06605 }

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

Referenced by manage_parkinglot().

04549 {
04550    struct ast_channel *chan = pu->chan;   /* shorthand */
04551    int tms;        /* timeout for this item */
04552    int x;          /* fd index in channel */
04553    int parking_complete = 0;
04554 
04555    tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04556    if (tms > pu->parkingtime) {
04557       /*
04558        * Call has been parked too long.
04559        * Stop entertaining the caller.
04560        */
04561       switch (pu->hold_method) {
04562       case AST_CONTROL_HOLD:
04563          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04564          break;
04565       case AST_CONTROL_RINGING:
04566          ast_indicate(pu->chan, -1);
04567          break;
04568       default:
04569          break;
04570       }
04571       pu->hold_method = 0;
04572 
04573       /* Get chan, exten from derived kludge */
04574       if (pu->peername[0]) {
04575          char *peername;
04576          char *dash;
04577          char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
04578          int i;
04579 
04580          peername = ast_strdupa(pu->peername);
04581          dash = strrchr(peername, '-');
04582          if (dash) {
04583             *dash = '\0';
04584          }
04585 
04586          peername_flat = ast_strdupa(peername);
04587          for (i = 0; peername_flat[i]; i++) {
04588             if (peername_flat[i] == '/') {
04589                peername_flat[i] = '_';
04590             }
04591          }
04592 
04593          if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) {
04594             ast_log(LOG_ERROR,
04595                "Parking dial context '%s' does not exist and unable to create\n",
04596                parking_con_dial);
04597          } else {
04598             char returnexten[AST_MAX_EXTENSION];
04599             struct ast_datastore *features_datastore;
04600             struct ast_dial_features *dialfeatures;
04601 
04602             if (!strncmp(peername, "Parked/", 7)) {
04603                peername += 7;
04604             }
04605 
04606             ast_channel_lock(chan);
04607             features_datastore = ast_channel_datastore_find(chan, &dial_features_info,
04608                NULL);
04609             if (features_datastore && (dialfeatures = features_datastore->data)) {
04610                char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
04611 
04612                snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername,
04613                   callback_dialoptions(&(dialfeatures->features_callee),
04614                      &(dialfeatures->features_caller), buf, sizeof(buf)));
04615             } else { /* Existing default */
04616                ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n",
04617                   chan->name);
04618                snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
04619             }
04620             ast_channel_unlock(chan);
04621 
04622             if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL,
04623                "Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) {
04624                ast_log(LOG_ERROR,
04625                   "Could not create parking return dial exten: %s@%s\n",
04626                   peername_flat, parking_con_dial);
04627             }
04628          }
04629          if (pu->options_specified) {
04630             /*
04631              * Park() was called with overriding return arguments, respect
04632              * those arguments.
04633              */
04634             set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04635          } else if (comebacktoorigin) {
04636             set_c_e_p(chan, parking_con_dial, peername_flat, 1);
04637          } else {
04638             char parkingslot[AST_MAX_EXTENSION];
04639 
04640             snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
04641             pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
04642             set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
04643          }
04644       } else {
04645          /*
04646           * They've been waiting too long, send them back to where they
04647           * came.  Theoretically they should have their original
04648           * extensions and such, but we copy to be on the safe side.
04649           */
04650          set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04651       }
04652       post_manager_event("ParkedCallTimeOut", pu);
04653       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
04654 
04655       ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n",
04656          pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context,
04657          pu->chan->exten, pu->chan->priority);
04658 
04659       /* Start up the PBX, or hang them up */
04660       if (ast_pbx_start(chan))  {
04661          ast_log(LOG_WARNING,
04662             "Unable to restart the PBX for user on '%s', hanging them up...\n",
04663             pu->chan->name);
04664          ast_hangup(chan);
04665       }
04666 
04667       /* And take them out of the parking lot */
04668       parking_complete = 1;
04669    } else { /* still within parking time, process descriptors */
04670       for (x = 0; x < AST_MAX_FDS; x++) {
04671          struct ast_frame *f;
04672          int y;
04673 
04674          if (chan->fds[x] == -1) {
04675             continue;   /* nothing on this descriptor */
04676          }
04677 
04678          for (y = 0; y < nfds; y++) {
04679             if (pfds[y].fd == chan->fds[x]) {
04680                /* Found poll record! */
04681                break;
04682             }
04683          }
04684          if (y == nfds) {
04685             /* Not found */
04686             continue;
04687          }
04688 
04689          if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
04690             /* Next x */
04691             continue;
04692          }
04693 
04694          if (pfds[y].revents & POLLPRI) {
04695             ast_set_flag(chan, AST_FLAG_EXCEPTION);
04696          } else {
04697             ast_clear_flag(chan, AST_FLAG_EXCEPTION);
04698          }
04699          chan->fdno = x;
04700 
04701          /* See if they need servicing */
04702          f = ast_read(pu->chan);
04703          /* Hangup? */
04704          if (!f || (f->frametype == AST_FRAME_CONTROL
04705             && f->subclass.integer == AST_CONTROL_HANGUP)) {
04706             if (f) {
04707                ast_frfree(f);
04708             }
04709             post_manager_event("ParkedCallGiveUp", pu);
04710             ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp",
04711                NULL);
04712 
04713             /* There's a problem, hang them up */
04714             ast_verb(2, "%s got tired of being parked\n", chan->name);
04715             ast_hangup(chan);
04716 
04717             /* And take them out of the parking lot */
04718             parking_complete = 1;
04719             break;
04720          } else {
04721             /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
04722             ast_frfree(f);
04723             if (pu->hold_method == AST_CONTROL_HOLD
04724                && pu->moh_trys < 3
04725                && !chan->generatordata) {
04726                ast_debug(1,
04727                   "MOH on parked call stopped by outside source.  Restarting on channel %s.\n",
04728                   chan->name);
04729                ast_indicate_data(chan, AST_CONTROL_HOLD,
04730                   S_OR(pu->parkinglot->cfg.mohclass, NULL),
04731                   (!ast_strlen_zero(pu->parkinglot->cfg.mohclass)
04732                      ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0));
04733                pu->moh_trys++;
04734             }
04735             goto std;   /* XXX Ick: jumping into an else statement??? XXX */
04736          }
04737       } /* End for */
04738       if (x >= AST_MAX_FDS) {
04739 std:     for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */
04740             if (chan->fds[x] > -1) {
04741                void *tmp = ast_realloc(*new_pfds,
04742                   (*new_nfds + 1) * sizeof(struct pollfd));
04743 
04744                if (!tmp) {
04745                   continue;
04746                }
04747                *new_pfds = tmp;
04748                (*new_pfds)[*new_nfds].fd = chan->fds[x];
04749                (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
04750                (*new_pfds)[*new_nfds].revents = 0;
04751                (*new_nfds)++;
04752             }
04753          }
04754          /* Keep track of our shortest wait */
04755          if (tms < *ms || *ms < 0) {
04756             *ms = tms;
04757          }
04758       }
04759    }
04760 
04761    return parking_complete;
04762 }

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

04766 {
04767    struct parkeduser *pu;
04768    struct ast_context *con;
04769 
04770    /* Lock parkings list */
04771    AST_LIST_LOCK(&curlot->parkings);
04772    AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
04773       if (pu->notquiteyet) { /* Pretend this one isn't here yet */
04774          continue;
04775       }
04776       if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) {
04777          /* Parking is complete for this call so remove it from the parking lot. */
04778          con = ast_context_find(pu->parkinglot->cfg.parking_con);
04779          if (con) {
04780             if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
04781                ast_log(LOG_WARNING,
04782                   "Whoa, failed to remove the parking extension %s@%s!\n",
04783                   pu->parkingexten, pu->parkinglot->cfg.parking_con);
04784             }
04785             notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con,
04786                AST_DEVICE_NOT_INUSE);
04787          } else {
04788             ast_log(LOG_WARNING,
04789                "Whoa, parking lot '%s' context '%s' does not exist.\n",
04790                pu->parkinglot->name, pu->parkinglot->cfg.parking_con);
04791          }
04792          AST_LIST_REMOVE_CURRENT(list);
04793          parkinglot_unref(pu->parkinglot);
04794          ast_free(pu);
04795       }
04796    }
04797    AST_LIST_TRAVERSE_SAFE_END;
04798    AST_LIST_UNLOCK(&curlot->parkings);
04799 }

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

07042 {
07043    const char *channel = astman_get_header(m, "Channel");
07044    const char *channel2 = astman_get_header(m, "Channel2");
07045    const char *timeout = astman_get_header(m, "Timeout");
07046    const char *parkinglotname = astman_get_header(m, "Parkinglot");
07047    char buf[BUFSIZ];
07048    int res = 0;
07049    struct ast_channel *ch1, *ch2;
07050    struct ast_park_call_args args = {
07051          /*
07052           * Don't say anything to ch2 since AMI is a third party parking
07053           * a call and we will likely crash if we do.
07054           *
07055           * XXX When the AMI action was originally implemented, the
07056           * parking space was announced to ch2.  Unfortunately, grabbing
07057           * the ch2 lock and holding it while the announcement is played
07058           * was not really a good thing to do to begin with since it
07059           * could hold up the system.  Also holding the lock is no longer
07060           * possible with a masquerade.
07061           *
07062           * Restoring the announcement to ch2 is not easily doable for
07063           * the following reasons:
07064           *
07065           * 1) The AMI manager is not the thread processing ch2.
07066           *
07067           * 2) ch2 could be the same as ch1, bridged to ch1, or some
07068           * random uninvolved channel.
07069           */
07070          .flags = AST_PARK_OPT_SILENCE,
07071       };
07072 
07073    if (ast_strlen_zero(channel)) {
07074       astman_send_error(s, m, "Channel not specified");
07075       return 0;
07076    }
07077 
07078    if (ast_strlen_zero(channel2)) {
07079       astman_send_error(s, m, "Channel2 not specified");
07080       return 0;
07081    }
07082 
07083    if (!ast_strlen_zero(timeout)) {
07084       if (sscanf(timeout, "%30d", &args.timeout) != 1) {
07085          astman_send_error(s, m, "Invalid timeout value.");
07086          return 0;
07087       }
07088    }
07089 
07090    if (!(ch1 = ast_channel_get_by_name(channel))) {
07091       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
07092       astman_send_error(s, m, buf);
07093       return 0;
07094    }
07095 
07096    if (!(ch2 = ast_channel_get_by_name(channel2))) {
07097       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
07098       astman_send_error(s, m, buf);
07099       ast_channel_unref(ch1);
07100       return 0;
07101    }
07102 
07103    if (!ast_strlen_zero(parkinglotname)) {
07104       args.parkinglot = find_parkinglot(parkinglotname);
07105    }
07106 
07107    res = masq_park_call(ch1, ch2, &args);
07108    if (!res) {
07109       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
07110       astman_send_ack(s, m, "Park successful");
07111    } else {
07112       astman_send_error(s, m, "Park failure");
07113    }
07114 
07115    if (args.parkinglot) {
07116       parkinglot_unref(args.parkinglot);
07117    }
07118    ch1 = ast_channel_unref(ch1);
07119    ch2 = ast_channel_unref(ch2);
07120 
07121    return 0;
07122 }

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

06976 {
06977    struct parkeduser *cur;
06978    const char *id = astman_get_header(m, "ActionID");
06979    char idText[256] = "";
06980    struct ao2_iterator iter;
06981    struct ast_parkinglot *curlot;
06982    int numparked = 0;
06983 
06984    if (!ast_strlen_zero(id))
06985       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
06986 
06987    astman_send_ack(s, m, "Parked calls will follow");
06988 
06989    iter = ao2_iterator_init(parkinglots, 0);
06990    while ((curlot = ao2_iterator_next(&iter))) {
06991       AST_LIST_LOCK(&curlot->parkings);
06992       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
06993          astman_append(s, "Event: ParkedCall\r\n"
06994             "Parkinglot: %s\r\n"
06995             "Exten: %d\r\n"
06996             "Channel: %s\r\n"
06997             "From: %s\r\n"
06998             "Timeout: %ld\r\n"
06999             "CallerIDNum: %s\r\n"
07000             "CallerIDName: %s\r\n"
07001             "ConnectedLineNum: %s\r\n"
07002             "ConnectedLineName: %s\r\n"
07003             "%s"
07004             "\r\n",
07005             curlot->name,
07006             cur->parkingnum, cur->chan->name, cur->peername,
07007             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
07008             S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""),   /* XXX in other places it is <unknown> */
07009             S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
07010             S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""),   /* XXX in other places it is <unknown> */
07011             S_COR(cur->chan->connected.id.name.valid, cur->chan->connected.id.name.str, ""),
07012             idText);
07013          ++numparked;
07014       }
07015       AST_LIST_UNLOCK(&curlot->parkings);
07016       ao2_ref(curlot, -1);
07017    }
07018    ao2_iterator_destroy(&iter);
07019 
07020    astman_append(s,
07021       "Event: ParkedCallsComplete\r\n"
07022       "Total: %d\r\n"
07023       "%s"
07024       "\r\n",
07025       numparked, idText);
07026 
07027    return RESULT_SUCCESS;
07028 }

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

01626 {
01627    struct ast_channel *chan;
01628 
01629    /* Make a new, channel that we'll use to masquerade in the real one */
01630    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten,
01631       rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s", rchan->name);
01632    if (!chan) {
01633       ast_log(LOG_WARNING, "Unable to create parked channel\n");
01634       if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
01635          if (peer == rchan) {
01636             /* Only have one channel to worry about. */
01637             ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01638          } else if (peer) {
01639             /* Have two different channels to worry about. */
01640             play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
01641          }
01642       }
01643       return -1;
01644    }
01645 
01646    args->pu = park_space_reserve(rchan, peer, args);
01647    if (!args->pu) {
01648       ast_hangup(chan);
01649       if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
01650          if (peer == rchan) {
01651             /* Only have one channel to worry about. */
01652             ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01653          } else if (peer) {
01654             /* Have two different channels to worry about. */
01655             play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
01656          }
01657       }
01658       return -1;
01659    }
01660 
01661    /* Make formats okay */
01662    chan->readformat = rchan->readformat;
01663    chan->writeformat = rchan->writeformat;
01664 
01665    if (ast_channel_masquerade(chan, rchan)) {
01666       park_space_abort(args->pu);
01667       args->pu = NULL;
01668       ast_hangup(chan);
01669       if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
01670          if (peer == rchan) {
01671             /* Only have one channel to worry about. */
01672             ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01673          } else if (peer) {
01674             /* Have two different channels to worry about. */
01675             play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
01676          }
01677       }
01678       return -1;
01679    }
01680 
01681    /* Setup the extensions and such */
01682    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
01683 
01684    /* Setup the macro extension and such */
01685    ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext));
01686    ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten));
01687    chan->macropriority = rchan->macropriority;
01688 
01689    /* Manually do the masquerade to make sure it is complete. */
01690    ast_do_masquerade(chan);
01691 
01692    if (peer == rchan) {
01693       peer = chan;
01694    }
01695 
01696    /* parking space reserved, return code check unnecessary */
01697    park_call_full(chan, peer, args);
01698 
01699    return 0;
01700 }

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

metermaids callback from devicestate.c

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

01016 {
01017    char *context;
01018    char *exten;
01019 
01020    context = ast_strdupa(data);
01021 
01022    exten = strsep(&context, "@");
01023    if (!context)
01024       return AST_DEVICE_INVALID;
01025    
01026    ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
01027 
01028    if (!ast_exists_extension(NULL, context, exten, 1, NULL))
01029       return AST_DEVICE_NOT_INUSE;
01030 
01031    return AST_DEVICE_INUSE;
01032 }

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

01007 {
01008    ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
01009       exten, context, ast_devstate2str(state));
01010 
01011    ast_devstate_changed(state, "park:%s@%s", exten, context);
01012 }

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

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

Referenced by parkinglot_activate().

05309 {
05310    int numext;
05311    char device[AST_MAX_EXTENSION];
05312    char exten[10];
05313 
05314    for (numext = start; numext <= stop; numext++) {
05315       snprintf(exten, sizeof(exten), "%d", numext);
05316       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
05317       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
05318    }
05319 }

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

Park a call.

Definition at line 4888 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(), park_app_args::pl_name, ast_channel::priority, park_app_args::return_con, park_app_args::return_ext, park_app_args::return_pri, and park_app_args::timeout.

Referenced by ast_features_init().

04889 {
04890    /* Cache the original channel name in case we get masqueraded in the middle
04891     * of a park--it is still theoretically possible for a transfer to happen before
04892     * we get here, but it is _really_ unlikely */
04893    char *orig_chan_name = ast_strdupa(chan->name);
04894    struct ast_park_call_args args = {
04895       .orig_chan_name = orig_chan_name,
04896    };
04897    struct ast_flags flags = { 0 };
04898    char orig_exten[AST_MAX_EXTENSION];
04899    int orig_priority;
04900    int res;
04901    const char *pl_name;
04902    char *parse;
04903    struct park_app_args app_args;
04904 
04905    /* Answer if call is not up */
04906    if (chan->_state != AST_STATE_UP) {
04907       if (ast_answer(chan)) {
04908          return -1;
04909       }
04910 
04911       /* Sleep to allow VoIP streams to settle down */
04912       if (ast_safe_sleep(chan, 1000)) {
04913          return -1;
04914       }
04915    }
04916 
04917    /* Process the dialplan application options. */
04918    parse = ast_strdupa(data);
04919    AST_STANDARD_APP_ARGS(app_args, parse);
04920 
04921    if (!ast_strlen_zero(app_args.timeout)) {
04922       if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
04923          ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
04924          args.timeout = 0;
04925       }
04926    }
04927    if (!ast_strlen_zero(app_args.return_con)) {
04928       args.return_con = app_args.return_con;
04929    }
04930    if (!ast_strlen_zero(app_args.return_ext)) {
04931       args.return_ext = app_args.return_ext;
04932    }
04933    if (!ast_strlen_zero(app_args.return_pri)) {
04934       if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
04935          ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
04936          args.return_pri = 0;
04937       }
04938    }
04939 
04940    ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
04941    args.flags = flags.flags;
04942 
04943    /*
04944     * Setup the exten/priority to be s/1 since we don't know where
04945     * this call should return.
04946     */
04947    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
04948    orig_priority = chan->priority;
04949    strcpy(chan->exten, "s");
04950    chan->priority = 1;
04951 
04952    /* Park the call */
04953    if (!ast_strlen_zero(app_args.pl_name)) {
04954       pl_name = app_args.pl_name;
04955    } else {
04956       pl_name = findparkinglotname(chan);
04957    }
04958    if (ast_strlen_zero(pl_name)) {
04959       /* Parking lot is not specified, so use the default parking lot. */
04960       args.parkinglot = parkinglot_addref(default_parkinglot);
04961    } else {
04962       args.parkinglot = find_parkinglot(pl_name);
04963       if (!args.parkinglot && parkeddynamic) {
04964          args.parkinglot = create_dynamic_parkinglot(pl_name, chan);
04965       }
04966    }
04967    if (args.parkinglot) {
04968       res = masq_park_call(chan, chan, &args);
04969       parkinglot_unref(args.parkinglot);
04970    } else {
04971       /* Parking failed because the parking lot does not exist. */
04972       if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
04973          ast_stream_and_wait(chan, "pbx-parkingfailed", "");
04974       }
04975       res = -1;
04976    }
04977    if (res) {
04978       /* Park failed, try to continue in the dialplan. */
04979       ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
04980       chan->priority = orig_priority;
04981       res = 0;
04982    } else {
04983       /* Park succeeded. */
04984       res = -1;
04985    }
04986 
04987    return res;
04988 }

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

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

01381 {
01382    struct parkeduser *pu = args->pu;
01383    const char *event_from;
01384    char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT];
01385 
01386    if (pu == NULL) {
01387       args->pu = pu = park_space_reserve(chan, peer, args);
01388       if (pu == NULL) {
01389          return -1;
01390       }
01391    }
01392 
01393    chan->appl = "Parked Call";
01394    chan->data = NULL;
01395 
01396    pu->chan = chan;
01397 
01398    /* Put the parked channel on hold if we have two different channels */
01399    if (chan != peer) {
01400       if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
01401          pu->hold_method = AST_CONTROL_RINGING;
01402          ast_indicate(pu->chan, AST_CONTROL_RINGING);
01403       } else {
01404          pu->hold_method = AST_CONTROL_HOLD;
01405          ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01406             S_OR(pu->parkinglot->cfg.mohclass, NULL),
01407             !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
01408       }
01409    }
01410    
01411    pu->start = ast_tvnow();
01412    pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->cfg.parkingtime;
01413    if (args->extout)
01414       *(args->extout) = pu->parkingnum;
01415 
01416    if (peer) { 
01417       /*
01418        * This is so ugly that it hurts, but implementing
01419        * get_base_channel() on local channels could have ugly side
01420        * effects.  We could have
01421        * transferer<->local,1<->local,2<->parking and we need the
01422        * callback name to be that of transferer.  Since local,1/2 have
01423        * the same name we can be tricky and just grab the bridged
01424        * channel from the other side of the local.
01425        */
01426       if (!strcasecmp(peer->tech->type, "Local")) {
01427          struct ast_channel *tmpchan, *base_peer;
01428          char other_side[AST_CHANNEL_NAME];
01429          char *c;
01430 
01431          ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side));
01432          if ((c = strrchr(other_side, ';'))) {
01433             *++c = '1';
01434          }
01435          if ((tmpchan = ast_channel_get_by_name(other_side))) {
01436             ast_channel_lock(tmpchan);
01437             if ((base_peer = ast_bridged_channel(tmpchan))) {
01438                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
01439             }
01440             ast_channel_unlock(tmpchan);
01441             tmpchan = ast_channel_unref(tmpchan);
01442          }
01443       } else {
01444          ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername));
01445       }
01446    }
01447 
01448    /*
01449     * Remember what had been dialed, so that if the parking
01450     * expires, we try to come back to the same place
01451     */
01452    pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
01453 
01454    /*
01455     * If extension has options specified, they override all other
01456     * possibilities such as the returntoorigin flag and transferred
01457     * context.  Information on extension options is lost here, so
01458     * we set a flag
01459     */
01460    ast_copy_string(pu->context, 
01461       S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 
01462       sizeof(pu->context));
01463    ast_copy_string(pu->exten, 
01464       S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 
01465       sizeof(pu->exten));
01466    pu->priority = args->return_pri ? args->return_pri : 
01467       (chan->macropriority ? chan->macropriority : chan->priority);
01468 
01469    /*
01470     * If parking a channel directly, don't quite yet get parking
01471     * running on it.  All parking lot entries are put into the
01472     * parking lot with notquiteyet on.
01473     */
01474    if (peer != chan) {
01475       pu->notquiteyet = 0;
01476    }
01477 
01478    /* Wake up the (presumably select()ing) thread */
01479    pthread_kill(parking_thread, SIGURG);
01480    ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n",
01481       pu->chan->name, pu->parkingnum, pu->parkinglot->name,
01482       pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000));
01483 
01484    ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
01485 
01486    if (peer) {
01487       event_from = peer->name;
01488    } else {
01489       event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
01490    }
01491 
01492    ast_manager_event(pu->chan, EVENT_FLAG_CALL, "ParkedCall",
01493       "Exten: %s\r\n"
01494       "Channel: %s\r\n"
01495       "Parkinglot: %s\r\n"
01496       "From: %s\r\n"
01497       "Timeout: %ld\r\n"
01498       "CallerIDNum: %s\r\n"
01499       "CallerIDName: %s\r\n"
01500       "ConnectedLineNum: %s\r\n"
01501       "ConnectedLineName: %s\r\n"
01502       "Uniqueid: %s\r\n",
01503       pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "",
01504       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
01505       S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
01506       S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
01507       S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
01508       S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
01509       pu->chan->uniqueid
01510       );
01511 
01512    if (peer && adsipark && ast_adsi_available(peer)) {
01513       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
01514       ast_adsi_unload_session(peer);
01515    }
01516 
01517    snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten,
01518       pu->parkinglot->name);
01519    if (ast_add_extension(pu->parkinglot->cfg.parking_con, 1, pu->parkingexten, 1,
01520       NULL, NULL, parkedcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
01521       ast_log(LOG_ERROR, "Could not create parked call exten: %s@%s\n",
01522          pu->parkingexten, pu->parkinglot->cfg.parking_con);
01523    } else {
01524       notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE);
01525    }
01526 
01527    AST_LIST_UNLOCK(&pu->parkinglot->parkings);
01528 
01529    /* Only say number if it's a number and the channel hasn't been masqueraded away */
01530    if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE)
01531       && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
01532       /*
01533        * If a channel is masqueraded into peer while playing back the
01534        * parking space number do not continue playing it back.  This
01535        * is the case if an attended transfer occurs.
01536        */
01537       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01538       /* Tell the peer channel the number of the parking space */
01539       ast_say_digits(peer, pu->parkingnum, "", peer->language);
01540       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01541    }
01542    if (peer == chan) { /* pu->notquiteyet = 1 */
01543       /* Wake up parking thread if we're really done */
01544       pu->hold_method = AST_CONTROL_HOLD;
01545       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01546          S_OR(pu->parkinglot->cfg.mohclass, NULL),
01547          !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
01548       pu->notquiteyet = 0;
01549       pthread_kill(parking_thread, SIGURG);
01550    }
01551    return 0;
01552 }

static void park_space_abort ( struct parkeduser pu  )  [static]

Definition at line 1182 of file features.c.

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

Referenced by masq_park_call().

01183 {
01184    struct ast_parkinglot *parkinglot;
01185 
01186    parkinglot = pu->parkinglot;
01187 
01188    /* Put back the parking space just allocated. */
01189    --parkinglot->next_parking_space;
01190 
01191    AST_LIST_REMOVE(&parkinglot->parkings, pu, list);
01192 
01193    AST_LIST_UNLOCK(&parkinglot->parkings);
01194    parkinglot_unref(parkinglot);
01195    ast_free(pu);
01196 }

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

01210 {
01211    struct parkeduser *pu;
01212    int i;
01213    int parking_space = -1;
01214    const char *parkinglotname;
01215    const char *parkingexten;
01216    struct parkeduser *cur;
01217    struct ast_parkinglot *parkinglot = NULL;
01218 
01219    if (args->parkinglot) {
01220       parkinglot = parkinglot_addref(args->parkinglot);
01221       parkinglotname = parkinglot->name;
01222    } else {
01223       if (parker) {
01224          parkinglotname = findparkinglotname(parker);
01225       } else { /* parker was NULL, check park_me (ParkAndAnnounce / res_agi) */
01226          parkinglotname = findparkinglotname(park_me);
01227       }
01228       if (!ast_strlen_zero(parkinglotname)) {
01229          parkinglot = find_parkinglot(parkinglotname);
01230       } else {
01231          /* Parking lot is not specified, so use the default parking lot. */
01232          ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
01233          parkinglot = parkinglot_addref(default_parkinglot);
01234       }
01235    }
01236 
01237    /* Dynamically create parkinglot */
01238    if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
01239       parkinglot = create_dynamic_parkinglot(parkinglotname, park_me);
01240    }
01241 
01242    if (!parkinglot) {
01243       ast_log(LOG_WARNING, "Parking lot not available to park %s.\n", park_me->name);
01244       return NULL;
01245    }
01246 
01247    ast_debug(1, "Parking lot: %s\n", parkinglot->name);
01248    if (parkinglot->disabled || parkinglot->cfg.is_invalid) {
01249       ast_log(LOG_WARNING, "Parking lot %s is not in a useable state.\n",
01250          parkinglot->name);
01251       parkinglot_unref(parkinglot);
01252       return NULL;
01253    }
01254 
01255    /* Allocate memory for parking data */
01256    if (!(pu = ast_calloc(1, sizeof(*pu)))) {
01257       parkinglot_unref(parkinglot);
01258       return NULL;
01259    }
01260 
01261    /* Lock parking list */
01262    AST_LIST_LOCK(&parkinglot->parkings);
01263 
01264    /* Check for channel variable PARKINGEXTEN */
01265    parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(park_me, "PARKINGEXTEN"), ""));
01266    if (!ast_strlen_zero(parkingexten)) {
01267       /*!
01268        * \note The API forces us to specify a numeric parking slot, even
01269        * though the architecture would tend to support non-numeric extensions
01270        * (as are possible with SIP, for example).  Hence, we enforce that
01271        * limitation here.  If extout was not numeric, we could permit
01272        * arbitrary non-numeric extensions.
01273        */
01274       if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space <= 0) {
01275          ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n",
01276             parkingexten);
01277          AST_LIST_UNLOCK(&parkinglot->parkings);
01278          parkinglot_unref(parkinglot);
01279          ast_free(pu);
01280          return NULL;
01281       }
01282 
01283       if (parking_space < parkinglot->cfg.parking_start
01284          || parkinglot->cfg.parking_stop < parking_space) {
01285          /*
01286           * Cannot allow park because parking lots are not setup for
01287           * spaces outside of the lot.  (Things like dialplan hints don't
01288           * exist for outside lot space.)
01289           */
01290          ast_log(LOG_WARNING, "PARKINGEXTEN=%d is not in %s (%d-%d).\n",
01291             parking_space, parkinglot->name, parkinglot->cfg.parking_start,
01292             parkinglot->cfg.parking_stop);
01293          AST_LIST_UNLOCK(&parkinglot->parkings);
01294          parkinglot_unref(parkinglot);
01295          ast_free(pu);
01296          return NULL;
01297       }
01298 
01299       /* Check if requested parking space is in use. */
01300       AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
01301          if (cur->parkingnum == parking_space) {
01302             ast_log(LOG_WARNING, "PARKINGEXTEN=%d is already in use in %s\n",
01303                parking_space, parkinglot->name);
01304             AST_LIST_UNLOCK(&parkinglot->parkings);
01305             parkinglot_unref(parkinglot);
01306             ast_free(pu);
01307             return NULL;
01308          }
01309       }
01310    } else {
01311       /* PARKINGEXTEN is empty, so find a usable extension in the lot to park the call */
01312       int start; /* The first slot we look in the parkinglot. It can be randomized. */
01313       int start_checked = 0; /* flag raised once the first slot is checked */
01314 
01315       /* If using randomize mode, set start to random position on parking range */
01316       if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
01317          start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1);
01318          start += parkinglot->cfg.parking_start;
01319       } else if (parkinglot->cfg.parkfindnext
01320          && parkinglot->cfg.parking_start <= parkinglot->next_parking_space
01321          && parkinglot->next_parking_space <= parkinglot->cfg.parking_stop) {
01322          /* Start looking with the next parking space in the lot. */
01323          start = parkinglot->next_parking_space;
01324       } else {
01325          /* Otherwise, just set it to the start position. */
01326          start = parkinglot->cfg.parking_start;
01327       }
01328 
01329       /* free parking extension linear search: O(n^2) */
01330       for (i = start; ; i++) {
01331          /* If we are past the end, wrap around to the first parking slot*/
01332          if (i == parkinglot->cfg.parking_stop + 1) {
01333             i = parkinglot->cfg.parking_start;
01334          }
01335 
01336          if (i == start) {
01337             /* At this point, if start_checked, we've exhausted all the possible slots. */
01338             if (start_checked) {
01339                break;
01340             } else {
01341                start_checked = 1;
01342             }
01343          }
01344 
01345          /* Search the list of parked calls already in use for i. If we find it, it's in use. */
01346          AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
01347             if (cur->parkingnum == i) {
01348                break;
01349             }
01350          }
01351          if (!cur) {
01352             /* We found a parking space. */
01353             parking_space = i;
01354             break;
01355          }
01356       }
01357       if (parking_space == -1) {
01358          /* We did not find a parking space.  Lot is full. */
01359          ast_log(LOG_WARNING, "No more parking spaces in %s\n", parkinglot->name);
01360          AST_LIST_UNLOCK(&parkinglot->parkings);
01361          parkinglot_unref(parkinglot);
01362          ast_free(pu);
01363          return NULL;
01364       }
01365    }
01366 
01367    /* Prepare for next parking space search. */
01368    parkinglot->next_parking_space = parking_space + 1;
01369 
01370    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
01371    pu->notquiteyet = 1;
01372    pu->parkingnum = parking_space;
01373    pu->parkinglot = parkinglot;
01374    AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
01375 
01376    return pu;
01377 }

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 4991 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, EVENT_FLAG_CALL, ast_dial_features::features_caller, find_parkinglot(), findparkinglotname(), parkeduser::hold_method, ast_party_connected_line::id, ast_party_caller::id, LOG_WARNING, ast_party_id::name, ast_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_party_name::valid, and ast_party_number::valid.

Referenced by ast_features_init().

04992 {
04993    int res = 0;
04994    struct ast_channel *peer = NULL;
04995    struct parkeduser *pu;
04996    struct ast_context *con;
04997    char *parse;
04998    const char *pl_name;
04999    int park = 0;
05000    struct ast_bridge_config config;
05001    struct ast_parkinglot *parkinglot;
05002    AST_DECLARE_APP_ARGS(app_args,
05003       AST_APP_ARG(pl_space);  /*!< Parking lot space to retrieve if present. */
05004       AST_APP_ARG(pl_name);   /*!< Parking lot name to use if present. */
05005       AST_APP_ARG(dummy);     /*!< Place to put any remaining args string. */
05006    );
05007 
05008    parse = ast_strdupa(data);
05009    AST_STANDARD_APP_ARGS(app_args, parse);
05010 
05011    if (!ast_strlen_zero(app_args.pl_space)) {
05012       if (sscanf(app_args.pl_space, "%30u", &park) != 1) {
05013          ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n",
05014             app_args.pl_space);
05015          park = -1;
05016       }
05017    }
05018 
05019    if (!ast_strlen_zero(app_args.pl_name)) {
05020       pl_name = app_args.pl_name;
05021    } else {
05022       pl_name = findparkinglotname(chan);
05023    }
05024    if (ast_strlen_zero(pl_name)) {
05025       /* Parking lot is not specified, so use the default parking lot. */
05026       parkinglot = parkinglot_addref(default_parkinglot);
05027    } else {
05028       parkinglot = find_parkinglot(pl_name);
05029       if (!parkinglot) {
05030          /* It helps to answer the channel if not already up. :) */
05031          if (chan->_state != AST_STATE_UP) {
05032             ast_answer(chan);
05033          }
05034          if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05035             ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n",
05036                "pbx-invalidpark", chan->name);
05037          }
05038          ast_log(LOG_WARNING,
05039             "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
05040             chan->name, pl_name);
05041          return -1;
05042       }
05043    }
05044 
05045    AST_LIST_LOCK(&parkinglot->parkings);
05046    AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
05047       if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
05048          && !pu->notquiteyet && !pu->chan->pbx) {
05049          /* The parking space has a call and can be picked up now. */
05050          AST_LIST_REMOVE_CURRENT(list);
05051          break;
05052       }
05053    }
05054    AST_LIST_TRAVERSE_SAFE_END;
05055    if (pu) {
05056       /* Found a parked call to pickup. */
05057       peer = pu->chan;
05058       con = ast_context_find(parkinglot->cfg.parking_con);
05059       if (con) {
05060          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
05061             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
05062          } else {
05063             notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
05064          }
05065       } else {
05066          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
05067       }
05068 
05069       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
05070       ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
05071          "Exten: %s\r\n"
05072          "Channel: %s\r\n"
05073          "From: %s\r\n"
05074          "CallerIDNum: %s\r\n"
05075          "CallerIDName: %s\r\n"
05076          "ConnectedLineNum: %s\r\n"
05077          "ConnectedLineName: %s\r\n",
05078          pu->parkingexten, pu->chan->name, chan->name,
05079          S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
05080          S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
05081          S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
05082          S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>")
05083          );
05084 
05085       /* Stop entertaining the caller. */
05086       switch (pu->hold_method) {
05087       case AST_CONTROL_HOLD:
05088          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
05089          break;
05090       case AST_CONTROL_RINGING:
05091          ast_indicate(pu->chan, -1);
05092          break;
05093       default:
05094          break;
05095       }
05096       pu->hold_method = 0;
05097 
05098       parkinglot_unref(pu->parkinglot);
05099       ast_free(pu);
05100    }
05101    AST_LIST_UNLOCK(&parkinglot->parkings);
05102 
05103    if (peer) {
05104       /* Update connected line between retrieving call and parked call. */
05105       struct ast_party_connected_line connected;
05106 
05107       ast_party_connected_line_init(&connected);
05108 
05109       /* Send our caller-id to peer. */
05110       ast_channel_lock(chan);
05111       ast_connected_line_copy_from_caller(&connected, &chan->caller);
05112       ast_channel_unlock(chan);
05113       connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05114       if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) {
05115          ast_channel_update_connected_line(peer, &connected, NULL);
05116       }
05117 
05118       /*
05119        * Get caller-id from peer.
05120        *
05121        * Update the retrieving call before it is answered if possible
05122        * for best results.  Some phones do not support updating the
05123        * connected line information after connection.
05124        */
05125       ast_channel_lock(peer);
05126       ast_connected_line_copy_from_caller(&connected, &peer->caller);
05127       ast_channel_unlock(peer);
05128       connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05129       if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) {
05130          ast_channel_update_connected_line(chan, &connected, NULL);
05131       }
05132 
05133       ast_party_connected_line_free(&connected);
05134    }
05135 
05136    /* JK02: it helps to answer the channel if not already up */
05137    if (chan->_state != AST_STATE_UP) {
05138       ast_answer(chan);
05139    }
05140 
05141    if (peer) {
05142       struct ast_datastore *features_datastore;
05143       struct ast_dial_features *dialfeatures = NULL;
05144 
05145       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
05146       if (!ast_strlen_zero(courtesytone)) {
05147          static const char msg[] = "courtesy tone";
05148 
05149          switch (parkedplay) {
05150          case 0:/* Courtesy tone to pickup chan */
05151             res = play_message_to_chans(chan, peer, -1, msg, courtesytone);
05152             break;
05153          case 1:/* Courtesy tone to parked chan */
05154             res = play_message_to_chans(chan, peer, 1, msg, courtesytone);
05155             break;
05156          case 2:/* Courtesy tone to both chans */
05157             res = play_message_to_chans(chan, peer, 0, msg, courtesytone);
05158             break;
05159          default:
05160             res = 0;
05161             break;
05162          }
05163          if (res) {
05164             ast_hangup(peer);
05165             parkinglot_unref(parkinglot);
05166             return -1;
05167          }
05168       }
05169 
05170       res = ast_channel_make_compatible(chan, peer);
05171       if (res < 0) {
05172          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
05173          ast_hangup(peer);
05174          parkinglot_unref(parkinglot);
05175          return -1;
05176       }
05177       /* This runs sorta backwards, since we give the incoming channel control, as if it
05178          were the person called. */
05179       ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
05180 
05181       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05182       ast_cdr_setdestchan(chan->cdr, peer->name);
05183       memset(&config, 0, sizeof(struct ast_bridge_config));
05184 
05185       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
05186       ast_channel_lock(peer);
05187       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
05188          dialfeatures = features_datastore->data;
05189       }
05190 
05191       /*
05192        * When the datastores for both caller and callee are created,
05193        * both the callee and caller channels use the features_caller
05194        * flag variable to represent themselves.  With that said, the
05195        * config.features_callee flags should be copied from the
05196        * datastore's caller feature flags regardless if peer was a
05197        * callee or caller.
05198        */
05199       if (dialfeatures) {
05200          ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
05201       }
05202       ast_channel_unlock(peer);
05203 
05204       if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05205          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
05206       }
05207       if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
05208          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
05209       }
05210       if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05211          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
05212       }
05213       if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
05214          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
05215       }
05216       if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05217          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
05218       }
05219       if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
05220          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
05221       }
05222       if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05223          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
05224       }
05225       if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
05226          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
05227       }
05228 
05229       res = ast_bridge_call(chan, peer, &config);
05230 
05231       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
05232       ast_cdr_setdestchan(chan->cdr, peer->name);
05233 
05234       /* Simulate the PBX hanging up */
05235       ast_hangup(peer);
05236    } else {
05237       if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
05238          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
05239             chan->name);
05240       }
05241       ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n",
05242          chan->name, park);
05243    }
05244 
05245    parkinglot_unref(parkinglot);
05246    return -1;
05247 }

static int parkinglot_activate ( struct ast_parkinglot parkinglot  )  [static]

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

05459 {
05460    int disabled = 0;
05461    char app_data[5 + AST_MAX_CONTEXT];
05462 
05463    /* Create Park option list.  Must match with struct park_app_args options. */
05464    if (parkinglot->cfg.parkext_exclusive) {
05465       /* Specify the parking lot this parking extension parks calls. */
05466       snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name);
05467    } else {
05468       /* The dialplan must specify which parking lot to use. */
05469       app_data[0] = '\0';
05470    }
05471 
05472    /* Create context */
05473    if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) {
05474       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n",
05475          parkinglot->cfg.parking_con);
05476       disabled = 1;
05477 
05478    /* Add a parking extension into the context */
05479    } else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext,
05480       1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
05481       ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n",
05482          parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con);
05483       disabled = 1;
05484    } else {
05485       /* Add parking hints */
05486       if (parkinglot->cfg.parkaddhints) {
05487          park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start,
05488             parkinglot->cfg.parking_stop);
05489       }
05490 
05491       /*
05492        * XXX Not sure why we should need to notify the metermaids for
05493        * this exten.  It was originally done for the default parking
05494        * lot entry exten only but should be done for all entry extens
05495        * if we do it for one.
05496        */
05497       /* Notify metermaids about parking lot entry exten state. */
05498       notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con,
05499          AST_DEVICE_INUSE);
05500    }
05501 
05502    parkinglot->disabled = disabled;
05503    return disabled ? -1 : 0;
05504 }

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

Definition at line 6505 of file features.c.

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

Referenced by load_config().

06506 {
06507    struct ast_parkinglot *parkinglot = obj;
06508 
06509    if (parkinglot->the_mark) {
06510       /*
06511        * Don't activate a parking lot that still bears the_mark since
06512        * it is effectively deleted.
06513        */
06514       return 0;
06515    }
06516 
06517    if (parkinglot_activate(parkinglot)) {
06518       /*
06519        * The parking lot failed to activate.  Allow reloading later to
06520        * see if that fixes it.
06521        */
06522       force_reload_load = 1;
06523       ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name);
06524    } else {
06525       ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n",
06526          parkinglot->name, parkinglot->cfg.parking_start,
06527          parkinglot->cfg.parking_stop);
06528    }
06529 
06530    return 0;
06531 }

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

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

05260 {
05261    int refcount;
05262 
05263    refcount = ao2_ref(parkinglot, +1);
05264    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
05265    return parkinglot;
05266 }

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

Definition at line 818 of file features.c.

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

Referenced by ast_features_init().

00819 {
00820    struct ast_parkinglot *parkinglot = obj;
00821    struct ast_parkinglot *parkinglot2 = arg;
00822 
00823    return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00824 }

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

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

05371 {
05372    int error = 0;
05373 
05374    while (var) {
05375       if (!strcasecmp(var->name, "context")) {
05376          ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con));
05377       } else if (!strcasecmp(var->name, "parkext")) {
05378          ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext));
05379       } else if (!strcasecmp(var->name, "parkext_exclusive")) {
05380          cfg->parkext_exclusive = ast_true(var->value);
05381       } else if (!strcasecmp(var->name, "parkinghints")) {
05382          cfg->parkaddhints = ast_true(var->value);
05383       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
05384          ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass));
05385       } else if (!strcasecmp(var->name, "parkingtime")) {
05386          int parkingtime = 0;
05387 
05388          if ((sscanf(var->value, "%30d", &parkingtime) != 1) || parkingtime < 1) {
05389             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
05390             error = -1;
05391          } else {
05392             cfg->parkingtime = parkingtime * 1000;
05393          }
05394       } else if (!strcasecmp(var->name, "parkpos")) {
05395          int start = 0;
05396          int end = 0;
05397 
05398          if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
05399             ast_log(LOG_WARNING,
05400                "Format for parking positions is a-b, where a and b are numbers at line %d of %s\n",
05401                var->lineno, var->file);
05402             error = -1;
05403          } else if (end < start || start <= 0 || end <= 0) {
05404             ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n",
05405                var->lineno, var->file);
05406             error = -1;
05407          } else {
05408             cfg->parking_start = start;
05409             cfg->parking_stop = end;
05410          }
05411       } else if (!strcasecmp(var->name, "findslot")) {
05412          cfg->parkfindnext = (!strcasecmp(var->value, "next"));
05413       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
05414          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var);
05415       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
05416          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var);
05417       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
05418          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var);
05419       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
05420          parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var);
05421       }
05422       var = var->next;
05423    }
05424 
05425    /* Check for configuration errors */
05426    if (ast_strlen_zero(cfg->parking_con)) {
05427       ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name);
05428       error = -1;
05429    }
05430    if (ast_strlen_zero(cfg->parkext)) {
05431       ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name);
05432       error = -1;
05433    }
05434    if (!cfg->parking_start) {
05435       ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name);
05436       error = -1;
05437    }
05438    if (error) {
05439       cfg->is_invalid = 1;
05440    }
05441 
05442    return error;
05443 }

static void parkinglot_destroy ( void *  obj  )  [static]

Destroy a parking lot.

Definition at line 5269 of file features.c.

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

Referenced by create_parkinglot().

05270 {
05271    struct ast_parkinglot *doomed = obj;
05272 
05273    /*
05274     * No need to destroy parked calls here because any parked call
05275     * holds a parking lot reference.  Therefore the parkings list
05276     * must be empty.
05277     */
05278    ast_assert(AST_LIST_EMPTY(&doomed->parkings));
05279    AST_LIST_HEAD_DESTROY(&doomed->parkings);
05280 }

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

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

05348 {
05349    ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value);
05350    if (!strcasecmp(var->value, "both")) {
05351       *param = AST_FEATURE_FLAG_BYBOTH;
05352    } else if (!strcasecmp(var->value, "caller")) {
05353       *param = AST_FEATURE_FLAG_BYCALLER;
05354    } else if (!strcasecmp(var->value, "callee")) {
05355       *param = AST_FEATURE_FLAG_BYCALLEE;
05356    }
05357 }

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

Definition at line 811 of file features.c.

References ast_str_case_hash(), and parkinglot.

Referenced by ast_features_init().

00812 {
00813    const struct ast_parkinglot *parkinglot = obj;
00814 
00815    return ast_str_case_hash(parkinglot->name);
00816 }

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

Definition at line 6485 of file features.c.

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

Referenced by load_config().

06486 {
06487    struct ast_parkinglot *parkinglot = obj;
06488 
06489    if (parkinglot->the_mark) {
06490       if (AST_LIST_EMPTY(&parkinglot->parkings)) {
06491          /* This parking lot can actually be deleted. */
06492          return CMP_MATCH;
06493       }
06494       /* Try reloading later when parking lot is empty. */
06495       ast_log(LOG_WARNING,
06496          "Parking lot %s has parked calls.  Could not remove.\n",
06497          parkinglot->name);
06498       parkinglot->disabled = 1;
06499       force_reload_load = 1;
06500    }
06501 
06502    return 0;
06503 }

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

Definition at line 6477 of file features.c.

References parkinglot.

Referenced by load_config().

06478 {
06479    struct ast_parkinglot *parkinglot = obj;
06480 
06481    parkinglot->the_mark = 1;
06482    return 0;
06483 }

static void parkinglot_unref ( struct ast_parkinglot parkinglot  )  [static]

Unreference parkinglot object.

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

05253 {
05254    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name,
05255       ao2_ref(parkinglot, 0) - 1);
05256    ao2_ref(parkinglot, -1);
05257 }

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

return the first unlocked cdr in a possible chain

Definition at line 3697 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

03698 {
03699    struct ast_cdr *cdr_orig = cdr;
03700    while (cdr) {
03701       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
03702          return cdr;
03703       cdr = cdr->next;
03704    }
03705    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
03706 }

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

References play_message_to_chans().

Referenced by builtin_automonitor().

01978 {
01979    return play_message_to_chans(caller_chan, callee_chan, 0, "automon message",
01980       audiofile);
01981 }

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

01924 {
01925    /* Put other channel in autoservice. */
01926    if (ast_autoservice_start(other)) {
01927       return -1;
01928    }
01929    ast_autoservice_ignore(other, AST_FRAME_DTMF_BEGIN);
01930    ast_autoservice_ignore(other, AST_FRAME_DTMF_END);
01931    if (ast_stream_and_wait(play_to, audiofile, "")) {
01932       ast_log(LOG_WARNING, "Failed to play %s '%s'!\n", msg, audiofile);
01933       ast_autoservice_stop(other);
01934       return -1;
01935    }
01936    if (ast_autoservice_stop(other)) {
01937       return -1;
01938    }
01939    return 0;
01940 }

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

References play_message_on_chan().

Referenced by parked_call_exec(), and play_message_in_bridged_call().

01959 {
01960    /* First play the file to the left channel if requested. */
01961    if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) {
01962       return -1;
01963    }
01964 
01965    /* Then play the file to the right channel if requested. */
01966    if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) {
01967       return -1;
01968    }
01969 
01970    return 0;
01971 }

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

Output parking event to manager.

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

04475 {
04476    manager_event(EVENT_FLAG_CALL, s,
04477       "Exten: %s\r\n"
04478       "Channel: %s\r\n"
04479       "Parkinglot: %s\r\n"
04480       "CallerIDNum: %s\r\n"
04481       "CallerIDName: %s\r\n"
04482       "ConnectedLineNum: %s\r\n"
04483       "ConnectedLineName: %s\r\n"
04484       "UniqueID: %s\r\n",
04485       pu->parkingexten, 
04486       pu->chan->name,
04487       pu->parkinglot->name,
04488       S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
04489       S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
04490       S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
04491       S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
04492       pu->chan->uniqueid
04493       );
04494 }

static void process_applicationmap_line ( struct ast_variable var  )  [static]

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

05587 {
05588    char *tmp_val = ast_strdupa(var->value);
05589    char *activateon;
05590    struct ast_call_feature *feature;
05591    AST_DECLARE_APP_ARGS(args,
05592       AST_APP_ARG(exten);
05593       AST_APP_ARG(activatedby);
05594       AST_APP_ARG(app);
05595       AST_APP_ARG(app_args);
05596       AST_APP_ARG(moh_class);
05597    );
05598 
05599    AST_STANDARD_APP_ARGS(args, tmp_val);
05600    if (strchr(args.app, '(')) {
05601       /* New syntax */
05602       args.moh_class = args.app_args;
05603       args.app_args = strchr(args.app, '(');
05604       *args.app_args++ = '\0';
05605       if (args.app_args[strlen(args.app_args) - 1] == ')') {
05606          args.app_args[strlen(args.app_args) - 1] = '\0';
05607       }
05608    }
05609 
05610    activateon = strsep(&args.activatedby, "/");
05611 
05612    /*! \todo XXX var_name or app_args ? */
05613    if (ast_strlen_zero(args.app)
05614       || ast_strlen_zero(args.exten)
05615       || ast_strlen_zero(activateon)
05616       || ast_strlen_zero(var->name)) {
05617       ast_log(LOG_NOTICE,
05618          "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
05619          args.app, args.exten, activateon, var->name);
05620       return;
05621    }
05622 
05623    AST_RWLIST_RDLOCK(&feature_list);
05624    if (find_dynamic_feature(var->name)) {
05625       AST_RWLIST_UNLOCK(&feature_list);
05626       ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n",
05627          var->name);
05628       return;
05629    }
05630    AST_RWLIST_UNLOCK(&feature_list);
05631 
05632    if (!(feature = ast_calloc(1, sizeof(*feature)))) {
05633       return;
05634    }
05635 
05636    ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
05637    ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
05638    ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
05639 
05640    if (args.app_args) {
05641       ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
05642    }
05643 
05644    if (args.moh_class) {
05645       ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
05646    }
05647 
05648    ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
05649    feature->operation = feature_exec_app;
05650    ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
05651 
05652    /* Allow caller and callee to be specified for backwards compatability */
05653    if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) {
05654       ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
05655    } else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) {
05656       ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
05657    } else {
05658       ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
05659          " must be 'self', or 'peer'\n", var->name);
05660       return;
05661    }
05662 
05663    if (ast_strlen_zero(args.activatedby)) {
05664       ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05665    } else if (!strcasecmp(args.activatedby, "caller")) {
05666       ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
05667    } else if (!strcasecmp(args.activatedby, "callee")) {
05668       ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
05669    } else if (!strcasecmp(args.activatedby, "both")) {
05670       ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05671    } else {
05672       ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
05673          " must be 'caller', or 'callee', or 'both'\n", var->name);
05674       return;
05675    }
05676 
05677    ast_register_feature(feature);
05678 
05679    ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n",
05680       var->name, args.app, args.app_args, args.exten);
05681 }

static int process_config ( struct ast_config cfg  )  [static]

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

05684 {
05685    int i;
05686    struct ast_variable *var = NULL;
05687    struct feature_group *fg = NULL;
05688    char *ctg; 
05689    static const char * const categories[] = { 
05690       /* Categories in features.conf that are not
05691        * to be parsed as group categories
05692        */
05693       "general",
05694       "featuremap",
05695       "applicationmap"
05696    };
05697 
05698    /* Set general features global defaults. */
05699    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05700 
05701    /* Set global call pickup defaults. */
05702    strcpy(pickup_ext, "*8");
05703    pickupsound[0] = '\0';
05704    pickupfailsound[0] = '\0';
05705 
05706    /* Set global call transfer defaults. */
05707    strcpy(xfersound, "beep");
05708    strcpy(xferfailsound, "beeperr");
05709    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05710    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05711    atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05712    atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
05713    atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05714 
05715    /* Set global call parking defaults. */
05716    comebacktoorigin = 1;
05717    courtesytone[0] = '\0';
05718    parkedplay = 0;
05719    adsipark = 0;
05720    parkeddynamic = 0;
05721 
05722    var = ast_variable_browse(cfg, "general");
05723    build_parkinglot(DEFAULT_PARKINGLOT, var);
05724    for (; var; var = var->next) {
05725       if (!strcasecmp(var->name, "parkeddynamic")) {
05726          parkeddynamic = ast_true(var->value);
05727       } else if (!strcasecmp(var->name, "adsipark")) {
05728          adsipark = ast_true(var->value);
05729       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
05730          if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
05731             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
05732             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
05733          } else {
05734             transferdigittimeout = transferdigittimeout * 1000;
05735          }
05736       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
05737          if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
05738             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
05739             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
05740          }
05741       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
05742          if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
05743             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
05744             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
05745          } else {
05746             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
05747          }
05748       } else if (!strcasecmp(var->name, "atxferloopdelay")) {
05749          if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
05750             ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
05751             atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
05752          } else {
05753             atxferloopdelay *= 1000;
05754          }
05755       } else if (!strcasecmp(var->name, "atxferdropcall")) {
05756          atxferdropcall = ast_true(var->value);
05757       } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
05758          if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
05759             ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
05760             atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
05761          }
05762       } else if (!strcasecmp(var->name, "courtesytone")) {
05763          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
05764       }  else if (!strcasecmp(var->name, "parkedplay")) {
05765          if (!strcasecmp(var->value, "both")) {
05766             parkedplay = 2;
05767          } else if (!strcasecmp(var->value, "parked")) {
05768             parkedplay = 1;
05769          } else {
05770             parkedplay = 0;
05771          }
05772       } else if (!strcasecmp(var->name, "xfersound")) {
05773          ast_copy_string(xfersound, var->value, sizeof(xfersound));
05774       } else if (!strcasecmp(var->name, "xferfailsound")) {
05775          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
05776       } else if (!strcasecmp(var->name, "pickupexten")) {
05777          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
05778       } else if (!strcasecmp(var->name, "pickupsound")) {
05779          ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
05780       } else if (!strcasecmp(var->name, "pickupfailsound")) {
05781          ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
05782       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
05783          comebacktoorigin = ast_true(var->value);
05784       }
05785    }
05786 
05787    unmap_features();
05788    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
05789       if (remap_feature(var->name, var->value)) {
05790          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
05791       }
05792    }
05793 
05794    /* Map a key combination to an application */
05795    ast_unregister_features();
05796    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
05797       process_applicationmap_line(var);
05798    }
05799 
05800    ast_unregister_groups();
05801    AST_RWLIST_WRLOCK(&feature_groups);
05802 
05803    ctg = NULL;
05804    while ((ctg = ast_category_browse(cfg, ctg))) {
05805       /* Is this a parkinglot definition ? */
05806       if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
05807          ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
05808          if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) {
05809             ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
05810          } else {
05811             ast_debug(1, "Configured parking context %s\n", ctg);
05812          }
05813          continue;   
05814       }
05815 
05816       /* No, check if it's a group */
05817       for (i = 0; i < ARRAY_LEN(categories); i++) {
05818          if (!strcasecmp(categories[i], ctg)) {
05819             break;
05820          }
05821       }
05822       if (i < ARRAY_LEN(categories)) {
05823          continue;
05824       }
05825 
05826       if (!(fg = register_group(ctg))) {
05827          continue;
05828       }
05829 
05830       for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
05831          struct ast_call_feature *feature;
05832 
05833          AST_RWLIST_RDLOCK(&feature_list);
05834          if (!(feature = find_dynamic_feature(var->name)) && 
05835              !(feature = ast_find_call_feature(var->name))) {
05836             AST_RWLIST_UNLOCK(&feature_list);
05837             ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
05838             continue;
05839          }
05840          AST_RWLIST_UNLOCK(&feature_list);
05841 
05842          register_group_feature(fg, var->value, feature);
05843       }
05844    }
05845 
05846    AST_RWLIST_UNLOCK(&feature_groups);
05847 
05848    return 0;
05849 }

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

02220 {
02221    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
02222    if (ast_strlen_zero(s)) {
02223       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
02224    }
02225    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
02226       s = transferer->macrocontext;
02227    }
02228    if (ast_strlen_zero(s)) {
02229       s = transferer->context;
02230    }
02231    return s;  
02232 }

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 2866 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.

02867 {
02868    struct feature_group *fg;
02869 
02870    if (!fgname) {
02871       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
02872       return NULL;
02873    }
02874 
02875    if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) {
02876       return NULL;
02877    }
02878 
02879    ast_string_field_set(fg, gname, fgname);
02880 
02881    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
02882 
02883    ast_verb(2, "Registered group '%s'\n", fg->gname);
02884 
02885    return fg;
02886 }

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 2897 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.

02898 {
02899    struct feature_group_exten *fge;
02900 
02901    if (!fg) {
02902       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
02903       return;
02904    }
02905 
02906    if (!feature) {
02907       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
02908       return;
02909    }
02910 
02911    if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) {
02912       return;
02913    }
02914 
02915    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
02916 
02917    fge->feature = feature;
02918 
02919    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
02920 
02921    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
02922                feature->sname, fg->gname, fge->exten);
02923 }

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

Definition at line 3105 of file features.c.

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

03106 {
03107    int x, res = -1;
03108 
03109    ast_rwlock_wrlock(&features_lock);
03110    for (x = 0; x < FEATURES_COUNT; x++) {
03111       if (strcasecmp(builtin_features[x].sname, name))
03112          continue;
03113 
03114       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
03115       res = 0;
03116       break;
03117    }
03118    ast_rwlock_unlock(&features_lock);
03119 
03120    return res;
03121 }

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

06411 {
06412    remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens);
06413    remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space);
06414 #if 0
06415    /* I don't think we should destroy hints if the parking space still exists. */
06416    remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint);
06417 #endif
06418 }

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

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

06434 {
06435    struct parking_dp_context *old_ctx;
06436    struct parking_dp_context *new_ctx;
06437    struct ast_context *con;
06438    int cmp;
06439 
06440    old_ctx = AST_LIST_FIRST(old_map);
06441    new_ctx = AST_LIST_FIRST(new_map);
06442 
06443    while (new_ctx) {
06444       if (!old_ctx) {
06445          /* No old contexts left, so no dead stuff can remain. */
06446          return;
06447       }
06448       cmp = strcmp(old_ctx->context, new_ctx->context);
06449       if (cmp < 0) {
06450          /* New map does not have old map context. */
06451          con = ast_context_find(old_ctx->context);
06452          if (con) {
06453             ast_context_destroy(con, registrar);
06454          }
06455          old_ctx = AST_LIST_NEXT(old_ctx, node);
06456          continue;
06457       }
06458       if (cmp == 0) {
06459          /* Old and new map have this context. */
06460          remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx);
06461          old_ctx = AST_LIST_NEXT(old_ctx, node);
06462       } else {
06463          /* Old map does not have new map context. */
06464       }
06465       new_ctx = AST_LIST_NEXT(new_ctx, node);
06466    }
06467 
06468    /* Any old contexts left must be dead. */
06469    for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) {
06470       con = ast_context_find(old_ctx->context);
06471       if (con) {
06472          ast_context_destroy(con, registrar);
06473       }
06474    }
06475 }

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

06270 {
06271    struct parking_dp_ramp *old_ramp;
06272    struct parking_dp_ramp *new_ramp;
06273    int cmp;
06274 
06275    old_ramp = AST_LIST_FIRST(old_ramps);
06276    new_ramp = AST_LIST_FIRST(new_ramps);
06277 
06278    while (new_ramp) {
06279       if (!old_ramp) {
06280          /* No old ramps left, so no dead ramps can remain. */
06281          return;
06282       }
06283       cmp = strcmp(old_ramp->exten, new_ramp->exten);
06284       if (cmp < 0) {
06285          /* New map does not have old ramp. */
06286          remove_exten_if_exist(context, old_ramp->exten, 1);
06287          old_ramp = AST_LIST_NEXT(old_ramp, node);
06288          continue;
06289       }
06290       if (cmp == 0) {
06291          /* Old and new map have this ramp. */
06292          old_ramp = AST_LIST_NEXT(old_ramp, node);
06293       } else {
06294          /* Old map does not have new ramp. */
06295       }
06296       new_ramp = AST_LIST_NEXT(new_ramp, node);
06297    }
06298 
06299    /* Any old ramps left must be dead. */
06300    for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) {
06301       remove_exten_if_exist(context, old_ramp->exten, 1);
06302    }
06303 }

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

06342 {
06343    struct parking_dp_spaces *old_range;
06344    struct parking_dp_spaces *new_range;
06345    int space;/*!< Current position in the current old range. */
06346    int stop;
06347 
06348    old_range = AST_LIST_FIRST(old_spaces);
06349    new_range = AST_LIST_FIRST(new_spaces);
06350    space = -1;
06351 
06352    while (old_range) {
06353       if (space < old_range->start) {
06354          space = old_range->start;
06355       }
06356       if (new_range) {
06357          if (space < new_range->start) {
06358             /* Current position in old range starts before new range. */
06359             if (old_range->stop < new_range->start) {
06360                /* Old range ends before new range. */
06361                stop = old_range->stop;
06362                old_range = AST_LIST_NEXT(old_range, node);
06363             } else {
06364                /* Tail of old range overlaps new range. */
06365                stop = new_range->start - 1;
06366             }
06367          } else if (/* new_range->start <= space && */ space <= new_range->stop) {
06368             /* Current position in old range overlaps new range. */
06369             if (old_range->stop <= new_range->stop) {
06370                /* Old range ends at or before new range. */
06371                old_range = AST_LIST_NEXT(old_range, node);
06372             } else {
06373                /* Old range extends beyond end of new range. */
06374                space = new_range->stop + 1;
06375                new_range = AST_LIST_NEXT(new_range, node);
06376             }
06377             continue;
06378          } else /* if (new_range->stop < space) */ {
06379             /* Current position in old range starts after new range. */
06380             new_range = AST_LIST_NEXT(new_range, node);
06381             continue;
06382          }
06383       } else {
06384          /* No more new ranges.  All remaining old spaces are dead. */
06385          stop = old_range->stop;
06386          old_range = AST_LIST_NEXT(old_range, node);
06387       }
06388 
06389       /* Destroy dead parking spaces. */
06390       for (; space <= stop; ++space) {
06391          destroy_space(context, space);
06392       }
06393    }
06394 }

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

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

06244 {
06245    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
06246 
06247    if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL,
06248       E_MATCH)) {
06249       ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n",
06250          context, exten, priority);
06251       ast_context_remove_extension(context, exten, priority, registrar);
06252    }
06253 }

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

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

03709 {
03710    const char *feature;
03711 
03712    if (ast_strlen_zero(features)) {
03713       return;
03714    }
03715 
03716    for (feature = features; *feature; feature++) {
03717       switch (*feature) {
03718       case 'T' :
03719       case 't' :
03720          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
03721          break;
03722       case 'K' :
03723       case 'k' :
03724          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
03725          break;
03726       case 'H' :
03727       case 'h' :
03728          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
03729          break;
03730       case 'W' :
03731       case 'w' :
03732          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
03733          break;
03734       default :
03735          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
03736       }
03737    }
03738 }

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

00831 {
00832    ast_copy_string(chan->context, context, sizeof(chan->context));
00833    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00834    chan->priority = pri;
00835 }

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

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

03293 {
03294    int x;
03295 
03296    ast_clear_flag(config, AST_FLAGS_ALL);
03297 
03298    ast_rwlock_rdlock(&features_lock);
03299    for (x = 0; x < FEATURES_COUNT; x++) {
03300       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
03301          continue;
03302 
03303       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
03304          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03305 
03306       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
03307          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03308    }
03309    ast_rwlock_unlock(&features_lock);
03310 
03311    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
03312       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
03313 
03314       if (dynamic_features) {
03315          char *tmp = ast_strdupa(dynamic_features);
03316          char *tok;
03317          struct ast_call_feature *feature;
03318 
03319          /* while we have a feature */
03320          while ((tok = strsep(&tmp, "#"))) {
03321             struct feature_group *fg;
03322 
03323             AST_RWLIST_RDLOCK(&feature_groups);
03324             AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
03325                struct feature_group_exten *fge;
03326 
03327                AST_LIST_TRAVERSE(&fg->features, fge, entry) {
03328                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
03329                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03330                   }
03331                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
03332                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03333                   }
03334                }
03335             }
03336             AST_RWLIST_UNLOCK(&feature_groups);
03337 
03338             AST_RWLIST_RDLOCK(&feature_list);
03339             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
03340                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
03341                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
03342                }
03343                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
03344                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
03345                }
03346             }
03347             AST_RWLIST_UNLOCK(&feature_list);
03348          }
03349       }
03350    }
03351 }

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

References FEATURE_SENSE_PEER.

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

01852 {
01853    if (sense == FEATURE_SENSE_PEER) {
01854       *caller = peer;
01855       *callee = chan;
01856    } else {
01857       *callee = peer;
01858       *caller = chan;
01859    }
01860 }

static void unmap_features ( void   )  [static]

Definition at line 3095 of file features.c.

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

03096 {
03097    int x;
03098 
03099    ast_rwlock_wrlock(&features_lock);
03100    for (x = 0; x < FEATURES_COUNT; x++)
03101       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
03102    ast_rwlock_unlock(&features_lock);
03103 }

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

05930 {
05931    struct parking_dp_ramp *cur_ramp;
05932    struct parking_dp_ramp *new_ramp;
05933    int cmp;
05934 
05935    /* Make sure that exclusive is only 0 or 1 */
05936    if (exclusive) {
05937       exclusive = 1;
05938    }
05939 
05940    AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) {
05941       cmp = strcmp(exten, cur_ramp->exten);
05942       if (cmp > 0) {
05943          /* The parking lot ramp goes after this node. */
05944          continue;
05945       }
05946       if (cmp == 0) {
05947          /* The ramp is already in the map. */
05948          if (complain && (cur_ramp->exclusive || exclusive)) {
05949             ast_log(LOG_WARNING,
05950                "Parking lot '%s' parkext %s@%s used by another parking lot.\n",
05951                lot->name, exten, lot->cfg.parking_con);
05952          }
05953          return 0;
05954       }
05955       /* The new parking lot ramp goes before this node. */
05956       new_ramp = build_dialplan_useage_ramp(exten, exclusive);
05957       if (!new_ramp) {
05958          return -1;
05959       }
05960       AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node);
05961       return 0;
05962    }
05963    AST_LIST_TRAVERSE_SAFE_END;
05964 
05965    /* New parking lot access ramp goes on the end. */
05966    new_ramp = build_dialplan_useage_ramp(exten, exclusive);
05967    if (!new_ramp) {
05968       return -1;
05969    }
05970    AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node);
05971    return 0;
05972 }

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

06011 {
06012    struct parking_dp_spaces *cur_node;
06013    struct parking_dp_spaces *expand_node;
06014    struct parking_dp_spaces *new_node;
06015 
06016    expand_node = NULL;
06017    AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) {
06018       /* NOTE: stop + 1 to combine immediately adjacent nodes into one. */
06019       if (expand_node) {
06020          /* The previous node is expanding to possibly eat following nodes. */
06021          if (expand_node->stop + 1 < cur_node->start) {
06022             /* Current node is completely after expanding node. */
06023             return 0;
06024          }
06025 
06026          if (complain
06027             && ((cur_node->start <= start && start <= cur_node->stop)
06028                || (cur_node->start <= stop && stop <= cur_node->stop)
06029                || (start < cur_node->start && cur_node->stop < stop))) {
06030             /* Only complain once per range add. */
06031             complain = 0;
06032             ast_log(LOG_WARNING,
06033                "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06034                lot->name, start, stop, lot->cfg.parking_con);
06035          }
06036 
06037          /* Current node is eaten by the expanding node. */
06038          if (expand_node->stop < cur_node->stop) {
06039             expand_node->stop = cur_node->stop;
06040          }
06041          AST_LIST_REMOVE_CURRENT(node);
06042          ast_free(cur_node);
06043          continue;
06044       }
06045 
06046       if (cur_node->stop + 1 < start) {
06047          /* New range is completely after current node. */
06048          continue;
06049       }
06050       if (stop + 1 < cur_node->start) {
06051          /* New range is completely before current node. */
06052          new_node = build_dialplan_useage_spaces(start, stop);
06053          if (!new_node) {
06054             return -1;
06055          }
06056          AST_LIST_INSERT_BEFORE_CURRENT(new_node, node);
06057          return 0;
06058       }
06059 
06060       if (complain
06061          && ((cur_node->start <= start && start <= cur_node->stop)
06062             || (cur_node->start <= stop && stop <= cur_node->stop)
06063             || (start < cur_node->start && cur_node->stop < stop))) {
06064          /* Only complain once per range add. */
06065          complain = 0;
06066          ast_log(LOG_WARNING,
06067             "Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
06068             lot->name, start, stop, lot->cfg.parking_con);
06069       }
06070 
06071       /* Current node range overlaps or is immediately adjacent to new range. */
06072       if (start < cur_node->start) {
06073          /* Expand the current node in the front. */
06074          cur_node->start = start;
06075       }
06076       if (stop <= cur_node->stop) {
06077          /* Current node is not expanding in the rear. */
06078          return 0;
06079       }
06080       cur_node->stop = stop;
06081       expand_node = cur_node;
06082    }
06083    AST_LIST_TRAVERSE_SAFE_END;
06084 
06085    if (expand_node) {
06086       /*
06087        * The previous node expanded and either ate all following nodes
06088        * or it was the last node.
06089        */
06090       return 0;
06091    }
06092 
06093    /* New range goes on the end. */
06094    new_node = build_dialplan_useage_spaces(start, stop);
06095    if (!new_node) {
06096       return -1;
06097    }
06098    AST_LIST_INSERT_TAIL(space_map, new_node, node);
06099    return 0;
06100 }

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

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

01791 {
01792    char *parse;
01793    const char *app_data;
01794    const char *pl_name;
01795    struct ast_park_call_args args = { 0, };
01796    struct park_app_args app_args;
01797    int res;
01798 
01799    app_data = ast_get_extension_app_data(park_exten);
01800    if (!app_data) {
01801       app_data = "";
01802    }
01803    parse = ast_strdupa(app_data);
01804    AST_STANDARD_APP_ARGS(app_args, parse);
01805 
01806    /* Find the parking lot */
01807    if (!ast_strlen_zero(app_args.pl_name)) {
01808       pl_name = app_args.pl_name;
01809    } else {
01810       pl_name = findparkinglotname(parker);
01811    }
01812    if (ast_strlen_zero(pl_name)) {
01813       /* Parking lot is not specified, so use the default parking lot. */
01814       args.parkinglot = parkinglot_addref(default_parkinglot);
01815    } else {
01816       args.parkinglot = find_parkinglot(pl_name);
01817       if (!args.parkinglot && parkeddynamic) {
01818          args.parkinglot = create_dynamic_parkinglot(pl_name, park_me);
01819       }
01820    }
01821 
01822    if (args.parkinglot) {
01823       /* Park the call */
01824       res = finishup(park_me);
01825       if (res) {
01826          /* park_me hungup on us. */
01827          parkinglot_unref(args.parkinglot);
01828          return -1;
01829       }
01830       res = masq_park_call(park_me, parker, &args);
01831       parkinglot_unref(args.parkinglot);
01832    } else {
01833       /* Parking failed because parking lot does not exist. */
01834       if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
01835          ast_stream_and_wait(parker, "pbx-parkingfailed", "");
01836       }
01837       finishup(park_me);
01838       res = -1;
01839    }
01840 
01841    return res ? AST_FEATURE_RETURN_SUCCESS : -1;
01842 }


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

Referenced by bridge_exec().

struct ast_call_feature builtin_features[] [static]

Definition at line 2832 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_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 6961 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 747 of file features.c.

Referenced by add_features_datastores(), 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 2830 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 4885 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 5332 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 5322 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 7130 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 Sat Mar 10 01:55:23 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7