Mon Jun 27 16:51:13 2011

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  parkeduser
 Description of one parked call, added to a list while active, then removed. The list belongs to a parkinglot. More...

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) }

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
void ast_channel_log (char *title, struct ast_channel *chan)
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_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, const char *parkexten, 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 ast_parkinglotbuild_parkinglot (char *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 struct ast_parkinglotcopy_parkinglot (const char *name, const struct ast_parkinglot *parkinglot)
 Copy parkinglot and store it with new name.
static struct ast_parkinglotcreate_parkinglot (const char *name)
 Allocate parking lot structure.
static void dial_features_destroy (void *data)
static void * dial_features_duplicate (void *data)
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_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, int 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.
ast_parkinglotfind_parkinglot (const char *name)
 Find parkinglot by name.
static int find_parkinglot_by_exten_cb (void *obj, void *args, int flags)
static int find_parkinglot_by_position_cb (void *obj, void *args, int flags)
static const char * findparkinglotname (struct ast_channel *chan)
 Find parking lot name from channel.
static int finishup (struct ast_channel *chan)
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 (void)
int manage_parkinglot (struct ast_parkinglot *curlot, const struct pollfd *pfds, const 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, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args)
static int masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
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 (char *context, int start, int stop)
 Add parking hints for all defined parking lots.
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 int park_exec (struct ast_channel *chan, const char *data)
static int park_exec_full (struct ast_channel *chan, const char *data)
 Pickup parked call.
static struct parkeduserpark_space_reserve (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
static int parkcall_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, struct ast_park_call_args *args)
static struct ast_parkinglotparkinglot_addref (struct ast_parkinglot *parkinglot)
static int parkinglot_cmp_cb (void *obj, void *arg, int flags)
static void parkinglot_destroy (void *obj)
 Destroy a parking lot.
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. If no more references, then go ahead and delete it.
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 void post_manager_event (const char *s, struct parkeduser *pu)
 Output parking event to manager.
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 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)

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]
ast_parkinglotdefault_parkinglot
static struct ast_datastore_info dial_features_info
static int featuredigittimeout
static ast_rwlock_t features_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 }
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 char * parkcall = PARK_APP_NAME
static char * parkedcall = "ParkedCall"
static int parkeddynamic = 0
static int parkedplay = 0
char parking_ext [AST_MAX_EXTENSION]
static pthread_t parking_thread
static struct ao2_containerparkinglots
 The list of parking lots configured. Always at least one - the default parking lot.
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 353 of file features.c.

#define DEFAULT_ATXFER_CALLBACK_RETRIES   2

Definition at line 351 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_DROP_CALL   0

Do not drop call.

Definition at line 349 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_LOOP_DELAY   10000

ms

Definition at line 350 of file features.c.

Referenced by load_config().

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

ms

Definition at line 347 of file features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

ms

Definition at line 348 of file features.c.

Referenced by load_config().

#define DEFAULT_PARK_EXTENSION   "700"

Definition at line 345 of file features.c.

Referenced by build_parkinglot(), and load_config().

#define DEFAULT_PARK_TIME   45000

ms

Definition at line 344 of file features.c.

Referenced by build_parkinglot(), and load_config().

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

ms

Definition at line 346 of file features.c.

Referenced by load_config().

#define FEATURES_COUNT   ARRAY_LEN(builtin_features)

Definition at line 2440 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 354 of file features.c.

Referenced by manage_parkinglot().


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

05663      {
05664    BRIDGE_OPT_PLAYTONE = (1 << 0),
05665    OPT_CALLEE_HANGUP =  (1 << 1),
05666    OPT_CALLER_HANGUP =  (1 << 2),
05667    OPT_DURATION_LIMIT = (1 << 3),
05668    OPT_DURATION_STOP =  (1 << 4),
05669    OPT_CALLEE_TRANSFER = (1 << 5),
05670    OPT_CALLER_TRANSFER = (1 << 6),
05671    OPT_CALLEE_MONITOR = (1 << 7),
05672    OPT_CALLER_MONITOR = (1 << 8),
05673    OPT_CALLEE_PARK = (1 << 9),
05674    OPT_CALLER_PARK = (1 << 10),
05675    OPT_CALLEE_KILL = (1 << 11),
05676 };

anonymous enum

Enumerator:
OPT_ARG_DURATION_LIMIT 
OPT_ARG_DURATION_STOP 
OPT_ARG_ARRAY_SIZE 

Definition at line 5678 of file features.c.

05678      {
05679    OPT_ARG_DURATION_LIMIT = 0,
05680    OPT_ARG_DURATION_STOP,
05681    /* note: this entry _MUST_ be the last one in the enum */
05682    OPT_ARG_ARRAY_SIZE,
05683 };

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

00884                            {
00885    /*! Provide ringing to the parked caller instead of music on hold */
00886    AST_PARK_OPT_RINGING =   (1 << 0),
00887    /*! Randomly choose a parking spot for the caller instead of choosing
00888     *  the first one that is available. */
00889    AST_PARK_OPT_RANDOMIZE = (1 << 1),
00890    /*! Do not announce the parking number */
00891    AST_PARK_OPT_SILENCE = (1 << 2),
00892 };


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

05267 {
05268    const char *channela = astman_get_header(m, "Channel1");
05269    const char *channelb = astman_get_header(m, "Channel2");
05270    const char *playtone = astman_get_header(m, "Tone");
05271    struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
05272    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
05273    struct ast_bridge_thread_obj *tobj = NULL;
05274 
05275    /* make sure valid channels were specified */
05276    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
05277       astman_send_error(s, m, "Missing channel parameter in request");
05278       return 0;
05279    }
05280 
05281    /* Start with chana */
05282    chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
05283 
05284    /* send errors if any of the channels could not be found/locked */
05285    if (!chana) {
05286       char buf[256];
05287       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
05288       astman_send_error(s, m, buf);
05289       return 0;
05290    }
05291 
05292    /* Answer the channels if needed */
05293    if (chana->_state != AST_STATE_UP)
05294       ast_answer(chana);
05295 
05296    /* create the placeholder channels and grab the other channels */
05297    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
05298       NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
05299       astman_send_error(s, m, "Unable to create temporary channel!");
05300       chana = ast_channel_unref(chana);
05301       return 1;
05302    }
05303 
05304    do_bridge_masquerade(chana, tmpchana);
05305 
05306    chana = ast_channel_unref(chana);
05307 
05308    /* now do chanb */
05309    chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
05310    /* send errors if any of the channels could not be found/locked */
05311    if (!chanb) {
05312       char buf[256];
05313       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
05314       ast_hangup(tmpchana);
05315       astman_send_error(s, m, buf);
05316       return 0;
05317    }
05318 
05319    /* Answer the channels if needed */
05320    if (chanb->_state != AST_STATE_UP)
05321       ast_answer(chanb);
05322 
05323    /* create the placeholder channels and grab the other channels */
05324    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
05325       NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
05326       astman_send_error(s, m, "Unable to create temporary channels!");
05327       ast_hangup(tmpchana);
05328       chanb = ast_channel_unref(chanb);
05329       return 1;
05330    }
05331 
05332    do_bridge_masquerade(chanb, tmpchanb);
05333 
05334    chanb = ast_channel_unref(chanb);
05335 
05336    /* make the channels compatible, send error if we fail doing so */
05337    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
05338       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
05339       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
05340       ast_hangup(tmpchana);
05341       ast_hangup(tmpchanb);
05342       return 1;
05343    }
05344 
05345    /* setup the bridge thread object and start the bridge */
05346    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
05347       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
05348       astman_send_error(s, m, "Unable to spawn a new bridge thread");
05349       ast_hangup(tmpchana);
05350       ast_hangup(tmpchanb);
05351       return 1;
05352    }
05353 
05354    tobj->chan = tmpchana;
05355    tobj->peer = tmpchanb;
05356    tobj->return_to_pbx = 1;
05357 
05358    if (ast_true(playtone)) {
05359       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
05360          if (ast_waitstream(tmpchanb, "") < 0)
05361             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
05362       }
05363    }
05364 
05365    chans[0] = tmpchana;
05366    chans[1] = tmpchanb;
05367 
05368    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
05369             "Response: Success\r\n"
05370             "Channel1: %s\r\n"
05371             "Channel2: %s\r\n", tmpchana->name, tmpchanb->name);
05372 
05373    bridge_call_thread_launch(tobj);
05374 
05375    astman_send_ack(s, m, "Launched bridge thread with success");
05376 
05377    return 0;
05378 }

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

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

03329 {
03330    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
03331    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
03332 
03333    ast_channel_lock(caller);
03334    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
03335    ast_channel_unlock(caller);
03336    if (!ds_caller_features) {
03337       if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03338          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
03339          return;
03340       }
03341       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
03342          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03343          ast_datastore_free(ds_caller_features);
03344          return;
03345       }
03346       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
03347       caller_features->is_caller = 1;
03348       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
03349       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
03350       ds_caller_features->data = caller_features;
03351       ast_channel_lock(caller);
03352       ast_channel_datastore_add(caller, ds_caller_features);
03353       ast_channel_unlock(caller);
03354    } else {
03355       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
03356        * flags over from the atxfer to the caller */
03357       return;
03358    }
03359 
03360    ast_channel_lock(callee);
03361    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
03362    ast_channel_unlock(callee);
03363    if (!ds_callee_features) {
03364       if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03365          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
03366          return;
03367       }
03368       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
03369          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03370          ast_datastore_free(ds_callee_features);
03371          return;
03372       }
03373       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
03374       callee_features->is_caller = 0;
03375       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
03376       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
03377       ds_callee_features->data = callee_features;
03378       ast_channel_lock(callee);
03379       ast_channel_datastore_add(callee, ds_callee_features);
03380       ast_channel_unlock(callee);
03381    }
03382 
03383    return;
03384 }

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

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

Referenced by park_call_full().

00823 {
00824    int res;
00825    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00826    char tmp[256];
00827    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00828 
00829    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00830    message[0] = tmp;
00831    res = ast_adsi_load_session(chan, NULL, 0, 1);
00832    if (res == -1)
00833       return res;
00834    return ast_adsi_print(chan, message, justify, 1);
00835 }

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,peer,config 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 3395 of file features.c.

References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_bridge(), ast_channel_connected_line_macro(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_log(), ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), 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, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, 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_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_channel::caller, ast_channel::cdr, ast_cdr::channel, config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_party_caller::id, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, ast_party_id::number, 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_channel::uniqueid, 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 park_exec_full().

03396 {
03397    /* Copy voice back and forth between the two channels.  Give the peer
03398       the ability to transfer calls with '#<extension' syntax. */
03399    struct ast_frame *f;
03400    struct ast_channel *who;
03401    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
03402    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
03403    char orig_channame[AST_MAX_EXTENSION];
03404    char orig_peername[AST_MAX_EXTENSION];
03405    int res;
03406    int diff;
03407    int hasfeatures=0;
03408    int hadfeatures=0;
03409    int autoloopflag;
03410    int we_disabled_peer_cdr = 0;
03411    struct ast_option_header *aoh;
03412    struct ast_cdr *bridge_cdr = NULL;
03413    struct ast_cdr *orig_peer_cdr = NULL;
03414    struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */
03415    struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */
03416    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
03417    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
03418 
03419    if (chan && peer) {
03420       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
03421       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
03422    } else if (chan) {
03423       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
03424    }
03425 
03426    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
03427    add_features_datastores(chan, peer, config);
03428 
03429    /* This is an interesting case.  One example is if a ringing channel gets redirected to
03430     * an extension that picks up a parked call.  This will make sure that the call taken
03431     * out of parking gets told that the channel it just got bridged to is still ringing. */
03432    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
03433       ast_indicate(peer, AST_CONTROL_RINGING);
03434    }
03435 
03436    if (monitor_ok) {
03437       const char *monitor_exec;
03438       struct ast_channel *src = NULL;
03439       if (!monitor_app) {
03440          if (!(monitor_app = pbx_findapp("Monitor")))
03441             monitor_ok=0;
03442       }
03443       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
03444          src = chan;
03445       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
03446          src = peer;
03447       if (monitor_app && src) {
03448          char *tmp = ast_strdupa(monitor_exec);
03449          pbx_exec(src, monitor_app, tmp);
03450       }
03451    }
03452 
03453    set_config_flags(chan, peer, config);
03454 
03455    /* Answer if need be */
03456    if (chan->_state != AST_STATE_UP) {
03457       if (ast_raw_answer(chan, 1)) {
03458          return -1;
03459       }
03460    }
03461 
03462 #ifdef FOR_DEBUG
03463    /* show the two channels and cdrs involved in the bridge for debug & devel purposes */
03464    ast_channel_log("Pre-bridge CHAN Channel info", chan);
03465    ast_channel_log("Pre-bridge PEER Channel info", peer);
03466 #endif
03467    /* two channels are being marked as linked here */
03468    ast_channel_set_linkgroup(chan,peer);
03469 
03470    /* copy the userfield from the B-leg to A-leg if applicable */
03471    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
03472       char tmp[256];
03473       if (!ast_strlen_zero(chan->cdr->userfield)) {
03474          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
03475          ast_cdr_appenduserfield(chan, tmp);
03476       } else
03477          ast_cdr_setuserfield(chan, peer->cdr->userfield);
03478       /* Don't delete the CDR; just disable it. */
03479       ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03480       we_disabled_peer_cdr = 1;
03481    }
03482    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
03483    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
03484    orig_peer_cdr = peer_cdr;
03485    
03486    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
03487       
03488       if (chan_cdr) {
03489          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
03490          ast_cdr_update(chan);
03491          bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
03492          /* rip any forked CDR's off of the chan_cdr and attach
03493           * them to the bridge_cdr instead */
03494          bridge_cdr->next = chan_cdr->next;
03495          chan_cdr->next = NULL;
03496          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03497          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03498          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
03499             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03500          }
03501          ast_cdr_setaccount(peer, chan->accountcode);
03502 
03503       } else {
03504          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
03505          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
03506          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
03507          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
03508          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
03509          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03510          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03511          ast_cdr_setcid(bridge_cdr, chan);
03512          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
03513          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
03514          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
03515          /* Destination information */
03516          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
03517          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
03518          if (peer_cdr) {
03519             bridge_cdr->start = peer_cdr->start;
03520             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03521          } else {
03522             ast_cdr_start(bridge_cdr);
03523          }
03524       }
03525       ast_debug(4,"bridge answer set, chan answer set\n");
03526       /* peer_cdr->answer will be set when a macro runs on the peer;
03527          in that case, the bridge answer will be delayed while the
03528          macro plays on the peer channel. The peer answered the call
03529          before the macro started playing. To the phone system,
03530          this is billable time for the call, even tho the caller
03531          hears nothing but ringing while the macro does its thing. */
03532 
03533       /* Another case where the peer cdr's time will be set, is when
03534          A self-parks by pickup up phone and dialing 700, then B
03535          picks up A by dialing its parking slot; there may be more 
03536          practical paths that get the same result, tho... in which
03537          case you get the previous answer time from the Park... which
03538          is before the bridge's start time, so I added in the 
03539          tvcmp check to the if below */
03540 
03541       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
03542          ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
03543          ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
03544          if (chan_cdr) {
03545             ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
03546             ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
03547          }
03548       } else {
03549          ast_cdr_answer(bridge_cdr);
03550          if (chan_cdr) {
03551             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
03552          }
03553       }
03554       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
03555          if (chan_cdr) {
03556             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
03557          }
03558          if (peer_cdr) {
03559             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
03560          }
03561       }
03562       /* the DIALED flag may be set if a dialed channel is transfered
03563        * and then bridged to another channel.  In order for the
03564        * bridge CDR to be written, the DIALED flag must not be
03565        * present. */
03566       ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
03567    }
03568    ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL);
03569    for (;;) {
03570       struct ast_channel *other; /* used later */
03571    
03572       res = ast_channel_bridge(chan, peer, config, &f, &who);
03573       
03574       /* When frame is not set, we are probably involved in a situation
03575          where we've timed out.
03576          When frame is set, we'll come this code twice; once for DTMF_BEGIN
03577          and also for DTMF_END. If we flow into the following 'if' for both, then 
03578          our wait times are cut in half, as both will subtract from the
03579          feature_timer. Not good!
03580       */
03581       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
03582          /* Update feature timer for next pass */
03583          diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
03584          if (res == AST_BRIDGE_RETRY) {
03585             /* The feature fully timed out but has not been updated. Skip
03586              * the potential round error from the diff calculation and
03587              * explicitly set to expired. */
03588             config->feature_timer = -1;
03589          } else {
03590             config->feature_timer -= diff;
03591          }
03592 
03593          if (hasfeatures) {
03594             if (config->feature_timer <= 0) {
03595                /* Not *really* out of time, just out of time for
03596                   digits to come in for features. */
03597                ast_debug(1, "Timed out for feature!\n");
03598                if (!ast_strlen_zero(peer_featurecode)) {
03599                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
03600                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
03601                }
03602                if (!ast_strlen_zero(chan_featurecode)) {
03603                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
03604                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
03605                }
03606                if (f)
03607                   ast_frfree(f);
03608                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03609                if (!hasfeatures) {
03610                   /* No more digits expected - reset the timer */
03611                   config->feature_timer = 0;
03612                }
03613                hadfeatures = hasfeatures;
03614                /* Continue as we were */
03615                continue;
03616             } else if (!f) {
03617                /* The bridge returned without a frame and there is a feature in progress.
03618                 * However, we don't think the feature has quite yet timed out, so just
03619                 * go back into the bridge. */
03620                continue;
03621             }
03622          } else {
03623             if (config->feature_timer <=0) {
03624                /* We ran out of time */
03625                config->feature_timer = 0;
03626                who = chan;
03627                if (f)
03628                   ast_frfree(f);
03629                f = NULL;
03630                res = 0;
03631             }
03632          }
03633       }
03634       if (res < 0) {
03635          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
03636             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
03637          }
03638          goto before_you_go;
03639       }
03640       
03641       if (!f || (f->frametype == AST_FRAME_CONTROL &&
03642             (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
03643                f->subclass.integer == AST_CONTROL_CONGESTION))) {
03644          res = -1;
03645          break;
03646       }
03647       /* many things should be sent to the 'other' channel */
03648       other = (who == chan) ? peer : chan;
03649       if (f->frametype == AST_FRAME_CONTROL) {
03650          switch (f->subclass.integer) {
03651          case AST_CONTROL_RINGING:
03652          case AST_CONTROL_FLASH:
03653          case -1:
03654             ast_indicate(other, f->subclass.integer);
03655             break;
03656          case AST_CONTROL_CONNECTED_LINE:
03657             if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
03658                break;
03659             }
03660             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03661             break;
03662          case AST_CONTROL_REDIRECTING:
03663             if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
03664                break;
03665             }
03666             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03667             break;
03668          case AST_CONTROL_AOC:
03669          case AST_CONTROL_HOLD:
03670          case AST_CONTROL_UNHOLD:
03671             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03672             break;
03673          case AST_CONTROL_OPTION:
03674             aoh = f->data.ptr;
03675             /* Forward option Requests, but only ones we know are safe
03676              * These are ONLY sent by chan_iax2 and I'm not convinced that
03677              * they are useful. I haven't deleted them entirely because I
03678              * just am not sure of the ramifications of removing them. */
03679             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
03680                   switch (ntohs(aoh->option)) {
03681                case AST_OPTION_TONE_VERIFY:
03682                case AST_OPTION_TDD:
03683                case AST_OPTION_RELAXDTMF:
03684                case AST_OPTION_AUDIO_MODE:
03685                case AST_OPTION_DIGIT_DETECT:
03686                case AST_OPTION_FAX_DETECT:
03687                   ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
03688                      f->datalen - sizeof(struct ast_option_header), 0);
03689                }
03690             }
03691             break;
03692          }
03693       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
03694          /* eat it */
03695       } else if (f->frametype == AST_FRAME_DTMF) {
03696          char *featurecode;
03697          int sense;
03698 
03699          hadfeatures = hasfeatures;
03700          /* This cannot overrun because the longest feature is one shorter than our buffer */
03701          if (who == chan) {
03702             sense = FEATURE_SENSE_CHAN;
03703             featurecode = chan_featurecode;
03704          } else  {
03705             sense = FEATURE_SENSE_PEER;
03706             featurecode = peer_featurecode;
03707          }
03708          /*! append the event to featurecode. we rely on the string being zero-filled, and
03709           * not overflowing it. 
03710           * \todo XXX how do we guarantee the latter ?
03711           */
03712          featurecode[strlen(featurecode)] = f->subclass.integer;
03713          /* Get rid of the frame before we start doing "stuff" with the channels */
03714          ast_frfree(f);
03715          f = NULL;
03716          config->feature_timer = 0;
03717          res = feature_interpret(chan, peer, config, featurecode, sense);
03718          switch(res) {
03719          case AST_FEATURE_RETURN_PASSDIGITS:
03720             ast_dtmf_stream(other, who, featurecode, 0, 0);
03721             /* Fall through */
03722          case AST_FEATURE_RETURN_SUCCESS:
03723             memset(featurecode, 0, sizeof(chan_featurecode));
03724             break;
03725          }
03726          if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
03727             res = 0;
03728          } else {
03729             break;
03730          }
03731          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03732          if (hadfeatures && !hasfeatures) {
03733             /* Feature completed or timed out */
03734             config->feature_timer = 0;
03735          } else if (hasfeatures) {
03736             if (config->timelimit) {
03737                /* No warning next time - we are waiting for future */
03738                ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
03739             }
03740             config->feature_start_time = ast_tvnow();
03741             config->feature_timer = featuredigittimeout;
03742             ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
03743          }
03744       }
03745       if (f)
03746          ast_frfree(f);
03747 
03748    }
03749    ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL);
03750    before_you_go:
03751 
03752    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
03753       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
03754       if (bridge_cdr) {
03755          ast_cdr_discard(bridge_cdr);
03756          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
03757       }
03758       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
03759    }
03760 
03761    if (config->end_bridge_callback) {
03762       config->end_bridge_callback(config->end_bridge_callback_data);
03763    }
03764 
03765    /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 
03766     * if it were, then chan belongs to a different thread now, and might have been hung up long
03767      * ago.
03768     */
03769    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN)
03770       && ast_exists_extension(chan, chan->context, "h", 1,
03771          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
03772       struct ast_cdr *swapper = NULL;
03773       char savelastapp[AST_MAX_EXTENSION];
03774       char savelastdata[AST_MAX_EXTENSION];
03775       char save_exten[AST_MAX_EXTENSION];
03776       int  save_prio;
03777       int  found = 0;   /* set if we find at least one match */
03778       int  spawn_error = 0;
03779       
03780       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
03781       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
03782       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
03783          ast_cdr_end(bridge_cdr);
03784       }
03785       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
03786          dialplan code operate on it */
03787       ast_channel_lock(chan);
03788       if (bridge_cdr) {
03789          swapper = chan->cdr;
03790          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
03791          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
03792          chan->cdr = bridge_cdr;
03793       }
03794       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
03795       save_prio = chan->priority;
03796       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
03797       chan->priority = 1;
03798       ast_channel_unlock(chan);
03799       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten,
03800          chan->priority,
03801          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
03802          &found, 1)) == 0) {
03803          chan->priority++;
03804       }
03805       if (spawn_error
03806          && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority,
03807             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
03808             || ast_check_hangup(chan))) {
03809          /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */
03810          spawn_error = 0;
03811       }
03812       if (found && spawn_error) {
03813          /* Something bad happened, or a hangup has been requested. */
03814          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03815          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03816       }
03817       /* swap it back */
03818       ast_channel_lock(chan);
03819       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
03820       chan->priority = save_prio;
03821       if (bridge_cdr) {
03822          if (chan->cdr == bridge_cdr) {
03823             chan->cdr = swapper;
03824          } else {
03825             bridge_cdr = NULL;
03826          }
03827       }
03828       if (!spawn_error) {
03829          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
03830       }
03831       ast_channel_unlock(chan);
03832       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
03833       if (bridge_cdr) {
03834          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
03835          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
03836       }
03837       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03838    }
03839    
03840    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
03841    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
03842    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
03843       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
03844 
03845    /* we can post the bridge CDR at this point */
03846    if (bridge_cdr) {
03847       ast_cdr_end(bridge_cdr);
03848       ast_cdr_detach(bridge_cdr);
03849    }
03850    
03851    /* do a specialized reset on the beginning channel
03852       CDR's, if they still exist, so as not to mess up
03853       issues in future bridges;
03854       
03855       Here are the rules of the game:
03856       1. The chan and peer channel pointers will not change
03857          during the life of the bridge.
03858       2. But, in transfers, the channel names will change.
03859          between the time the bridge is started, and the
03860          time the channel ends. 
03861          Usually, when a channel changes names, it will
03862          also change CDR pointers.
03863       3. Usually, only one of the two channels (chan or peer)
03864          will change names.
03865       4. Usually, if a channel changes names during a bridge,
03866          it is because of a transfer. Usually, in these situations,
03867          it is normal to see 2 bridges running simultaneously, and
03868          it is not unusual to see the two channels that change
03869          swapped between bridges.
03870       5. After a bridge occurs, we have 2 or 3 channels' CDRs
03871          to attend to; if the chan or peer changed names,
03872          we have the before and after attached CDR's.
03873    */
03874 
03875    if (new_chan_cdr) {
03876       struct ast_channel *chan_ptr = NULL;
03877 
03878       if (strcasecmp(orig_channame, chan->name) != 0) { 
03879          /* old channel */
03880          if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
03881             ast_channel_lock(chan_ptr);
03882             if (!ast_bridged_channel(chan_ptr)) {
03883                struct ast_cdr *cur;
03884                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03885                   if (cur == chan_cdr) {
03886                      break;
03887                   }
03888                }
03889                if (cur) {
03890                   ast_cdr_specialized_reset(chan_cdr, 0);
03891                }
03892             }
03893             ast_channel_unlock(chan_ptr);
03894             chan_ptr = ast_channel_unref(chan_ptr);
03895          }
03896          /* new channel */
03897          ast_cdr_specialized_reset(new_chan_cdr, 0);
03898       } else {
03899          ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr  */
03900       }
03901    }
03902 
03903    {
03904       struct ast_channel *chan_ptr = NULL;
03905       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
03906       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))
03907          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
03908       if (strcasecmp(orig_peername, peer->name) != 0) { 
03909          /* old channel */
03910          if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
03911             ast_channel_lock(chan_ptr);
03912             if (!ast_bridged_channel(chan_ptr)) {
03913                struct ast_cdr *cur;
03914                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03915                   if (cur == peer_cdr) {
03916                      break;
03917                   }
03918                }
03919                if (cur) {
03920                   ast_cdr_specialized_reset(peer_cdr, 0);
03921                }
03922             }
03923             ast_channel_unlock(chan_ptr);
03924             chan_ptr = ast_channel_unref(chan_ptr);
03925          }
03926          /* new channel */
03927          if (new_peer_cdr) {
03928             ast_cdr_specialized_reset(new_peer_cdr, 0);
03929          }
03930       } else {
03931          if (we_disabled_peer_cdr) {
03932             ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03933          }
03934          ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr  */
03935       }
03936    }
03937    
03938    return res;
03939 }

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

