Wed Oct 28 11:46:09 2009

Asterisk developer's documentation


features.h File Reference

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

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_call_feature
 main call feature structure More...

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 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, char *code, int sense, void *data)

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_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature)
 detect a feature before bridging
int ast_features_reload (void)
 Reload call features from features.conf.
struct ast_call_featureast_find_call_feature (const char *name)
 look for a call feature entry by its sname
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *host, int timeout, int *extout)
 Park a call and read back parked location.
const char * ast_parking_ext (void)
 Determine system parking extension.
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 34 of file features.h.

#define AST_FEATURE_RETURN_KEEPTRYING   24

Definition at line 41 of file features.h.

Referenced by feature_interpret_helper().

#define AST_FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 37 of file features.h.

#define AST_FEATURE_RETURN_PARKFAILED   25

Definition at line 42 of file features.h.

#define AST_FEATURE_RETURN_PASSDIGITS   21

Definition at line 38 of file features.h.

Referenced by feature_interpret_helper().

#define AST_FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 36 of file features.h.

#define AST_FEATURE_RETURN_STOREDIGITS   22

Definition at line 39 of file features.h.

Referenced by detect_disconnect(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_SUCCESS   23

Definition at line 40 of file features.h.

#define AST_FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 35 of file features.h.

#define FEATURE_APP_ARGS_LEN   256

Definition at line 29 of file features.h.

Referenced by load_config().

#define FEATURE_APP_LEN   64

Definition at line 28 of file features.h.

Referenced by load_config().

#define FEATURE_EXTEN_LEN   32

Definition at line 31 of file features.h.

Referenced by load_config().

#define FEATURE_MAX_LEN   11

Definition at line 27 of file features.h.

Referenced by ast_bridge_call(), and wait_for_answer().

#define FEATURE_MOH_LEN   80

Definition at line 32 of file features.h.

Referenced by load_config().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 44 of file features.h.

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

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 45 of file features.h.

Referenced by ast_bridge_call(), and set_peers().

#define FEATURE_SNAME_LEN   32

Definition at line 30 of file features.h.

Referenced by load_config().


Typedef Documentation

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

Definition at line 47 of file features.h.


Function Documentation

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

Bridge a call, optionally allowing redirection.

Bridge a call, optionally allowing redirection.

Parameters:
chan,peer,config 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 2187 of file features.c.

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, 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_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_bridge_config::end_sound, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_frame::frametype, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_bridge_config::play_warning, ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, ast_channel::visible_indication, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), park_exec(), and try_calling().

