Sat Mar 10 01:55:23 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 3826 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_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().

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

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

07329 {
07330    char *stringp = ast_strdupa(parse);
07331    char *limit_str, *warning_str, *warnfreq_str;
07332    const char *var;
07333    int play_to_caller = 0, play_to_callee = 0;
07334    int delta;
07335 
07336    limit_str = strsep(&stringp, ":");
07337    warning_str = strsep(&stringp, ":");
07338    warnfreq_str = strsep(&stringp, ":");
07339 
07340    config->timelimit = atol(limit_str);
07341    if (warning_str)
07342       config->play_warning = atol(warning_str);
07343    if (warnfreq_str)
07344       config->warning_freq = atol(warnfreq_str);
07345 
07346    if (!config->timelimit) {
07347       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
07348       config->timelimit = config->play_warning = config->warning_freq = 0;
07349       config->warning_sound = NULL;
07350       return -1; /* error */
07351    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
07352       int w = config->warning_freq;
07353 
07354       /*
07355        * If the first warning is requested _after_ the entire call
07356        * would end, and no warning frequency is requested, then turn
07357        * off the warning. If a warning frequency is requested, reduce
07358        * the 'first warning' time by that frequency until it falls
07359        * within the call's total time limit.
07360        *
07361        * Graphically:
07362        *                timelim->|    delta        |<-playwarning
07363        *      0__________________|_________________|
07364        *                       | w  |    |    |    |
07365        *
07366        * so the number of intervals to cut is 1+(delta-1)/w
07367        */
07368       if (w == 0) {
07369          config->play_warning = 0;
07370       } else {
07371          config->play_warning -= w * ( 1 + (delta-1)/w );
07372          if (config->play_warning < 1)
07373             config->play_warning = config->warning_freq = 0;
07374       }
07375    }
07376    
07377    ast_channel_lock(chan);
07378 
07379    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
07380    play_to_caller = var ? ast_true(var) : 1;
07381 
07382    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
07383    play_to_callee = var ? ast_true(var) : 0;
07384 
07385    if (!play_to_caller && !play_to_callee)
07386       play_to_caller = 1;
07387 
07388    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
07389    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
07390 
07391    /* The code looking at config wants a NULL, not just "", to decide
07392     * that the message should not be played, so we replace "" with NULL.
07393     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
07394     * not found.
07395     */
07396 
07397    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
07398    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07399 
07400    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
07401    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
07402 
07403    ast_channel_unlock(chan);
07404 
07405    /* undo effect of S(x) in case they are both used */
07406    calldurationlimit->tv_sec = 0;
07407    calldurationlimit->tv_usec = 0;
07408 
07409    /* more efficient to do it like S(x) does since no advanced opts */
07410    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
07411       calldurationlimit->tv_sec = config->timelimit / 1000;
07412       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
07413       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
07414          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
07415       config->timelimit = play_to_caller = play_to_callee =
07416       config->play_warning = config->warning_freq = 0;
07417    } else {
07418       ast_verb(4, "Limit Data for this call:\n");
07419       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
07420       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
07421       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
07422       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
07423       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
07424       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
07425       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
07426       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
07427    }
07428    if (play_to_caller)
07429       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
07430    if (play_to_callee)
07431       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
07432    return 0;
07433 }

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

07135 {
07136    if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE)
07137       && (chan->_state == AST_STATE_RINGING
07138          || chan->_state == AST_STATE_RING
07139          /*
07140           * Check the down state as well because some SIP devices do not
07141           * give 180 ringing when they can just give 183 session progress
07142           * instead.  Issue 14005.  (Some ISDN switches as well for that
07143           * matter.)
07144           */
07145          || chan->_state == AST_STATE_DOWN)
07146       && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
07147       return 1;
07148    }
07149    return 0;
07150 }

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

