Thu Jul 9 13:41:18 2009

Asterisk developer's documentation


features.h File Reference

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

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

#define FEATURE_APP_LEN   64

Definition at line 28 of file features.h.

#define FEATURE_EXTEN_LEN   32

Definition at line 31 of file features.h.

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

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


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.

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 2183 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_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, 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_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.

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

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

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 chan, feature_group_exten::feature, and 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 3483 of file features.c.

References load_config(), and RESULT_SUCCESS.

03484 {
03485    load_config();
03486 
03487    return RESULT_SUCCESS;
03488 }

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

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by handle_request_info().

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(), 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 host,
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 chan, and 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(), 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 3851 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, chan, 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().

03852 {
03853    struct ast_channel *cur = NULL;
03854    int res = -1;
03855 
03856    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
03857       if (!cur->pbx && 
03858          (cur != chan) &&
03859          (chan->pickupgroup & cur->callgroup) &&
03860          ((cur->_state == AST_STATE_RINGING) ||
03861           (cur->_state == AST_STATE_RING))) {
03862             break;
03863       }
03864       ast_channel_unlock(cur);
03865    }
03866    if (cur) {
03867       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
03868       res = ast_answer(chan);
03869       if (res)
03870          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
03871       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
03872       if (res)
03873          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
03874       res = ast_channel_masquerade(cur, chan);
03875       if (res)
03876          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
03877       ast_channel_unlock(cur);
03878    } else   {
03879       ast_debug(1, "No call pickup possible...\n");
03880    }
03881    return res;
03882 }

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, feature_group_exten::feature, LOG_NOTICE, and ast_call_feature::sname.

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, AST_RWLIST_WRLOCK, and feature_group_exten::feature.

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 Thu Jul 9 13:41:18 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7