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/test.h"
#include "asterisk/bridge.h"
#include "asterisk/bridge_features.h"
#include "asterisk/bridge_basic.h"
#include "asterisk/bridge_after.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/features_config.h"

Include dependency graph for features.c:

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  ast_dial_features

Enumerations

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

Functions

static int action_bridge (struct mansession *s, const struct message *m)
 Bridge channels together.
static int add_features_datastore (struct ast_channel *chan, const struct ast_flags *my_features, const struct ast_flags *peer_features)
static void add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 bridge the call and set CDR
int ast_bridge_call_with_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
 Bridge a call, and add additional flags to the bridge.
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_features_init (void)
static void bridge_check_monitor (struct ast_channel *chan, struct ast_channel *peer)
static void bridge_config_set_limits (struct ast_bridge_config *config, struct ast_bridge_features_limits *caller_limits, struct ast_bridge_features_limits *callee_limits)
static void bridge_config_set_limits_warning_values (struct ast_bridge_config *config, struct ast_bridge_features_limits *limits)
static int bridge_exec (struct ast_channel *chan, const char *data)
 Bridge channels.
static void bridge_failed_peer_goto (struct ast_channel *chan, struct ast_channel *peer)
static void clear_dialed_interfaces (struct ast_channel *chan)
static void * dial_features_duplicate (void *data)
static void features_shutdown (void)
static enum play_tone_action parse_playtone (const char *playtone_val)
static int pre_bridge_setup (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, struct ast_bridge_features *chan_features, struct ast_bridge_features *peer_features)
static void set_bridge_features_on_config (struct ast_bridge_config *config, const char *features)
static void set_config_flags (struct ast_channel *chan, struct ast_bridge_config *config)

Variables

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


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file features.c.


Enumeration Type Documentation

anonymous enum

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

Definition at line 848 of file features.c.

00848      {
00849    BRIDGE_OPT_PLAYTONE = (1 << 0),
00850    OPT_CALLEE_HANGUP =  (1 << 1),
00851    OPT_CALLER_HANGUP =  (1 << 2),
00852    OPT_DURATION_LIMIT = (1 << 3),
00853    OPT_DURATION_STOP =  (1 << 4),
00854    OPT_CALLEE_TRANSFER = (1 << 5),
00855    OPT_CALLER_TRANSFER = (1 << 6),
00856    OPT_CALLEE_MONITOR = (1 << 7),
00857    OPT_CALLER_MONITOR = (1 << 8),
00858    OPT_CALLEE_PARK = (1 << 9),
00859    OPT_CALLER_PARK = (1 << 10),
00860    OPT_CALLEE_KILL = (1 << 11),
00861    OPT_CALLEE_GO_ON = (1 << 12),
00862 };

anonymous enum

Enumerator:
OPT_ARG_DURATION_LIMIT 
OPT_ARG_DURATION_STOP 
OPT_ARG_CALLEE_GO_ON 
OPT_ARG_ARRAY_SIZE 

Definition at line 864 of file features.c.

00864      {
00865    OPT_ARG_DURATION_LIMIT = 0,
00866    OPT_ARG_DURATION_STOP,
00867    OPT_ARG_CALLEE_GO_ON,
00868    /* note: this entry _MUST_ be the last one in the enum */
00869    OPT_ARG_ARRAY_SIZE,
00870 };

Enumerator:
FEATURE_INTERPRET_DETECT 
FEATURE_INTERPRET_DO 
FEATURE_INTERPRET_CHECK 

Definition at line 235 of file features.c.

00235              {
00236    FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */
00237    FEATURE_INTERPRET_DO,     /* Used by feature_interpret */
00238    FEATURE_INTERPRET_CHECK,  /* Used by feature_check */
00239 } feature_interpret_op;

Enumerator:
PLAYTONE_NONE 
PLAYTONE_CHANNEL1 
PLAYTONE_CHANNEL2 
PLAYTONE_BOTH 

Definition at line 723 of file features.c.

00723                       {
00724    PLAYTONE_NONE = 0,
00725    PLAYTONE_CHANNEL1 = (1 << 0),
00726    PLAYTONE_CHANNEL2 = (1 << 1),
00727    PLAYTONE_BOTH = PLAYTONE_CHANNEL1 | PLAYTONE_CHANNEL2,
00728 };


Function Documentation

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

Bridge channels together.

Parameters:
s 
m Make sure valid channels were specified, send errors if any of the channels could not be found/locked, answer channels if needed, create the placeholder channels and grab the other channels make the channels compatible, send error if we fail doing so setup the bridge thread object and start the bridge.
Return values:
0 

Definition at line 759 of file features.c.

