Fri Apr 15 20:39:55 2016

Asterisk developer's documentation


features.h File Reference

Call Parking and Pickup API Includes code and algorithms from the Zapata library. More...

#include "asterisk/pbx.h"
#include "asterisk/linkedlists.h"
Include dependency graph for features.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_call_feature

Defines

#define AST_FEATURE_RETURN_HANGUP   -1
#define AST_FEATURE_RETURN_KEEPTRYING   24
#define AST_FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
#define AST_FEATURE_RETURN_PARKFAILED   25
#define AST_FEATURE_RETURN_PASSDIGITS   21
#define AST_FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
#define AST_FEATURE_RETURN_STOREDIGITS   22
#define AST_FEATURE_RETURN_SUCCESS   23
#define AST_FEATURE_RETURN_SUCCESSBREAK   0
#define DEFAULT_PARKINGLOT   "default"
#define FEATURE_APP_ARGS_LEN   256
#define FEATURE_APP_LEN   64
#define FEATURE_EXTEN_LEN   32
#define FEATURE_MAX_LEN   11
#define FEATURE_MOH_LEN   80
#define FEATURE_SENSE_CHAN   (1 << 0)
#define FEATURE_SENSE_PEER   (1 << 1)
#define FEATURE_SNAME_LEN   32

Typedefs

typedef int(* ast_feature_operation )(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)

Enumerations

enum  {
  AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
  AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3)
}
 

main call feature structure

More...

Functions

int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
void ast_bridge_end_dtmf (struct ast_channel *chan, char digit, struct timeval start, const char *why)
 Simulate a DTMF end on a broken bridge channel.
int ast_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit)
 parse L option and read associated channel variables to set warning, warning frequency, and timelimit
int ast_can_pickup (struct ast_channel *chan)
 Test if a channel can be picked up.
int ast_do_pickup (struct ast_channel *chan, struct ast_channel *target)
 Pickup a call target.
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature)
 detect a feature before bridging
int ast_features_reload (void)
 Reload call features from features.conf.
struct ast_call_featureast_find_call_feature (const char *name)
 look for a call feature entry by its sname
int ast_masq_park_call (struct ast_channel *park_me, struct ast_channel *parker, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_masq_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout)
 Park a call and read back parked location.
int ast_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
 Park a call and read back parked location.
int ast_parking_ext_valid (const char *exten_str, struct ast_channel *chan, const char *context)
 Determine if parking extension exists in a given context.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
const char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_rdlock_call_features (void)
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unlock_call_features (void)
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set

Detailed Description

Call Parking and Pickup API Includes code and algorithms from the Zapata library.

Definition in file features.h.


Define Documentation

#define AST_FEATURE_RETURN_HANGUP   -1

Definition at line 39 of file features.h.

Referenced by builtin_disconnect().

#define AST_FEATURE_RETURN_KEEPTRYING   24

Definition at line 46 of file features.h.