02188 {
02189    /* Copy voice back and forth between the two channels.  Give the peer
02190       the ability to transfer calls with '#<extension' syntax. */
02191    struct ast_frame *f;
02192    struct ast_channel *who;
02193    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
02194    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
02195    char orig_channame[AST_MAX_EXTENSION];
02196    char orig_peername[AST_MAX_EXTENSION];
02197    int res;
02198    int diff;
02199    int hasfeatures=0;
02200    int hadfeatures=0;
02201    int autoloopflag;
02202    struct ast_option_header *aoh;
02203    struct ast_bridge_config backup_config;
02204    struct ast_cdr *bridge_cdr = NULL;
02205    struct ast_cdr *orig_peer_cdr = NULL;
02206    struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02207    struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02208    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02209    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02210 
02211    memset(&backup_config, 0, sizeof(backup_config));
02212 
02213    config->start_time = ast_tvnow();
02214 
02215    if (chan && peer) {
02216       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
02217       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
02218    } else if (chan) {
02219       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
02220    }
02221 
02222    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
02223    add_features_datastores(chan, peer, config);
02224 
02225    /* This is an interesting case.  One example is if a ringing channel gets redirected to
02226     * an extension that picks up a parked call.  This will make sure that the call taken
02227     * out of parking gets told that the channel it just got bridged to is still ringing. */
02228    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
02229       ast_indicate(peer, AST_CONTROL_RINGING);
02230    }
02231 
02232    if (monitor_ok) {
02233       const char *monitor_exec;
02234       struct ast_channel *src = NULL;
02235       if (!monitor_app) { 
02236          if (!(monitor_app = pbx_findapp("Monitor")))
02237             monitor_ok=0;
02238       }
02239       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
02240          src = chan;
02241       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
02242          src = peer;
02243       if (monitor_app && src) {
02244          char *tmp = ast_strdupa(monitor_exec);
02245          pbx_exec(src, monitor_app, tmp);
02246       }
02247    }
02248 
02249    set_config_flags(chan, peer, config);
02250    config->firstpass = 1;
02251 
02252    /* Answer if need be */
02253    if (chan->_state != AST_STATE_UP) {
02254       if (ast_raw_answer(chan, 1)) {
02255          return -1;
02256       }
02257    }
02258 
02259    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
02260    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
02261    orig_peer_cdr = peer_cdr;
02262    
02263    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
02264       
02265       if (chan_cdr) {
02266          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
02267          ast_cdr_update(chan);
02268          bridge_cdr = ast_cdr_dup(chan_cdr);
02269          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02270          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02271       } else {
02272          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
02273          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
02274          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
02275          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
02276          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
02277          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02278          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02279          ast_cdr_setcid(bridge_cdr, chan);
02280          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
02281          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
02282          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
02283          /* Destination information */
02284          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
02285          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
02286          if (peer_cdr) {
02287             bridge_cdr->start = peer_cdr->start;
02288             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02289          } else {
02290             ast_cdr_start(bridge_cdr);
02291          }
02292       }
02293       ast_debug(4,"bridge answer set, chan answer set\n");
02294       /* peer_cdr->answer will be set when a macro runs on the peer;
02295          in that case, the bridge answer will be delayed while the
02296          macro plays on the peer channel. The peer answered the call
02297          before the macro started playing. To the phone system,
02298          this is billable time for the call, even tho the caller
02299          hears nothing but ringing while the macro does its thing. */
02300 
02301       /* Another case where the peer cdr's time will be set, is when
02302          A self-parks by pickup up phone and dialing 700, then B
02303          picks up A by dialing its parking slot; there may be more 
02304          practical paths that get the same result, tho... in which
02305          case you get the previous answer time from the Park... which
02306          is before the bridge's start time, so I added in the 
02307          tvcmp check to the if below */
02308 
02309       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
02310          bridge_cdr->answer = peer_cdr->answer;
02311          bridge_cdr->disposition = peer_cdr->disposition;
02312          if (chan_cdr) {
02313             chan_cdr->answer = peer_cdr->answer;
02314             chan_cdr->disposition = peer_cdr->disposition;
02315          }
02316       } else {
02317          ast_cdr_answer(bridge_cdr);
02318          if (chan_cdr) {
02319             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
02320          }
02321       }
02322       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
02323          if (chan_cdr) {
02324             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
02325          }
02326          if (peer_cdr) {
02327             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
02328          }
02329       }
02330    }
02331    for (;;) {
02332       struct ast_channel *other; /* used later */
02333    
02334       res = ast_channel_bridge(chan, peer, config, &f, &who);
02335       
02336       /* When frame is not set, we are probably involved in a situation
02337          where we've timed out.
02338          When frame is set, we'll come this code twice; once for DTMF_BEGIN
02339          and also for DTMF_END. If we flow into the following 'if' for both, then 
02340          our wait times are cut in half, as both will subtract from the
02341          feature_timer. Not good!
02342       */
02343       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
02344          /* Update time limit for next pass */
02345          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
02346          if (res == AST_BRIDGE_RETRY) {
02347             /* The feature fully timed out but has not been updated. Skip
02348              * the potential round error from the diff calculation and
02349              * explicitly set to expired. */
02350             config->feature_timer = -1;
02351          } else {
02352             config->feature_timer -= diff;
02353          }
02354 
02355          if (hasfeatures) {
02356             /* Running on backup config, meaning a feature might be being
02357                activated, but that's no excuse to keep things going 
02358                indefinitely! */
02359             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
02360                ast_debug(1, "Timed out, realtime this time!\n");
02361                config->feature_timer = 0;
02362                who = chan;
02363                if (f)
02364                   ast_frfree(f);
02365                f = NULL;
02366                res = 0;
02367             } else if (config->feature_timer <= 0) {
02368                /* Not *really* out of time, just out of time for
02369                   digits to come in for features. */
02370                ast_debug(1, "Timed out for feature!\n");
02371                if (!ast_strlen_zero(peer_featurecode)) {
02372                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
02373                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
02374                }
02375                if (!ast_strlen_zero(chan_featurecode)) {
02376                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
02377                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
02378                }
02379                if (f)
02380                   ast_frfree(f);
02381                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02382                if (!hasfeatures) {
02383                   /* Restore original (possibly time modified) bridge config */
02384                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02385                   memset(&backup_config, 0, sizeof(backup_config));
02386                }
02387                hadfeatures = hasfeatures;
02388                /* Continue as we were */
02389                continue;
02390             } else if (!f) {
02391                /* The bridge returned without a frame and there is a feature in progress.
02392                 * However, we don't think the feature has quite yet timed out, so just
02393                 * go back into the bridge. */
02394                continue;
02395             }
02396          } else {
02397             if (config->feature_timer <=0) {
02398                /* We ran out of time */
02399                config->feature_timer = 0;
02400                who = chan;
02401                if (f)
02402                   ast_frfree(f);
02403                f = NULL;
02404                res = 0;
02405             }
02406          }
02407       }
02408       if (res < 0) {
02409          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
02410             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
02411          goto before_you_go;
02412       }
02413       
02414       if (!f || (f->frametype == AST_FRAME_CONTROL &&
02415             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
02416                f->subclass == AST_CONTROL_CONGESTION))) {
02417          res = -1;
02418          break;
02419       }
02420       /* many things should be sent to the 'other' channel */
02421       other = (who == chan) ? peer : chan;
02422       if (f->frametype == AST_FRAME_CONTROL) {
02423          switch (f->subclass) {
02424          case AST_CONTROL_RINGING:
02425          case AST_CONTROL_FLASH:
02426          case -1:
02427             ast_indicate(other, f->subclass);
02428             break;
02429          case AST_CONTROL_HOLD:
02430          case AST_CONTROL_UNHOLD:
02431             ast_indicate_data(other, f->subclass, f->data, f->datalen);
02432             break;
02433          case AST_CONTROL_OPTION:
02434             aoh = f->data;
02435             /* Forward option Requests */
02436             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02437                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
02438                   f->datalen - sizeof(struct ast_option_header), 0);
02439             }
02440             break;
02441          }
02442       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02443          /* eat it */
02444       } else if (f->frametype == AST_FRAME_DTMF) {
02445          char *featurecode;
02446          int sense;
02447 
02448          hadfeatures = hasfeatures;
02449          /* This cannot overrun because the longest feature is one shorter than our buffer */
02450          if (who == chan) {
02451             sense = FEATURE_SENSE_CHAN;
02452             featurecode = chan_featurecode;
02453          } else  {
02454             sense = FEATURE_SENSE_PEER;
02455             featurecode = peer_featurecode;
02456          }
02457          /*! append the event to featurecode. we rely on the string being zero-filled, and
02458           * not overflowing it. 
02459           * \todo XXX how do we guarantee the latter ?
02460           */
02461          featurecode[strlen(featurecode)] = f->subclass;
02462          /* Get rid of the frame before we start doing "stuff" with the channels */
02463          ast_frfree(f);
02464          f = NULL;
02465          config->feature_timer = backup_config.feature_timer;
02466          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
02467          switch(res) {
02468          case FEATURE_RETURN_PASSDIGITS:
02469             ast_dtmf_stream(other, who, featurecode, 0, 0);
02470             /* Fall through */
02471          case FEATURE_RETURN_SUCCESS:
02472             memset(featurecode, 0, sizeof(chan_featurecode));
02473             break;
02474          }
02475          if (res >= FEATURE_RETURN_PASSDIGITS) {
02476             res = 0;
02477          } else 
02478             break;
02479          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02480          if (hadfeatures && !hasfeatures) {
02481             /* Restore backup */
02482             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02483             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02484          } else if (hasfeatures) {
02485             if (!hadfeatures) {
02486                /* Backup configuration */
02487                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02488                /* Setup temporary config options */
02489                config->play_warning = 0;
02490                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02491                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02492                config->warning_freq = 0;
02493                config->warning_sound = NULL;
02494                config->end_sound = NULL;
02495                config->start_sound = NULL;
02496                config->firstpass = 0;
02497             }
02498             config->start_time = ast_tvnow();
02499             config->feature_timer = featuredigittimeout;
02500             ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
02501          }
02502       }
02503       if (f)
02504          ast_frfree(f);
02505 
02506    }
02507    before_you_go:
02508 
02509    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02510       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
02511       if (bridge_cdr) {
02512          ast_cdr_discard(bridge_cdr);
02513          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
02514       }
02515       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
02516    }
02517 
02518    if (config->end_bridge_callback) {
02519       config->end_bridge_callback(config->end_bridge_callback_data);
02520    }
02521 
02522    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) &&
02523       ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02524       struct ast_cdr *swapper = NULL;
02525       char savelastapp[AST_MAX_EXTENSION];
02526       char savelastdata[AST_MAX_EXTENSION];
02527       char save_exten[AST_MAX_EXTENSION];
02528       int  save_prio;
02529       int  found = 0;   /* set if we find at least one match */
02530       int  spawn_error = 0;
02531       
02532       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02533       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02534       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02535          ast_cdr_end(bridge_cdr);
02536       }
02537       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
02538          dialplan code operate on it */
02539       ast_channel_lock(chan);
02540       if (bridge_cdr) {
02541          swapper = chan->cdr;
02542          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02543          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02544          chan->cdr = bridge_cdr;
02545       }
02546       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02547       save_prio = chan->priority;
02548       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02549       chan->priority = 1;
02550       ast_channel_unlock(chan);
02551       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) {
02552          chan->priority++;
02553       }
02554       if (found && spawn_error) {
02555          /* Something bad happened, or a hangup has been requested. */
02556          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02557          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02558       }
02559       /* swap it back */
02560       ast_channel_lock(chan);
02561       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02562       chan->priority = save_prio;
02563       if (bridge_cdr) {
02564          if (chan->cdr == bridge_cdr) {
02565             chan->cdr = swapper;
02566          } else {
02567             bridge_cdr = NULL;
02568          }
02569       }
02570       if (chan->priority != 1 || !spawn_error) {
02571          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02572       }
02573       ast_channel_unlock(chan);
02574       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
02575       if (bridge_cdr) {
02576          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02577          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02578       }
02579       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02580    }
02581    
02582    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
02583    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02584    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
02585       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02586 
02587    /* we can post the bridge CDR at this point */
02588    if (bridge_cdr) {
02589       ast_cdr_end(bridge_cdr);
02590       ast_cdr_detach(bridge_cdr);
02591    }
02592    
02593    /* do a specialized reset on the beginning channel
02594       CDR's, if they still exist, so as not to mess up
02595       issues in future bridges;
02596       
02597       Here are the rules of the game:
02598       1. The chan and peer channel pointers will not change
02599          during the life of the bridge.
02600       2. But, in transfers, the channel names will change.
02601          between the time the bridge is started, and the
02602          time the channel ends. 
02603          Usually, when a channel changes names, it will
02604          also change CDR pointers.
02605       3. Usually, only one of the two channels (chan or peer)
02606          will change names.
02607       4. Usually, if a channel changes names during a bridge,
02608          it is because of a transfer. Usually, in these situations,
02609          it is normal to see 2 bridges running simultaneously, and
02610          it is not unusual to see the two channels that change
02611          swapped between bridges.
02612       5. After a bridge occurs, we have 2 or 3 channels' CDRs
02613          to attend to; if the chan or peer changed names,
02614          we have the before and after attached CDR's.
02615    */
02616    
02617    if (new_chan_cdr) {
02618       struct ast_channel *chan_ptr = NULL;
02619  
02620       if (strcasecmp(orig_channame, chan->name) != 0) { 
02621          /* old channel */
02622          chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02623          if (chan_ptr) {
02624             if (!ast_bridged_channel(chan_ptr)) {
02625                struct ast_cdr *cur;
02626                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02627                   if (cur == chan_cdr) {
02628                      break;
02629                   }
02630                }
02631                if (cur)
02632                   ast_cdr_specialized_reset(chan_cdr,0);
02633             }
02634             ast_channel_unlock(chan_ptr);
02635          }
02636          /* new channel */
02637          ast_cdr_specialized_reset(new_chan_cdr,0);
02638       } else {
02639          ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr  */
02640       }
02641    }
02642    
02643    {
02644       struct ast_channel *chan_ptr = NULL;
02645       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02646       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))
02647          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
02648       if (strcasecmp(orig_peername, peer->name) != 0) { 
02649          /* old channel */
02650          chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02651          if (chan_ptr) {
02652             if (!ast_bridged_channel(chan_ptr)) {
02653                struct ast_cdr *cur;
02654                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02655                   if (cur == peer_cdr) {
02656                      break;
02657                   }
02658                }
02659                if (cur)
02660                   ast_cdr_specialized_reset(peer_cdr,0);
02661             }
02662             ast_channel_unlock(chan_ptr);
02663          }
02664          /* new channel */
02665          ast_cdr_specialized_reset(new_peer_cdr,0);
02666       } else {
02667          ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr  */
02668       }
02669    }
02670    
02671    return res;
02672 }