05702 {
05703    char *stringp = ast_strdupa(parse);
05704    char *limit_str, *warning_str, *warnfreq_str;
05705    const char *var;
05706    int play_to_caller = 0, play_to_callee = 0;
05707    int delta;
05708 
05709    limit_str = strsep(&stringp, ":");
05710    warning_str = strsep(&stringp, ":");
05711    warnfreq_str = strsep(&stringp, ":");
05712 
05713    config->timelimit = atol(limit_str);
05714    if (warning_str)
05715       config->play_warning = atol(warning_str);
05716    if (warnfreq_str)
05717       config->warning_freq = atol(warnfreq_str);
05718 
05719    if (!config->timelimit) {
05720       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
05721       config->timelimit = config->play_warning = config->warning_freq = 0;
05722       config->warning_sound = NULL;
05723       return -1; /* error */
05724    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
05725       int w = config->warning_freq;
05726 
05727       /* If the first warning is requested _after_ the entire call would end,
05728          and no warning frequency is requested, then turn off the warning. If
05729          a warning frequency is requested, reduce the 'first warning' time by
05730          that frequency until it falls within the call's total time limit.
05731          Graphically:
05732               timelim->|    delta        |<-playwarning
05733          0__________________|_________________|
05734                 | w  |    |    |    |
05735 
05736          so the number of intervals to cut is 1+(delta-1)/w
05737       */
05738 
05739       if (w == 0) {
05740          config->play_warning = 0;
05741       } else {
05742          config->play_warning -= w * ( 1 + (delta-1)/w );
05743          if (config->play_warning < 1)
05744             config->play_warning = config->warning_freq = 0;
05745       }
05746    }
05747    
05748    ast_channel_lock(chan);
05749 
05750    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
05751    play_to_caller = var ? ast_true(var) : 1;
05752 
05753    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
05754    play_to_callee = var ? ast_true(var) : 0;
05755 
05756    if (!play_to_caller && !play_to_callee)
05757       play_to_caller = 1;
05758 
05759    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
05760    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
05761 
05762    /* The code looking at config wants a NULL, not just "", to decide
05763     * that the message should not be played, so we replace "" with NULL.
05764     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
05765     * not found.
05766     */
05767 
05768    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
05769    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05770 
05771    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
05772    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05773 
05774    ast_channel_unlock(chan);
05775 
05776    /* undo effect of S(x) in case they are both used */
05777    calldurationlimit->tv_sec = 0;
05778    calldurationlimit->tv_usec = 0;
05779 
05780    /* more efficient to do it like S(x) does since no advanced opts */
05781    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
05782       calldurationlimit->tv_sec = config->timelimit / 1000;
05783       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
05784       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
05785          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
05786       config->timelimit = play_to_caller = play_to_callee =
05787       config->play_warning = config->warning_freq = 0;
05788    } else {
05789       ast_verb(4, "Limit Data for this call:\n");
05790       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
05791       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
05792       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
05793       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
05794       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
05795       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
05796       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
05797       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
05798    }
05799    if (play_to_caller)
05800       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
05801    if (play_to_callee)
05802       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
05803    return 0;
05804 }

void ast_channel_log ( char *  title,
struct ast_channel chan 
)

Definition at line 3263 of file features.c.

References ast_log(), and LOG_NOTICE.

Referenced by ast_bridge_call().

03264 {
03265        ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
03266        ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
03267                        chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
03268        ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
03269                        chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
03270        ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
03271                        chan->masq, chan->masqr,
03272                        chan->_bridge, chan->uniqueid, chan->linkedid);
03273        if (chan->masqr)
03274                ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
03275                                chan->masqr->name, chan->masqr->cdr);
03276        if (chan->_bridge)
03277                ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
03278 
03279    ast_log(LOG_NOTICE, "===== done ====\n");
03280 }

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

References feature_group_exten::feature, and feature_interpret_helper().

Referenced by detect_disconnect().

02881                                                                                                                                  {
02882 
02883    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02884 }

int ast_features_init ( void   ) 

Provided by features.c

Definition at line 5975 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(), park_exec(), parkcall, parkedcall, parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), and parkinglots.

Referenced by main().

05976 {
05977    int res;
05978 
05979    ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
05980 
05981    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
05982 
05983    if ((res = load_config()))
05984       return res;
05985    ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
05986    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
05987    res = ast_register_application2(parkedcall, park_exec, NULL, NULL, NULL);
05988    if (!res)
05989       res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
05990    if (!res) {
05991       ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
05992       ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
05993       ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
05994    }
05995 
05996    res |= ast_devstate_prov_add("Park", metermaidstate);
05997 #ifdef TEST_FRAMEWORK
05998    res |= AST_TEST_REGISTER(features_test);
05999 #endif
06000 
06001    return res;
06002 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 5198 of file features.c.

References ao2_t_callback, load_config(), OBJ_NODATA, OBJ_UNLINK, parkinglot_is_marked_cb(), parkinglot_markall_cb(), and parkinglots.

Referenced by handle_features_reload().

05199 {
05200    int res;
05201 
05202    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, "callback to mark all parkinglots");
05203    res = load_config(); /* Reload configuration */
05204    ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, "callback to remove all marked parkinglots");
05205    
05206    return res;
05207 }

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

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

02624 {
02625    int x;
02626    for (x = 0; x < FEATURES_COUNT; x++) {
02627       if (!strcasecmp(name, builtin_features[x].sname))
02628          return &builtin_features[x];
02629    }
02630    return NULL;
02631 }

int ast_masq_park_call ( struct ast_channel rchan,
struct ast_channel host,
int  timeout,
int *  extout 
)

Park a call via a masqueraded channel.

Parameters:
rchan the real channel to be parked
host the channel to have the parking read to.
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 channel rchan into a new, empty channel which is then parked with ast_park_call
Return values:
0 on success.
-1 on failure.

Definition at line 1299 of file features.c.

References masq_park_call().

Referenced by __analog_ss_thread(), analog_ss_thread(), handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), mgcp_ss(), parkandannounce_exec(), and rpt_exec().

01300 {
01301    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
01302 }

int ast_park_call ( struct ast_channel chan,
struct ast_channel host,
int  timeout,
const char *  parkexten,
int *  extout 
)

Park a call and read back parked location.

Parameters:
chan the channel to actually be parked
host the channel which will have the parked location read to.
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 channel chan, and read back the parked location to the host. 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 1225 of file features.c.

References ao2_callback, args, find_parkinglot_by_exten_cb(), park_call_full(), and parkinglots.

Referenced by iax_park_thread(), and sip_park_thread().

01226 {
01227    struct ast_parkinglot *found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, (void *) parkexten);
01228 
01229    struct ast_park_call_args args = {
01230       .timeout = timeout,
01231       .extout = extout,
01232       .parkinglot = found_lot,
01233    };
01234 
01235    return park_call_full(chan, peer, &args);
01236 }

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

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

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

00644 {
00645    struct ast_exten *exten;
00646    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
00647    const char *app_at_exten;
00648 
00649    exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, E_MATCH);
00650    if (!exten) {
00651       return 0;
00652    }
00653 
00654    app_at_exten = ast_get_extension_app(exten);
00655    if (!app_at_exten || strcmp(PARK_APP_NAME, app_at_exten)) {
00656       return 0;
00657    }
00658 
00659    return 1;
00660 }

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.

Definition at line 5598 of file features.c.

References ast_answer(), ast_channel_callback(), ast_channel_connected_line_macro(), ast_channel_lock_both, ast_channel_masquerade(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_unref, ast_channel_update_connected_line(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_manager_event_multichan, ast_party_connected_line_collect_caller(), ast_queue_control(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_channel::caller, ast_channel::connected, EVENT_FLAG_CALL, find_channel_by_group(), LOG_WARNING, ast_channel::name, pickupfailsound, pickupsound, and ast_party_connected_line::source.

Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), handle_request_invite(), mgcp_ss(), and pickup_exec().

05599 {
05600    struct ast_channel *cur, *chans[2] = { chan, };
05601    struct ast_party_connected_line connected_caller;
05602    int res;
05603    const char *chan_name;
05604    const char *cur_name;
05605 
05606    if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
05607       ast_debug(1, "No call pickup possible...\n");
05608       if (!ast_strlen_zero(pickupfailsound)) {
05609          ast_stream_and_wait(chan, pickupfailsound, "");
05610       }
05611       return -1;
05612    }
05613 
05614    chans[1] = cur;
05615 
05616    ast_channel_lock_both(cur, chan);
05617 
05618    cur_name = ast_strdupa(cur->name);
05619    chan_name = ast_strdupa(chan->name);
05620 
05621    ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name);
05622 
05623    connected_caller = cur->connected;
05624    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05625    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
05626       ast_channel_update_connected_line(chan, &connected_caller, NULL);
05627    }
05628 
05629    ast_party_connected_line_collect_caller(&connected_caller, &chan->caller);
05630    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05631    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
05632 
05633    ast_channel_unlock(cur);
05634    ast_channel_unlock(chan);
05635 
05636    if (ast_answer(chan)) {
05637       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
05638    }
05639 
05640    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
05641       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
05642    }
05643 
05644    if ((res = ast_channel_masquerade(cur, chan))) {
05645       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name);
05646    }
05647 
05648    if (!ast_strlen_zero(pickupsound)) {
05649       ast_stream_and_wait(cur, pickupsound, "");
05650    }
05651 
05652    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
05653    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
05654       "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, cur->name);
05655 
05656    cur = ast_channel_unref(cur);
05657 
05658    return res;
05659 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 662 of file features.c.

References pickup_ext.

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

00663 {
00664    return pickup_ext;
00665 }

void ast_rdlock_call_features ( void   ) 

Definition at line 2613 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

02614 {
02615    ast_rwlock_rdlock(&features_lock);
02616 }

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

02458 {
02459    if (!feature) {
02460       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02461       return;
02462    }
02463   
02464    AST_RWLIST_WRLOCK(&feature_list);
02465    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02466    AST_RWLIST_UNLOCK(&feature_list);
02467 
02468    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02469 }

void ast_unlock_call_features ( void   ) 

Definition at line 2618 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

02619 {
02620    ast_rwlock_unlock(&features_lock);
02621 }

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

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

02538 {
02539    if (!feature) {
02540       return;
02541    }
02542 
02543    AST_RWLIST_WRLOCK(&feature_list);
02544    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02545    AST_RWLIST_UNLOCK(&feature_list);
02546 
02547    ast_free(feature);
02548 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

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

02552 {
02553    struct ast_call_feature *feature;
02554 
02555    AST_RWLIST_WRLOCK(&feature_list);
02556    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
02557       ast_free(feature);
02558    }
02559    AST_RWLIST_UNLOCK(&feature_list);
02560 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

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

02578 {
02579    struct feature_group *fg;
02580    struct feature_group_exten *fge;
02581 
02582    AST_RWLIST_WRLOCK(&feature_groups);
02583    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
02584       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
02585          ast_string_field_free_memory(fge);
02586          ast_free(fge);
02587       }
02588 
02589       ast_string_field_free_memory(fg);
02590       ast_free(fg);
02591    }
02592    AST_RWLIST_UNLOCK(&feature_groups);
02593 }

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

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

01997 {
01998    finishup(transferee);
01999 
02000    /*
02001     * Restore party B connected line info about party A.
02002     *
02003     * Party B was the caller to party C and is the last known mode
02004     * for party B.
02005     */
02006    if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
02007       ast_channel_update_connected_line(transferer, connected_line, NULL);
02008    }
02009    ast_party_connected_line_free(connected_line);
02010 }

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

00758 {
00759    struct ast_bridge_thread_obj *tobj = data;
00760    int res;
00761 
00762    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00763    tobj->chan->data = tobj->peer->name;
00764    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00765    tobj->peer->data = tobj->chan->name;
00766 
00767    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00768 
00769    if (tobj->return_to_pbx) {
00770       if (!ast_check_hangup(tobj->peer)) {
00771          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00772          res = ast_pbx_start(tobj->peer);
00773          if (res != AST_PBX_SUCCESS)
00774             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00775       } else
00776          ast_hangup(tobj->peer);
00777       if (!ast_check_hangup(tobj->chan)) {
00778          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00779          res = ast_pbx_start(tobj->chan);
00780          if (res != AST_PBX_SUCCESS)
00781             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00782       } else
00783          ast_hangup(tobj->chan);
00784    } else {
00785       ast_hangup(tobj->chan);
00786       ast_hangup(tobj->peer);
00787    }
00788 
00789    ast_free(tobj);
00790 
00791    return NULL;
00792 }

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

References ast_pthread_create, bridge_call_thread(), and thread.

Referenced by action_bridge(), and builtin_atxfer().

00801 {
00802    pthread_t thread;
00803    pthread_attr_t attr;
00804    struct sched_param sched;
00805 
00806    pthread_attr_init(&attr);
00807    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00808    ast_pthread_create(&thread, &attr, bridge_call_thread, data);
00809    pthread_attr_destroy(&attr);
00810    memset(&sched, 0, sizeof(sched));
00811    pthread_setschedparam(thread, SCHED_RR, &sched);
00812 }

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

References ast_channel::_state, 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_unlock, ast_channel_unref, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_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().