Referenced by feature_exec_app(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 42 of file features.h.

#define AST_FEATURE_RETURN_PARKFAILED   25

Definition at line 47 of file features.h.

#define AST_FEATURE_RETURN_PASSDIGITS   21

Definition at line 43 of file features.h.

Referenced by ast_bridge_call(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 41 of file features.h.

#define AST_FEATURE_RETURN_STOREDIGITS   22

Definition at line 44 of file features.h.

Referenced by detect_disconnect(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_SUCCESS   23
#define AST_FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 40 of file features.h.

Referenced by builtin_blindtransfer(), and feature_exec_app().

#define DEFAULT_PARKINGLOT   "default"

Default parking lot

Definition at line 37 of file features.h.

Referenced by build_parkinglot(), load_config(), process_config(), and reload_config().

#define FEATURE_APP_ARGS_LEN   256

Definition at line 32 of file features.h.

Referenced by process_applicationmap_line().

#define FEATURE_APP_LEN   64

Definition at line 31 of file features.h.

Referenced by process_applicationmap_line().

#define FEATURE_EXTEN_LEN   32

Definition at line 34 of file features.h.

Referenced by process_applicationmap_line().

#define FEATURE_MAX_LEN   11

Definition at line 30 of file features.h.

Referenced by ast_bridge_call(), and wait_for_answer().

#define FEATURE_MOH_LEN   80

Definition at line 35 of file features.h.

Referenced by process_applicationmap_line().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 49 of file features.h.

Referenced by ast_bridge_call(), feature_exec_app(), and feature_interpret().

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 50 of file features.h.

Referenced by ast_bridge_call(), and set_peers().

#define FEATURE_SNAME_LEN   32

Definition at line 33 of file features.h.

Referenced by process_applicationmap_line().


Typedef Documentation

typedef int(* ast_feature_operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)

Definition at line 52 of file features.h.


Enumeration Type Documentation

anonymous enum

main call feature structure

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 56 of file features.h.

00056      {
00057    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00058    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00059    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00060    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00061    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00062    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00063 };


Function Documentation

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

Bridge a call, optionally allowing redirection.

Bridge a call, optionally allowing redirection.

Parameters:
chan The bridge considers this channel the caller.
peer The bridge considers this channel the callee.
config Configuration for this bridge.

Set start time, check for two channels,check if monitor on check for feature activation, create new CDR

Return values:
res on success.
-1 on failure to bridge.

append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.

Todo:
XXX how do we guarantee the latter ?

Definition at line 3944 of file features.c.

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

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

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

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

Simulate a DTMF end on a broken bridge channel.

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

Definition at line 3911 of file features.c.

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

Referenced by ast_bridge_call(), and ast_do_masquerade().

03912 {
03913    int dead;
03914    long duration;
03915 
03916    ast_channel_lock(chan);
03917    dead = ast_test_flag(chan, AST_FLAG_ZOMBIE)
03918       || (chan->_softhangup
03919          & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE));
03920    ast_channel_unlock(chan);
03921    if (dead) {
03922       /* Channel is a zombie or a real hangup. */
03923       return;
03924    }
03925 
03926    duration = ast_tvdiff_ms(ast_tvnow(), start);
03927    ast_senddigit_end(chan, digit, duration);
03928    ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n",
03929       digit, chan->name, why, duration);
03930 }

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

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

Referenced by bridge_exec(), and dial_exec_full().

07494 {
07495    char *stringp = ast_strdupa(parse);
07496    char *limit_str, *warning_str, *warnfreq_str;
07497    const char *var;
07498    int play_to_caller = 0, play_to_callee = 0;
07499    int delta;
07500 
07501    limit_str = strsep(&stringp, ":");
07502    warning_str = strsep(&stringp, ":");
07503    warnfreq_str = strsep(&stringp, ":");
07504 
07505    config->timelimit = atol(limit_str);
07506    if (warning_str)
07507       config->play_warning = atol(warning_str);
07508    if (warnfreq_str)
07509       config->warning_freq = atol(warnfreq_str);
07510 
07511    if (!config->timelimit) {
07512       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07513       config->timelimit = config->play_warning = config->warning_freq = 0;
07514       config->warning_sound = NULL;
07515       return -1; /* error */
07516    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07517       int w = config->warning_freq;
07518 
07519       /*
07520        * If the first warning is requested _after_ the entire call
07521        * would end, and no warning frequency is requested, then turn
07522        * off the warning. If a warning frequency is requested, reduce
07523        * the 'first warning' time by that frequency until it falls
07524        * within the call's total time limit.
07525        *
07526        * Graphically:
07527        *                timelim->|    delta        |<-playwarning
07528        *      0__________________|_________________|
07529        *                       | w  |    |    |    |
07530        *
07531        * so the number of intervals to cut is 1+(delta-1)/w
07532        */
07533       if (w == 0) {
07534          config->play_warning = 0;
07535       } else {
07536          config->play_warning -= w * ( 1 + (delta-1)/w );
07537          if (config->play_warning < 1)
07538             config->play_warning = config->warning_freq = 0;
07539       }
07540    }
07541    
07542    ast_channel_lock(chan);
07543 
07544    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07545    play_to_caller = var ? ast_true(var) : 1;
07546 
07547    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07548    play_to_callee = var ? ast_true(var) : 0;
07549 
07550    if (!play_to_caller && !play_to_callee)
07551       play_to_caller = 1;
07552 
07553    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07554    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07555 
07556    /* The code looking at config wants a NULL, not just "", to decide
07557     * that the message should not be played, so we replace "" with NULL.
07558     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
07559     * not found.
07560     */
07561 
07562    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07563    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07564 
07565    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07566    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07567 
07568    ast_channel_unlock(chan);
07569 
07570    /* undo effect of S(x) in case they are both used */
07571    calldurationlimit->tv_sec = 0;
07572    calldurationlimit->tv_usec = 0;
07573 
07574    /* more efficient to do it like S(x) does since no advanced opts */
07575    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07576       calldurationlimit->tv_sec = config->timelimit / 1000;
07577       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07578       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07579          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07580       config->timelimit = play_to_caller = play_to_callee =
07581       config->play_warning = config->warning_freq = 0;
07582    } else {
07583       ast_verb(4, "Limit Data for this call:\n");
07584       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07585       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07586       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07587       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07588       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07589       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
07590       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
07591       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
07592    }
07593    if (play_to_caller)
07594       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07595    if (play_to_callee)
07596       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07597    return 0;
07598 }