References ao2_cleanup, ast_bridge_add_channel(), ast_bridge_basic_new(), ast_bridge_destroy(), ast_bridge_set_after_go_on(), ast_channel_context(), ast_channel_exten(), ast_channel_flags(), ast_channel_get_by_name_prefix(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_unlock, ast_debug, AST_FLAG_IN_AUTOLOOP, ast_get_chan_features_xfer_config(), ast_strdupa, ast_strlen_zero, ast_test_flag, astman_get_header(), astman_send_ack(), astman_send_error(), buf, NULL, parse_playtone(), playtone(), PLAYTONE_CHANNEL1, PLAYTONE_CHANNEL2, and RAII_VAR.

Referenced by ast_features_init().

00760 {
00761    const char *channela = astman_get_header(m, "Channel1");
00762    const char *channelb = astman_get_header(m, "Channel2");
00763    enum play_tone_action playtone = parse_playtone(astman_get_header(m, "Tone"));
00764    RAII_VAR(struct ast_channel *, chana, NULL, ao2_cleanup);
00765    RAII_VAR(struct ast_channel *, chanb, NULL, ao2_cleanup);
00766    const char *chana_exten;
00767    const char *chana_context;
00768    int chana_priority;
00769    const char *chanb_exten;
00770    const char *chanb_context;
00771    int chanb_priority;
00772    struct ast_bridge *bridge;
00773    char buf[256];
00774    RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_a, NULL, ao2_cleanup);
00775    RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_b, NULL, ao2_cleanup);
00776 
00777    /* make sure valid channels were specified */
00778    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
00779       astman_send_error(s, m, "Missing channel parameter in request");
00780       return 0;
00781    }
00782 
00783    ast_debug(1, "Performing Bridge action on %s and %s\n", channela, channelb);
00784 
00785    /* Start with chana */
00786    chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
00787    if (!chana) {
00788       snprintf(buf, sizeof(buf), "Channel1 does not exist: %s", channela);
00789       astman_send_error(s, m, buf);
00790       return 0;
00791    }
00792    xfer_cfg_a = ast_get_chan_features_xfer_config(chana);
00793    ast_channel_lock(chana);
00794    chana_exten = ast_strdupa(ast_channel_exten(chana));
00795    chana_context = ast_strdupa(ast_channel_context(chana));
00796    chana_priority = ast_channel_priority(chana);
00797    if (!ast_test_flag(ast_channel_flags(chana), AST_FLAG_IN_AUTOLOOP)) {
00798       chana_priority++;
00799    }
00800    ast_channel_unlock(chana);
00801 
00802    chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
00803    if (!chanb) {
00804       snprintf(buf, sizeof(buf), "Channel2 does not exist: %s", channelb);
00805       astman_send_error(s, m, buf);
00806       return 0;
00807    }
00808    xfer_cfg_b = ast_get_chan_features_xfer_config(chanb);
00809    ast_channel_lock(chanb);
00810    chanb_exten = ast_strdupa(ast_channel_exten(chanb));
00811    chanb_context = ast_strdupa(ast_channel_context(chanb));
00812    chanb_priority = ast_channel_priority(chanb);
00813    if (!ast_test_flag(ast_channel_flags(chanb), AST_FLAG_IN_AUTOLOOP)) {
00814       chanb_priority++;
00815    }
00816    ast_channel_unlock(chanb);
00817 
00818    bridge = ast_bridge_basic_new();
00819    if (!bridge) {
00820       astman_send_error(s, m, "Unable to create bridge\n");
00821       return 0;
00822    }
00823 
00824    ast_bridge_set_after_go_on(chana, chana_context, chana_exten, chana_priority, NULL);
00825    if (ast_bridge_add_channel(bridge, chana, NULL, playtone & PLAYTONE_CHANNEL1, xfer_cfg_a ? xfer_cfg_a->xfersound : NULL)) {
00826       snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", ast_channel_name(chana));
00827       astman_send_error(s, m, buf);
00828       ast_bridge_destroy(bridge, 0);
00829       return 0;
00830    }
00831 
00832    ast_bridge_set_after_go_on(chanb, chanb_context, chanb_exten, chanb_priority, NULL);
00833    if (ast_bridge_add_channel(bridge, chanb, NULL, playtone & PLAYTONE_CHANNEL2, xfer_cfg_b ? xfer_cfg_b->xfersound : NULL)) {
00834       snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", ast_channel_name(chanb));
00835       astman_send_error(s, m, buf);
00836       ast_bridge_destroy(bridge, 0);
00837       return 0;
00838    }
00839 
00840    astman_send_ack(s, m, "Channels have been bridged");
00841    ao2_cleanup(bridge);
00842 
00843    return 0;
00844 }

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

Definition at line 277 of file features.c.

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

Referenced by add_features_datastores().

