Thu Sep 7 01:03:28 2017

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"

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

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

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

03928 {
03929    int dead;
03930    long duration;
03931 
03932    ast_channel_lock(chan);
03933    dead = ast_test_flag(chan, AST_FLAG_ZOMBIE)
03934       || (chan->_softhangup
03935          & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE));
03936    ast_channel_unlock(chan);
03937    if (dead) {
03938       /* Channel is a zombie or a real hangup. */
03939       return;
03940    }
03941 
03942    duration = ast_tvdiff_ms(ast_tvnow(), start);
03943    ast_senddigit_end(chan, digit, duration);
03944    ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n",
03945       digit, chan->name, why, duration);
03946 }

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

07534 {
07535    char *stringp = ast_strdupa(parse);
07536    char *limit_str, *warning_str, *warnfreq_str;
07537    const char *var;
07538    int play_to_caller = 0, play_to_callee = 0;
07539    int delta;
07540 
07541    limit_str = strsep(&stringp, ":");
07542    warning_str = strsep(&stringp, ":");
07543    warnfreq_str = strsep(&stringp, ":");
07544 
07545    config->timelimit = atol(limit_str);
07546    if (warning_str)
07547       config->play_warning = atol(warning_str);
07548    if (warnfreq_str)
07549       config->warning_freq = atol(warnfreq_str);
07550 
07551    if (!config->timelimit) {
07552       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07553       config->timelimit = config->play_warning = config->warning_freq = 0;
07554       config->warning_sound = NULL;
07555       return -1; /* error */
07556    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07557       int w = config->warning_freq;
07558 
07559       /*
07560        * If the first warning is requested _after_ the entire call
07561        * would end, and no warning frequency is requested, then turn
07562        * off the warning. If a warning frequency is requested, reduce
07563        * the 'first warning' time by that frequency until it falls
07564        * within the call's total time limit.
07565        *
07566        * Graphically:
07567        *                timelim->|    delta        |<-playwarning
07568        *      0__________________|_________________|
07569        *                       | w  |    |    |    |
07570        *
07571        * so the number of intervals to cut is 1+(delta-1)/w
07572        */
07573       if (w == 0) {
07574          config->play_warning = 0;
07575       } else {
07576          config->play_warning -= w * ( 1 + (delta-1)/w );
07577          if (config->play_warning < 1)
07578             config->play_warning = config->warning_freq = 0;
07579       }
07580    }
07581    
07582    ast_channel_lock(chan);
07583 
07584    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07585    play_to_caller = var ? ast_true(var) : 1;
07586 
07587    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07588    play_to_callee = var ? ast_true(var) : 0;
07589 
07590    if (!play_to_caller && !play_to_callee)
07591       play_to_caller = 1;
07592 
07593    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07594    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07595 
07596    /* The code looking at config wants a NULL, not just "", to decide
07597     * that the message should not be played, so we replace "" with NULL.
07598     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
07599     * not found.
07600     */
07601 
07602    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07603    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07604 
07605    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07606    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07607 
07608    ast_channel_unlock(chan);
07609 
07610    /* undo effect of S(x) in case they are both used */
07611    calldurationlimit->tv_sec = 0;
07612    calldurationlimit->tv_usec = 0;
07613 
07614    /* more efficient to do it like S(x) does since no advanced opts */
07615    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07616       calldurationlimit->tv_sec = config->timelimit / 1000;
07617       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07618       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07619          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07620       config->timelimit = play_to_caller = play_to_callee =
07621       config->play_warning = config->warning_freq = 0;
07622    } else {
07623       ast_verb(4, "Limit Data for this call:\n");
07624       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07625       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07626       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07627       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07628       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07629       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
07630       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
07631       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
07632    }
07633    if (play_to_caller)
07634       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07635    if (play_to_callee)
07636       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07637    return 0;
07638 }

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

07339 {
07340    if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07341       && (chan->_state == AST_STATE_RINGING
07342          || chan->_state == AST_STATE_RING
07343          /*
07344           * Check the down state as well because some SIP devices do not
07345           * give 180 ringing when they can just give 183 session progress
07346           * instead.  Issue 14005.  (Some ISDN switches as well for that
07347           * matter.)
07348           */
07349          || chan->_state == AST_STATE_DOWN)
07350       && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07351       return 1;
07352    }
07353    return 0;
07354 }

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