int ast_can_pickup ( struct ast_channel chan  ) 

Test if a channel can be picked up.

Parameters:
chan Channel to test if can be picked up.
Note:
This function assumes that chan is locked.
Returns:
TRUE if channel can be picked up.

Definition at line 7298 of file features.c.

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

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

07299 {
07300    if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07301       && (chan->_state == AST_STATE_RINGING
07302          || chan->_state == AST_STATE_RING
07303          /*
07304           * Check the down state as well because some SIP devices do not
07305           * give 180 ringing when they can just give 183 session progress
07306           * instead.  Issue 14005.  (Some ISDN switches as well for that
07307           * matter.)
07308           */
07309          || chan->_state == AST_STATE_DOWN)
07310       && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07311       return 1;
07312    }
07313    return 0;
07314 }

int ast_do_pickup ( struct ast_channel chan,
struct ast_channel target 
)

Pickup a call target.

Parameters:
chan channel that initiated pickup.
target channel to be picked up.
Note:
This function assumes that target is locked.
Return values:
0 on success.
-1 on failure.

< A masquerade changes channel names.

< A masquerade changes channel names.

Definition at line 7374 of file features.c.

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

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

07375 {
07376    struct ast_party_connected_line connected_caller;
07377    struct ast_channel *chans[2] = { chan, target };
07378    struct ast_datastore *ds_pickup;
07379    const char *chan_name;/*!< A masquerade changes channel names. */
07380    const char *target_name;/*!< A masquerade changes channel names. */
07381    int res = -1;
07382 
07383    target_name = ast_strdupa(target->name);
07384    ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name);
07385 
07386    /* Mark the target to block any call pickup race. */
07387    ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07388    if (!ds_pickup) {
07389       ast_log(LOG_WARNING,
07390          "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07391       return -1;
07392    }
07393    ast_channel_datastore_add(target, ds_pickup);
07394 
07395    ast_party_connected_line_init(&connected_caller);
07396    ast_party_connected_line_copy(&connected_caller, &target->connected);
07397    ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
07398    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07399    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07400       ast_channel_update_connected_line(chan, &connected_caller, NULL);
07401    }
07402    ast_party_connected_line_free(&connected_caller);
07403 
07404    ast_channel_lock(chan);
07405    chan_name = ast_strdupa(chan->name);
07406    ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07407    ast_channel_unlock(chan);
07408    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07409 
07410    ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07411 
07412    if (ast_answer(chan)) {
07413       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07414       goto pickup_failed;
07415    }
07416 
07417    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07418       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07419       goto pickup_failed;
07420    }
07421    
07422    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07423 
07424    /* setting this flag to generate a reason header in the cancel message to the ringing channel */
07425    ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07426 
07427    if (ast_channel_masquerade(target, chan)) {
07428       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07429          target_name);
07430       goto pickup_failed;
07431    }
07432 
07433    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
07434    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07435       "Channel: %s\r\n"
07436       "TargetChannel: %s\r\n",
07437       chan_name, target_name);
07438 
07439    /* Do the masquerade manually to make sure that it is completed. */
07440    ast_do_masquerade(target);
07441    res = 0;
07442 
07443 pickup_failed:
07444    ast_channel_lock(target);
07445    if (!ast_channel_datastore_remove(target, ds_pickup)) {
07446       ast_datastore_free(ds_pickup);
07447    }
07448    ast_party_connected_line_free(&connected_caller);
07449 
07450    return res;
07451 }

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

References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