00278 {
00279    struct ast_datastore *datastore;
00280    struct ast_dial_features *dialfeatures;
00281 
00282    ast_channel_lock(chan);
00283    datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL);
00284    ast_channel_unlock(chan);
00285    if (datastore) {
00286       /* Already exists. */
00287       return 1;
00288    }
00289 
00290    /* Create a new datastore with specified feature flags. */
00291    datastore = ast_datastore_alloc(&dial_features_info, NULL);
00292    if (!datastore) {
00293       ast_log(LOG_WARNING, "Unable to create channel features datastore.\n");
00294       return 0;
00295    }
00296    dialfeatures = ast_calloc(1, sizeof(*dialfeatures));
00297    if (!dialfeatures) {
00298       ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n");
00299       ast_datastore_free(datastore);
00300       return 0;
00301    }
00302    ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL);
00303    ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL);
00304    datastore->inheritance = DATASTORE_INHERIT_FOREVER;
00305    datastore->data = dialfeatures;
00306    ast_channel_lock(chan);
00307    ast_channel_datastore_add(chan, datastore);
00308    ast_channel_unlock(chan);
00309    return 0;
00310 }

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

Definition at line 409 of file features.c.

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

Referenced by pre_bridge_setup().

00410 {
00411    if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) {
00412       /*
00413        * If we don't return here, then when we do a builtin_atxfer we
00414        * will copy the disconnect flags over from the atxfer to the
00415        * callee (Party C).
00416        */
00417       return;
00418    }
00419 
00420    add_features_datastore(callee, &config->features_callee, &config->features_caller);
00421 }

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

bridge the call and set CDR

Bridge a call, optionally allowing redirection.

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

Definition at line 718 of file features.c.

References ast_bridge_call_with_flags().

Referenced by app_exec(), and dial_exec_full().

00719 {
00720    return ast_bridge_call_with_flags(chan, peer, config, 0);
00721 }

int ast_bridge_call_with_flags ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
unsigned int  flags 
)

Bridge a call, and add additional flags to the bridge.

This does the same thing as ast_bridge_call, except that once the bridge is created, the provided flags are set on the bridge. The provided flags are added to the bridge's flags; they will not clear any flags already set.

Parameters:
chan The calling channel
peer The called channel
config Bridge configuration for the channels
flags Additional flags to set on the created bridge
Note:
The function caller is assumed to have already done the COLP exchange for the initial bridging of the two channels if it was desired.

Definition at line 636 of file features.c.

References ast_bridge_basic_new(), ast_bridge_basic_set_flags(), ast_bridge_destroy(), ast_bridge_features_cleanup(), ast_bridge_features_destroy(), ast_bridge_features_init(), ast_bridge_features_new(), ast_bridge_impart(), AST_BRIDGE_IMPART_CHAN_INDEPENDENT, AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP, ast_bridge_join(), AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP, AST_BRIDGE_JOIN_PASS_REFERENCE, ast_channel_lock, ast_channel_softhangup_internal_flag(), ast_channel_unlock, AST_SOFTHANGUP_ASYNCGOTO, bridge_failed_peer_goto(), ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, NULL, and pre_bridge_setup().

Referenced by ast_bridge_call(), and try_calling().

00637 {
00638    int res;
00639    struct ast_bridge *bridge;
00640    struct ast_bridge_features chan_features;
00641    struct ast_bridge_features *peer_features;
00642 
00643    /* Setup features. */
00644    res = ast_bridge_features_init(&chan_features);
00645    peer_features = ast_bridge_features_new();
00646    if (res || !peer_features) {
00647       ast_bridge_features_destroy(peer_features);
00648       ast_bridge_features_cleanup(&chan_features);
00649       bridge_failed_peer_goto(chan, peer);
00650       return -1;
00651    }
00652 
00653    if (pre_bridge_setup(chan, peer, config, &chan_features, peer_features)) {
00654       ast_bridge_features_destroy(peer_features);
00655       ast_bridge_features_cleanup(&chan_features);
00656       bridge_failed_peer_goto(chan, peer);
00657       return -1;
00658    }
00659 
00660    /* Create bridge */
00661    bridge = ast_bridge_basic_new();
00662    if (!bridge) {
00663       ast_bridge_features_destroy(peer_features);
00664       ast_bridge_features_cleanup(&chan_features);
00665       bridge_failed_peer_goto(chan, peer);
00666       return -1;
00667    }
00668 
00669    ast_bridge_basic_set_flags(bridge, flags);
00670 
00671    /* Put peer into the bridge */
00672    if (ast_bridge_impart(bridge, peer, NULL, peer_features,
00673       AST_BRIDGE_IMPART_CHAN_INDEPENDENT | AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP)) {
00674       ast_bridge_destroy(bridge, 0);
00675       ast_bridge_features_cleanup(&chan_features);
00676       bridge_failed_peer_goto(chan, peer);
00677       return -1;
00678    }
00679 
00680    /* Join bridge */
00681    ast_bridge_join(bridge, chan, NULL, &chan_features, NULL,
00682       AST_BRIDGE_JOIN_PASS_REFERENCE | AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP);
00683 
00684    /*
00685     * If the bridge was broken for a hangup that isn't real, then
00686     * don't run the h extension, because the channel isn't really
00687     * hung up.  This should really only happen with
00688     * AST_SOFTHANGUP_ASYNCGOTO.
00689     */
00690    res = -1;
00691    ast_channel_lock(chan);
00692    if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
00693       res = 0;
00694    }
00695    ast_channel_unlock(chan);
00696 
00697    ast_bridge_features_cleanup(&chan_features);
00698 
00699    if (res && config->end_bridge_callback) {
00700       config->end_bridge_callback(config->end_bridge_callback_data);
00701    }
00702 
00703    return res;
00704 }

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

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

