Mon Oct 8 12:39:22 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"

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

Definition at line 45 of file features.h.

Referenced by ast_bridge_call(), builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), builtin_parkcall(), feature_exec_app(), feature_interpret_helper(), and xfer_park_call_helper().

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

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

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_cdr::answer, 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_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(), config, ast_channel::context, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_party_caller::id, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, monitor_app, monitor_ok, ast_channel::name, 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, S_COR, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_party_number::str, ast_cdr::uniqueid, ast_cdr::userfield, ast_party_number::valid, and ast_channel::visible_indication.

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

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

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

References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, config, LOG_WARNING, pbx_builtin_getvar_helper(), S_OR, strsep(), and var.

Referenced by bridge_exec(), and dial_exec_full().

07446 {
07447    char *stringp = ast_strdupa(parse);
07448    char *limit_str, *warning_str, *warnfreq_str;
07449    const char *var;
07450    int play_to_caller = 0, play_to_callee = 0;
07451    int delta;
07452 
07453    limit_str = strsep(&stringp, ":");
07454    warning_str = strsep(&stringp, ":");
07455    warnfreq_str = strsep(&stringp, ":");
07456 
07457    config->timelimit = atol(limit_str);
07458    if (warning_str)
07459       config->play_warning = atol(warning_str);
07460    if (warnfreq_str)
07461       config->warning_freq = atol(warnfreq_str);
07462 
07463    if (!config->timelimit) {
07464       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07465       config->timelimit = config->play_warning = config->warning_freq = 0;
07466       config->warning_sound = NULL;
07467       return -1; /* error */
07468    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07469       int w = config->warning_freq;
07470 
07471       /*
07472        * If the first warning is requested _after_ the entire call
07473        * would end, and no warning frequency is requested, then turn
07474        * off the warning. If a warning frequency is requested, reduce
07475        * the 'first warning' time by that frequency until it falls
07476        * within the call's total time limit.
07477        *
07478        * Graphically:
07479        *                timelim->|    delta        |<-playwarning
07480        *      0__________________|_________________|
07481        *                       | w  |    |    |    |
07482        *
07483        * so the number of intervals to cut is 1+(delta-1)/w
07484        */
07485       if (w == 0) {
07486          config->play_warning = 0;
07487       } else {
07488          config->play_warning -= w * ( 1 + (delta-1)/w );
07489          if (config->play_warning < 1)
07490             config->play_warning = config->warning_freq = 0;
07491       }
07492    }
07493    
07494    ast_channel_lock(chan);
07495 
07496    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07497    play_to_caller = var ? ast_true(var) : 1;
07498 
07499    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07500    play_to_callee = var ? ast_true(var) : 0;
07501 
07502    if (!play_to_caller && !play_to_callee)
07503       play_to_caller = 1;
07504 
07505    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07506    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07507 
07508    /* The code looking at config wants a NULL, not just "", to decide
07509     * that the message should not be played, so we replace "" with NULL.
07510     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
07511     * not found.
07512     */
07513 
07514    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07515    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07516 
07517    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07518    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07519 
07520    ast_channel_unlock(chan);
07521 
07522    /* undo effect of S(x) in case they are both used */
07523    calldurationlimit->tv_sec = 0;
07524    calldurationlimit->tv_usec = 0;
07525 
07526    /* more efficient to do it like S(x) does since no advanced opts */
07527    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07528       calldurationlimit->tv_sec = config->timelimit / 1000;
07529       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07530       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07531          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07532       config->timelimit = play_to_caller = play_to_callee =
07533       config->play_warning = config->warning_freq = 0;
07534    } else {
07535       ast_verb(4, "Limit Data for this call:\n");
07536       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07537       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07538       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07539       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07540       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07541       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
07542       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
07543       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
07544    }
07545    if (play_to_caller)
07546       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07547    if (play_to_callee)
07548       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07549    return 0;
07550 }

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 7250 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, ast_channel::pbx, and pickup_active.

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

07251 {
07252    if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07253       && (chan->_state == AST_STATE_RINGING
07254          || chan->_state == AST_STATE_RING
07255          /*
07256           * Check the down state as well because some SIP devices do not
07257           * give 180 ringing when they can just give 183 session progress
07258           * instead.  Issue 14005.  (Some ISDN switches as well for that
07259           * matter.)
07260           */
07261          || chan->_state == AST_STATE_DOWN)
07262       && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07263       return 1;
07264    }
07265    return 0;
07266 }

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 7326 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, EVENT_FLAG_CALL, LOG_WARNING, ast_channel::name, pickup_active, 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().

07327 {
07328    struct ast_party_connected_line connected_caller;
07329    struct ast_channel *chans[2] = { chan, target };
07330    struct ast_datastore *ds_pickup;
07331    const char *chan_name;/*!< A masquerade changes channel names. */
07332    const char *target_name;/*!< A masquerade changes channel names. */
07333    int res = -1;
07334 
07335    target_name = ast_strdupa(target->name);
07336    ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name);
07337 
07338    /* Mark the target to block any call pickup race. */
07339    ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07340    if (!ds_pickup) {
07341       ast_log(LOG_WARNING,
07342          "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07343       return -1;
07344    }
07345    ast_channel_datastore_add(target, ds_pickup);
07346 
07347    ast_party_connected_line_init(&connected_caller);
07348    ast_party_connected_line_copy(&connected_caller, &target->connected);
07349    ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
07350    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07351    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07352       ast_channel_update_connected_line(chan, &connected_caller, NULL);
07353    }
07354    ast_party_connected_line_free(&connected_caller);
07355 
07356    ast_channel_lock(chan);
07357    chan_name = ast_strdupa(chan->name);
07358    ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07359    ast_channel_unlock(chan);
07360    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07361 
07362    ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07363 
07364    if (ast_answer(chan)) {
07365       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07366       goto pickup_failed;
07367    }
07368 
07369    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07370       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07371       goto pickup_failed;
07372    }
07373    
07374    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07375 
07376    /* setting this flag to generate a reason header in the cancel message to the ringing channel */
07377    ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07378 
07379    if (ast_channel_masquerade(target, chan)) {
07380       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07381          target_name);
07382       goto pickup_failed;
07383    }
07384 
07385    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
07386    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07387       "Channel: %s\r\n"
07388       "TargetChannel: %s\r\n",
07389       chan_name, target_name);
07390 
07391    /* Do the masquerade manually to make sure that it is completed. */
07392    ast_do_masquerade(target);
07393    res = 0;
07394 
07395 pickup_failed:
07396    ast_channel_lock(target);
07397    if (!ast_channel_datastore_remove(target, ds_pickup)) {
07398       ast_datastore_free(ds_pickup);
07399    }
07400    ast_party_connected_line_free(&connected_caller);
07401 
07402    return res;
07403 }

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