int ast_feature_detect ( struct ast_channel chan,
struct ast_flags features,
char *  code,
struct ast_call_feature feature 
)

detect a feature before bridging

Parameters:
chan 
ast_flags ptr
char ptr of input code
Return values:
ast_call_feature ptr to be set if found
Returns:
result, was feature found or not

Definition at line 1842 of file features.c.

References feature_interpret_helper().

Referenced by detect_disconnect().

01842                                                                                                                            {
01843 
01844    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01845 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 3496 of file features.c.

References load_config(), and RESULT_SUCCESS.

03497 {
03498    load_config();
03499 
03500    return RESULT_SUCCESS;
03501 }

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

look for a call feature entry by its sname

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

Definition at line 1597 of file features.c.

References FEATURES_COUNT, and ast_call_feature::sname.

Referenced by handle_request_info(), and load_config().

01598 {
01599    int x;
01600    for (x = 0; x < FEATURES_COUNT; x++) {
01601       if (!strcasecmp(name, builtin_features[x].sname))
01602          return &builtin_features[x];
01603    }
01604    return NULL;
01605 }

int ast_masq_park_call ( struct ast_channel rchan,
struct ast_channel host,
int  timeout,
int *  extout 
)

Park a call via a masqueraded channel.

Parameters:
rchan the real channel to be parked
host the channel to have the parking read to.
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 channel rchan into a new, empty channel which is then parked with ast_park_call
Return values:
0 on success.
-1 on failure.

Definition at line 665 of file features.c.

References masq_park_call().

Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().

00666 {
00667    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00668 }

int ast_park_call ( struct ast_channel chan,
struct ast_channel peer,
int  timeout,
int *  extout 
)

Park a call and read back parked location.

Parameters:
chan the channel to actually be parked
host the channel which will have the parked location read to.
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 channel chan, and read back the parked location to the host. 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 611 of file features.c.

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00612 {
00613    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00614 }

const char* ast_parking_ext ( void   ) 

Determine system parking extension.

Returns:
the call parking extension for drivers that provide special call parking help

Definition at line 226 of file features.c.

References parking_ext.

Referenced by builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), load_config(), mgcp_ss(), socket_process(), and ss_thread().

