Fri Feb 10 06:36:04 2012

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.
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(), gtalk_load_config(), 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 3851 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_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_accountcode(), 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_NAME, ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_uniqueid(), 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_MCID, AST_CONTROL_OPTION, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, ast_opt_transmit_silence, AST_OPTION_AUDIO_MODE, AST_OPTION_DIGIT_DETECT, AST_OPTION_FAX_DETECT, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_UNBRIDGE, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_write(), ast_channel::caller, ast_channel::cdr, ast_cdr::channel, clear_dialed_interfaces(), 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, ast_frame::len, 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, 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().

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

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 7390 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, strsep(), ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by bridge_exec(), and dial_exec_full().

07392 {
07393    char *stringp = ast_strdupa(parse);
07394    char *limit_str, *warning_str, *warnfreq_str;
07395    const char *var;
07396    int play_to_caller = 0, play_to_callee = 0;
07397    int delta;
07398 
07399    limit_str = strsep(&stringp, ":");
07400    warning_str = strsep(&stringp, ":");
07401    warnfreq_str = strsep(&stringp, ":");
07402 
07403    config->timelimit = atol(limit_str);
07404    if (warning_str)
07405       config->play_warning = atol(warning_str);
07406    if (warnfreq_str)
07407       config->warning_freq = atol(warnfreq_str);
07408 
07409    if (!config->timelimit) {
07410       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07411       config->timelimit = config->play_warning = config->warning_freq = 0;
07412       config->warning_sound = NULL;
07413       return -1; /* error */
07414    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07415       int w = config->warning_freq;
07416 
07417       /*
07418        * If the first warning is requested _after_ the entire call
07419        * would end, and no warning frequency is requested, then turn
07420        * off the warning. If a warning frequency is requested, reduce
07421        * the 'first warning' time by that frequency until it falls
07422        * within the call's total time limit.
07423        *
07424        * Graphically:
07425        *                timelim->|    delta        |<-playwarning
07426        *      0__________________|_________________|
07427        *                       | w  |    |    |    |
07428        *
07429        * so the number of intervals to cut is 1+(delta-1)/w
07430        */
07431       if (w == 0) {
07432          config->play_warning = 0;
07433       } else {
07434          config->play_warning -= w * ( 1 + (delta-1)/w );
07435          if (config->play_warning < 1)
07436             config->play_warning = config->warning_freq = 0;
07437       }
07438    }
07439    
07440    ast_channel_lock(chan);
07441 
07442    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07443    play_to_caller = var ? ast_true(var) : 1;
07444 
07445    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07446    play_to_callee = var ? ast_true(var) : 0;
07447 
07448    if (!play_to_caller && !play_to_callee)
07449       play_to_caller = 1;
07450 
07451    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07452    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07453 
07454    /* The code looking at config wants a NULL, not just "", to decide
07455     * that the message should not be played, so we replace "" with NULL.
07456     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
07457     * not found.
07458     */
07459 
07460    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07461    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07462 
07463    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07464    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07465 
07466    ast_channel_unlock(chan);
07467 
07468    /* undo effect of S(x) in case they are both used */
07469    calldurationlimit->tv_sec = 0;
07470    calldurationlimit->tv_usec = 0;
07471 
07472    /* more efficient to do it like S(x) does since no advanced opts */
07473    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07474       calldurationlimit->tv_sec = config->timelimit / 1000;
07475       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07476       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07477          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07478       config->timelimit = play_to_caller = play_to_callee =
07479       config->play_warning = config->warning_freq = 0;
07480    } else {
07481       ast_verb(4, "Limit Data for this call:\n");
07482       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07483       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07484       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07485       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07486       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07487       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
07488       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
07489       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
07490    }
07491    if (play_to_caller)
07492       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07493    if (play_to_callee)
07494       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07495    return 0;
07496 }

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

07198 {
07199    if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07200       && (chan->_state == AST_STATE_RINGING
07201          || chan->_state == AST_STATE_RING
07202          /*
07203           * Check the down state as well because some SIP devices do not
07204           * give 180 ringing when they can just give 183 session progress
07205           * instead.  Issue 14005.  (Some ISDN switches as well for that
07206           * matter.)
07207           */
07208          || chan->_state == AST_STATE_DOWN)
07209       && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07210       return 1;
07211    }
07212    return 0;
07213 }

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 7273 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_name(), 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().