Referenced by bridge_exec(), and dial_exec_full().

00890 {
00891    char *stringp = ast_strdupa(parse);
00892    char *limit_str, *warning_str, *warnfreq_str;
00893    const char *var;
00894    int play_to_caller = 0, play_to_callee = 0;
00895    int delta;
00896 
00897    limit_str = strsep(&stringp, ":");
00898    warning_str = strsep(&stringp, ":");
00899    warnfreq_str = strsep(&stringp, ":");
00900 
00901    config->timelimit = atol(limit_str);
00902    if (warning_str)
00903       config->play_warning = atol(warning_str);
00904    if (warnfreq_str)
00905       config->warning_freq = atol(warnfreq_str);
00906 
00907    if (!config->timelimit) {
00908       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
00909       config->timelimit = config->play_warning = config->warning_freq = 0;
00910       config->warning_sound = NULL;
00911       return -1; /* error */
00912    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
00913       int w = config->warning_freq;
00914 
00915       /*
00916        * If the first warning is requested _after_ the entire call
00917        * would end, and no warning frequency is requested, then turn
00918        * off the warning. If a warning frequency is requested, reduce
00919        * the 'first warning' time by that frequency until it falls
00920        * within the call's total time limit.
00921        *
00922        * Graphically:
00923        *                timelim->|    delta        |<-playwarning
00924        *      0__________________|_________________|
00925        *                       | w  |    |    |    |
00926        *
00927        * so the number of intervals to cut is 1+(delta-1)/w
00928        */
00929       if (w == 0) {
00930          config->play_warning = 0;
00931       } else {
00932          config->play_warning -= w * ( 1 + (delta-1)/w );
00933          if (config->play_warning < 1)
00934             config->play_warning = config->warning_freq = 0;
00935       }
00936    }
00937 
00938    ast_channel_lock(chan);
00939 
00940    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
00941    play_to_caller = var ? ast_true(var) : 1;
00942 
00943    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
00944    play_to_callee = var ? ast_true(var) : 0;
00945 
00946    if (!play_to_caller && !play_to_callee)
00947       play_to_caller = 1;
00948 
00949    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
00950    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
00951 
00952    /* The code looking at config wants a NULL, not just "", to decide
00953     * that the message should not be played, so we replace "" with NULL.
00954     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
00955     * not found.
00956     */
00957 
00958    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
00959    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
00960 
00961    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
00962    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
00963 
00964    ast_channel_unlock(chan);
00965 
00966    /* undo effect of S(x) in case they are both used */
00967    calldurationlimit->tv_sec = 0;
00968    calldurationlimit->tv_usec = 0;
00969 
00970    /* more efficient to do it like S(x) does since no advanced opts */
00971    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
00972       calldurationlimit->tv_sec = config->timelimit / 1000;
00973       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
00974       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
00975          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
00976       play_to_caller = 0;
00977       play_to_callee = 0;
00978       config->timelimit = 0;
00979       config->play_warning = 0;
00980       config->warning_freq = 0;
00981    } else {
00982       ast_verb(4, "Limit Data for this call:\n");
00983       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
00984       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
00985       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
00986       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
00987       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
00988       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
00989       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
00990       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
00991    }
00992    if (play_to_caller)
00993       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
00994    if (play_to_callee)
00995       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
00996    return 0;
00997 }

void ast_channel_log ( char *  title,
struct ast_channel chan 
)

Definition at line 349 of file features.c.

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

Referenced by pre_bridge_setup().

00350 {
00351    ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long) chan);
00352    ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
00353       ast_channel_name(chan), ast_channel_appl(chan), ast_channel_data(chan),
00354       ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
00355    ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
00356       ast_channel_accountcode(chan), ast_channel_dialcontext(chan), ast_channel_amaflags(chan),
00357       ast_channel_macrocontext(chan), ast_channel_macroexten(chan), ast_channel_macropriority(chan));
00358    ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; uniqueID: %s; linkedID:%s\n",
00359       ast_channel_masq(chan), ast_channel_masqr(chan),
00360       ast_channel_uniqueid(chan), ast_channel_linkedid(chan));
00361    if (ast_channel_masqr(chan)) {
00362       ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
00363          ast_channel_name(ast_channel_masqr(chan)), ast_channel_cdr(ast_channel_masqr(chan)));
00364    }
00365 
00366    ast_log(LOG_NOTICE, "===== done ====\n");
00367 }

int ast_features_init ( void   ) 

Provided by features.c

Definition at line 1168 of file features.c.

References action_bridge(), ast_features_config_init(), ast_manager_register_xml_core, ast_register_application2(), ast_register_cleanup(), bridge_exec(), EVENT_FLAG_CALL, features_shutdown(), and NULL.