00227 {
00228    return parking_ext;
00229 }

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.

Definition at line 3864 of file features.c.

References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup.

Referenced by cb_events(), handle_request_invite(), mgcp_ss(), pickup_exec(), and ss_thread().

03865 {
03866    struct ast_channel *cur = NULL;
03867    int res = -1;
03868 
03869    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
03870       if (!cur->pbx && 
03871          (cur != chan) &&
03872          (chan->pickupgroup & cur->callgroup) &&
03873          ((cur->_state == AST_STATE_RINGING) ||
03874           (cur->_state == AST_STATE_RING))) {
03875             break;
03876       }
03877       ast_channel_unlock(cur);
03878    }
03879    if (cur) {
03880       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
03881       res = ast_answer(chan);
03882       if (res)
03883          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
03884       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
03885       if (res)
03886          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
03887       res = ast_channel_masquerade(cur, chan);
03888       if (res)
03889          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
03890       ast_channel_unlock(cur);
03891    } else   {
03892       ast_debug(1, "No call pickup possible...\n");
03893    }
03894    return res;
03895 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 231 of file features.c.

References pickup_ext.

Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().

00232 {
00233    return pickup_ext;
00234 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1587 of file features.c.

References ast_rwlock_rdlock(), and features_lock.

Referenced by handle_request_info().

01588 {
01589    ast_rwlock_rdlock(&features_lock);
01590 }

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

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

Referenced by load_config().

01425 {
01426    if (!feature) {
01427       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01428       return;
01429    }
01430   
01431    AST_RWLIST_WRLOCK(&feature_list);
01432    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01433    AST_RWLIST_UNLOCK(&feature_list);
01434 
01435    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01436 }

void ast_unlock_call_features ( void   ) 

Definition at line 1592 of file features.c.

References ast_rwlock_unlock(), and features_lock.

Referenced by handle_request_info().

01593 {
01594    ast_rwlock_unlock(&features_lock);
01595 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

01513 {
01514    if (!feature) {
01515       return;
01516    }
01517 
01518    AST_RWLIST_WRLOCK(&feature_list);
01519    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01520    AST_RWLIST_UNLOCK(&feature_list);
01521 
01522    ast_free(feature);
01523 }


Generated on Wed Oct 28 11:46:09 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6