05817 {
05818    struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
05819    char *tmp_data  = NULL;
05820    struct ast_flags opts = { 0, };
05821    struct ast_bridge_config bconfig = { { 0, }, };
05822    char *opt_args[OPT_ARG_ARRAY_SIZE];
05823    struct timeval calldurationlimit = { 0, };
05824 
05825    AST_DECLARE_APP_ARGS(args,
05826       AST_APP_ARG(dest_chan);
05827       AST_APP_ARG(options);
05828    );
05829    
05830    if (ast_strlen_zero(data)) {
05831       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
05832       return -1;
05833    }
05834 
05835    tmp_data = ast_strdupa(data);
05836    AST_STANDARD_APP_ARGS(args, tmp_data);
05837    if (!ast_strlen_zero(args.options))
05838       ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
05839 
05840    /* avoid bridge with ourselves */
05841    if (!strcmp(chan->name, args.dest_chan)) {
05842       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
05843       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05844                "Response: Failed\r\n"
05845                "Reason: Unable to bridge channel to itself\r\n"
05846                "Channel1: %s\r\n"
05847                "Channel2: %s\r\n",
05848                chan->name, args.dest_chan);
05849       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
05850       return 0;
05851    }
05852 
05853    /* make sure we have a valid end point */
05854    if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
05855          strlen(args.dest_chan)))) {
05856       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
05857          "cannot get its lock\n", args.dest_chan);
05858       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05859                "Response: Failed\r\n"
05860                "Reason: Cannot grab end point\r\n"
05861                "Channel1: %s\r\n"
05862                "Channel2: %s\r\n", chan->name, args.dest_chan);
05863       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
05864       return 0;
05865    }
05866 
05867    /* answer the channel if needed */
05868    if (current_dest_chan->_state != AST_STATE_UP) {
05869       ast_answer(current_dest_chan);
05870    }
05871 
05872    /* try to allocate a place holder where current_dest_chan will be placed */
05873    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
05874       NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
05875       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
05876       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05877                "Response: Failed\r\n"
05878                "Reason: cannot create placeholder\r\n"
05879                "Channel1: %s\r\n"
05880                "Channel2: %s\r\n", chan->name, args.dest_chan);
05881    }
05882 
05883    ast_channel_unlock(current_dest_chan);
05884 
05885    do_bridge_masquerade(current_dest_chan, final_dest_chan);
05886 
05887    chans[0] = current_dest_chan;
05888    chans[1] = final_dest_chan;
05889 
05890    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
05891    /* try to make compatible, send error if we fail */
05892    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
05893       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
05894       ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
05895                "Response: Failed\r\n"
05896                "Reason: Could not make channels compatible for bridge\r\n"
05897                "Channel1: %s\r\n"
05898                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05899       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
05900       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
05901       current_dest_chan = ast_channel_unref(current_dest_chan);
05902       return 0;
05903    }
05904 
05905    /* Report that the bridge will be successfull */
05906    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
05907             "Response: Success\r\n"
05908             "Channel1: %s\r\n"
05909             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05910 
05911    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
05912    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
05913       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
05914          if (ast_waitstream(final_dest_chan, "") < 0)
05915             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
05916       }
05917    }
05918    
05919    current_dest_chan = ast_channel_unref(current_dest_chan);
05920    
05921    if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
05922       if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
05923          goto done;
05924    }
05925 
05926    if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
05927       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
05928    if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
05929       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
05930    if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
05931       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
05932    if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
05933       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
05934    if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
05935       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
05936    if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 
05937       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
05938    if (ast_test_flag(&opts, OPT_CALLEE_PARK))
05939       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
05940    if (ast_test_flag(&opts, OPT_CALLER_PARK))
05941       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
05942 
05943    ast_bridge_call(chan, final_dest_chan, &bconfig);
05944 
05945    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
05946    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
05947    if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) {
05948       ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 
05949          final_dest_chan->context, final_dest_chan->exten, 
05950          final_dest_chan->priority, final_dest_chan->name);
05951 
05952       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
05953          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
05954          ast_hangup(final_dest_chan);
05955       } else
05956          ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
05957    } else {
05958       ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name);
05959       ast_hangup(final_dest_chan);
05960    }
05961 done:
05962    if (bconfig.warning_sound) {
05963       ast_free((char *)bconfig.warning_sound);
05964    }
05965    if (bconfig.end_sound) {
05966       ast_free((char *)bconfig.end_sound);
05967    }
05968    if (bconfig.start_sound) {
05969       ast_free((char *)bconfig.start_sound);
05970    }
05971 
05972    return 0;
05973 }

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

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

Definition at line 4621 of file features.c.

References ao2_link, ao2_lock, ao2_unlock, ast_add_extension2(), ast_context_find_or_create(), ast_copy_string(), ast_debug, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, ast_free_ptr, ast_log(), ast_strlen_zero(), create_parkinglot(), DEFAULT_PARK_EXTENSION, DEFAULT_PARK_TIME, find_parkinglot(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, park_add_hints(), parkcall, parkinglot, parkinglot_destroy(), parkinglot_unref(), parkinglots, registrar, strdup, ast_variable::value, and var.

Referenced by load_config().

04622 {
04623    struct ast_parkinglot *parkinglot;
04624    struct ast_context *con = NULL;
04625 
04626    struct ast_variable *confvar = var;
04627    int error = 0;
04628    int start = 0, end = 0;
04629    int oldparkinglot = 0;
04630 
04631    parkinglot = find_parkinglot(name);
04632    if (parkinglot)
04633       oldparkinglot = 1;
04634    else
04635       parkinglot = create_parkinglot(name);
04636 
04637    if (!parkinglot)
04638       return NULL;
04639 
04640    ao2_lock(parkinglot);
04641 
04642    ast_debug(1, "Building parking lot %s\n", name);
04643 
04644    /* Do some config stuff */
04645    while(confvar) {
04646       if (!strcasecmp(confvar->name, "context")) {
04647          ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
04648       } else if (!strcasecmp(confvar->name, "parkext")) {
04649          ast_copy_string(parkinglot->parkext, confvar->value, sizeof(parkinglot->parkext));
04650       } else if (!strcasecmp(confvar->name, "parkingtime")) {
04651          if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
04652             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
04653             parkinglot->parkingtime = DEFAULT_PARK_TIME;
04654          } else
04655             parkinglot->parkingtime = parkinglot->parkingtime * 1000;
04656       } else if (!strcasecmp(confvar->name, "parkpos")) {
04657          if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) {
04658             ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", confvar->lineno);
04659             error = 1;
04660          } else {
04661             parkinglot->parking_start = start;
04662             parkinglot->parking_stop = end;
04663          }
04664       } else if (!strcasecmp(confvar->name, "findslot")) {
04665          parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next"));
04666       } else if (!strcasecmp(confvar->name, "parkedcalltransfers")) {
04667                         ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04668                         if (!strcasecmp(confvar->value, "both"))
04669                                 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
04670                         else if (!strcasecmp(confvar->value, "caller"))
04671                                 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
04672                         else if (!strcasecmp(confvar->value, "callee"))
04673                                 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
04674                 } else if (!strcasecmp(confvar->name, "parkedcallreparking")) {
04675                         ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04676                         if (!strcasecmp(confvar->value, "both"))
04677                                 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
04678                         else if (!strcasecmp(confvar->value, "caller"))
04679                                 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
04680                         else if (!strcasecmp(confvar->value, "callee"))
04681                                 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
04682                 } else if (!strcasecmp(confvar->name, "parkedcallhangup")) {
04683                         ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04684                         if (!strcasecmp(confvar->value, "both"))
04685                                 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
04686                         else if (!strcasecmp(confvar->value, "caller"))
04687                                 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
04688                         else if (!strcasecmp(confvar->value, "callee"))
04689                                 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
04690                 } else if (!strcasecmp(confvar->name, "parkedcallrecording")) {
04691                         ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04692                         if (!strcasecmp(confvar->value, "both"))
04693                                 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
04694                         else if (!strcasecmp(confvar->value, "caller"))
04695                                 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
04696                         else if (!strcasecmp(confvar->value, "callee"))
04697                                 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
04698                 }
04699       confvar = confvar->next;
04700    }
04701    /* make sure parkingtime is set if not specified */
04702    if (parkinglot->parkingtime == 0) {
04703       parkinglot->parkingtime = DEFAULT_PARK_TIME;
04704    }
04705    if (ast_strlen_zero(parkinglot->parkext)) {
04706       ast_debug(2, "no parkext specified for %s - setting it to %s\n", parkinglot->name, DEFAULT_PARK_EXTENSION);
04707       ast_copy_string(parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(parkinglot->parkext));
04708    }
04709 
04710    if (!var) { /* Default parking lot */
04711       ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
04712       ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass));
04713    }
04714    ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial));
04715 
04716    /* Check for errors */
04717    if (ast_strlen_zero(parkinglot->parking_con)) {
04718       ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name);
04719       error = 1;
04720    }
04721 
04722    /* Create context */
04723    if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) {
04724       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
04725       error = 1;
04726    }
04727 
04728    /* Add a parking extension into the context */
04729    if (!error && !oldparkinglot) {
04730       if (!ast_strlen_zero(parkinglot->parkext)) {
04731          if (ast_add_extension2(con, 1, parkinglot->parkext, 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
04732             error = 1;
04733       }
04734    }
04735 
04736    /* Add parking hints */
04737    if (parkinglot->parkaddhints)
04738       park_add_hints(parkinglot->parking_con, parkinglot->parking_start, parkinglot->parking_stop);
04739 
04740    ao2_unlock(parkinglot);
04741 
04742    if (error) {
04743       ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
04744       parkinglot_destroy(parkinglot);
04745       parkinglot_unref(parkinglot);
04746       return NULL;
04747    }
04748    ast_debug(1, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
04749    parkinglot->the_mark = 0;
04750 
04751    /* Move it into the list, if it wasn't already there */
04752    if (!oldparkinglot) {
04753       ao2_link(parkinglots, parkinglot);
04754    }
04755    parkinglot_unref(parkinglot);
04756 
04757    return parkinglot;
04758 }

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

References ast_channel::_state, ao2_callback, args, 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, find_parkinglot_by_exten_cb(), finishup(), ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, parkcall_helper(), parkinglot, parkinglots, 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, xferfailsound, and xfersound.

02028 {
02029    struct ast_channel *transferer;/* Party B */
02030    struct ast_channel *transferee;/* Party A */
02031    const char *transferer_real_context;
02032    char xferto[256] = "";
02033    int res;
02034    int outstate=0;
02035    struct ast_channel *newchan;
02036    struct ast_channel *xferchan;
02037    struct ast_bridge_thread_obj *tobj;
02038    struct ast_bridge_config bconfig;
02039    int l;
02040    struct ast_party_connected_line connected_line;
02041    struct ast_datastore *features_datastore;
02042    struct ast_dial_features *dialfeatures = NULL;
02043    struct ast_parkinglot *parkinglot;
02044    char *transferer_tech;
02045    char *transferer_name;
02046    char *transferer_name_orig;
02047    char *dash;
02048 
02049    ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02050    set_peers(&transferer, &transferee, peer, chan, sense);
02051    transferer_real_context = real_ctx(transferer, transferee);
02052 
02053    /* Start autoservice on transferee while we talk to the transferer */
02054    ast_autoservice_start(transferee);
02055    ast_indicate(transferee, AST_CONTROL_HOLD);
02056 
02057    /* Transfer */
02058    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02059    if (res < 0) {
02060       finishup(transferee);
02061       return -1;
02062    }
02063    if (res > 0) /* If they've typed a digit already, handle it */
02064       xferto[0] = (char) res;
02065 
02066    /* this is specific of atxfer */
02067    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02068    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
02069       finishup(transferee);
02070       return -1;
02071    }
02072    l = strlen(xferto);
02073    if (res == 0) {
02074       if (l) {
02075          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02076             xferto, transferer_real_context);
02077       } else {
02078          /* Does anyone care about this case? */
02079          ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
02080       }
02081       ast_stream_and_wait(transferer, "pbx-invalid", "");
02082       finishup(transferee);
02083       return AST_FEATURE_RETURN_SUCCESS;
02084    }
02085 
02086    /* If we are attended transfering to parking, just use parkcall_helper instead of trying to track all of
02087     * the different variables for handling this properly with a builtin_atxfer */
02088    parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
02089    if (parkinglot) {
02090       struct ast_park_call_args args = {
02091          .parkinglot = parkinglot,
02092       };
02093       finishup(transferee);
02094       return parkcall_helper(chan, peer, config, code, sense, &args);
02095    }
02096 
02097    /* Append context to dialed transfer number. */
02098    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
02099 
02100    /* If we are performing an attended transfer and we have two channels involved then
02101       copy sound file information to play upon attended transfer completion */
02102    if (transferee) {
02103       const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02104       const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02105 
02106       if (!ast_strlen_zero(chan1_attended_sound)) {
02107          pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
02108       }
02109       if (!ast_strlen_zero(chan2_attended_sound)) {
02110          pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
02111       }
02112    }
02113 
02114    /* Extract redial transferer information from the channel name. */
02115    transferer_name_orig = ast_strdupa(transferer->name);
02116    transferer_name = ast_strdupa(transferer_name_orig);
02117    transferer_tech = strsep(&transferer_name, "/");
02118    dash = strrchr(transferer_name, '-');
02119    if (dash) {
02120       /* Trim off channel name sequence/serial number. */
02121       *dash = '\0';
02122    }
02123 
02124    /* Stop autoservice so we can monitor all parties involved in the transfer. */
02125    if (ast_autoservice_stop(transferee) < 0) {
02126       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02127       return -1;
02128    }
02129 
02130    /* Save connected line info for party B about party A in case transfer fails. */
02131    ast_party_connected_line_init(&connected_line);
02132    ast_channel_lock(transferer);
02133    ast_party_connected_line_copy(&connected_line, &transferer->connected);
02134    ast_channel_unlock(transferer);
02135    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02136 
02137    /* Dial party C */
02138    newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
02139       transferee, "Local", ast_best_codec(transferer->nativeformats), xferto,
02140       atxfernoanswertimeout, &outstate, transferer->language);
02141    ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
02142 
02143    if (!ast_check_hangup(transferer)) {
02144       int hangup_dont = 0;
02145 
02146       /* Transferer (party B) is up */
02147       ast_debug(1, "Actually doing an attended transfer.\n");
02148 
02149       /* Start autoservice on transferee while the transferer deals with party C. */
02150       ast_autoservice_start(transferee);
02151 
02152       ast_indicate(transferer, -1);
02153       if (!newchan) {
02154          /* any reason besides user requested cancel and busy triggers the failed sound */
02155          switch (outstate) {
02156          case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */
02157          case AST_CONTROL_BUSY:
02158          case AST_CONTROL_CONGESTION:
02159             if (ast_stream_and_wait(transferer, xfersound, "")) {
02160                ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02161             }
02162             break;
02163          default:
02164             if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02165                ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02166             }
02167             break;
02168          }
02169          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02170          return AST_FEATURE_RETURN_SUCCESS;
02171       }
02172 
02173       if (check_compat(transferer, newchan)) {
02174          if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02175             ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02176          }
02177          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02178          return AST_FEATURE_RETURN_SUCCESS;
02179       }
02180       memset(&bconfig,0,sizeof(struct ast_bridge_config));
02181       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
02182       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
02183 
02184       /* ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we don't
02185          want that to happen here because we're also in another bridge already
02186        */
02187       if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) {
02188          hangup_dont = 1;
02189       }
02190       /* Let party B and party C talk as long as they want. */
02191       ast_bridge_call(transferer, newchan, &bconfig);
02192       if (hangup_dont) {
02193          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
02194       }
02195 
02196       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
02197          ast_hangup(newchan);
02198          if (ast_stream_and_wait(transferer, xfersound, "")) {
02199             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02200          }
02201          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02202          return AST_FEATURE_RETURN_SUCCESS;
02203       }
02204 
02205       /* Transferer (party B) is confirmed hung up at this point. */
02206       if (check_compat(transferee, newchan)) {
02207          finishup(transferee);
02208          ast_party_connected_line_free(&connected_line);
02209          return -1;
02210       }
02211 
02212       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02213       if ((ast_autoservice_stop(transferee) < 0)
02214          || (ast_waitfordigit(transferee, 100) < 0)
02215          || (ast_waitfordigit(newchan, 100) < 0)
02216          || ast_check_hangup(transferee)
02217          || ast_check_hangup(newchan)) {
02218          ast_hangup(newchan);
02219          ast_party_connected_line_free(&connected_line);
02220          return -1;
02221       }
02222    } else if (!ast_check_hangup(transferee)) {
02223       /* Transferer (party B) has hung up at this point.  Doing blonde transfer. */
02224       ast_debug(1, "Actually doing a blonde transfer.\n");
02225 
02226       if (!newchan && !atxferdropcall) {
02227          /* Party C is not available, try to call party B back. */
02228          unsigned int tries = 0;
02229 
02230          if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
02231             ast_log(LOG_WARNING,
02232                "Transferer channel name: '%s' cannot be used for callback.\n",
02233                transferer_name_orig);
02234             ast_indicate(transferee, AST_CONTROL_UNHOLD);
02235             ast_party_connected_line_free(&connected_line);
02236             return -1;
02237          }
02238 
02239          tries = 0;
02240          for (;;) {
02241             /* Try to get party B back. */
02242             ast_debug(1, "We're trying to callback %s/%s\n",
02243                transferer_tech, transferer_name);
02244             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02245                transferee, transferee, transferer_tech,
02246                ast_best_codec(transferee->nativeformats), transferer_name,
02247                atxfernoanswertimeout, &outstate, transferer->language);
02248             ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
02249                !!newchan, outstate);
02250             if (newchan || ast_check_hangup(transferee)) {
02251                break;
02252             }
02253 
02254             ++tries;
02255             if (atxfercallbackretries <= tries) {
02256                /* No more callback tries remaining. */
02257                break;
02258             }
02259 
02260             if (atxferloopdelay) {
02261                /* Transfer failed, sleeping */
02262                ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n",
02263                   atxferloopdelay);
02264                ast_safe_sleep(transferee, atxferloopdelay);
02265                if (ast_check_hangup(transferee)) {
02266                   ast_party_connected_line_free(&connected_line);
02267                   return -1;
02268                }
02269             }
02270 
02271             /* Retry dialing party C. */
02272             ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
02273             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02274                transferer, transferee, "Local",
02275                ast_best_codec(transferee->nativeformats), xferto,
02276                atxfernoanswertimeout, &outstate, transferer->language);
02277             ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
02278                !!newchan, outstate);
02279             if (newchan || ast_check_hangup(transferee)) {
02280                break;
02281             }
02282          }
02283       }
02284       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02285       if (!newchan) {
02286          /* No party C or could not callback party B. */
02287          ast_party_connected_line_free(&connected_line);
02288          return -1;
02289       }
02290 
02291       /* newchan is up, we should prepare transferee and bridge them */
02292       if (ast_check_hangup(newchan)) {
02293          ast_hangup(newchan);
02294          ast_party_connected_line_free(&connected_line);
02295          return -1;
02296       }
02297       if (check_compat(transferee, newchan)) {
02298          ast_party_connected_line_free(&connected_line);
02299          return -1;
02300       }
02301    } else {
02302       /*
02303        * Both the transferer and transferee have hungup.  If newchan
02304        * is up, hang it up as it has no one to talk to.
02305        */
02306       ast_debug(1, "Everyone is hungup.\n");
02307       if (newchan) {
02308          ast_hangup(newchan);
02309       }
02310       ast_party_connected_line_free(&connected_line);
02311       return -1;
02312    }
02313 
02314    /* Initiate the channel transfer of party A to party C (or recalled party B). */
02315    ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
02316 
02317    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name);
02318    if (!xferchan) {
02319       ast_hangup(newchan);
02320       ast_party_connected_line_free(&connected_line);
02321       return -1;
02322    }
02323 
02324    /* Give party A a momentary ringback tone during transfer. */
02325    xferchan->visible_indication = AST_CONTROL_RINGING;
02326 
02327    /* Make formats okay */
02328    xferchan->readformat = transferee->readformat;
02329    xferchan->writeformat = transferee->writeformat;
02330 
02331    ast_channel_masquerade(xferchan, transferee);
02332    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
02333    xferchan->_state = AST_STATE_UP;
02334    ast_clear_flag(xferchan, AST_FLAGS_ALL);
02335 
02336    /* Do the masquerade manually to make sure that is is completed. */
02337    ast_do_masquerade(xferchan);
02338 
02339    newchan->_state = AST_STATE_UP;
02340    ast_clear_flag(newchan, AST_FLAGS_ALL);
02341    tobj = ast_calloc(1, sizeof(*tobj));
02342    if (!tobj) {
02343       ast_hangup(xferchan);
02344       ast_hangup(newchan);
02345       ast_party_connected_line_free(&connected_line);
02346       return -1;
02347    }
02348 
02349    ast_channel_lock(newchan);
02350    if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
02351       dialfeatures = features_datastore->data;
02352    }
02353    ast_channel_unlock(newchan);
02354 
02355    if (dialfeatures) {
02356       /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
02357          I don't currently understand, the abilities of newchan seem to be stored on the caller side */
02358       ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02359       dialfeatures = NULL;
02360    }
02361 
02362    ast_channel_lock(xferchan);
02363    if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
02364       dialfeatures = features_datastore->data;
02365    }
02366    ast_channel_unlock(xferchan);
02367 
02368    if (dialfeatures) {
02369       ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02370    }
02371 
02372    tobj->chan = newchan;
02373    tobj->peer = xferchan;
02374    tobj->bconfig = *config;
02375 
02376    if (tobj->bconfig.end_bridge_callback_data_fixup) {
02377       tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
02378    }
02379 
02380    /*
02381     * xferchan is transferee, and newchan is the transfer target
02382     * So...in a transfer, who is the caller and who is the callee?
02383     *
02384     * When the call is originally made, it is clear who is caller and callee.
02385     * When a transfer occurs, it is my humble opinion that the transferee becomes
02386     * the caller, and the transfer target is the callee.
02387     *
02388     * The problem is that these macros were set with the intention of the original
02389     * caller and callee taking those roles.  A transfer can totally mess things up,
02390     * to be technical.  What sucks even more is that you can't effectively change
02391     * the macros in the dialplan during the call from the transferer to the transfer
02392     * target because the transferee is stuck with whatever role he originally had.
02393     *
02394     * I think the answer here is just to make sure that it is well documented that
02395     * during a transfer, the transferee is the "caller" and the transfer target
02396     * is the "callee."
02397     *
02398     * This means that if party B calls party A, and party B transfers party A to
02399     * party C, then A has switched roles for the call.  Now party A will have the
02400     * caller macro called on his channel instead of the callee macro.
02401     *
02402     * Luckily, the method by which the party B to party C bridge is
02403     * launched above ensures that the transferee is the "chan" on
02404     * the bridge and the transfer target is the "peer," so my idea
02405     * for the roles post-transfer does not require extensive code
02406     * changes.
02407     */
02408 
02409    /* Transfer party C connected line to party A */
02410    ast_channel_lock(transferer);
02411    /*
02412     * Due to a limitation regarding when callerID is set on a Local channel,
02413     * we use the transferer's connected line information here.
02414     */
02415    ast_party_connected_line_copy(&connected_line, &transferer->connected);
02416    ast_channel_unlock(transferer);
02417    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02418    if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
02419       ast_channel_update_connected_line(xferchan, &connected_line, NULL);
02420    }
02421 
02422    /* Transfer party A connected line to party C */
02423    ast_channel_lock(xferchan);
02424    ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller);
02425    ast_channel_unlock(xferchan);
02426    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02427    if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
02428       ast_channel_update_connected_line(newchan, &connected_line, NULL);
02429    }
02430 
02431    if (ast_stream_and_wait(newchan, xfersound, ""))
02432       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02433    bridge_call_thread_launch(tobj);
02434 
02435    ast_party_connected_line_free(&connected_line);
02436    return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */
02437 }

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