Referenced by main().

01169 {
01170    int res;
01171 
01172    res = ast_features_config_init();
01173    if (res) {
01174       return res;
01175    }
01176    res |= ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
01177    res |= ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge);
01178 
01179    if (res) {
01180       features_shutdown();
01181    } else {
01182       ast_register_cleanup(features_shutdown);
01183    }
01184 
01185    return res;
01186 }

static void bridge_check_monitor ( struct ast_channel chan,
struct ast_channel peer 
) [static]

Definition at line 488 of file features.c.

References ast_channel_lock, ast_channel_unlock, ast_strdupa, ast_strlen_zero, NULL, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), and value.

Referenced by pre_bridge_setup().

00489 {
00490    const char *value;
00491    const char *monitor_args = NULL;
00492    struct ast_channel *monitor_chan = NULL;
00493 
00494    ast_channel_lock(chan);
00495    value = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR");
00496    if (!ast_strlen_zero(value)) {
00497       monitor_args = ast_strdupa(value);
00498       monitor_chan = chan;
00499    }
00500    ast_channel_unlock(chan);
00501    if (!monitor_chan) {
00502       ast_channel_lock(peer);
00503       value = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR");
00504       if (!ast_strlen_zero(value)) {
00505          monitor_args = ast_strdupa(value);
00506          monitor_chan = peer;
00507       }
00508       ast_channel_unlock(peer);
00509    }
00510    if (monitor_chan) {
00511       struct ast_app *monitor_app;
00512 
00513       monitor_app = pbx_findapp("Monitor");
00514       if (monitor_app) {
00515          pbx_exec(monitor_chan, monitor_app, monitor_args);
00516       }
00517    }
00518 }

static void bridge_config_set_limits ( struct ast_bridge_config config,
struct ast_bridge_features_limits caller_limits,
struct ast_bridge_features_limits callee_limits 
) [static]

static void bridge_config_set_limits_warning_values ( struct ast_bridge_config config,
struct ast_bridge_features_limits limits 
) [static]

Definition at line 439 of file features.c.

References ast_string_field_set, ast_bridge_config::end_sound, ast_bridge_features_limits::frequency, ast_bridge_config::play_warning, ast_bridge_config::start_sound, ast_bridge_features_limits::warning, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by bridge_config_set_limits().

00440 {
00441    if (config->end_sound) {
00442       ast_string_field_set(limits, duration_sound, config->end_sound);
00443    }
00444 
00445    if (config->warning_sound) {
00446       ast_string_field_set(limits, warning_sound, config->warning_sound);
00447    }
00448 
00449    if (config->start_sound) {
00450       ast_string_field_set(limits, connect_sound, config->start_sound);
00451    }
00452 
00453    limits->frequency = config->warning_freq;
00454    limits->warning = config->play_warning;
00455 }

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

Bridge channels.

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

Definition at line 1009 of file features.c.