03418                                                                                                                                  {
03419 
03420    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03421 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 6839 of file features.c.

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

Referenced by handle_features_reload().

06840 {
06841    struct ast_context *con;
06842    int res;
06843 
06844    ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
06845 
06846    /*
06847     * Always destroy the parking_con_dial context to remove buildup
06848     * of recalled extensions in the context.  At worst, the parked
06849     * call gets hungup attempting to run an invalid extension when
06850     * we are trying to callback the parker or the preset return
06851     * extension.  This is a small window of opportunity on an
06852     * execution chain that is not expected to happen very often.
06853     */
06854    con = ast_context_find(parking_con_dial);
06855    if (con) {
06856       ast_context_destroy(con, registrar);
06857    }
06858 
06859    res = load_config(1);
06860    ast_mutex_unlock(&features_reload_lock);
06861 
06862    return res;
06863 }

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

look for a call feature entry by its sname

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

Definition at line 3144 of file features.c.

References FEATURES_COUNT, and ast_call_feature::sname.

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

03145 {
03146    int x;
03147    for (x = 0; x < FEATURES_COUNT; x++) {
03148       if (!strcasecmp(name, builtin_features[x].sname))
03149          return &builtin_features[x];
03150    }
03151    return NULL;
03152 }

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

Park a call via a masqueraded channel.

Parameters:
park_me Channel to be parked.
parker Channel parking the call.
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.

Masquerade the park_me channel into a new, empty channel which is then parked.

Note:
Use ast_masq_park_call_exten() instead.
Return values:
0 on success.
-1 on failure.

Definition at line 1850 of file features.c.

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

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

01851 {
01852    struct ast_park_call_args args = {
01853       .timeout = timeout,
01854       .extout = extout,
01855    };
01856 
01857    if (peer) {
01858       args.orig_chan_name = ast_strdupa(peer->name);
01859    }
01860    return masq_park_call(rchan, peer, &args);
01861 }

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

Park a call via a masqueraded channel.

Since:
1.8.9
Parameters:
park_me Channel to be parked.
parker Channel parking the call.
park_exten Parking lot access extension
park_context Parking lot context
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.

Masquerade the park_me channel into a new, empty channel which is then parked.

Return values:
0 on success.
-1 on failure.

Definition at line 1796 of file features.c.

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

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

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

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

Park a call and read back parked location.

Parameters:
park_me Channel to be parked.
parker Channel parking the call.
timeout is a timeout in milliseconds
park_exten Parking lot access extension (Not used)
extout is a parameter to an int that will hold the parked location, or NULL if you want.

Park the park_me channel, and read back the parked location to the parker channel. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context).

Note:
Use ast_park_call_exten() instead.
Return values:
0 on success.
-1 on failure.

Definition at line 1699 of file features.c.

References park_call_full(), and ast_park_call_args::timeout.

01700 {
01701    struct ast_park_call_args args = {
01702       .timeout = timeout,
01703       .extout = extout,
01704    };
01705 
01706    return park_call_full(park_me, parker, &args);
01707 }

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

Park a call and read back parked location.

Since:
1.8.9
Parameters:
park_me Channel to be parked.
parker Channel parking the call.
park_exten Parking lot access extension
park_context Parking lot context
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.

Park the park_me channel, and read back the parked location to the parker channel. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context).

Return values:
0 on success.
-1 on failure.

Definition at line 1648 of file features.c.

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

Referenced by iax_park_thread(), and sip_park_thread().

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

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

Determine if parking extension exists in a given context.

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

Definition at line 840 of file features.c.

References get_parking_exten().

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

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

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Parameters:
chan channel that initiated pickup.

Walk list of channels, checking it is not itself, channel is pbx one, check that the callgroup for both channels are the same and the channel is ringing. Answer calling channel, flag channel as answered on queue, masq channels together.

< Potential pickup target

Definition at line 7340 of file features.c.

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

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

07341 {
07342    struct ast_channel *target;/*!< Potential pickup target */
07343    int res = -1;
07344    ast_debug(1, "pickup attempt by %s\n", chan->name);
07345 
07346    /* The found channel is already locked. */
07347    target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07348    if (target) {
07349       ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
07350 
07351       res = ast_do_pickup(chan, target);
07352       ast_channel_unlock(target);
07353       if (!res) {
07354          if (!ast_strlen_zero(pickupsound)) {
07355             pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07356          }
07357       } else {
07358          ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name);
07359       }
07360       target = ast_channel_unref(target);
07361    }
07362 
07363    if (res < 0) {
07364       ast_debug(1, "No call pickup possible... for %s\n", chan->name);
07365       if (!ast_strlen_zero(pickupfailsound)) {
07366          ast_answer(chan);
07367          ast_stream_and_wait(chan, pickupfailsound, "");
07368       }
07369    }
07370 
07371    return res;
07372 }

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

Definition at line 3134 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

03135 {
03136    ast_rwlock_rdlock(&features_lock);
03137 }

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

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

Referenced by process_applicationmap_line().

02979 {
02980    if (!feature) {
02981       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02982       return;
02983    }
02984   
02985    AST_RWLIST_WRLOCK(&feature_list);
02986    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02987    AST_RWLIST_UNLOCK(&feature_list);
02988 
02989    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02990 }

void ast_unlock_call_features ( void   ) 

Definition at line 3139 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

03140 {
03141    ast_rwlock_unlock(&features_lock);
03142 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

03059 {
03060    if (!feature) {
03061       return;
03062    }
03063 
03064    AST_RWLIST_WRLOCK(&feature_list);
03065    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
03066    AST_RWLIST_UNLOCK(&feature_list);
03067 
03068    ast_free(feature);
03069 }


Generated on 15 Apr 2016 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1