07211 {
07212    struct ast_party_connected_line connected_caller;
07213    struct ast_channel *chans[2] = { chan, target };
07214    struct ast_datastore *ds_pickup;
07215    const char *chan_name;/*!< A masquerade changes channel names. */
07216    const char *target_name;/*!< A masquerade changes channel names. */
07217    int res = -1;
07218 
07219    target_name = ast_strdupa(target->name);
07220    ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name);
07221 
07222    /* Mark the target to block any call pickup race. */
07223    ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
07224    if (!ds_pickup) {
07225       ast_log(LOG_WARNING,
07226          "Unable to create channel datastore on '%s' for call pickup\n", target_name);
07227       return -1;
07228    }
07229    ast_channel_datastore_add(target, ds_pickup);
07230 
07231    ast_party_connected_line_init(&connected_caller);
07232    ast_party_connected_line_copy(&connected_caller, &target->connected);
07233    ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
07234    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07235    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
07236       ast_channel_update_connected_line(chan, &connected_caller, NULL);
07237    }
07238    ast_party_connected_line_free(&connected_caller);
07239 
07240    ast_channel_lock(chan);
07241    chan_name = ast_strdupa(chan->name);
07242    ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
07243    ast_channel_unlock(chan);
07244    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
07245    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
07246    ast_party_connected_line_free(&connected_caller);
07247 
07248    ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
07249 
07250    if (ast_answer(chan)) {
07251       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
07252       goto pickup_failed;
07253    }
07254 
07255    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
07256       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
07257       goto pickup_failed;
07258    }
07259    
07260    /* setting this flag to generate a reason header in the cancel message to the ringing channel */
07261    ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
07262 
07263    if (ast_channel_masquerade(target, chan)) {
07264       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
07265          target_name);
07266       goto pickup_failed;
07267    }
07268 
07269    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
07270    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
07271       "Channel: %s\r\n"
07272       "TargetChannel: %s\r\n",
07273       chan_name, target_name);
07274 
07275    /* Do the masquerade manually to make sure that it is completed. */
07276    ast_do_masquerade(target);
07277    res = 0;
07278 
07279 pickup_failed:
07280    ast_channel_lock(target);
07281    if (!ast_channel_datastore_remove(target, ds_pickup)) {
07282       ast_datastore_free(ds_pickup);
07283    }
07284 
07285    return res;
07286 }

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

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

Referenced by detect_disconnect().

03277                                                                                                                                  {
03278 
03279    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
03280 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

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

06697 {
06698    struct ast_context *con;
06699    int res;
06700 
06701    ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
06702 
06703    /*
06704     * Always destroy the parking_con_dial context to remove buildup
06705     * of recalled extensions in the context.  At worst, the parked
06706     * call gets hungup attempting to run an invalid extension when
06707     * we are trying to callback the parker or the preset return
06708     * extension.  This is a small window of opportunity on an
06709     * execution chain that is not expected to happen very often.
06710     */
06711    con = ast_context_find(parking_con_dial);
06712    if (con) {
06713       ast_context_destroy(con, registrar);
06714    }
06715 
06716    res = load_config(1);
06717    ast_mutex_unlock(&features_reload_lock);
06718 
06719    return res;
06720 }

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

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

03012 {
03013    int x;
03014    for (x = 0; x < FEATURES_COUNT; x++) {
03015       if (!strcasecmp(name, builtin_features[x].sname))
03016          return &builtin_features[x];
03017    }
03018    return NULL;
03019 }

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

01757 {
01758    struct ast_park_call_args args = {
01759       .timeout = timeout,
01760       .extout = extout,
01761    };
01762 
01763    if (peer) {
01764       args.orig_chan_name = ast_strdupa(peer->name);
01765    }
01766    return masq_park_call(rchan, peer, &args);
01767 }

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

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

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

References args, and park_call_full().

01606 {
01607    struct ast_park_call_args args = {
01608       .timeout = timeout,
01609       .extout = extout,
01610    };
01611 
01612    return park_call_full(park_me, parker, &args);
01613 }

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

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

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

00794 {
00795    return get_parking_exten(exten_str, chan, context) ? 1 : 0;
00796 }

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

07177 {
07178    struct ast_channel *target;/*!< Potential pickup target */
07179    int res = -1;
07180    ast_debug(1, "pickup attempt by %s\n", chan->name);
07181 
07182    /* The found channel is already locked. */
07183    target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
07184    if (target) {
07185       ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
07186 
07187       res = ast_do_pickup(chan, target);
07188       ast_channel_unlock(target);
07189       if (!res) {
07190          if (!ast_strlen_zero(pickupsound)) {
07191             pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
07192          }
07193       } else {
07194          ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name);
07195       }
07196       target = ast_channel_unref(target);
07197    }
07198 
07199    if (res < 0) {
07200       ast_debug(1, "No call pickup possible... for %s\n", chan->name);
07201       if (!ast_strlen_zero(pickupfailsound)) {
07202          ast_answer(chan);
07203          ast_stream_and_wait(chan, pickupfailsound, "");
07204       }
07205    }
07206 
07207    return res;
07208 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

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

00799 {
00800    return pickup_ext;
00801 }

void ast_rdlock_call_features ( void   ) 

Definition at line 3001 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

03002 {
03003    ast_rwlock_rdlock(&features_lock);
03004 }

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

02846 {
02847    if (!feature) {
02848       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02849       return;
02850    }
02851   
02852    AST_RWLIST_WRLOCK(&feature_list);
02853    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02854    AST_RWLIST_UNLOCK(&feature_list);
02855 
02856    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02857 }

void ast_unlock_call_features ( void   ) 

Definition at line 3006 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

03007 {
03008    ast_rwlock_unlock(&features_lock);
03009 }

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

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

02926 {
02927    if (!feature) {
02928       return;
02929    }
02930 
02931    AST_RWLIST_WRLOCK(&feature_list);
02932    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02933    AST_RWLIST_UNLOCK(&feature_list);
02934 
02935    ast_free(feature);
02936 }


Generated on Sat Mar 10 01:55:23 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7