01684 {
01685    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01686    int x = 0;
01687    size_t len;
01688    struct ast_channel *caller_chan, *callee_chan;
01689    const char *mixmonitor_spy_type = "MixMonitor";
01690    int count = 0;
01691 
01692    if (!mixmonitor_ok) {
01693       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01694       return -1;
01695    }
01696 
01697    if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
01698       mixmonitor_ok = 0;
01699       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01700       return -1;
01701    }
01702 
01703    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01704 
01705    if (!ast_strlen_zero(courtesytone)) {
01706       if (ast_autoservice_start(callee_chan))
01707          return -1;
01708       ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
01709       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
01710          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01711          ast_autoservice_stop(callee_chan);
01712          return -1;
01713       }
01714       if (ast_autoservice_stop(callee_chan))
01715          return -1;
01716    }
01717 
01718    ast_channel_lock(callee_chan);
01719    count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01720    ast_channel_unlock(callee_chan);
01721 
01722    /* This means a mixmonitor is attached to the channel, running or not is unknown. */
01723    if (count > 0) {
01724       
01725       ast_verb(3, "User hit '%s' to stop recording call.\n", code);
01726 
01727       /* Make sure they are running */
01728       ast_channel_lock(callee_chan);
01729       count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01730       ast_channel_unlock(callee_chan);
01731       if (count > 0) {
01732          if (!stopmixmonitor_ok) {
01733             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01734             return -1;
01735          }
01736          if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
01737             stopmixmonitor_ok = 0;
01738             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01739             return -1;
01740          } else {
01741             pbx_exec(callee_chan, stopmixmonitor_app, "");
01742             return AST_FEATURE_RETURN_SUCCESS;
01743          }
01744       }
01745       
01746       ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 
01747    }        
01748 
01749    if (caller_chan && callee_chan) {
01750       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
01751       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
01752 
01753       if (!touch_format)
01754          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
01755 
01756       if (!touch_monitor)
01757          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
01758 
01759       if (touch_monitor) {
01760          len = strlen(touch_monitor) + 50;
01761          args = alloca(len);
01762          touch_filename = alloca(len);
01763          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
01764          snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
01765       } else {
01766          caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
01767             caller_chan->caller.id.number.str, caller_chan->name));
01768          callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
01769             callee_chan->caller.id.number.str, callee_chan->name));
01770          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01771          args = alloca(len);
01772          touch_filename = alloca(len);
01773          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
01774          snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
01775       }
01776 
01777       for( x = 0; x < strlen(args); x++) {
01778          if (args[x] == '/')
01779             args[x] = '-';
01780       }
01781 
01782       ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
01783 
01784       pbx_exec(callee_chan, mixmonitor_app, args);
01785       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01786       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01787       return AST_FEATURE_RETURN_SUCCESS;
01788    
01789    }
01790 
01791    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
01792    return -1;
01793 
01794 }

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

01589 {
01590    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01591    int x = 0;
01592    size_t len;
01593    struct ast_channel *caller_chan, *callee_chan;
01594    const char *automon_message_start = NULL;
01595    const char *automon_message_stop = NULL;
01596 
01597    if (!monitor_ok) {
01598       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
01599       return -1;
01600    }
01601 
01602    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
01603       monitor_ok = 0;
01604       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
01605       return -1;
01606    }
01607 
01608    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01609    if (caller_chan) {   /* Find extra messages */
01610       automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
01611       automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
01612    }
01613 
01614    if (!ast_strlen_zero(courtesytone)) {  /* Play courtesy tone if configured */
01615       if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
01616          return -1;
01617       }
01618    }
01619    
01620    if (callee_chan->monitor) {
01621       ast_verb(4, "User hit '%s' to stop recording call.\n", code);
01622       if (!ast_strlen_zero(automon_message_stop)) {
01623          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
01624       }
01625       callee_chan->monitor->stop(callee_chan, 1);
01626       return AST_FEATURE_RETURN_SUCCESS;
01627    }
01628 
01629    if (caller_chan && callee_chan) {
01630       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
01631       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
01632       const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
01633 
01634       if (!touch_format)
01635          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
01636 
01637       if (!touch_monitor)
01638          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
01639    
01640       if (!touch_monitor_prefix)
01641          touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
01642    
01643       if (touch_monitor) {
01644          len = strlen(touch_monitor) + 50;
01645          args = alloca(len);
01646          touch_filename = alloca(len);
01647          snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
01648          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
01649       } else {
01650          caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
01651             caller_chan->caller.id.number.str, caller_chan->name));
01652          callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
01653             callee_chan->caller.id.number.str, callee_chan->name));
01654          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01655          args = alloca(len);
01656          touch_filename = alloca(len);
01657          snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
01658          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
01659       }
01660 
01661       for(x = 0; x < strlen(args); x++) {
01662          if (args[x] == '/')
01663             args[x] = '-';
01664       }
01665       
01666       ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
01667 
01668       pbx_exec(callee_chan, monitor_app, args);
01669       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01670       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01671 
01672       if (!ast_strlen_zero(automon_message_start)) {  /* Play start message for both channels */
01673          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
01674       }
01675    
01676       return AST_FEATURE_RETURN_SUCCESS;
01677    }
01678    
01679    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
01680    return -1;
01681 }

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

References ao2_callback, args, ast_app_dtget(), ast_async_goto(), ast_autoservice_ignore(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CEL_BLINDTRANSFER, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_update_connected_line(), AST_CONTROL_HOLD, AST_DIGIT_ANY, AST_FEATURE_RETURN_PARKFAILED, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FRAME_DTMF_END, ast_indicate(), ast_log(), ast_set_flag, ast_stopstream(), ast_stream_and_wait(), ast_verb, ast_channel::cdr, ast_cdr::channel, check_goto_on_transfer(), ast_channel::connected, ast_cdr::dstchannel, find_parkinglot_by_exten_cb(), finishup(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, masq_park_call_announce(), ast_channel::name, parkinglots, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), transferdigittimeout, and xferfailsound.

01847 {
01848    struct ast_channel *transferer;
01849    struct ast_channel *transferee;
01850    const char *transferer_real_context;
01851    struct ast_parkinglot *found_lot = NULL;
01852    char xferto[256];
01853    int res, parkstatus = 0;
01854 
01855    set_peers(&transferer, &transferee, peer, chan, sense);
01856    transferer_real_context = real_ctx(transferer, transferee);
01857    /* Start autoservice on chan while we talk to the originator */
01858    ast_autoservice_start(transferee);
01859    ast_autoservice_ignore(transferee, AST_FRAME_DTMF_END);
01860    ast_indicate(transferee, AST_CONTROL_HOLD);
01861 
01862    memset(xferto, 0, sizeof(xferto));
01863 
01864    /* Transfer */
01865    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01866    if (res < 0) {
01867       finishup(transferee);
01868       return -1; /* error ? */
01869    }
01870    if (res > 0)   /* If they've typed a digit already, handle it */
01871       xferto[0] = (char) res;
01872 
01873    ast_stopstream(transferer);
01874    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01875    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
01876       finishup(transferee);
01877       return -1;
01878    }
01879    if (res == 0) {
01880       if (xferto[0]) {
01881          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
01882             xferto, transferer_real_context);
01883       } else {
01884          /* Does anyone care about this case? */
01885          ast_log(LOG_WARNING, "No digits dialed.\n");
01886       }
01887       ast_stream_and_wait(transferer, "pbx-invalid", "");
01888       finishup(transferee);
01889       return AST_FEATURE_RETURN_SUCCESS;
01890    }
01891 
01892    found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
01893    if (found_lot) {
01894       struct ast_park_call_args args = {
01895          .parkinglot = found_lot,
01896       };
01897       res = finishup(transferee);
01898       if (res) {
01899       } else if (!(parkstatus = masq_park_call_announce(transferee, transferer, &args))) {   /* success */
01900          /* We return non-zero, but tell the PBX not to hang the channel when
01901             the thread dies -- We have to be careful now though.  We are responsible for 
01902             hanging up the channel, else it will never be hung up! */
01903 
01904          return 0;
01905       } else {
01906          ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01907       }
01908       ast_autoservice_start(transferee);
01909    } else {
01910       ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
01911       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01912       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01913       res=finishup(transferee);
01914       if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
01915          transferer->cdr=ast_cdr_alloc();
01916          if (transferer->cdr) {
01917             ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */
01918             ast_cdr_start(transferer->cdr);
01919          }
01920       }
01921       if (transferer->cdr) {
01922          struct ast_cdr *swap = transferer->cdr;
01923          ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01924                transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 
01925                transferer->cdr->channel, transferer->cdr->dstchannel);
01926          ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01927                transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01928          ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01929          /* swap cdrs-- it will save us some time & work */
01930          transferer->cdr = transferee->cdr;
01931          transferee->cdr = swap;
01932       }
01933       if (!transferee->pbx) {
01934          /* Doh!  Use our handy async_goto functions */
01935          ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01936                         ,transferee->name, xferto, transferer_real_context);
01937          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01938             ast_log(LOG_WARNING, "Async goto failed :-(\n");
01939       } else {
01940          /* Set the channel's new extension, since it exists, using transferer context */
01941          ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
01942          ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01943          if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) {
01944             ast_channel_update_connected_line(transferer, &transferer->connected, NULL);
01945          }
01946          set_c_e_p(transferee, transferer_real_context, xferto, 0);
01947       }
01948       check_goto_on_transfer(transferer);
01949       return res;
01950    }
01951    if (parkstatus != AST_FEATURE_RETURN_PARKFAILED
01952       && ast_stream_and_wait(transferer, xferfailsound, "")) {
01953       finishup(transferee);
01954       return -1;
01955    }
01956    ast_stopstream(transferer);
01957    res = finishup(transferee);
01958    if (res) {
01959       ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01960       return res;
01961    }
01962    return AST_FEATURE_RETURN_SUCCESS;
01963 }

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

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

01797 {
01798    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
01799    return AST_FEATURE_RETURN_HANGUP;
01800 }

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 Setup channel, set return exten,priority to 's,1' answer chan, sleep chan, park call

Definition at line 1539 of file features.c.

References config, and parkcall_helper().

01540 {
01541    return parkcall_helper(chan, peer, config, code, sense, NULL);
01542 }

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

Definition at line 3960 of file features.c.

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

Referenced by manage_parkinglot().

03961 {
03962    int i = 0;
03963    enum {
03964       OPT_CALLEE_REDIRECT   = 't',
03965       OPT_CALLER_REDIRECT   = 'T',
03966       OPT_CALLEE_AUTOMON    = 'w',
03967       OPT_CALLER_AUTOMON    = 'W',
03968       OPT_CALLEE_DISCONNECT = 'h',
03969       OPT_CALLER_DISCONNECT = 'H',
03970       OPT_CALLEE_PARKCALL   = 'k',
03971       OPT_CALLER_PARKCALL   = 'K',
03972    };
03973 
03974    memset(options, 0, len);
03975    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
03976       options[i++] = OPT_CALLER_REDIRECT;
03977    }
03978    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
03979       options[i++] = OPT_CALLER_AUTOMON;
03980    }
03981    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
03982       options[i++] = OPT_CALLER_DISCONNECT;
03983    }
03984    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
03985       options[i++] = OPT_CALLER_PARKCALL;
03986    }
03987 
03988    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
03989       options[i++] = OPT_CALLEE_REDIRECT;
03990    }
03991    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
03992       options[i++] = OPT_CALLEE_AUTOMON;
03993    }
03994    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
03995       options[i++] = OPT_CALLEE_DISCONNECT;
03996    }
03997    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
03998       options[i++] = OPT_CALLEE_PARKCALL;
03999    }
04000 
04001    return options;
04002 }

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

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

Referenced by builtin_atxfer().

01973 {
01974    if (ast_channel_make_compatible(c, newchan) < 0) {
01975       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01976          c->name, newchan->name);
01977       ast_hangup(newchan);
01978       return -1;
01979    }
01980    return 0;
01981 }

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

References ast_channel::_state, ast_channel_alloc, ast_channel_clear_softhangup(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_SOFTHANGUP_ALL, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), f, ast_channel::linkedid, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.

Referenced by builtin_blindtransfer().

00709 {
00710    struct ast_channel *xferchan;
00711    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00712    char *x, *goto_on_transfer;
00713    struct ast_frame *f;
00714 
00715    if (ast_strlen_zero(val))
00716       return;
00717 
00718    goto_on_transfer = ast_strdupa(val);
00719 
00720    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, "%s", chan->name)))
00721       return;
00722 
00723    for (x = goto_on_transfer; x && *x; x++) {
00724       if (*x == '^')
00725          *x = ',';
00726    }
00727    /* Make formats okay */
00728    xferchan->readformat = chan->readformat;
00729    xferchan->writeformat = chan->writeformat;
00730    ast_channel_masquerade(xferchan, chan);
00731    ast_parseable_goto(xferchan, goto_on_transfer);
00732    xferchan->_state = AST_STATE_UP;
00733    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00734    ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
00735    if ((f = ast_read(xferchan))) {
00736       ast_frfree(f);
00737       f = NULL;
00738       ast_pbx_start(xferchan);
00739    } else {
00740       ast_hangup(xferchan);
00741    }
00742 }

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

References ao2_ref, ast_copy_string(), ast_debug, AST_LIST_HEAD_INIT, ast_strlen_zero(), create_parkinglot(), find_parkinglot(), ast_parkinglot::name, parkinglot, and ast_parkinglot::parkings.

Referenced by park_space_reserve().

04265                                                                                                   {
04266    struct ast_parkinglot *copylot;
04267 
04268    if (ast_strlen_zero(name)) { /* No name specified */
04269       return NULL;
04270    }
04271    if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
04272       if (copylot) {
04273          ao2_ref(copylot, -1);
04274       }
04275       return NULL;
04276    }
04277 
04278    copylot = create_parkinglot(name);
04279    ast_debug(1, "Building parking lot %s\n", name);
04280 
04281    memcpy(copylot, parkinglot, sizeof(struct ast_parkinglot));
04282    ast_copy_string(copylot->name, name, sizeof(copylot->name));
04283    AST_LIST_HEAD_INIT(&copylot->parkings);
04284 
04285    return copylot;
04286 }

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

Allocate parking lot structure.

Definition at line 4574 of file features.c.

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

Referenced by build_parkinglot(), and copy_parkinglot().

04575 {
04576    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
04577 
04578    if (!name)
04579       return NULL;
04580 
04581    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
04582    if (!newlot)
04583       return NULL;
04584    
04585    ast_copy_string(newlot->name, name, sizeof(newlot->name));
04586    AST_LIST_HEAD_INIT(&newlot->parkings);
04587 
04588    return newlot;
04589 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 596 of file features.c.

References ast_free.

00597 {
00598    struct ast_dial_features *df = data;
00599    if (df) {
00600       ast_free(df);
00601    }
00602 }

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

Definition at line 583 of file features.c.

References ast_calloc.

00584 {
00585    struct ast_dial_features *df = data, *df_copy;
00586  
00587    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00588       return NULL;
00589    }
00590  
00591    memcpy(df_copy, df, sizeof(*df));
00592  
00593    return df_copy;
00594 }

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

05235 {
05236    ast_moh_stop(chan);
05237    ast_channel_lock_both(chan, tmpchan);
05238    ast_setstate(tmpchan, chan->_state);
05239    tmpchan->readformat = chan->readformat;
05240    tmpchan->writeformat = chan->writeformat;
05241    ast_channel_masquerade(tmpchan, chan);
05242    ast_channel_unlock(chan);
05243    ast_channel_unlock(tmpchan);
05244 
05245    /* must be done without any channel locks held */
05246    ast_do_masquerade(tmpchan);
05247 
05248    /* when returning from bridge, the channel will continue at the next priority */
05249    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
05250 }

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

04216 {
04217    struct pollfd *pfds = NULL, *new_pfds = NULL;
04218    int nfds = 0, new_nfds = 0;
04219 
04220    for (;;) {
04221       struct ao2_iterator iter;
04222       struct ast_parkinglot *curlot;
04223       int ms = -1;   /* poll2 timeout, uninitialized */
04224       iter = ao2_iterator_init(parkinglots, 0);
04225 
04226       while ((curlot = ao2_iterator_next(&iter))) {
04227          manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
04228          ao2_ref(curlot, -1);
04229       }
04230       ao2_iterator_destroy(&iter);
04231 
04232       /* Recycle */
04233       ast_free(pfds);
04234       pfds = new_pfds;
04235       nfds = new_nfds;
04236       new_pfds = NULL;
04237       new_nfds = 0;
04238 
04239       /* Wait for something to happen */
04240       ast_poll(pfds, nfds, ms);
04241       pthread_testcancel();
04242    }
04243    /* If this WERE reached, we'd need to free(pfds) */
04244    return NULL;   /* Never reached */
04245 }

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

