Sat Aug 6 00:39:55 2011

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"

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.

#define FEATURE_APP_LEN   64

Definition at line 30 of file features.h.

#define FEATURE_EXTEN_LEN   32

Definition at line 33 of file features.h.

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

#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

Definition at line 44 of file features.h.

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

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

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

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_channel::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(), config, ast_channel::context, ast_channel::data, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, 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_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_cdr::uniqueid, ast_channel::uniqueid, ast_cdr::userfield, VERBOSE_PREFIX_2, and ast_channel::visible_indication.

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

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

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

References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

01665                                                                                                                            {
01666 
01667    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
01668 }

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

References masq_park_call().

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

00793 {
00794    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00795 }

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

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

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00732 {
00733    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00734 }

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

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

00381 {
00382    return parking_ext;
00383 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

03450 {
03451    struct ast_channel *cur = NULL;
03452    int res = -1;
03453 
03454    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
03455       if (!cur->pbx && 
03456          (cur != chan) &&
03457          (chan->pickupgroup & cur->callgroup) &&
03458          ((cur->_state == AST_STATE_RINGING) ||
03459           (cur->_state == AST_STATE_RING)) &&
03460          !cur->masq &&
03461          !ast_test_flag(cur, AST_FLAG_ZOMBIE)) {
03462             break;
03463       }
03464       ast_channel_unlock(cur);
03465    }
03466    if (cur) {
03467       res = pickup_do(chan, cur);
03468       if (res) {
03469          ast_log(LOG_WARNING, "pickup %s failed by %s\n", cur->name, chan->name);
03470       }
03471       ast_channel_unlock(cur);
03472    } else   {
03473       if (option_debug)
03474          ast_log(LOG_DEBUG, "No call pickup possible... for %s\n", chan->name);
03475    }
03476    return res;
03477 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 385 of file res_features.c.

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

00386 {
00387    return pickup_ext;
00388 }

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

01392 {
01393    if (!feature) {
01394       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01395          return;
01396    }
01397   
01398    AST_RWLIST_WRLOCK(&feature_list);
01399    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01400    AST_RWLIST_UNLOCK(&feature_list);
01401 
01402    if (option_verbose >= 2) {
01403       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01404    }
01405 }

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

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

01409 {
01410    if (!feature)
01411       return;
01412 
01413    AST_RWLIST_WRLOCK(&feature_list);
01414    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01415    AST_RWLIST_UNLOCK(&feature_list);
01416    
01417    free(feature);
01418 }


Generated on Sat Aug 6 00:39:55 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7