References feature_group_exten::feature, FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

03401                                                                                                                                  {
03402 
03403    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03404 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

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

06792 {
06793    struct ast_context *con;
06794    int res;
06795 
06796    ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
06797 
06798    /*
06799     * Always destroy the parking_con_dial context to remove buildup
06800     * of recalled extensions in the context.  At worst, the parked
06801     * call gets hungup attempting to run an invalid extension when
06802     * we are trying to callback the parker or the preset return
06803     * extension.  This is a small window of opportunity on an
06804     * execution chain that is not expected to happen very often.
06805     */
06806    con = ast_context_find(parking_con_dial);
06807    if (con) {
06808       ast_context_destroy(con, registrar);
06809    }
06810 
06811    res = load_config(1);
06812    ast_mutex_unlock(&features_reload_lock);
06813 
06814    return res;
06815 }

struct ast_call_feature* ast_find_call_feature ( const char *  name  ) 

look for a call feature entry by its sname

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

Definition at line 3133 of file features.c.

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

03134 {
03135    int x;
03136    for (x = 0; x < FEATURES_COUNT; x++) {
03137       if (!strcasecmp(name, builtin_features[x].sname))
03138          return &builtin_features[x];
03139    }
03140    return NULL;
03141 }

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

References args, ast_strdupa, masq_park_call(), and ast_channel::name.

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

01846 {
01847    struct ast_park_call_args args = {
01848       .timeout = timeout,
01849       .extout = extout,
01850    };
01851 
01852    if (peer) {
01853       args.orig_chan_name = ast_strdupa(peer->name);
01854    }
01855    return masq_park_call(rchan, peer, &args);
01856 }

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

References args, ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), feature_group_exten::exten, find_parkinglot(), get_parking_exten(), masq_park_call(), ast_channel::name, parkeddynamic, parkinglot_unref(), parse(), and park_app_args::pl_name.

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

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

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

References args, and park_call_full().

01695 {
01696    struct ast_park_call_args args = {
01697       .timeout = timeout,
01698       .extout = extout,
01699    };
01700 
01701    return park_call_full(park_me, parker, &args);
01702 }

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

References args, ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), feature_group_exten::exten, find_parkinglot(), get_parking_exten(), park_call_full(), parkeddynamic, parkinglot_unref(), parse(), and park_app_args::pl_name.

Referenced by iax_park_thread(), and sip_park_thread().

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

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

Determine if parking extension exists in a given context.

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

Definition at line 840 of file features.c.

References get_parking_exten().

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

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

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

< Potential pickup target

Definition at line 7292 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, ast_channel::name, pbx_builtin_setvar_helper(), pickupfailsound, and pickupsound.

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

07293 {
07294    struct ast_channel *target;/*!< Potential pickup target */
07295    int res = -1;
07296    ast_debug(1, "pickup attempt by %s\n", chan->name);
07297 
07298    /* The found channel is already locked. */
07299    target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07300    if (target) {
07301       ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
07302 
07303       res = ast_do_pickup(chan, target);
07304       ast_channel_unlock(target);
07305       if (!res) {
07306          if (!ast_strlen_zero(pickupsound)) {
07307             pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07308          }
07309       } else {
07310          ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name);
07311       }
07312       target = ast_channel_unref(target);
07313    }
07314 
07315    if (res < 0) {
07316       ast_debug(1, "No call pickup possible... for %s\n", chan->name);
07317       if (!ast_strlen_zero(pickupfailsound)) {
07318          ast_answer(chan);
07319          ast_stream_and_wait(chan, pickupfailsound, "");
07320       }
07321    }
07322 
07323    return res;
07324 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 845 of file features.c.

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

00846 {
00847    return pickup_ext;
00848 }

void ast_rdlock_call_features ( void   ) 

Definition at line 3123 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

03124 {
03125    ast_rwlock_rdlock(&features_lock);
03126 }

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

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

Referenced by process_applicationmap_line().

02968 {
02969    if (!feature) {
02970       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02971       return;
02972    }
02973   
02974    AST_RWLIST_WRLOCK(&feature_list);
02975    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02976    AST_RWLIST_UNLOCK(&feature_list);
02977 
02978    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02979 }

void ast_unlock_call_features ( void   ) 

Definition at line 3128 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

03129 {
03130    ast_rwlock_unlock(&features_lock);
03131 }

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

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

03048 {
03049    if (!feature) {
03050       return;
03051    }
03052 
03053    AST_RWLIST_WRLOCK(&feature_list);
03054    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
03055    AST_RWLIST_UNLOCK(&feature_list);
03056 
03057    ast_free(feature);
03058 }


Generated on Mon Oct 8 12:39:22 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7