07274 {
07275    struct ast_party_connected_line connected_caller;
07276    struct ast_channel *chans[2] = { chan, target };
07277    struct ast_datastore *ds_pickup;
07278    const char *chan_name;/*!< A masquerade changes channel names. */
07279    const char *target_name;/*!< A masquerade changes channel names. */
07280    int res = -1;
07281 
07282    target_name = ast_strdupa(ast_channel_name(target));
07283    ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));
07284 
07285    /* Mark the target to block any call pickup race. */
07286    ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07287    if (!ds_pickup) {
07288       ast_log(LOG_WARNING,
07289          "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07290       return -1;
07291    }
07292    ast_channel_datastore_add(target, ds_pickup);
07293 
07294    ast_party_connected_line_init(&connected_caller);
07295    ast_party_connected_line_copy(&connected_caller, &target->connected);
07296    ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
07297    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07298    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07299       ast_channel_update_connected_line(chan, &connected_caller, NULL);
07300    }
07301    ast_party_connected_line_free(&connected_caller);
07302 
07303    ast_channel_lock(chan);
07304    chan_name = ast_strdupa(ast_channel_name(chan));
07305    ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07306    ast_channel_unlock(chan);
07307    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07308    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07309    ast_party_connected_line_free(&connected_caller);
07310 
07311    ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07312 
07313    if (ast_answer(chan)) {
07314       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07315       goto pickup_failed;
07316    }
07317 
07318    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07319       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07320       goto pickup_failed;
07321    }
07322    
07323    /* setting this flag to generate a reason header in the cancel message to the ringing channel */
07324    ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07325 
07326    if (ast_channel_masquerade(target, chan)) {
07327       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07328          target_name);
07329       goto pickup_failed;
07330    }
07331 
07332    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
07333    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07334       "Channel: %s\r\n"
07335       "TargetChannel: %s\r\n",
07336       chan_name, target_name);
07337 
07338    /* Do the masquerade manually to make sure that it is completed. */
07339    ast_do_masquerade(target);
07340    res = 0;
07341 
07342 pickup_failed:
07343    ast_channel_lock(target);
07344    if (!ast_channel_datastore_remove(target, ds_pickup)) {
07345       ast_datastore_free(ds_pickup);
07346    }
07347 
07348    return res;
07349 }

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

References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

03286                                                                                                                                  {
03287 
03288    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03289 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

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

06760 {
06761    struct ast_context *con;
06762    int res;
06763 
06764    ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
06765 
06766    /*
06767     * Always destroy the parking_con_dial context to remove buildup
06768     * of recalled extensions in the context.  At worst, the parked
06769     * call gets hungup attempting to run an invalid extension when
06770     * we are trying to callback the parker or the preset return
06771     * extension.  This is a small window of opportunity on an
06772     * execution chain that is not expected to happen very often.
06773     */
06774    con = ast_context_find(parking_con_dial);
06775    if (con) {
06776       ast_context_destroy(con, registrar);
06777    }
06778 
06779    res = load_config(1);
06780    ast_mutex_unlock(&features_reload_lock);
06781 
06782    return res;
06783 }

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

References FEATURES_COUNT, find_dynamic_feature(), and ast_call_feature::sname.

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

03020 {
03021    int x;
03022    for (x = 0; x < FEATURES_COUNT; x++) {
03023       if (!strcasecmp(name, builtin_features[x].sname))
03024          return &builtin_features[x];
03025    }
03026 
03027    return find_dynamic_feature(name);
03028 }

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

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

01765 {
01766    struct ast_park_call_args args = {
01767       .timeout = timeout,
01768       .extout = extout,
01769    };
01770 
01771    if (peer) {
01772       args.orig_chan_name = ast_strdupa(ast_channel_name(peer));
01773    }
01774    return masq_park_call(rchan, peer, &args);
01775 }

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

References ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), 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().

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

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

References park_call_full(), and ast_park_call_args::timeout.

01614 {
01615    struct ast_park_call_args args = {
01616       .timeout = timeout,
01617       .extout = extout,
01618    };
01619 
01620    return park_call_full(park_me, parker, &args);
01621 }

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

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

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

00802 {
00803    return get_parking_exten(exten_str, chan, context) ? 1 : 0;
00804 }

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

References ast_answer(), ast_channel_callback(), ast_channel_name(), 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().

07240 {
07241    struct ast_channel *target;/*!< Potential pickup target */
07242    int res = -1;
07243    ast_debug(1, "pickup attempt by %s\n", ast_channel_name(chan));
07244 
07245    /* The found channel is already locked. */
07246    target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07247    if (target) {
07248       ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan));
07249 
07250       res = ast_do_pickup(chan, target);
07251       ast_channel_unlock(target);
07252       if (!res) {
07253          if (!ast_strlen_zero(pickupsound)) {
07254             pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07255          }
07256       } else {
07257          ast_log(LOG_WARNING, "pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan));
07258       }
07259       target = ast_channel_unref(target);
07260    }
07261 
07262    if (res < 0) {
07263       ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan));
07264       if (!ast_strlen_zero(pickupfailsound)) {
07265          ast_answer(chan);
07266          ast_stream_and_wait(chan, pickupfailsound, "");
07267       }
07268    }
07269 
07270    return res;
07271 }

const char* ast_pickup_ext ( void   ) 

void ast_rdlock_call_features ( void   ) 

Definition at line 3009 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

03010 {
03011    ast_rwlock_rdlock(&features_lock);
03012 }

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

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

Referenced by process_applicationmap_line().

02854 {
02855    if (!feature) {
02856       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02857       return;
02858    }
02859   
02860    AST_RWLIST_WRLOCK(&feature_list);
02861    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02862    AST_RWLIST_UNLOCK(&feature_list);
02863 
02864    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02865 }

void ast_unlock_call_features ( void   ) 

Definition at line 3014 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

03015 {
03016    ast_rwlock_unlock(&features_lock);
03017 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

02934 {
02935    if (!feature) {
02936       return;
02937    }
02938 
02939    AST_RWLIST_WRLOCK(&feature_list);
02940    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02941    AST_RWLIST_UNLOCK(&feature_list);
02942 
02943    ast_free(feature);
02944 }


Generated on Fri Feb 10 06:36:05 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6