References ao2_cleanup, args, AST_APP_ARG, ast_app_parse_options(), ast_bridge_add_channel(), ast_bridge_basic_new(), ast_bridge_destroy(), ast_bridge_features_cleanup(), ast_bridge_features_destroy(), ast_bridge_features_init(), ast_bridge_features_new(), ast_bridge_join(), AST_BRIDGE_JOIN_PASS_REFERENCE, ast_bridge_set_after_go_on(), ast_bridge_timelimit(), ast_channel_cleanup, ast_channel_context(), ast_channel_exten(), ast_channel_get_by_name_prefix(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_unlock, ast_channel_unref, AST_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_free, ast_get_chan_features_xfer_config(), ast_log, ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, ast_test_flag, bridge_exec_options, BRIDGE_OPT_PLAYTONE, context, ast_bridge_config::end_sound, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, NULL, OPT_ARG_ARRAY_SIZE, OPT_ARG_CALLEE_GO_ON, OPT_ARG_DURATION_LIMIT, OPT_CALLEE_GO_ON, OPT_CALLEE_HANGUP, OPT_CALLEE_KILL, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DURATION_LIMIT, pbx_builtin_setvar_helper(), pre_bridge_setup(), ast_bridge_config::start_sound, ast_bridge_config::warning_sound, and ast_features_xfer_config::xfersound.

Referenced by ast_features_init().

01010 {
01011    struct ast_channel *current_dest_chan;
01012    char *tmp_data  = NULL;
01013    struct ast_flags opts = { 0, };
01014    struct ast_bridge_config bconfig = { { 0, }, };
01015    char *opt_args[OPT_ARG_ARRAY_SIZE];
01016    struct timeval calldurationlimit = { 0, };
01017    const char *context;
01018    const char *extension;
01019    int priority;
01020    int bridge_add_failed;
01021    struct ast_bridge_features chan_features;
01022    struct ast_bridge_features *peer_features;
01023    struct ast_bridge *bridge;
01024    struct ast_features_xfer_config *xfer_cfg;
01025 
01026    AST_DECLARE_APP_ARGS(args,
01027       AST_APP_ARG(dest_chan);
01028       AST_APP_ARG(options);
01029    );
01030 
01031    if (ast_strlen_zero(data)) {
01032       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
01033       return -1;
01034    }
01035 
01036    tmp_data = ast_strdupa(data);
01037    AST_STANDARD_APP_ARGS(args, tmp_data);
01038    if (!ast_strlen_zero(args.options))
01039       ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
01040 
01041    /* make sure we have a valid end point */
01042    current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
01043       strlen(args.dest_chan));
01044    if (!current_dest_chan) {
01045       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
01046          args.dest_chan);
01047       return 0;
01048    }
01049 
01050    /* avoid bridge with ourselves */
01051    if (chan == current_dest_chan) {
01052       ast_channel_unref(current_dest_chan);
01053       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", ast_channel_name(chan));
01054       return 0;
01055    }
01056 
01057    if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
01058       && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
01059       && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
01060       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
01061       goto done;
01062    }
01063 
01064    if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
01065       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
01066    if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
01067       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
01068    if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
01069       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
01070    if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
01071       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
01072    if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
01073       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
01074    if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
01075       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
01076    if (ast_test_flag(&opts, OPT_CALLEE_PARK))
01077       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
01078    if (ast_test_flag(&opts, OPT_CALLER_PARK))
01079       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
01080 
01081    /* Setup after bridge goto location. */
01082    if (ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
01083       ast_channel_lock(chan);
01084       context = ast_strdupa(ast_channel_context(chan));
01085       extension = ast_strdupa(ast_channel_exten(chan));
01086       priority = ast_channel_priority(chan);
01087       ast_channel_unlock(chan);
01088       ast_bridge_set_after_go_on(current_dest_chan, context, extension, priority,
01089          opt_args[OPT_ARG_CALLEE_GO_ON]);
01090    } else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
01091       ast_channel_lock(current_dest_chan);
01092       context = ast_strdupa(ast_channel_context(current_dest_chan));
01093       extension = ast_strdupa(ast_channel_exten(current_dest_chan));
01094       priority = ast_channel_priority(current_dest_chan);
01095       ast_channel_unlock(current_dest_chan);
01096       ast_bridge_set_after_go_on(current_dest_chan, context, extension, priority, NULL);
01097    }
01098 
01099    if (ast_bridge_features_init(&chan_features)) {
01100       ast_bridge_features_cleanup(&chan_features);
01101       goto done;
01102    }
01103 
01104    peer_features = ast_bridge_features_new();
01105    if (!peer_features) {
01106       ast_bridge_features_cleanup(&chan_features);
01107       goto done;
01108    }
01109 
01110    if (pre_bridge_setup(chan, current_dest_chan, &bconfig, &chan_features, peer_features)) {
01111       ast_bridge_features_destroy(peer_features);
01112       ast_bridge_features_cleanup(&chan_features);
01113       goto done;
01114    }
01115 
01116    bridge = ast_bridge_basic_new();
01117    if (!bridge) {
01118       ast_bridge_features_destroy(peer_features);
01119       ast_bridge_features_cleanup(&chan_features);
01120       goto done;
01121    }
01122 
01123    xfer_cfg = ast_get_chan_features_xfer_config(current_dest_chan);
01124    bridge_add_failed = ast_bridge_add_channel(bridge, current_dest_chan, peer_features,
01125       ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE),
01126       xfer_cfg ? xfer_cfg->xfersound : NULL);
01127    ao2_cleanup(xfer_cfg);
01128    if (bridge_add_failed) {
01129       ast_bridge_features_destroy(peer_features);
01130       ast_bridge_features_cleanup(&chan_features);
01131       ast_bridge_destroy(bridge, 0);
01132       goto done;
01133    }
01134 
01135    /* Don't keep the channel ref in case it was not already in a bridge. */
01136    current_dest_chan = ast_channel_unref(current_dest_chan);
01137 
01138    ast_bridge_join(bridge, chan, NULL, &chan_features, NULL,
01139       AST_BRIDGE_JOIN_PASS_REFERENCE);
01140 
01141    ast_bridge_features_cleanup(&chan_features);
01142 
01143    /* The bridge has ended, set BRIDGERESULT to SUCCESS. */
01144    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
01145 done:
01146    ast_free((char *) bconfig.warning_sound);
01147    ast_free((char *) bconfig.end_sound);
01148    ast_free((char *) bconfig.start_sound);
01149 
01150    ast_channel_cleanup(current_dest_chan);
01151    return 0;
01152 }

static void bridge_failed_peer_goto ( struct ast_channel chan,
struct ast_channel peer 
) [static]

Definition at line 530 of file features.c.

References ast_autoservice_chan_hangup_peer(), ast_bridge_setup_after_goto(), and ast_pbx_start().

Referenced by ast_bridge_call_with_flags().

00531 {
00532    if (ast_bridge_setup_after_goto(peer)
00533       || ast_pbx_start(peer)) {
00534       ast_autoservice_chan_hangup_peer(chan, peer);
00535    }
00536 }