02643 {
02644    struct ast_app *app;
02645    struct ast_call_feature *feature = data;
02646    struct ast_channel *work, *idle;
02647    int res;
02648 
02649    if (!feature) { /* shouldn't ever happen! */
02650       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
02651       return -1; 
02652    }
02653 
02654    if (sense == FEATURE_SENSE_CHAN) {
02655       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
02656          return AST_FEATURE_RETURN_KEEPTRYING;
02657       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02658          work = chan;
02659          idle = peer;
02660       } else {
02661          work = peer;
02662          idle = chan;
02663       }
02664    } else {
02665       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
02666          return AST_FEATURE_RETURN_KEEPTRYING;
02667       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02668          work = peer;
02669          idle = chan;
02670       } else {
02671          work = chan;
02672          idle = peer;
02673       }
02674    }
02675 
02676    if (!(app = pbx_findapp(feature->app))) {
02677       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
02678       return -2;
02679    }
02680 
02681    ast_autoservice_start(idle);
02682    ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
02683    
02684    if(work && idle) {
02685       pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name);
02686       pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name);
02687       pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
02688       pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
02689    }
02690 
02691    if (!ast_strlen_zero(feature->moh_class))
02692       ast_moh_start(idle, feature->moh_class, NULL);
02693 
02694    res = pbx_exec(work, app, feature->app_args);
02695 
02696    if (!ast_strlen_zero(feature->moh_class))
02697       ast_moh_stop(idle);
02698 
02699    ast_autoservice_stop(idle);
02700 
02701    if (res) {
02702       return AST_FEATURE_RETURN_SUCCESSBREAK;
02703    }
02704    return AST_FEATURE_RETURN_SUCCESS;  /*! \todo XXX should probably return res */
02705 }

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 2852 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_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

02852                                                                                                                                                 {
02853 
02854    char dynamic_features_buf[128];
02855    const char *peer_dynamic_features, *chan_dynamic_features;
02856    struct ast_flags features;
02857    struct ast_call_feature feature;
02858    if (sense == FEATURE_SENSE_CHAN) {
02859       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
02860    }
02861    else {
02862       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
02863    }
02864 
02865    ast_channel_lock(peer);
02866    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
02867    ast_channel_unlock(peer);
02868 
02869    ast_channel_lock(chan);
02870    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
02871    ast_channel_unlock(chan);
02872 
02873    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,""));
02874 
02875    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);
02876 
02877    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
02878 }

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,
int  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 2745 of file features.c.

References ast_debug, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_STOREDIGITS, 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, 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(), and feature_interpret().

02748 {
02749    int x;
02750    struct feature_group *fg = NULL;
02751    struct feature_group_exten *fge;
02752    struct ast_call_feature *tmpfeature;
02753    char *tmp, *tok;
02754    int res = AST_FEATURE_RETURN_PASSDIGITS;
02755    int feature_detected = 0;
02756 
02757    if (!(peer && chan && config) && operation) {
02758       return -1; /* can not run feature operation */
02759    }
02760 
02761    ast_rwlock_rdlock(&features_lock);
02762    for (x = 0; x < FEATURES_COUNT; x++) {
02763       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
02764           !ast_strlen_zero(builtin_features[x].exten)) {
02765          /* Feature is up for consideration */
02766          if (!strcmp(builtin_features[x].exten, code)) {
02767             ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
02768             if (operation) {
02769                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
02770             }
02771             memcpy(feature, &builtin_features[x], sizeof(feature));
02772             feature_detected = 1;
02773             break;
02774          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
02775             if (res == AST_FEATURE_RETURN_PASSDIGITS)
02776                res = AST_FEATURE_RETURN_STOREDIGITS;
02777          }
02778       }
02779    }
02780    ast_rwlock_unlock(&features_lock);
02781 
02782    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
02783       return res;
02784    }
02785 
02786    tmp = dynamic_features_buf;
02787 
02788    while ((tok = strsep(&tmp, "#"))) {
02789       AST_RWLIST_RDLOCK(&feature_groups);
02790 
02791       fg = find_group(tok);
02792 
02793       if (fg) {
02794          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
02795             if (!strcmp(fge->exten, code)) {
02796                if (operation) {
02797                   res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
02798                }
02799                memcpy(feature, fge->feature, sizeof(feature));
02800                if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02801                   AST_RWLIST_UNLOCK(&feature_groups);
02802                   break;
02803                }
02804                res = AST_FEATURE_RETURN_PASSDIGITS;
02805             } else if (!strncmp(fge->exten, code, strlen(code))) {
02806                res = AST_FEATURE_RETURN_STOREDIGITS;
02807             }
02808          }
02809          if (fge) {
02810             break;
02811          }
02812       }
02813 
02814       AST_RWLIST_UNLOCK(&feature_groups);
02815 
02816       AST_RWLIST_RDLOCK(&feature_list);
02817 
02818       if (!(tmpfeature = find_dynamic_feature(tok))) {
02819          AST_RWLIST_UNLOCK(&feature_list);
02820          continue;
02821       }
02822 
02823       /* Feature is up for consideration */
02824       if (!strcmp(tmpfeature->exten, code)) {
02825          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
02826          if (operation) {
02827             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
02828          }
02829          memcpy(feature, tmpfeature, sizeof(feature));
02830          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02831             AST_RWLIST_UNLOCK(&feature_list);
02832             break;
02833          }
02834          res = AST_FEATURE_RETURN_PASSDIGITS;
02835       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
02836          res = AST_FEATURE_RETURN_STOREDIGITS;
02837 
02838       AST_RWLIST_UNLOCK(&feature_list);
02839    }
02840 
02841    return res;
02842 }

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

02985 {
02986    int state = 0;
02987    int cause = 0;
02988    int to;
02989    int caller_hungup;
02990    int transferee_hungup;
02991    struct ast_channel *chan;
02992    struct ast_channel *monitor_chans[3];
02993    struct ast_channel *active_channel;
02994    int res;
02995    int ready = 0;
02996    struct timeval started;
02997    int x, len = 0;
02998    char *disconnect_code = NULL, *dialed_code = NULL;
02999    struct ast_frame *f;
03000    AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
03001 
03002    caller_hungup = ast_check_hangup(caller);
03003 
03004    if (!(chan = ast_request(type, format, requestor, data, &cause))) {
03005       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
03006       switch (cause) {
03007       case AST_CAUSE_BUSY:
03008          state = AST_CONTROL_BUSY;
03009          break;
03010       case AST_CAUSE_CONGESTION:
03011          state = AST_CONTROL_CONGESTION;
03012          break;
03013       default:
03014          state = 0;
03015          break;
03016       }
03017       goto done;
03018    }
03019 
03020    ast_string_field_set(chan, language, language);
03021    ast_channel_inherit_variables(caller, chan);
03022    pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
03023 
03024    ast_channel_lock(chan);
03025    ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller);
03026    ast_channel_unlock(chan);
03027 
03028    if (ast_call(chan, data, timeout)) {
03029       ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
03030       switch (chan->hangupcause) {
03031       case AST_CAUSE_BUSY:
03032          state = AST_CONTROL_BUSY;
03033          break;
03034       case AST_CAUSE_CONGESTION:
03035          state = AST_CONTROL_CONGESTION;
03036          break;
03037       default:
03038          state = 0;
03039          break;
03040       }
03041       goto done;
03042    }
03043 
03044    /* support dialing of the featuremap disconnect code while performing an attended tranfer */
03045    ast_rwlock_rdlock(&features_lock);
03046    for (x = 0; x < FEATURES_COUNT; x++) {
03047       if (strcasecmp(builtin_features[x].sname, "disconnect"))
03048          continue;
03049 
03050       disconnect_code = builtin_features[x].exten;
03051       len = strlen(disconnect_code) + 1;
03052       dialed_code = alloca(len);
03053       memset(dialed_code, 0, len);
03054       break;
03055    }
03056    ast_rwlock_unlock(&features_lock);
03057    x = 0;
03058    started = ast_tvnow();
03059    to = timeout;
03060    AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
03061 
03062    ast_poll_channel_add(caller, chan);
03063 
03064    transferee_hungup = 0;
03065    while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) {
03066       int num_chans = 0;
03067 
03068       monitor_chans[num_chans++] = transferee;
03069       monitor_chans[num_chans++] = chan;
03070       if (!caller_hungup) {
03071          if (ast_check_hangup(caller)) {
03072             caller_hungup = 1;
03073 
03074 #if defined(ATXFER_NULL_TECH)
03075             /* Change caller's name to ensure that it will remain unique. */
03076             set_new_chan_name(caller);
03077 
03078             /*
03079              * Get rid of caller's physical technology so it is free for
03080              * other calls.
03081              */
03082             set_null_chan_tech(caller);
03083 #endif   /* defined(ATXFER_NULL_TECH) */
03084          } else {
03085             /* caller is not hungup so monitor it. */
03086             monitor_chans[num_chans++] = caller;
03087          }
03088       }
03089 
03090       /* see if the timeout has been violated */
03091       if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
03092          state = AST_CONTROL_UNHOLD;
03093          ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name);
03094          break; /*doh! timeout*/
03095       }
03096 
03097       active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
03098       if (!active_channel)
03099          continue;
03100 
03101       f = NULL;
03102       if (transferee == active_channel) {
03103          struct ast_frame *dup_f;
03104 
03105          f = ast_read(transferee);
03106          if (f == NULL) { /*doh! where'd he go?*/
03107             transferee_hungup = 1;
03108             state = 0;
03109             break;
03110          }
03111          if (ast_is_deferrable_frame(f)) {
03112             dup_f = ast_frisolate(f);
03113             if (dup_f) {
03114                if (dup_f == f) {
03115                   f = NULL;
03116                }
03117                AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
03118             }
03119          }
03120       } else if (chan == active_channel) {
03121          if (!ast_strlen_zero(chan->call_forward)) {
03122             state = 0;
03123             chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
03124             if (!chan) {
03125                break;
03126             }
03127             continue;
03128          }
03129          f = ast_read(chan);
03130          if (f == NULL) { /*doh! where'd he go?*/
03131             switch (chan->hangupcause) {
03132             case AST_CAUSE_BUSY:
03133                state = AST_CONTROL_BUSY;
03134                break;
03135             case AST_CAUSE_CONGESTION:
03136                state = AST_CONTROL_CONGESTION;
03137                break;
03138             default:
03139                state = 0;
03140                break;
03141             }
03142             break;
03143          }
03144 
03145          if (f->frametype == AST_FRAME_CONTROL) {
03146             if (f->subclass.integer == AST_CONTROL_RINGING) {
03147                ast_verb(3, "%s is ringing\n", chan->name);
03148                ast_indicate(caller, AST_CONTROL_RINGING);
03149             } else if (f->subclass.integer == AST_CONTROL_BUSY) {
03150                state = f->subclass.integer;
03151                ast_verb(3, "%s is busy\n", chan->name);
03152                ast_indicate(caller, AST_CONTROL_BUSY);
03153                ast_frfree(f);
03154                break;
03155             } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
03156                state = f->subclass.integer;
03157                ast_verb(3, "%s is congested\n", chan->name);
03158                ast_indicate(caller, AST_CONTROL_CONGESTION);
03159                ast_frfree(f);
03160                break;
03161             } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
03162                /* This is what we are hoping for */
03163                state = f->subclass.integer;
03164                ast_frfree(f);
03165                ready=1;
03166                break;
03167             } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
03168                if (caller_hungup) {
03169                   struct ast_party_connected_line connected;
03170 
03171                   /* Just save it for the transfer. */
03172                   ast_party_connected_line_set_init(&connected, &caller->connected);
03173                   res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
03174                      &connected);
03175                   if (!res) {
03176                      ast_channel_set_connected_line(caller, &connected, NULL);
03177                   }
03178                   ast_party_connected_line_free(&connected);
03179                } else {
03180                   ast_autoservice_start(transferee);
03181                   if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
03182                      ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
03183                         f->data.ptr, f->datalen);
03184                   }
03185                   ast_autoservice_stop(transferee);
03186                }
03187             } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
03188                if (!caller_hungup) {
03189                   ast_autoservice_start(transferee);
03190                   if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
03191                      ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
03192                         f->data.ptr, f->datalen);
03193                   }
03194                   ast_autoservice_stop(transferee);
03195                }
03196             } else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) {
03197                ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
03198             }
03199             /* else who cares */
03200          } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03201             ast_write(caller, f);
03202          }
03203       } else if (caller == active_channel) {
03204          f = ast_read(caller);
03205          if (f) {
03206             if (f->frametype == AST_FRAME_DTMF) {
03207                dialed_code[x++] = f->subclass.integer;
03208                dialed_code[x] = '\0';
03209                if (strlen(dialed_code) == len) {
03210                   x = 0;
03211                } else if (x && strncmp(dialed_code, disconnect_code, x)) {
03212                   x = 0;
03213                   dialed_code[x] = '\0';
03214                }
03215                if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
03216                   /* Caller Canceled the call */
03217                   state = AST_CONTROL_UNHOLD;
03218                   ast_frfree(f);
03219                   break;
03220                }
03221             } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03222                ast_write(chan, f);
03223             }
03224          }
03225       }
03226       if (f)
03227          ast_frfree(f);
03228    } /* end while */
03229 
03230    ast_poll_channel_del(caller, chan);
03231 
03232    /*
03233     * We need to free all the deferred frames, but we only need to
03234     * queue the deferred frames if no hangup was received.
03235     */
03236    ast_channel_lock(transferee);
03237    transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
03238    while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
03239       if (!transferee_hungup) {
03240          ast_queue_frame_head(transferee, f);
03241       }
03242       ast_frfree(f);
03243    }
03244    ast_channel_unlock(transferee);
03245 
03246 done:
03247    ast_indicate(caller, -1);
03248    if (chan && (ready || chan->_state == AST_STATE_UP)) {
03249       state = AST_CONTROL_ANSWER;
03250    } else if (chan) {
03251       ast_hangup(chan);
03252       chan = NULL;
03253    }
03254 
03255    if (outstate)
03256       *outstate = state;
03257 
03258    return chan;
03259 }

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

Definition at line 5573 of file features.c.

References ast_channel::_state, AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, CMP_MATCH, CMP_STOP, ast_channel::masq, ast_channel::pbx, and ast_channel::pickupgroup.

Referenced by ast_pickup_call().

05574 {
05575    struct ast_channel *c = data;
05576    struct ast_channel *chan = obj;
05577 
05578    int i = !chan->pbx &&
05579       /* Accessing 'chan' here is safe without locking, because there is no way for
05580          the channel do disappear from under us at this point.  pickupgroup *could*
05581          change while we're here, but that isn't a problem. */
05582       (c != chan) &&
05583       (chan->pickupgroup & c->callgroup) &&
05584       ((chan->_state == AST_STATE_RINGING) || (chan->_state == AST_STATE_RING)) &&
05585       !c->masq;
05586 
05587    return i ? CMP_MATCH | CMP_STOP : 0;
05588 }

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

find a call feature by name

Definition at line 2563 of file features.c.

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

Referenced by feature_interpret_helper(), and set_config_flags().

02564 {
02565    struct ast_call_feature *tmp;
02566 
02567    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
02568       if (!strcasecmp(tmp->sname, name)) {
02569          break;
02570       }
02571    }
02572 
02573    return tmp;
02574 }

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

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

Referenced by feature_interpret_helper().

02602 {
02603    struct feature_group *fg = NULL;
02604 
02605    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
02606       if (!strcasecmp(fg->gname, name))
02607          break;
02608    }
02609 
02610    return fg;
02611 }

struct ast_parkinglot * find_parkinglot ( const char *  name  ) 

Find parkinglot by name.

Definition at line 4248 of file features.c.

References ao2_find, ast_debug, ast_strlen_zero(), parkinglot, and parkinglots.

Referenced by build_parkinglot(), copy_parkinglot(), manager_park(), and park_space_reserve().

04249 {
04250    struct ast_parkinglot *parkinglot;
04251 
04252    if (ast_strlen_zero(name)) {
04253       return NULL;
04254    }
04255 
04256    parkinglot = ao2_find(parkinglots, (void *) name, 0);
04257    if (parkinglot) {
04258       ast_debug(1, "Found Parkinglot: %s\n", parkinglot->name);
04259    }
04260 
04261    return parkinglot;
04262 }

static int find_parkinglot_by_exten_cb ( void *  obj,
void *  args,
int  flags 
) [static]

Definition at line 631 of file features.c.

References CMP_MATCH, CMP_STOP, and parkinglot.

Referenced by ast_park_call(), builtin_atxfer(), builtin_blindtransfer(), and park_call_exec().

00632 {
00633    struct ast_parkinglot *parkinglot = obj;
00634    const char *parkext = args;
00635 
00636    if (!strcmp(parkinglot->parkext, parkext)) {
00637       return CMP_MATCH | CMP_STOP;
00638    }
00639 
00640    return 0;
00641 }

static int find_parkinglot_by_position_cb ( void *  obj,
void *  args,
int  flags 
) [static]

Definition at line 619 of file features.c.

References CMP_MATCH, CMP_STOP, and parkinglot.

Referenced by park_exec_full().

00620 {
00621    struct ast_parkinglot *parkinglot = obj;
00622    int *parkpos = args;
00623 
00624    if (*parkpos >= parkinglot->parking_start && *parkpos <= parkinglot->parking_stop) {
00625       return CMP_MATCH | CMP_STOP;
00626    }
00627 
00628    return 0;
00629 }

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

Find parking lot name from channel.

Definition at line 838 of file features.c.

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

Referenced by park_space_reserve().

00839 {
00840    const char *temp, *parkinglot = NULL;
00841 
00842    /* Check if the channel has a parking lot */
00843    if (!ast_strlen_zero(chan->parkinglot))
00844       parkinglot = chan->parkinglot;
00845 
00846    /* Channel variables override everything */
00847 
00848    if ((temp  = pbx_builtin_getvar_helper(chan, "PARKINGLOT")))
00849       return temp;
00850 
00851    return parkinglot;
00852 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 1802 of file features.c.

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

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

01803 {
01804    ast_indicate(chan, AST_CONTROL_UNHOLD);
01805 
01806    return ast_autoservice_stop(chan);
01807 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), 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, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, 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, ast_parkinglot::mohclass, ast_parkinglot::name, ast_parkinglot::parkext, ast_parkinglot::parking_con, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglots, ast_parkinglot::parkingtime, ast_call_feature::sname, and ast_cli_entry::usage.

05108 {
05109    int i;
05110    struct ast_call_feature *feature;
05111    struct ao2_iterator iter;
05112    struct ast_parkinglot *curlot;
05113 #define HFS_FORMAT "%-25s %-7s %-7s\n"
05114 
05115    switch (cmd) {
05116    
05117    case CLI_INIT:
05118       e->command = "features show";
05119       e->usage =
05120          "Usage: features show\n"
05121          "       Lists configured features\n";
05122       return NULL;
05123    case CLI_GENERATE:
05124       return NULL;
05125    }
05126 
05127    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
05128    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
05129 
05130    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
05131 
05132    ast_rwlock_rdlock(&features_lock);
05133    for (i = 0; i < FEATURES_COUNT; i++)
05134       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
05135    ast_rwlock_unlock(&features_lock);
05136 
05137    ast_cli(a->fd, "\n");
05138    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
05139    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
05140    if (AST_RWLIST_EMPTY(&feature_list)) {
05141       ast_cli(a->fd, "(none)\n");
05142    } else {
05143       AST_RWLIST_RDLOCK(&feature_list);
05144       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
05145          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
05146       }
05147       AST_RWLIST_UNLOCK(&feature_list);
05148    }
05149 
05150    ast_cli(a->fd, "\nFeature Groups:\n");
05151    ast_cli(a->fd, "---------------\n");
05152    if (AST_RWLIST_EMPTY(&feature_groups)) {
05153       ast_cli(a->fd, "(none)\n");
05154    } else {
05155       struct feature_group *fg;
05156       struct feature_group_exten *fge;
05157 
05158       AST_RWLIST_RDLOCK(&feature_groups);
05159       AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
05160          ast_cli(a->fd, "===> Group: %s\n", fg->gname);
05161          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
05162             ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
05163          }
05164       }
05165       AST_RWLIST_UNLOCK(&feature_groups);
05166    }
05167 
05168    iter = ao2_iterator_init(parkinglots, 0);
05169    while ((curlot = ao2_iterator_next(&iter))) {
05170       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
05171       ast_cli(a->fd, "------------\n");
05172       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", curlot->parkext);
05173       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->parking_con);
05174       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
05175       ast_cli(a->fd,"%-22s:      %d\n", "Parkingtime", curlot->parkingtime);
05176       ast_cli(a->fd,"%-22s:      %s\n", "MusicOnHold class", curlot->mohclass);
05177       ast_cli(a->fd,"\n");
05178       ao2_ref(curlot, -1);
05179    }
05180    ao2_iterator_destroy(&iter);
05181 
05182    return CLI_SUCCESS;
05183 }

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

Definition at line 5209 of file features.c.

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

