Thu Oct 11 06:43:28 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/linkedlists.h"

Include dependency graph for features.h:

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

Go to the source code of this file.

Data Structures

struct  ast_call_feature
 main call feature structure More...

Defines

#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_RETURN_HANGUP   -1
#define FEATURE_RETURN_KEEPTRYING   24
#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
#define FEATURE_RETURN_PARKFAILED   25
#define FEATURE_RETURN_PASSDIGITS   21
#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
#define FEATURE_RETURN_STOREDIGITS   22
#define FEATURE_RETURN_SUCCESS   23
#define FEATURE_RETURN_SUCCESSBREAK   0
#define FEATURE_SENSE_CHAN   (1 << 0)
#define FEATURE_SENSE_PEER   (1 << 1)
#define FEATURE_SNAME_LEN   32
#define PARK_APP_NAME   "Park"

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_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.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
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 FEATURE_APP_ARGS_LEN   256

Definition at line 31 of file features.h.

Referenced by load_config().

#define FEATURE_APP_LEN   64

Definition at line 30 of file features.h.

Referenced by load_config().

#define FEATURE_EXTEN_LEN   32

Definition at line 33 of file features.h.

Referenced by load_config().

#define FEATURE_MAX_LEN   11

Definition at line 29 of file features.h.

Referenced by ast_bridge_call(), and wait_for_answer().

#define FEATURE_MOH_LEN   80

Definition at line 34 of file features.h.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 38 of file features.h.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 45 of file features.h.

Referenced by feature_exec_app(), and feature_interpret_helper().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 41 of file features.h.

#define FEATURE_RETURN_PARKFAILED   25

Definition at line 46 of file features.h.

Referenced by builtin_blindtransfer(), and masq_park_call().

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 42 of file features.h.

Referenced by ast_bridge_call(), and feature_interpret_helper().

#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 40 of file features.h.

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 43 of file features.h.

Referenced by detect_disconnect(), and feature_interpret_helper().

#define FEATURE_RETURN_SUCCESS   23

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 39 of file features.h.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 48 of file features.h.

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

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 49 of file features.h.

Referenced by ast_bridge_call(), and set_peers().

#define FEATURE_SNAME_LEN   32

Definition at line 32 of file features.h.

Referenced by load_config().

#define PARK_APP_NAME   "Park"

Definition at line 36 of file features.h.

Referenced by handle_exec().


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

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 2115 of file res_features.c.

References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, ast_answer(), 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_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NOANSWER, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), 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_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), 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_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, ast_opt_transmit_silence, AST_OPTION_AUDIO_MODE, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, 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_verbose(), ast_write(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, clear_dialed_interfaces(), ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_bridge_config::end_sound, ast_channel::exten, f, feature_check(), feature_interpret(), 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_option_header::flag, ast_frame::frametype, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, ast_channel::name, ast_cdr::next, ast_option_header::option, option_debug, option_verbose, 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, VERBOSE_PREFIX_2, ast_channel::visible_indication, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

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

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 1649 of file res_features.c.

References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

01649                                                                                                                            {
01650 
01651    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
01652 }

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 Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_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

Definition at line 785 of file res_features.c.

References masq_park_call().

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

00786 {
00787    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00788 }

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 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)
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 a call and read back parked location.

Note:
We put the user in the parking list, then wake up the parking thread to be sure it looks after these channels too

Definition at line 724 of file res_features.c.

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00725 {
00726    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00727 }

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 376 of file res_features.c.

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

00377 {
00378    return parking_ext;
00379 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 3418 of file res_features.c.

References ast_channel::_state, ast_channel_unlock, ast_channel_walk_locked(), AST_FLAG_ZOMBIE, ast_log(), AST_STATE_RING, AST_STATE_RINGING, ast_test_flag, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, ast_channel::masq, ast_channel::name, option_debug, ast_channel::pbx, pickup_do(), and ast_channel::pickupgroup.

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

03419 {
03420    struct ast_channel *cur = NULL;
03421    int res = -1;
03422 
03423    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
03424       if (!cur->pbx && 
03425          (cur != chan) &&
03426          (chan->pickupgroup & cur->callgroup) &&
03427          ((cur->_state == AST_STATE_RINGING) ||
03428           (cur->_state == AST_STATE_RING)) &&
03429          !cur->masq &&
03430          !ast_test_flag(cur, AST_FLAG_ZOMBIE)) {
03431             break;
03432       }
03433       ast_channel_unlock(cur);
03434    }
03435    if (cur) {
03436       res = pickup_do(chan, cur);
03437       if (res) {
03438          ast_log(LOG_WARNING, "pickup %s failed by %s\n", cur->name, chan->name);
03439       }
03440       ast_channel_unlock(cur);
03441    } else   {
03442       if (option_debug)
03443          ast_log(LOG_DEBUG, "No call pickup possible... for %s\n", chan->name);
03444    }
03445    return res;
03446 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 381 of file res_features.c.

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

00382 {
00383    return pickup_ext;
00384 }

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 1375 of file res_features.c.

References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verbose(), ast_call_feature::feature_entry, LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.

Referenced by load_config().

01376 {
01377    if (!feature) {
01378       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01379          return;
01380    }
01381   
01382    AST_RWLIST_WRLOCK(&feature_list);
01383    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01384    AST_RWLIST_UNLOCK(&feature_list);
01385 
01386    if (option_verbose >= 2) {
01387       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01388    }
01389 }

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 1392 of file res_features.c.

References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.

01393 {
01394    if (!feature)
01395       return;
01396 
01397    AST_RWLIST_WRLOCK(&feature_list);
01398    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01399    AST_RWLIST_UNLOCK(&feature_list);
01400    
01401    free(feature);
01402 }


Generated on Thu Oct 11 06:43:29 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6