static void clear_dialed_interfaces ( struct ast_channel chan  )  [static]

Definition at line 423 of file features.c.

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

Referenced by pre_bridge_setup().

00424 {
00425    struct ast_datastore *di_datastore;
00426 
00427    ast_channel_lock(chan);
00428    if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
00429       if (option_debug) {
00430          ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", ast_channel_name(chan));
00431       }
00432       if (!ast_channel_datastore_remove(chan, di_datastore)) {
00433          ast_datastore_free(di_datastore);
00434       }
00435    }
00436    ast_channel_unlock(chan);
00437 }

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

Definition at line 248 of file features.c.

References ast_calloc, and NULL.

00249 {
00250    struct ast_dial_features *df = data, *df_copy;
00251 
00252    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00253       return NULL;
00254    }
00255 
00256    memcpy(df_copy, df, sizeof(*df));
00257 
00258    return df_copy;
00259 }

static void features_shutdown ( void   )  [static]

Definition at line 1158 of file features.c.

References ast_features_config_shutdown(), ast_manager_unregister(), and ast_unregister_application().

Referenced by ast_features_init().

01159 {
01160    ast_features_config_shutdown();
01161 
01162    ast_manager_unregister("Bridge");
01163 
01164    ast_unregister_application(app_bridge);
01165 
01166 }

static enum play_tone_action parse_playtone ( const char *  playtone_val  )  [static]

Definition at line 730 of file features.c.

References ast_false(), ast_strlen_zero, ast_true(), PLAYTONE_BOTH, PLAYTONE_CHANNEL1, PLAYTONE_CHANNEL2, and PLAYTONE_NONE.

Referenced by action_bridge().

00731 {
00732    if (ast_strlen_zero(playtone_val) || ast_false(playtone_val)) {
00733       return PLAYTONE_NONE;
00734    } if (!strcasecmp(playtone_val, "channel1")) {
00735       return PLAYTONE_CHANNEL1;
00736    } else if (!strcasecmp(playtone_val, "channel2") || ast_true(playtone_val)) {
00737       return PLAYTONE_CHANNEL2;
00738    } else if (!strcasecmp(playtone_val, "both")) {
00739       return PLAYTONE_BOTH;
00740    } else {
00741       /* Invalid input. Assume none */
00742       return PLAYTONE_NONE;
00743    }
00744 }

static int pre_bridge_setup ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
struct ast_bridge_features chan_features,
struct ast_bridge_features peer_features 
) [static]

Definition at line 538 of file features.c.

References add_features_datastores(), ast_bridge_features_ds_append(), ast_bridge_features_limits_construct(), ast_bridge_features_limits_destroy(), ast_bridge_features_set_limits(), ast_channel_lock, ast_channel_log(), ast_channel_unlock, ast_channel_visible_indication(), AST_CONTROL_RINGING, ast_indicate(), ast_log, ast_raw_answer(), AST_STATE_RINGING, AST_STATE_UP, bridge_check_monitor(), bridge_config_set_limits(), clear_dialed_interfaces(), ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_ERROR, pbx_builtin_getvar_helper(), set_bridge_features_on_config(), set_config_flags(), and ast_bridge_config::timelimit.

Referenced by ast_bridge_call_with_flags(), and bridge_exec().