05210 {
05211    switch (cmd) { 
05212    case CLI_INIT:
05213       e->command = "features reload";
05214       e->usage =
05215          "Usage: features reload\n"
05216          "       Reloads configured call features from features.conf\n";
05217       return NULL;
05218    case CLI_GENERATE:
05219       return NULL;
05220    }
05221    ast_features_reload();
05222 
05223    return CLI_SUCCESS;
05224 }

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

References 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, 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.

05392 {
05393    struct parkeduser *cur;
05394    int numparked = 0;
05395    struct ao2_iterator iter;
05396    struct ast_parkinglot *curlot;
05397 
05398    switch (cmd) {
05399    case CLI_INIT:
05400       e->command = "parkedcalls show";
05401       e->usage =
05402          "Usage: parkedcalls show\n"
05403          "       List currently parked calls\n";
05404       return NULL;
05405    case CLI_GENERATE:
05406       return NULL;
05407    }
05408 
05409    if (a->argc > e->args)
05410       return CLI_SHOWUSAGE;
05411 
05412    ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
05413       , "Context", "Extension", "Pri", "Timeout");
05414 
05415    iter = ao2_iterator_init(parkinglots, 0);
05416    while ((curlot = ao2_iterator_next(&iter))) {
05417       int lotparked = 0;
05418       /* subtract ref for iterator and for configured parking lot */
05419       ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, ao2_ref(curlot, 0) - 2);
05420 
05421       AST_LIST_LOCK(&curlot->parkings);
05422       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
05423          ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
05424             ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
05425             ,cur->priority,
05426             (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
05427          numparked++;
05428          numparked += lotparked;
05429       }
05430       AST_LIST_UNLOCK(&curlot->parkings);
05431       if (lotparked)
05432          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
05433 
05434       ao2_ref(curlot, -1);
05435    }
05436 
05437    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
05438 
05439    return CLI_SUCCESS;
05440 }

static int load_config ( void   )  [static]

Definition at line 4760 of file features.c.

References adsipark, ao2_lock, ao2_unlock, ast_config_load2(), ast_copy_string(), ast_debug, ast_log(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_EXTENSION, DEFAULT_PARK_TIME, DEFAULT_PARKINGLOT, default_parkinglot, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_ERROR, LOG_WARNING, parkeddynamic, pickup_ext, pickupfailsound, pickupsound, transferdigittimeout, var, xferfailsound, and xfersound.

04761 {
04762    int start = 0, end = 0;
04763    int res;
04764    int i;
04765    struct ast_context *con = NULL;
04766    struct ast_config *cfg = NULL;
04767    struct ast_variable *var = NULL;
04768    struct feature_group *fg = NULL;
04769    struct ast_flags config_flags = { 0 };
04770    char *ctg; 
04771    static const char * const categories[] = { 
04772       /* Categories in features.conf that are not
04773        * to be parsed as group categories
04774        */
04775       "general",
04776       "featuremap",
04777       "applicationmap"
04778    };
04779 
04780    default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
04781    if (default_parkinglot) {
04782       ao2_lock(default_parkinglot);
04783       ast_copy_string(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(default_parkinglot->parkext));
04784       default_parkinglot->parking_start = 701;
04785       default_parkinglot->parking_stop = 750;
04786       default_parkinglot->parking_offset = 0;
04787       default_parkinglot->parkfindnext = 0;
04788       default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
04789       ao2_unlock(default_parkinglot);
04790    }
04791    
04792    if (default_parkinglot) {
04793       ast_debug(1, "Configuration of default parkinglot done.\n");
04794    } else {
04795       ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n");
04796       return -1;
04797    }
04798 
04799    /* Reset to defaults */
04800    strcpy(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION);
04801    strcpy(pickup_ext, "*8");
04802    courtesytone[0] = '\0';
04803    strcpy(xfersound, "beep");
04804    strcpy(xferfailsound, "beeperr");
04805    pickupsound[0] = '\0';
04806    pickupfailsound[0] = '\0';
04807    adsipark = 0;
04808    comebacktoorigin = 1;
04809    parkeddynamic = 0;
04810 
04811    default_parkinglot->parkaddhints = 0;
04812    default_parkinglot->parkedcalltransfers = 0;
04813    default_parkinglot->parkedcallreparking = 0;
04814    default_parkinglot->parkedcallrecording = 0;
04815    default_parkinglot->parkedcallhangup = 0;
04816 
04817    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04818    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04819    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04820    atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04821    atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
04822    atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04823 
04824    cfg = ast_config_load2("features.conf", "features", config_flags);
04825    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
04826       ast_log(LOG_WARNING,"Could not load features.conf\n");
04827       return 0;
04828    }
04829    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04830       if (!strcasecmp(var->name, "parkext")) {
04831          ast_copy_string(default_parkinglot->parkext, var->value, sizeof(default_parkinglot->parkext));
04832       } else if (!strcasecmp(var->name, "context")) {
04833          ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con));
04834       } else if (!strcasecmp(var->name, "parkingtime")) {
04835          if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) {
04836             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
04837             default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
04838          } else
04839             default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000;
04840       } else if (!strcasecmp(var->name, "parkpos")) {
04841          if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
04842             ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno);
04843          } else if (default_parkinglot) {
04844             default_parkinglot->parking_start = start;
04845             default_parkinglot->parking_stop = end;
04846          } else {
04847             ast_log(LOG_WARNING, "No default parking lot!\n");
04848          }
04849       } else if (!strcasecmp(var->name, "findslot")) {
04850          default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next"));
04851       } else if (!strcasecmp(var->name, "parkinghints")) {
04852          default_parkinglot->parkaddhints = ast_true(var->value);
04853       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
04854          if (!strcasecmp(var->value, "both"))
04855             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
04856          else if (!strcasecmp(var->value, "caller"))
04857             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
04858          else if (!strcasecmp(var->value, "callee"))
04859             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
04860       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
04861          if (!strcasecmp(var->value, "both"))
04862             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
04863          else if (!strcasecmp(var->value, "caller"))
04864             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
04865          else if (!strcasecmp(var->value, "callee"))
04866             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
04867       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
04868          if (!strcasecmp(var->value, "both"))
04869             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
04870          else if (!strcasecmp(var->value, "caller"))
04871             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
04872          else if (!strcasecmp(var->value, "callee"))
04873             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
04874       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
04875          if (!strcasecmp(var->value, "both"))
04876             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
04877          else if (!strcasecmp(var->value, "caller"))
04878             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
04879          else if (!strcasecmp(var->value, "callee"))
04880             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
04881       } else if (!strcasecmp(var->name, "parkeddynamic")) {
04882          parkeddynamic = ast_true(var->value);
04883       } else if (!strcasecmp(var->name, "adsipark")) {
04884          adsipark = ast_true(var->value);
04885       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
04886          if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
04887             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
04888             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04889          } else
04890             transferdigittimeout = transferdigittimeout * 1000;
04891       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
04892          if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
04893             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
04894             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04895          }
04896       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
04897          if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
04898             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
04899             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04900          } else
04901             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
04902       } else if (!strcasecmp(var->name, "atxferloopdelay")) {
04903          if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
04904             ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
04905             atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04906          } else 
04907             atxferloopdelay *= 1000;
04908       } else if (!strcasecmp(var->name, "atxferdropcall")) {
04909          atxferdropcall = ast_true(var->value);
04910       } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
04911          if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
04912             ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
04913             atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04914          }
04915       } else if (!strcasecmp(var->name, "courtesytone")) {
04916          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
04917       }  else if (!strcasecmp(var->name, "parkedplay")) {
04918          if (!strcasecmp(var->value, "both"))
04919             parkedplay = 2;
04920          else if (!strcasecmp(var->value, "parked"))
04921             parkedplay = 1;
04922          else
04923             parkedplay = 0;
04924       } else if (!strcasecmp(var->name, "xfersound")) {
04925          ast_copy_string(xfersound, var->value, sizeof(xfersound));
04926       } else if (!strcasecmp(var->name, "xferfailsound")) {
04927          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
04928       } else if (!strcasecmp(var->name, "pickupexten")) {
04929          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
04930       } else if (!strcasecmp(var->name, "pickupsound")) {
04931          ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
04932       } else if (!strcasecmp(var->name, "pickupfailsound")) {
04933          ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
04934       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
04935          comebacktoorigin = ast_true(var->value);
04936       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
04937          ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass));
04938       }
04939    }
04940 
04941    unmap_features();
04942    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
04943       if (remap_feature(var->name, var->value))
04944          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
04945    }
04946 
04947    /* Map a key combination to an application*/
04948    ast_unregister_features();
04949    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
04950       char *tmp_val = ast_strdupa(var->value);
04951       char *activateon; 
04952       struct ast_call_feature *feature;
04953       AST_DECLARE_APP_ARGS(args,
04954          AST_APP_ARG(exten);
04955          AST_APP_ARG(activatedby);
04956          AST_APP_ARG(app);
04957          AST_APP_ARG(app_args);
04958          AST_APP_ARG(moh_class);
04959       );
04960 
04961       AST_STANDARD_APP_ARGS(args, tmp_val);
04962       if (strchr(args.app, '(')) {
04963          /* New syntax */
04964          args.moh_class = args.app_args;
04965          args.app_args = strchr(args.app, '(');
04966          *args.app_args++ = '\0';
04967          if (args.app_args[strlen(args.app_args) - 1] == ')') {
04968             args.app_args[strlen(args.app_args) - 1] = '\0';
04969          }
04970       }
04971 
04972       activateon = strsep(&args.activatedby, "/"); 
04973 
04974       /*! \todo XXX var_name or app_args ? */
04975       if (ast_strlen_zero(args.app) || ast_strlen_zero(args.exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
04976          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
04977             args.app, args.exten, activateon, var->name);
04978          continue;
04979       }
04980 
04981       AST_RWLIST_RDLOCK(&feature_list);
04982       if ((feature = find_dynamic_feature(var->name))) {
04983          AST_RWLIST_UNLOCK(&feature_list);
04984          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
04985          continue;
04986       }
04987       AST_RWLIST_UNLOCK(&feature_list);
04988             
04989       if (!(feature = ast_calloc(1, sizeof(*feature)))) {
04990          continue;
04991       }
04992 
04993       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
04994       ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
04995       ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
04996       
04997       if (args.app_args) {
04998          ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
04999       }
05000 
05001       if (args.moh_class) {
05002          ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
05003       }
05004 
05005       ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
05006       feature->operation = feature_exec_app;
05007       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
05008 
05009       /* Allow caller and calle to be specified for backwards compatability */
05010       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
05011          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
05012       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
05013          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
05014       else {
05015          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
05016             " must be 'self', or 'peer'\n", var->name);
05017          continue;
05018       }
05019 
05020       if (ast_strlen_zero(args.activatedby))
05021          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05022       else if (!strcasecmp(args.activatedby, "caller"))
05023          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
05024       else if (!strcasecmp(args.activatedby, "callee"))
05025          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
05026       else if (!strcasecmp(args.activatedby, "both"))
05027          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05028       else {
05029          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
05030             " must be 'caller', or 'callee', or 'both'\n", var->name);
05031          continue;
05032       }
05033 
05034       ast_register_feature(feature);
05035 
05036       ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, args.app, args.app_args, args.exten);
05037    }
05038 
05039    ast_unregister_groups();
05040    AST_RWLIST_WRLOCK(&feature_groups);
05041 
05042    ctg = NULL;
05043    while ((ctg = ast_category_browse(cfg, ctg))) {
05044       /* Is this a parkinglot definition ? */
05045       if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
05046          ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
05047          if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg)))
05048             ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
05049          else
05050             ast_debug(1, "Configured parking context %s\n", ctg);
05051          continue;   
05052       }
05053       /* No, check if it's a group */
05054       for (i = 0; i < ARRAY_LEN(categories); i++) {
05055          if (!strcasecmp(categories[i], ctg))
05056             break;
05057       }
05058 
05059       if (i < ARRAY_LEN(categories)) 
05060          continue;
05061 
05062       if (!(fg = register_group(ctg)))
05063          continue;
05064 
05065       for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
05066          struct ast_call_feature *feature;
05067 
05068          AST_RWLIST_RDLOCK(&feature_list);
05069          if (!(feature = find_dynamic_feature(var->name)) && 
05070              !(feature = ast_find_call_feature(var->name))) {
05071             AST_RWLIST_UNLOCK(&feature_list);
05072             ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
05073             continue;
05074          }
05075          AST_RWLIST_UNLOCK(&feature_list);
05076 
05077          register_group_feature(fg, var->value, feature);
05078       }
05079    }
05080 
05081    AST_RWLIST_UNLOCK(&feature_groups);
05082 
05083    ast_config_destroy(cfg);
05084 
05085    if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) {
05086       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con);
05087       return -1;
05088    }
05089    res = ast_add_extension2(con, 1, default_parkinglot->parkext, 1, NULL, NULL, parkcall, NULL, NULL, registrar);
05090    if (default_parkinglot->parkaddhints)
05091       park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop);
05092    if (!res)
05093       notify_metermaids(default_parkinglot->parkext, default_parkinglot->parking_con, AST_DEVICE_INUSE); 
05094    return res;
05095 
05096 }

int manage_parkinglot ( struct ast_parkinglot curlot,
const struct pollfd *  pfds,
const int  nfds,
struct pollfd **  new_pfds,
int *  new_nfds,
int *  fs 
)

Run management on parkinglots, called once per parkinglot.

Definition at line 4005 of file features.c.

References ast_add_extension2(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_debug, AST_DEVICE_NOT_INUSE, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, ast_log(), ast_pbx_start(), ast_read(), ast_realloc, ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, callback_dialoptions(), 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, free, ast_channel::generatordata, parkeduser::list, LOG_ERROR, LOG_NOTICE, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_unref(), parkeduser::parkingnum, ast_parkinglot::parkings, 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 do_parking_thread().

04006 {
04007    struct parkeduser *pu;
04008    int res = 0;
04009    char parkingslot[AST_MAX_EXTENSION];
04010 
04011    /* Lock parking list */
04012    AST_LIST_LOCK(&curlot->parkings);
04013    AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
04014       struct ast_channel *chan = pu->chan;   /* shorthand */
04015       int tms;        /* timeout for this item */
04016       int x;          /* fd index in channel */
04017       struct ast_context *con;
04018 
04019       if (pu->notquiteyet) { /* Pretend this one isn't here yet */
04020          continue;
04021       }
04022       tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04023       if (tms > pu->parkingtime) {
04024          /* Stop music on hold */
04025          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04026          /* Get chan, exten from derived kludge */
04027          if (pu->peername[0]) {
04028             char *peername = ast_strdupa(pu->peername);
04029             char *dash = strrchr(peername, '-');
04030             char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
04031             int i;
04032 
04033             if (dash) {
04034                *dash = '\0';
04035             }
04036 
04037             peername_flat = ast_strdupa(peername);
04038             for (i = 0; peername_flat[i]; i++) {
04039                if (peername_flat[i] == '/') {
04040                   peername_flat[i]= '_';
04041                }
04042             }
04043 
04044             con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
04045             if (!con) {
04046                ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
04047             } else {
04048                char returnexten[AST_MAX_EXTENSION];
04049                struct ast_datastore *features_datastore;
04050                struct ast_dial_features *dialfeatures = NULL;
04051 
04052                ast_channel_lock(chan);
04053 
04054                if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
04055                   dialfeatures = features_datastore->data;
04056 
04057                ast_channel_unlock(chan);
04058 
04059                if (!strncmp(peername, "Parked/", 7)) {
04060                   peername += 7;
04061                }
04062 
04063                if (dialfeatures) {
04064                   char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
04065                   snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
04066                } else { /* Existing default */
04067                   ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", chan->name);
04068                   snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
04069                }
04070 
04071                ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
04072             }
04073             if (pu->options_specified == 1) {
04074                /* Park() was called with overriding return arguments, respect those arguments */
04075                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04076             } else {
04077                if (comebacktoorigin) {
04078                   set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1);
04079                } else {
04080                   snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
04081                   pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
04082                   set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
04083                }
04084             }
04085          } else {
04086             /* They've been waiting too long, send them back to where they came.  Theoretically they
04087                should have their original extensions and such, but we copy to be on the safe side */
04088             set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04089          }
04090          post_manager_event("ParkedCallTimeOut", pu);
04091          ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
04092 
04093          ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, pu->chan->exten, pu->chan->priority);
04094          /* Start up the PBX, or hang them up */
04095          if (ast_pbx_start(chan))  {
04096             ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
04097             ast_hangup(chan);
04098          }
04099          /* And take them out of the parking lot */
04100          con = ast_context_find(pu->parkinglot->parking_con);
04101          if (con) {
04102             if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04103                ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
04104             else
04105                notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
04106          } else
04107             ast_log(LOG_WARNING, "Whoa, no parking context?\n");
04108          AST_LIST_REMOVE_CURRENT(list);
04109          free(pu);
04110       } else { /* still within parking time, process descriptors */
04111          for (x = 0; x < AST_MAX_FDS; x++) {
04112             struct ast_frame *f;
04113             int y;
04114 
04115             if (chan->fds[x] == -1) {
04116                continue;   /* nothing on this descriptor */
04117             }
04118 
04119             for (y = 0; y < nfds; y++) {
04120                if (pfds[y].fd == chan->fds[x]) {
04121                   /* Found poll record! */
04122                   break;
04123                }
04124             }
04125             if (y == nfds) {
04126                /* Not found */
04127                continue;
04128             }
04129 
04130             if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
04131                /* Next x */
04132                continue;
04133             }
04134 
04135             if (pfds[y].revents & POLLPRI) {
04136                ast_set_flag(chan, AST_FLAG_EXCEPTION);
04137             } else {
04138                ast_clear_flag(chan, AST_FLAG_EXCEPTION);
04139             }
04140             chan->fdno = x;
04141 
04142             /* See if they need servicing */
04143             f = ast_read(pu->chan);
04144             /* Hangup? */
04145             if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer ==  AST_CONTROL_HANGUP))) {
04146                if (f)
04147                   ast_frfree(f);
04148                post_manager_event("ParkedCallGiveUp", pu);
04149                ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", NULL);
04150 
04151                /* There's a problem, hang them up*/
04152                ast_verb(2, "%s got tired of being parked\n", chan->name);
04153                ast_hangup(chan);
04154                /* And take them out of the parking lot */
04155                con = ast_context_find(curlot->parking_con);
04156                if (con) {
04157                   if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04158                      ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
04159                   else
04160                      notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
04161                } else
04162                   ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
04163                AST_LIST_REMOVE_CURRENT(list);
04164                parkinglot_unref(pu->parkinglot);
04165                free(pu);
04166                break;
04167             } else {
04168                /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
04169                ast_frfree(f);
04170                if (pu->moh_trys < 3 && !chan->generatordata) {
04171                   ast_debug(1, "MOH on parked call stopped by outside source.  Restarting on channel %s.\n", chan->name);
04172                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
04173                      S_OR(curlot->mohclass, NULL),
04174                      (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0));
04175                   pu->moh_trys++;
04176                }
04177                goto std;   /* XXX Ick: jumping into an else statement??? XXX */
04178             }
04179          } /* End for */
04180          if (x >= AST_MAX_FDS) {
04181 std:        for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */
04182                if (chan->fds[x] > -1) {
04183                   void *tmp = ast_realloc(*new_pfds, (*new_nfds + 1) * sizeof(struct pollfd));
04184                   if (!tmp) {
04185                      continue;
04186                   }
04187                   *new_pfds = tmp;
04188                   (*new_pfds)[*new_nfds].fd = chan->fds[x];
04189                   (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
04190                   (*new_pfds)[*new_nfds].revents = 0;
04191                   (*new_nfds)++;
04192                }
04193             }
04194             /* Keep track of our shortest wait */
04195             if (tms < *ms || *ms < 0) {
04196                *ms = tms;
04197             }
04198          }
04199       }
04200    }
04201    AST_LIST_TRAVERSE_SAFE_END;
04202    AST_LIST_UNLOCK(&curlot->parkings);
04203 
04204    return res;
04205 }

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

Definition at line 5510 of file features.c.

References args, ast_channel_get_by_name(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), CHANNEL_DEADLOCK_AVOIDANCE, find_parkinglot(), and masq_park_call().

Referenced by ast_features_init().