07415 {
07416    struct ast_party_connected_line connected_caller;
07417    struct ast_channel *chans[2] = { chan, target };
07418    struct ast_datastore *ds_pickup;
07419    const char *chan_name;/*!< A masquerade changes channel names. */
07420    const char *target_name;/*!< A masquerade changes channel names. */
07421    int res = -1;
07422 
07423    target_name = ast_strdupa(target->name);
07424    ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name);
07425 
07426    /* Mark the target to block any call pickup race. */
07427    ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07428    if (!ds_pickup) {
07429       ast_log(LOG_WARNING,
07430          "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07431       return -1;
07432    }
07433    ast_channel_datastore_add(target, ds_pickup);
07434 
07435    ast_party_connected_line_init(&connected_caller);
07436    ast_party_connected_line_copy(&connected_caller, &target->connected);
07437    ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
07438    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07439    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07440       ast_channel_update_connected_line(chan, &connected_caller, NULL);
07441    }
07442    ast_party_connected_line_free(&connected_caller);
07443 
07444    ast_channel_lock(chan);
07445    chan_name = ast_strdupa(chan->name);
07446    ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07447    ast_channel_unlock(chan);
07448    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07449 
07450    ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07451 
07452    if (ast_answer(chan)) {
07453       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07454       goto pickup_failed;
07455    }
07456 
07457    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07458       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07459       goto pickup_failed;
07460    }
07461    
07462    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07463 
07464    /* setting this flag to generate a reason header in the cancel message to the ringing channel */
07465    ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07466 
07467    if (ast_channel_masquerade(target, chan)) {
07468       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07469          target_name);
07470       goto pickup_failed;
07471    }
07472 
07473    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
07474    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07475       "Channel: %s\r\n"
07476       "TargetChannel: %s\r\n",
07477       chan_name, target_name);
07478 
07479    /* Do the masquerade manually to make sure that it is completed. */
07480    ast_do_masquerade(target);
07481    res = 0;
07482 
07483 pickup_failed:
07484    ast_channel_lock(target);
07485    if (!ast_channel_datastore_remove(target, ds_pickup)) {
07486       ast_datastore_free(ds_pickup);
07487    }
07488    ast_party_connected_line_free(&connected_caller);
07489 
07490    return res;
07491 }

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

References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

03434                                                                                                                                  {
03435 
03436    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03437 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

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

06880 {
06881    struct ast_context *con;
06882    int res;
06883 
06884    ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
06885 
06886    /*
06887     * Always destroy the parking_con_dial context to remove buildup
06888     * of recalled extensions in the context.  At worst, the parked
06889     * call gets hungup attempting to run an invalid extension when
06890     * we are trying to callback the parker or the preset return
06891     * extension.  This is a small window of opportunity on an
06892     * execution chain that is not expected to happen very often.
06893     */
06894    con = ast_context_find(parking_con_dial);
06895    if (con) {
06896       ast_context_destroy(con, registrar);
06897    }
06898 
06899    res = load_config(1);
06900    ast_mutex_unlock(&features_reload_lock);
06901 
06902    return res;
06903 }

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

References FEATURES_COUNT, and ast_call_feature::sname.

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

03161 {
03162    int x;
03163    for (x = 0; x < FEATURES_COUNT; x++) {
03164       if (!strcasecmp(name, builtin_features[x].sname))
03165          return &builtin_features[x];
03166    }
03167    return NULL;
03168 }

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

01858 {
01859    struct ast_park_call_args args = {
01860       .timeout = timeout,
01861       .extout = extout,
01862    };
01863 
01864    if (peer) {
01865       args.orig_chan_name = ast_strdupa(peer->name);
01866    }
01867    return masq_park_call(rchan, peer, &args);
01868 }

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

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

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

References park_call_full(), and ast_park_call_args::timeout.

01707 {
01708    struct ast_park_call_args args = {
01709       .timeout = timeout,
01710       .extout = extout,
01711    };
01712 
01713    return park_call_full(park_me, parker, &args);
01714 }

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

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

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

00845 {
00846    return get_parking_exten(exten_str, chan, context) ? 1 : 0;
00847 }

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

07381 {
07382    struct ast_channel *target;/*!< Potential pickup target */
07383    int res = -1;
07384    ast_debug(1, "pickup attempt by %s\n", chan->name);
07385 
07386    /* The found channel is already locked. */
07387    target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07388    if (target) {
07389       ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
07390 
07391       res = ast_do_pickup(chan, target);
07392       ast_channel_unlock(target);
07393       if (!res) {
07394          if (!ast_strlen_zero(pickupsound)) {
07395             pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07396          }
07397       } else {
07398          ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name);
07399       }
07400       target = ast_channel_unref(target);
07401    }
07402 
07403    if (res < 0) {
07404       ast_debug(1, "No call pickup possible... for %s\n", chan->name);
07405       if (!ast_strlen_zero(pickupfailsound)) {
07406          ast_answer(chan);
07407          ast_stream_and_wait(chan, pickupfailsound, "");
07408       }
07409    }
07410 
07411    return res;
07412 }

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

Definition at line 3150 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

03151 {
03152    ast_rwlock_rdlock(&features_lock);
03153 }

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

02995 {
02996    if (!feature) {
02997       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02998       return;
02999    }
03000   
03001    AST_RWLIST_WRLOCK(&feature_list);
03002    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
03003    AST_RWLIST_UNLOCK(&feature_list);
03004 
03005    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
03006 }

void ast_unlock_call_features ( void   ) 

Definition at line 3155 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

03156 {
03157    ast_rwlock_unlock(&features_lock);
03158 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

03075 {
03076    if (!feature) {
03077       return;
03078    }
03079 
03080    AST_RWLIST_WRLOCK(&feature_list);
03081    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
03082    AST_RWLIST_UNLOCK(&feature_list);
03083 
03084    ast_free(feature);
03085 }


Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1