00540 {
00541    int res;
00542 
00543    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
00544    add_features_datastores(chan, peer, config);
00545 
00546    /*
00547     * This is an interesting case.  One example is if a ringing
00548     * channel gets redirected to an extension that picks up a
00549     * parked call.  This will make sure that the call taken out of
00550     * parking gets told that the channel it just got bridged to is
00551     * still ringing.
00552     */
00553    if (ast_channel_state(chan) == AST_STATE_RINGING
00554       && ast_channel_visible_indication(peer) != AST_CONTROL_RINGING) {
00555       ast_indicate(peer, AST_CONTROL_RINGING);
00556    }
00557 
00558    bridge_check_monitor(chan, peer);
00559 
00560    set_config_flags(chan, config);
00561 
00562    /* Answer if need be */
00563    if (ast_channel_state(chan) != AST_STATE_UP) {
00564       if (ast_raw_answer(chan)) {
00565          return -1;
00566       }
00567    }
00568 
00569 #ifdef FOR_DEBUG
00570    /* show the two channels and cdrs involved in the bridge for debug & devel purposes */
00571    ast_channel_log("Pre-bridge CHAN Channel info", chan);
00572    ast_channel_log("Pre-bridge PEER Channel info", peer);
00573 #endif
00574 
00575    /*
00576     * If we are bridging a call, stop worrying about forwarding
00577     * loops.  We presume that if a call is being bridged, that the
00578     * humans in charge know what they're doing.  If they don't,
00579     * well, what can we do about that?
00580     */
00581    clear_dialed_interfaces(chan);
00582    clear_dialed_interfaces(peer);
00583 
00584    res = 0;
00585    ast_channel_lock(chan);
00586    res |= ast_bridge_features_ds_append(chan, &config->features_caller);
00587    ast_channel_unlock(chan);
00588    ast_channel_lock(peer);
00589    res |= ast_bridge_features_ds_append(peer, &config->features_callee);
00590    ast_channel_unlock(peer);
00591 
00592    if (res) {
00593       return -1;
00594    }
00595 
00596    if (config->timelimit) {
00597       struct ast_bridge_features_limits call_duration_limits_chan;
00598       struct ast_bridge_features_limits call_duration_limits_peer;
00599       int abandon_call = 0; /* TRUE if set limits fails so we can abandon the call. */
00600 
00601       if (ast_bridge_features_limits_construct(&call_duration_limits_chan)) {
00602          ast_log(LOG_ERROR, "Could not construct caller duration limits. Bridge canceled.\n");
00603 
00604          return -1;
00605       }
00606 
00607       if (ast_bridge_features_limits_construct(&call_duration_limits_peer)) {
00608          ast_log(LOG_ERROR, "Could not construct callee duration limits. Bridge canceled.\n");
00609          ast_bridge_features_limits_destroy(&call_duration_limits_chan);
00610 
00611          return -1;
00612       }
00613 
00614       bridge_config_set_limits(config, &call_duration_limits_chan, &call_duration_limits_peer);
00615 
00616       if (ast_bridge_features_set_limits(chan_features, &call_duration_limits_chan, 0)) {
00617          abandon_call = 1;
00618       }
00619       if (ast_bridge_features_set_limits(peer_features, &call_duration_limits_peer, 0)) {
00620          abandon_call = 1;
00621       }
00622 
00623       /* At this point we are done with the limits structs since they have been copied to the individual feature sets. */
00624       ast_bridge_features_limits_destroy(&call_duration_limits_chan);
00625       ast_bridge_features_limits_destroy(&call_duration_limits_peer);
00626 
00627       if (abandon_call) {
00628          ast_log(LOG_ERROR, "Could not set duration limits on one or more sides of the call. Bridge canceled.\n");
00629          return -1;
00630       }
00631    }
00632 
00633    return 0;
00634 }

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

Definition at line 369 of file features.c.

References AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log, ast_set_flag, ast_strlen_zero, ast_bridge_config::features_callee, ast_bridge_config::features_caller, and LOG_WARNING.

Referenced by pre_bridge_setup().

00370 {
00371    const char *feature;
00372 
00373    if (ast_strlen_zero(features)) {
00374       return;
00375    }
00376 
00377    for (feature = features; *feature; feature++) {
00378       struct ast_flags *party;
00379 
00380       if (isupper(*feature)) {
00381          party = &config->features_caller;
00382       } else {
00383          party = &config->features_callee;
00384       }
00385 
00386       switch (tolower(*feature)) {
00387       case 't' :
00388          ast_set_flag(party, AST_FEATURE_REDIRECT);
00389          break;
00390       case 'k' :
00391          ast_set_flag(party, AST_FEATURE_PARKCALL);
00392          break;
00393       case 'h' :
00394          ast_set_flag(party, AST_FEATURE_DISCONNECT);
00395          break;
00396       case 'w' :
00397          ast_set_flag(party, AST_FEATURE_AUTOMON);
00398          break;
00399       case 'x' :
00400          ast_set_flag(party, AST_FEATURE_AUTOMIXMON);
00401          break;
00402       default :
00403          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
00404          break;
00405       }
00406    }
00407 }

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

Definition at line 320 of file features.c.

References ao2_cleanup, AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_channel_lock, ast_channel_unlock, ast_clear_flag, AST_FEATURE_DTMF_MASK, AST_FLAGS_ALL, ast_get_chan_applicationmap(), ast_set_flag, ast_test_flag, ast_bridge_config::features_callee, ast_bridge_config::features_caller, NULL, and RAII_VAR.

Referenced by pre_bridge_setup().

00321 {
00322    ast_clear_flag(config, AST_FLAGS_ALL);
00323 
00324    if (ast_test_flag(&config->features_caller, AST_FEATURE_DTMF_MASK)) {
00325       ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
00326    }
00327    if (ast_test_flag(&config->features_callee, AST_FEATURE_DTMF_MASK)) {
00328       ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
00329    }
00330 
00331    if (!(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
00332       RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
00333 
00334       ast_channel_lock(chan);
00335       applicationmap = ast_get_chan_applicationmap(chan);
00336       ast_channel_unlock(chan);
00337 
00338       if (!applicationmap) {
00339          return;
00340       }
00341 
00342       /* If an applicationmap exists for this channel at all, then the channel needs the DTMF flag set */
00343       ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
00344    }
00345 }


Variable Documentation

char* app_bridge = "Bridge" [static]

Definition at line 846 of file features.c.

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

Definition at line 886 of file features.c.

Referenced by bridge_exec().

Initial value:

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

Definition at line 261 of file features.c.


Generated on Thu Apr 16 06:30:58 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6