05511 {
05512    const char *channel = astman_get_header(m, "Channel");
05513    const char *channel2 = astman_get_header(m, "Channel2");
05514    const char *timeout = astman_get_header(m, "Timeout");
05515    const char *parkinglotname = astman_get_header(m, "Parkinglot");
05516    char buf[BUFSIZ];
05517    int res = 0;
05518    struct ast_channel *ch1, *ch2;
05519    struct ast_park_call_args args = {0,};
05520 
05521    if (ast_strlen_zero(channel)) {
05522       astman_send_error(s, m, "Channel not specified");
05523       return 0;
05524    }
05525 
05526    if (ast_strlen_zero(channel2)) {
05527       astman_send_error(s, m, "Channel2 not specified");
05528       return 0;
05529    }
05530 
05531    if (!(ch1 = ast_channel_get_by_name(channel))) {
05532       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
05533       astman_send_error(s, m, buf);
05534       return 0;
05535    }
05536 
05537    if (!(ch2 = ast_channel_get_by_name(channel2))) {
05538       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
05539       astman_send_error(s, m, buf);
05540       ast_channel_unref(ch1);
05541       return 0;
05542    }
05543 
05544    if (!ast_strlen_zero(timeout)) {
05545       sscanf(timeout, "%30d", &args.timeout);
05546    }
05547    if (!ast_strlen_zero(parkinglotname)) {
05548       args.parkinglot = find_parkinglot(parkinglotname);
05549    }
05550 
05551    ast_channel_lock(ch1);
05552    while (ast_channel_trylock(ch2)) {
05553       CHANNEL_DEADLOCK_AVOIDANCE(ch1);
05554    }
05555 
05556    res = masq_park_call(ch1, ch2, 0, NULL, 0, &args);
05557    if (!res) {
05558       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
05559       astman_send_ack(s, m, "Park successful");
05560    } else {
05561       astman_send_error(s, m, "Park failure");
05562    }
05563 
05564    ast_channel_unlock(ch1);
05565    ast_channel_unlock(ch2);
05566 
05567    ch1 = ast_channel_unref(ch1);
05568    ch2 = ast_channel_unref(ch2);
05569 
05570    return 0;
05571 }

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

References 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_party_caller::id, ast_party_id::name, ast_channel::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().

05457 {
05458    struct parkeduser *cur;
05459    const char *id = astman_get_header(m, "ActionID");
05460    char idText[256] = "";
05461    struct ao2_iterator iter;
05462    struct ast_parkinglot *curlot;
05463 
05464    if (!ast_strlen_zero(id))
05465       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
05466 
05467    astman_send_ack(s, m, "Parked calls will follow");
05468 
05469    iter = ao2_iterator_init(parkinglots, 0);
05470    while ((curlot = ao2_iterator_next(&iter))) {
05471 
05472       AST_LIST_LOCK(&curlot->parkings);
05473       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
05474          astman_append(s, "Event: ParkedCall\r\n"
05475             "Exten: %d\r\n"
05476             "Channel: %s\r\n"
05477             "From: %s\r\n"
05478             "Timeout: %ld\r\n"
05479             "CallerIDNum: %s\r\n"
05480             "CallerIDName: %s\r\n"
05481             "%s"
05482             "\r\n",
05483             cur->parkingnum, cur->chan->name, cur->peername,
05484             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
05485             S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""),   /* XXX in other places it is <unknown> */
05486             S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
05487             idText);
05488       }
05489       AST_LIST_UNLOCK(&curlot->parkings);
05490       ao2_ref(curlot, -1);
05491    }
05492 
05493    astman_append(s,
05494       "Event: ParkedCallsComplete\r\n"
05495       "%s"
05496       "\r\n",idText);
05497 
05498 
05499    return RESULT_SUCCESS;
05500 }

static int masq_park_call ( struct ast_channel rchan,
struct ast_channel peer,
int  timeout,
int *  extout,
int  play_announcement,
struct ast_park_call_args args 
) [static]

Parameters:
rchan is the transferee
peer is the transferer

Definition at line 1242 of file features.c.

References ast_channel::accountcode, ast_channel::amaflags, args, ast_channel_alloc, ast_channel_masquerade(), ast_copy_string(), AST_FEATURE_RETURN_PARKFAILED, ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), ast_channel::context, ast_channel::exten, f, ast_channel::linkedid, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, ast_channel::name, park_call_full(), park_space_reserve(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

Referenced by ast_masq_park_call(), manager_park(), and masq_park_call_announce().

01243 {
01244    struct ast_channel *chan;
01245    struct ast_frame *f;
01246    struct ast_park_call_args park_args = {0,};
01247 
01248    if (!args) {
01249       args = &park_args;
01250       args->timeout = timeout;
01251       args->extout = extout;
01252    }
01253 
01254    if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
01255       if (peer) {
01256          ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01257       }
01258       return AST_FEATURE_RETURN_PARKFAILED;
01259    }
01260 
01261    /* Make a new, fake channel that we'll use to masquerade in the real one */
01262    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s",rchan->name))) {
01263       ast_log(LOG_WARNING, "Unable to create parked channel\n");
01264       return -1;
01265    }
01266 
01267    /* Make formats okay */
01268    chan->readformat = rchan->readformat;
01269    chan->writeformat = rchan->writeformat;
01270    ast_channel_masquerade(chan, rchan);
01271 
01272    /* Setup the extensions and such */
01273    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
01274 
01275    /* Setup the macro extension and such */
01276    ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext));
01277    ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten));
01278    chan->macropriority = rchan->macropriority;
01279 
01280    /* Make the masq execute */
01281    if ((f = ast_read(chan)))
01282       ast_frfree(f);
01283 
01284    if (peer == rchan) {
01285       peer = chan;
01286    }
01287 
01288    if (peer && (!play_announcement && args == &park_args)) {
01289       args->orig_chan_name = ast_strdupa(peer->name);
01290    }
01291 
01292    /* parking space reserved, return code check unnecessary */
01293    park_call_full(chan, peer, args);
01294 
01295    return 0;
01296 }

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

Definition at line 1304 of file features.c.

References args, and masq_park_call().

Referenced by builtin_blindtransfer(), park_call_exec(), and parkcall_helper().

01305 {
01306    return masq_park_call(rchan, peer, 0, NULL, 1, args);
01307 }

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

metermaids callback from devicestate.c

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

00865 {
00866    char *context;
00867    char *exten;
00868 
00869    context = ast_strdupa(data);
00870 
00871    exten = strsep(&context, "@");
00872    if (!context)
00873       return AST_DEVICE_INVALID;
00874    
00875    ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
00876 
00877    if (!ast_exists_extension(NULL, context, exten, 1, NULL))
00878       return AST_DEVICE_NOT_INUSE;
00879 
00880    return AST_DEVICE_INUSE;
00881 }

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

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

Referenced by manage_parkinglot(), park_call_full(), and park_exec_full().

00856 {
00857    ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
00858       exten, context, ast_devstate2str(state));
00859 
00860    ast_devstate_changed(state, "park:%s@%s", exten, context);
00861 }

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

Add parking hints for all defined parking lots.

Parameters:
context 
start starting parkinglot number
stop ending parkinglot number

Definition at line 4607 of file features.c.

References ast_add_extension(), PRIORITY_HINT, and registrar.

Referenced by build_parkinglot().

04608 {
04609    int numext;
04610    char device[AST_MAX_EXTENSION];
04611    char exten[10];
04612 
04613    for (numext = start; numext <= stop; numext++) {
04614       snprintf(exten, sizeof(exten), "%d", numext);
04615       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
04616       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
04617    }
04618 }

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

Park a call.

Definition at line 4295 of file features.c.

References ast_channel::_state, ao2_callback, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_channel::exten, find_parkinglot_by_exten_cb(), ast_flags::flags, LOG_WARNING, masq_park_call_announce(), ast_channel::name, orig_exten(), park_call_options, parkinglots, parse(), and ast_channel::priority.

Referenced by ast_features_init().

04296 {
04297    /* Cache the original channel name in case we get masqueraded in the middle
04298     * of a park--it is still theoretically possible for a transfer to happen before
04299     * we get here, but it is _really_ unlikely */
04300    char *orig_chan_name = ast_strdupa(chan->name);
04301    char orig_exten[AST_MAX_EXTENSION];
04302    int orig_priority = chan->priority;
04303 
04304    /* Data is unused at the moment but could contain a parking
04305       lot context eventually */
04306    int res = 0;
04307 
04308    char *parse = NULL;
04309    AST_DECLARE_APP_ARGS(app_args,
04310       AST_APP_ARG(timeout);
04311       AST_APP_ARG(return_con);
04312       AST_APP_ARG(return_ext);
04313       AST_APP_ARG(return_pri);
04314       AST_APP_ARG(options);
04315    );
04316 
04317    parse = ast_strdupa(data);
04318    AST_STANDARD_APP_ARGS(app_args, parse);
04319 
04320    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
04321 
04322    /* Setup the exten/priority to be s/1 since we don't know
04323       where this call should return */
04324    strcpy(chan->exten, "s");
04325    chan->priority = 1;
04326 
04327    /* Answer if call is not up */
04328    if (chan->_state != AST_STATE_UP)
04329       res = ast_answer(chan);
04330 
04331    /* Sleep to allow VoIP streams to settle down */
04332    if (!res)
04333       res = ast_safe_sleep(chan, 1000);
04334 
04335    /* Park the call */
04336    if (!res) {
04337       struct ast_park_call_args args = {
04338          .orig_chan_name = orig_chan_name,
04339       };
04340       struct ast_flags flags = { 0 };
04341 
04342       if (parse) {
04343          if (!ast_strlen_zero(app_args.timeout)) {
04344             if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
04345                ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
04346                args.timeout = 0;
04347             }
04348          }
04349          if (!ast_strlen_zero(app_args.return_con)) {
04350             args.return_con = app_args.return_con;
04351          }
04352          if (!ast_strlen_zero(app_args.return_ext)) {
04353             args.return_ext = app_args.return_ext;
04354          }
04355          if (!ast_strlen_zero(app_args.return_pri)) {
04356             if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
04357                ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
04358                args.return_pri = 0;
04359             }
04360          }
04361       }
04362 
04363       ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
04364       args.flags = flags.flags;
04365 
04366       args.parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &orig_exten);
04367       res = masq_park_call_announce(chan, chan, &args);
04368       /* Continue on in the dialplan */
04369       if (res == 1) {
04370          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
04371          chan->priority = orig_priority;
04372          res = 0;
04373       } else if (!res) {
04374          res = 1;
04375       }
04376    }
04377 
04378    return res;
04379 }

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

Definition at line 1076 of file features.c.

References adsi_announce_park(), adsipark, ast_channel::appl, args, ast_add_extension2(), 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_context_find_or_create(), 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_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, parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, ast_party_caller::id, ast_channel::language, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, ast_parkinglot::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(), parkedcall, ast_parkinglot::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, ast_parkinglot::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(), and masq_park_call().

01077 {
01078    struct ast_context *con;
01079    int parkingnum_copy;
01080    struct parkeduser *pu = args->pu;
01081    const char *event_from;
01082 
01083    if (pu == NULL)
01084       args->pu = pu = park_space_reserve(chan, peer, args);
01085    if (pu == NULL)
01086       return 1; /* Continue execution if possible */
01087 
01088    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
01089 
01090    chan->appl = "Parked Call";
01091    chan->data = NULL;
01092 
01093    pu->chan = chan;
01094 
01095    /* Put the parked channel on hold if we have two different channels */
01096    if (chan != peer) {
01097       if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
01098          ast_indicate(pu->chan, AST_CONTROL_RINGING);
01099       } else {
01100          ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01101             S_OR(pu->parkinglot->mohclass, NULL),
01102             !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
01103       }
01104    }
01105    
01106    pu->start = ast_tvnow();
01107    pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime;
01108    parkingnum_copy = pu->parkingnum;
01109    if (args->extout)
01110       *(args->extout) = pu->parkingnum;
01111 
01112    if (peer) { 
01113       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
01114          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
01115          and we need the callback name to be that of transferer.  Since local,1/2 have the same
01116          name we can be tricky and just grab the bridged channel from the other side of the local
01117       */
01118       if (!strcasecmp(peer->tech->type, "Local")) {
01119          struct ast_channel *tmpchan, *base_peer;
01120          char other_side[AST_CHANNEL_NAME];
01121          char *c;
01122          ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side));
01123          if ((c = strrchr(other_side, ';'))) {
01124             *++c = '1';
01125          }
01126          if ((tmpchan = ast_channel_get_by_name(other_side))) {
01127             ast_channel_lock(tmpchan);
01128             if ((base_peer = ast_bridged_channel(tmpchan))) {
01129                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
01130             }
01131             ast_channel_unlock(tmpchan);
01132             tmpchan = ast_channel_unref(tmpchan);
01133          }
01134       } else {
01135          ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername));
01136       }
01137    }
01138 
01139    /* Remember what had been dialed, so that if the parking
01140       expires, we try to come back to the same place */
01141 
01142    pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
01143 
01144    /* If extension has options specified, they override all other possibilities
01145    such as the returntoorigin flag and transferred context. Information on
01146    extension options is lost here, so we set a flag */
01147 
01148    ast_copy_string(pu->context, 
01149       S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 
01150       sizeof(pu->context));
01151    ast_copy_string(pu->exten, 
01152       S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 
01153       sizeof(pu->exten));
01154    pu->priority = args->return_pri ? args->return_pri : 
01155       (chan->macropriority ? chan->macropriority : chan->priority);
01156 
01157    /* If parking a channel directly, don't quiet yet get parking running on it.
01158     * All parking lot entries are put into the parking lot with notquiteyet on. */
01159    if (peer != chan) 
01160       pu->notquiteyet = 0;
01161 
01162    /* Wake up the (presumably select()ing) thread */
01163    pthread_kill(parking_thread, SIGURG);
01164    ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
01165 
01166    ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
01167 
01168    if (peer) {
01169       event_from = peer->name;
01170    } else {
01171       event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
01172    }
01173 
01174    ast_manager_event(pu->chan, EVENT_FLAG_CALL, "ParkedCall",
01175       "Exten: %s\r\n"
01176       "Channel: %s\r\n"
01177       "Parkinglot: %s\r\n"
01178       "From: %s\r\n"
01179       "Timeout: %ld\r\n"
01180       "CallerIDNum: %s\r\n"
01181       "CallerIDName: %s\r\n"
01182       "Uniqueid: %s\r\n",
01183       pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "",
01184       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
01185       S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
01186       S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
01187       pu->chan->uniqueid
01188       );
01189 
01190    if (peer && adsipark && ast_adsi_available(peer)) {
01191       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
01192       ast_adsi_unload_session(peer);
01193    }
01194 
01195    con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar);
01196    if (!con)   /* Still no context? Bad */
01197       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con);
01198    if (con) {
01199       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
01200          notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE);
01201    }
01202 
01203    AST_LIST_UNLOCK(&pu->parkinglot->parkings);
01204 
01205    /* Only say number if it's a number and the channel hasn't been masqueraded away */
01206    if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
01207       /* If a channel is masqueraded into peer while playing back the parking slot number do not continue playing it back. This is the case if an attended transfer occurs. */
01208       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01209       /* Tell the peer channel the number of the parking space */
01210       ast_say_digits(peer, pu->parkingnum, "", peer->language);
01211       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01212    }
01213    if (peer == chan) { /* pu->notquiteyet = 1 */
01214       /* Wake up parking thread if we're really done */
01215       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01216          S_OR(pu->parkinglot->mohclass, NULL),
01217          !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
01218       pu->notquiteyet = 0;
01219       pthread_kill(parking_thread, SIGURG);
01220    }
01221    return 0;
01222 }

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

Definition at line 4553 of file features.c.

References park_exec_full().

Referenced by ast_features_init().

04554 {
04555    return park_exec_full(chan, data);
04556 }

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

Pickup parked call.

Todo:
XXX we would like to wait on both!

Todo:
XXX Play a message XXX

Definition at line 4382 of file features.c.

References ast_channel::_state, ao2_callback, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, ast_copy_flags, 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_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), ast_channel::caller, parkeduser::chan, config, courtesytone, ast_datastore::data, default_parkinglot, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_caller, find_parkinglot_by_position_cb(), ast_party_caller::id, LOG_WARNING, ast_party_id::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkedplay, parkeduser::parkingexten, parkinglot, parkinglot_unref(), parkinglots, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), S_COR, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.

Referenced by park_exec().

04383 {
04384    int res = 0;
04385    struct ast_channel *peer=NULL;
04386    struct parkeduser *pu;
04387    struct ast_context *con;
04388    int park = 0;
04389    struct ast_bridge_config config;
04390    struct ast_parkinglot *parkinglot;
04391 
04392    if (data) {
04393       park = atoi((char *) data);
04394    }
04395 
04396    parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_position_cb, (void *) &park);
04397    if (!parkinglot)
04398       parkinglot = default_parkinglot;
04399 
04400    AST_LIST_LOCK(&parkinglot->parkings);
04401    AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
04402       if (!pu->notquiteyet && (!data || pu->parkingnum == park)) {
04403          if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
04404             AST_LIST_UNLOCK(&parkinglot->parkings);
04405             return -1;
04406          }
04407          AST_LIST_REMOVE_CURRENT(list);
04408          break;
04409       }
04410    }
04411    AST_LIST_TRAVERSE_SAFE_END;
04412    AST_LIST_UNLOCK(&parkinglot->parkings);
04413 
04414    if (pu) {
04415       peer = pu->chan;
04416       con = ast_context_find(parkinglot->parking_con);
04417       if (con) {
04418          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04419             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
04420          else
04421             notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
04422       } else
04423          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
04424 
04425       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
04426       ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
04427          "Exten: %s\r\n"
04428          "Channel: %s\r\n"
04429          "From: %s\r\n"
04430          "CallerIDNum: %s\r\n"
04431          "CallerIDName: %s\r\n",
04432          pu->parkingexten, pu->chan->name, chan->name,
04433          S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
04434          S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>")
04435          );
04436 
04437       ast_free(pu);
04438    }
04439    /* JK02: it helps to answer the channel if not already up */
04440    if (chan->_state != AST_STATE_UP)
04441       ast_answer(chan);
04442 
04443    //XXX Why do we unlock here ?
04444    // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain
04445    //ASTOBJ_UNLOCK(parkinglot);
04446 
04447    if (peer) {
04448       struct ast_datastore *features_datastore;
04449       struct ast_dial_features *dialfeatures = NULL;
04450 
04451       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
04452 
04453       if (!ast_strlen_zero(courtesytone)) {
04454          int error = 0;
04455          ast_indicate(peer, AST_CONTROL_UNHOLD);
04456          if (parkedplay == 0) {
04457             error = ast_stream_and_wait(chan, courtesytone, "");
04458          } else if (parkedplay == 1) {
04459             error = ast_stream_and_wait(peer, courtesytone, "");
04460          } else if (parkedplay == 2) {
04461             if (!ast_streamfile(chan, courtesytone, chan->language) &&
04462                   !ast_streamfile(peer, courtesytone, chan->language)) {
04463                /*! \todo XXX we would like to wait on both! */
04464                res = ast_waitstream(chan, "");
04465                if (res >= 0)
04466                   res = ast_waitstream(peer, "");
04467                if (res < 0)
04468                   error = 1;
04469             }
04470          }
04471          if (error) {
04472             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
04473             ast_hangup(peer);
04474             return -1;
04475          }
04476       } else
04477          ast_indicate(peer, AST_CONTROL_UNHOLD);
04478 
04479       res = ast_channel_make_compatible(chan, peer);
04480       if (res < 0) {
04481          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
04482          ast_hangup(peer);
04483          return -1;
04484       }
04485       /* This runs sorta backwards, since we give the incoming channel control, as if it
04486          were the person called. */
04487       ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
04488 
04489       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
04490       ast_cdr_setdestchan(chan->cdr, peer->name);
04491       memset(&config, 0, sizeof(struct ast_bridge_config));
04492 
04493       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
04494       ast_channel_lock(peer);
04495       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
04496          dialfeatures = features_datastore->data;
04497       }
04498       ast_channel_unlock(peer);
04499 
04500       /* When the datastores for both caller and callee are created, both the callee and caller channels
04501        * use the features_caller flag variable to represent themselves. With that said, the config.features_callee
04502        * flags should be copied from the datastore's caller feature flags regardless if peer was a callee
04503        * or caller. */
04504       if (dialfeatures) {
04505          ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
04506       }
04507 
04508       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
04509          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
04510       }
04511       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
04512          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
04513       }
04514       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
04515          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
04516       }
04517       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
04518          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
04519       }
04520       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
04521          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
04522       }
04523       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
04524          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
04525       }
04526       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
04527          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
04528       }
04529       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
04530          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
04531       }
04532 
04533       parkinglot_unref(parkinglot);
04534       res = ast_bridge_call(chan, peer, &config);
04535 
04536       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
04537       ast_cdr_setdestchan(chan->cdr, peer->name);
04538 
04539       /* Simulate the PBX hanging up */
04540       ast_hangup(peer);
04541       return -1;
04542    } else {
04543       /*! \todo XXX Play a message XXX */
04544       if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
04545          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
04546       ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
04547       res = -1;
04548    }
04549 
04550    return -1;
04551 }

static struct parkeduser* park_space_reserve ( struct ast_channel chan,
struct ast_channel peer,
struct ast_park_call_args args 
) [static]

Definition at line 912 of file features.c.

References ao2_link, args, ast_calloc, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, ast_exists_extension(), 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, copy_parkinglot(), default_parkinglot, find_parkinglot(), findparkinglotname(), free, parkeduser::list, LOG_ERROR, LOG_WARNING, parkeddynamic, parkinglot, parkinglot_addref(), parkinglot_unref(), parkinglots, parkeduser::parkingnum, pbx_builtin_getvar_helper(), and S_OR.

Referenced by masq_park_call(), and park_call_full().

00913 {
00914    struct parkeduser *pu;
00915    int i, parking_space = -1, parking_range;
00916    const char *parkinglotname = NULL;
00917    const char *parkingexten;
00918    struct ast_parkinglot *parkinglot = NULL;
00919 
00920    if (args->parkinglot) {
00921       parkinglot = args->parkinglot;
00922       parkinglotname = parkinglot->name;
00923    } else if (peer) {
00924       parkinglotname = findparkinglotname(peer);
00925    } else { /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */
00926       parkinglotname = findparkinglotname(chan);
00927    }
00928 
00929    if (!args->parkinglot) {
00930       if (parkinglotname) {
00931          parkinglot = find_parkinglot(parkinglotname);
00932       } else {
00933          ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
00934          parkinglot = parkinglot_addref(default_parkinglot);
00935       }
00936       ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglot->name);
00937    }
00938 
00939    /* Dynamically create parkinglot */
00940    if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
00941       const char *dyn_context, *dyn_range;
00942       const char *parkinglotname_copy = NULL;
00943       struct ast_parkinglot *parkinglot_copy = NULL;
00944       int dyn_start, dyn_end;
00945 
00946       ast_channel_lock(chan);
00947       parkinglotname_copy = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
00948       dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
00949       dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
00950       ast_channel_unlock(chan);
00951 
00952       if (!ast_strlen_zero(parkinglotname_copy)) {
00953          parkinglot_copy = find_parkinglot(parkinglotname_copy);
00954       }
00955       if (!parkinglot_copy) {
00956          parkinglot_copy = parkinglot_addref(default_parkinglot);
00957          ast_debug(1, "Using default parking lot for copy\n");
00958       }
00959       if (!(parkinglot = copy_parkinglot(parkinglotname, parkinglot_copy))) {
00960          ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
00961       } else {
00962          if (!ast_strlen_zero(dyn_context)) {
00963             ast_copy_string(parkinglot->parking_con, dyn_context, sizeof(parkinglot->parking_con));
00964          }
00965          if (!ast_strlen_zero(dyn_range)) {
00966             if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
00967                ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers\n");
00968             } else {
00969                parkinglot->parking_start = dyn_start;
00970                parkinglot->parking_stop = dyn_end;
00971             }
00972          }
00973          ao2_link(parkinglots, parkinglot);
00974       }
00975 
00976       if (parkinglot_copy) {
00977          /* unref our tempory copy */
00978          parkinglot_unref(parkinglot_copy);
00979          parkinglot_copy = NULL;
00980       }
00981    }
00982 
00983    if (!parkinglot) {
00984       parkinglot = parkinglot_addref(default_parkinglot);
00985    }
00986 
00987    ast_debug(1, "Parkinglot: %s\n", parkinglot->name);
00988 
00989    /* Allocate memory for parking data */
00990    if (!(pu = ast_calloc(1, sizeof(*pu)))) {
00991       parkinglot_unref(parkinglot);
00992       return NULL;
00993    }
00994 
00995    /* Lock parking list */
00996    AST_LIST_LOCK(&parkinglot->parkings);
00997    /* Check for channel variable PARKINGEXTEN */
00998    ast_channel_lock(chan);
00999    parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"), ""));
01000    ast_channel_unlock(chan);
01001    if (!ast_strlen_zero(parkingexten)) {
01002       /*!\note The API forces us to specify a numeric parking slot, even
01003        * though the architecture would tend to support non-numeric extensions
01004        * (as are possible with SIP, for example).  Hence, we enforce that
01005        * limitation here.  If extout was not numeric, we could permit
01006        * arbitrary non-numeric extensions.
01007        */
01008         if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) {
01009          AST_LIST_UNLOCK(&parkinglot->parkings);
01010          parkinglot_unref(parkinglot);
01011             free(pu);
01012             ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
01013             return NULL;
01014         }
01015         snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
01016 
01017       if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) {
01018          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
01019          AST_LIST_UNLOCK(&parkinglot->parkings);
01020          parkinglot_unref(parkinglot);
01021          ast_free(pu);
01022          return NULL;
01023       }
01024    } else {
01025       int start;
01026       struct parkeduser *cur = NULL;
01027 
01028       /* Select parking space within range */
01029       parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1;
01030 
01031       if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
01032          start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1);
01033       } else {
01034          start = parkinglot->parking_start;
01035       }
01036 
01037       for (i = start; 1; i++) {
01038          if (i == parkinglot->parking_stop + 1) {
01039             i = parkinglot->parking_start - 1;
01040             break;
01041          }
01042 
01043          AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
01044             if (cur->parkingnum == i) {
01045                break;
01046             }
01047          }
01048          if (!cur) {
01049             parking_space = i;
01050             break;
01051          }
01052       }
01053 
01054       if (i == start - 1 && cur) {
01055          ast_log(LOG_WARNING, "No more parking spaces\n");
01056          ast_free(pu);
01057          AST_LIST_UNLOCK(&parkinglot->parkings);
01058          parkinglot_unref(parkinglot);
01059          return NULL;
01060       }
01061       /* Set pointer for next parking */
01062       if (parkinglot->parkfindnext) 
01063          parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
01064       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
01065    }
01066 
01067    pu->notquiteyet = 1;
01068    pu->parkingnum = parking_space;
01069    pu->parkinglot = parkinglot;
01070    AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
01071 
01072    return pu;
01073 }

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

Definition at line 1495 of file features.c.

References ast_channel::_state, args, ast_answer(), ast_debug, ast_safe_sleep(), AST_STATE_UP, masq_park_call_announce(), and set_peers().

Referenced by builtin_atxfer(), and builtin_parkcall().

01496 {
01497    int res = 0;
01498 
01499    if (args) {
01500       ast_debug(1, "Parkinglot specified for builtin_parkcall: %s\n", args->parkinglot->name);
01501    }
01502 
01503    /* we used to set chan's exten and priority to "s" and 1
01504       here, but this generates (in some cases) an invalid
01505       extension, and if "s" exists, could errantly
01506       cause execution of extensions you don't expect. It
01507       makes more sense to let nature take its course
01508       when chan finishes, and let the pbx do its thing
01509       and hang up when the park is over.
01510    */
01511    if (chan->_state != AST_STATE_UP)
01512       res = ast_answer(chan);
01513    if (!res)
01514       res = ast_safe_sleep(chan, 1000);
01515 
01516    if (!res) { /* one direction used to call park_call.... */
01517       struct ast_channel *parker;
01518       struct ast_channel *parkee;
01519       set_peers(&parker, &parkee, peer, chan, sense);
01520       res = masq_park_call_announce(parkee, parker, args);
01521       /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
01522    }
01523 
01524    return res;
01525 }

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

Definition at line 4566 of file features.c.

References ao2_ref, ast_debug, and parkinglot.

Referenced by park_space_reserve().

04567 {
04568    int refcount = ao2_ref(parkinglot, +1);
04569    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
04570    return parkinglot;
04571 }

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

Definition at line 682 of file features.c.

References CMP_MATCH, CMP_STOP, and parkinglot.

Referenced by ast_features_init().

00683 {
00684    struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg;
00685 
00686    return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00687 }

static void parkinglot_destroy ( void *  obj  )  [static]

Destroy a parking lot.

Definition at line 4592 of file features.c.

References ast_context_destroy(), ast_context_find(), ast_parkinglot::parking_con, and registrar.

Referenced by build_parkinglot(), and create_parkinglot().

04593 {
04594    struct ast_parkinglot *ruin = obj;
04595    struct ast_context *con;
04596    con = ast_context_find(ruin->parking_con);
04597    if (con)
04598       ast_context_destroy(con, registrar);
04599 }

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

Definition at line 675 of file features.c.

References ast_str_case_hash(), and parkinglot.

Referenced by ast_features_init().

00676 {
00677    const struct ast_parkinglot *parkinglot = obj;
00678 
00679    return ast_str_case_hash(parkinglot->name);
00680 }

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

Definition at line 5192 of file features.c.

References CMP_MATCH, and parkinglot.

Referenced by ast_features_reload().

05193 {
05194    struct ast_parkinglot *parkinglot = obj;
05195    return parkinglot->the_mark ? CMP_MATCH : 0;
05196 }

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

Definition at line 5185 of file features.c.

References parkinglot.

Referenced by ast_features_reload().

05186 {
05187    struct ast_parkinglot *parkinglot = obj;
05188    parkinglot->the_mark = 1;
05189    return 0;
05190 }

static void parkinglot_unref ( struct ast_parkinglot parkinglot  )  [static]

Unreference parkinglot object. If no more references, then go ahead and delete it.

Definition at line 4560 of file features.c.

References ao2_ref, ast_debug, and parkinglot.

Referenced by build_parkinglot(), manage_parkinglot(), park_exec_full(), and park_space_reserve().

04561 {
04562    int refcount = ao2_ref(parkinglot, -1);
04563    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
04564 }

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

return the first unlocked cdr in a possible chain

Definition at line 3285 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

03286 {
03287    struct ast_cdr *cdr_orig = cdr;
03288    while (cdr) {
03289       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
03290          return cdr;
03291       cdr = cdr->next;
03292    }
03293    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
03294 }

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

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

Referenced by builtin_automonitor().

01548 {
01549    /* First play for caller, put other channel on auto service */
01550    if (ast_autoservice_start(callee_chan))
01551       return -1;
01552    ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
01553    if (ast_stream_and_wait(caller_chan, audiofile, "")) {
01554       ast_log(LOG_WARNING, "Failed to play automon message!\n");
01555       ast_autoservice_stop(callee_chan);
01556       return -1;
01557    }
01558    if (ast_autoservice_stop(callee_chan))
01559       return -1;
01560    /* Then play for callee, put other channel on auto service */
01561    if (ast_autoservice_start(caller_chan))
01562       return -1;
01563    ast_autoservice_ignore(caller_chan, AST_FRAME_DTMF_END);
01564    if (ast_stream_and_wait(callee_chan, audiofile, "")) {
01565       ast_log(LOG_WARNING, "Failed to play automon message !\n");
01566       ast_autoservice_stop(caller_chan);
01567       return -1;
01568    }
01569    if (ast_autoservice_stop(caller_chan))
01570       return -1;
01571    return(0);
01572 }

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

Output parking event to manager.

Definition at line 3942 of file features.c.

References ast_channel::caller, parkeduser::chan, EVENT_FLAG_CALL, 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_parkinglot().

03943 {
03944    manager_event(EVENT_FLAG_CALL, s,
03945       "Exten: %s\r\n"
03946       "Channel: %s\r\n"
03947       "Parkinglot: %s\r\n"
03948       "CallerIDNum: %s\r\n"
03949       "CallerIDName: %s\r\n"
03950       "UniqueID: %s\r\n",
03951       pu->parkingexten, 
03952       pu->chan->name,
03953       pu->parkinglot->name,
03954       S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
03955       S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
03956       pu->chan->uniqueid
03957       );
03958 }

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

01818 {
01819    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
01820    if (ast_strlen_zero(s)) {
01821       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
01822    }
01823    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
01824       s = transferer->macrocontext;
01825    }
01826    if (ast_strlen_zero(s)) {
01827       s = transferer->context;
01828    }
01829    return s;  
01830 }

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

02479 {
02480    struct feature_group *fg;
02481 
02482    if (!fgname) {
02483       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
02484       return NULL;
02485    }
02486 
02487    if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) {
02488       return NULL;
02489    }
02490 
02491    ast_string_field_set(fg, gname, fgname);
02492 
02493    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
02494 
02495    ast_verb(2, "Registered group '%s'\n", fg->gname);
02496 
02497    return fg;
02498 }

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

02510 {
02511    struct feature_group_exten *fge;
02512 
02513    if (!fg) {
02514       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
02515       return;
02516    }
02517 
02518    if (!feature) {
02519       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
02520       return;
02521    }
02522 
02523    if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) {
02524       return;
02525    }
02526 
02527    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
02528 
02529    fge->feature = feature;
02530 
02531    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
02532 
02533    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
02534                feature->sname, fg->gname, fge->exten);
02535 }

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

Definition at line 2717 of file features.c.

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

02718 {
02719    int x, res = -1;
02720 
02721    ast_rwlock_wrlock(&features_lock);
02722    for (x = 0; x < FEATURES_COUNT; x++) {
02723       if (strcasecmp(builtin_features[x].sname, name))
02724          continue;
02725 
02726       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
02727       res = 0;
02728       break;
02729    }
02730    ast_rwlock_unlock(&features_lock);
02731 
02732    return res;
02733 }

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

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

03297 {
03298    const char *feature;
03299 
03300    if (ast_strlen_zero(features)) {
03301       return;
03302    }
03303 
03304    for (feature = features; *feature; feature++) {
03305       switch (*feature) {
03306       case 'T' :
03307       case 't' :
03308          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
03309          break;
03310       case 'K' :
03311       case 'k' :
03312          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
03313          break;
03314       case 'H' :
03315       case 'h' :
03316          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
03317          break;
03318       case 'W' :
03319       case 'w' :
03320          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
03321          break;
03322       default :
03323          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
03324       }
03325    }
03326 }

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

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

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

00694 {
00695    ast_copy_string(chan->context, context, sizeof(chan->context));
00696    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00697    chan->priority = pri;
00698 }

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

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

02887 {
02888    int x;
02889 
02890    ast_clear_flag(config, AST_FLAGS_ALL);
02891 
02892    ast_rwlock_rdlock(&features_lock);
02893    for (x = 0; x < FEATURES_COUNT; x++) {
02894       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
02895          continue;
02896 
02897       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
02898          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02899 
02900       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
02901          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02902    }
02903    ast_rwlock_unlock(&features_lock);
02904 
02905    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
02906       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
02907 
02908       if (dynamic_features) {
02909          char *tmp = ast_strdupa(dynamic_features);
02910          char *tok;
02911          struct ast_call_feature *feature;
02912 
02913          /* while we have a feature */
02914          while ((tok = strsep(&tmp, "#"))) {
02915             struct feature_group *fg;
02916 
02917             AST_RWLIST_RDLOCK(&feature_groups);
02918             AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
02919                struct feature_group_exten *fge;
02920 
02921                AST_LIST_TRAVERSE(&fg->features, fge, entry) {
02922                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
02923                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02924                   }
02925                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
02926                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02927                   }
02928                }
02929             }
02930             AST_RWLIST_UNLOCK(&feature_groups);
02931 
02932             AST_RWLIST_RDLOCK(&feature_list);
02933             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
02934                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
02935                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02936                }
02937                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
02938                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02939                }
02940             }
02941             AST_RWLIST_UNLOCK(&feature_list);
02942          }
02943       }
02944    }
02945 }

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

References FEATURE_SENSE_PEER.

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

01485 {
01486    if (sense == FEATURE_SENSE_PEER) {
01487       *caller = peer;
01488       *callee = chan;
01489    } else {
01490       *callee = peer;
01491       *caller = chan;
01492    }
01493 }

static void unmap_features ( void   )  [static]

Definition at line 2707 of file features.c.

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

02708 {
02709    int x;
02710 
02711    ast_rwlock_wrlock(&features_lock);
02712    for (x = 0; x < FEATURES_COUNT; x++)
02713       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
02714    ast_rwlock_unlock(&features_lock);
02715 }


Variable Documentation

int adsipark [static]

Definition at line 433 of file features.c.

Referenced by load_config(), and park_call_full().

char* app_bridge = "Bridge" [static]

Definition at line 5661 of file features.c.

unsigned int atxfercallbackretries [static]

Definition at line 442 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferdropcall [static]

Definition at line 440 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferloopdelay [static]

Definition at line 441 of file features.c.

Referenced by builtin_atxfer(), and load_config().

int atxfernoanswertimeout [static]

Definition at line 439 of file features.c.

Referenced by builtin_atxfer(), and load_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 5698 of file features.c.

Referenced by bridge_exec().

struct ast_call_feature builtin_features[] [static]

Definition at line 2444 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 5442 of file features.c.

Referenced by ast_features_init().

int comebacktoorigin = 1 [static]

Definition at line 437 of file features.c.

Referenced by load_config(), and manage_parkinglot().

char courtesytone[256] [static]

Courtesy tone

Definition at line 425 of file features.c.

Referenced by builtin_automixmonitor(), builtin_automonitor(), load_config(), and park_exec_full().

struct ast_parkinglot* default_parkinglot

Definition at line 422 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 604 of file features.c.

Referenced by add_features_datastores(), builtin_atxfer(), manage_parkinglot(), and park_exec_full().

int featuredigittimeout [static]

Definition at line 436 of file features.c.

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

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

struct ast_app* mixmonitor_app = NULL [static]

Definition at line 452 of file features.c.

Referenced by builtin_automixmonitor().

int mixmonitor_ok = 1 [static]

Definition at line 453 of file features.c.

Referenced by builtin_automixmonitor().

struct ast_app* monitor_app = NULL [static]

Definition at line 449 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 450 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 4292 of file features.c.

Referenced by park_call_exec().

char* parkcall = PARK_APP_NAME [static]

Definition at line 447 of file features.c.

Referenced by ast_features_init(), and build_parkinglot().

char* parkedcall = "ParkedCall" [static]

Definition at line 374 of file features.c.

Referenced by ast_features_init(), and park_call_full().

int parkeddynamic = 0 [static]

Enable creation of parkinglots dynamically

Definition at line 427 of file features.c.

Referenced by load_config(), and park_space_reserve().

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 426 of file features.c.

Referenced by park_exec_full().

char parking_ext[AST_MAX_EXTENSION]

Extension you type to park the call

Definition at line 423 of file features.c.

pthread_t parking_thread [static]

Definition at line 458 of file features.c.

Referenced by ast_features_init(), and park_call_full().

struct ao2_container* parkinglots [static]

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

Definition at line 420 of file features.c.

Referenced by ast_features_init(), ast_features_reload(), ast_park_call(), build_parkinglot(), builtin_atxfer(), builtin_blindtransfer(), do_parking_thread(), find_parkinglot(), handle_feature_show(), handle_parkedcalls(), manager_parking_status(), park_call_exec(), park_exec_full(), and park_space_reserve().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 376 of file features.c.

Referenced by ast_pickup_ext(), and load_config().

char pickupfailsound[256] [static]

Pickup failure sound

Definition at line 431 of file features.c.

Referenced by ast_pickup_call(), and load_config().

char pickupsound[256] [static]

Pickup sound

Definition at line 430 of file features.c.

Referenced by ast_pickup_call(), and load_config().

char* registrar = "features" [static]

Registrar for operations

Definition at line 444 of file features.c.

Referenced by build_parkinglot(), manage_parkinglot(), park_add_hints(), park_call_full(), and parkinglot_destroy().

struct ast_app* stopmixmonitor_app = NULL [static]

Definition at line 455 of file features.c.

Referenced by builtin_automixmonitor().

int stopmixmonitor_ok = 1 [static]

Definition at line 456 of file features.c.

Referenced by builtin_automixmonitor().

int transferdigittimeout [static]

Definition at line 435 of file features.c.

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

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 429 of file features.c.

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

char xfersound[256] [static]

Call transfer sound

Definition at line 428 of file features.c.

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


Generated on Mon Jun 27 16:51:14 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7