Tue Mar 2 17:33:24 2010

Asterisk developer's documentation


features.h File Reference

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

#include "asterisk/pbx.h"
#include "asterisk/linkedlists.h"
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

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

Enumerations

enum  {
  AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
  AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3)
}
 

main call feature structure

More...

Functions

int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature)
 detect a feature before bridging
int ast_features_reload (void)
 Reload call features from features.conf.
struct ast_call_featureast_find_call_feature (const char *name)
 look for a call feature entry by its sname
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *host, int timeout, int *extout)
 Park a call and read back parked location.
const char * ast_parking_ext (void)
 Determine system parking extension.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
const char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_rdlock_call_features (void)
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unlock_call_features (void)
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set

Detailed Description

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

Definition in file features.h.


Define Documentation

#define AST_FEATURE_RETURN_HANGUP   -1

Definition at line 39 of file features.h.

Referenced by builtin_disconnect().

#define AST_FEATURE_RETURN_KEEPTRYING   24

Definition at line 46 of file features.h.

Referenced by feature_exec_app(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 42 of file features.h.

#define AST_FEATURE_RETURN_PARKFAILED   25

Definition at line 47 of file features.h.

Referenced by builtin_blindtransfer(), and masq_park_call().

#define AST_FEATURE_RETURN_PASSDIGITS   21

Definition at line 43 of file features.h.

Referenced by ast_bridge_call(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 41 of file features.h.

#define AST_FEATURE_RETURN_STOREDIGITS   22

Definition at line 44 of file features.h.

Referenced by detect_disconnect(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_SUCCESS   23
#define AST_FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 40 of file features.h.

Referenced by feature_exec_app().

#define FEATURE_APP_ARGS_LEN   256

Definition at line 32 of file features.h.

Referenced by load_config().

#define FEATURE_APP_LEN   64

Definition at line 31 of file features.h.

Referenced by load_config().

#define FEATURE_EXTEN_LEN   32

Definition at line 34 of file features.h.

Referenced by load_config().

#define FEATURE_MAX_LEN   11

Definition at line 30 of file features.h.

Referenced by ast_bridge_call(), and wait_for_answer().

#define FEATURE_MOH_LEN   80

Definition at line 35 of file features.h.

Referenced by load_config().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 49 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 50 of file features.h.

Referenced by ast_bridge_call(), and set_peers().

#define FEATURE_SNAME_LEN   32

Definition at line 33 of file features.h.

Referenced by load_config().

#define PARK_APP_NAME   "Park"

Definition at line 37 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 52 of file features.h.


Enumeration Type Documentation

anonymous enum

main call feature structure

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 56 of file features.h.

00056      {
00057    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00058    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00059    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00060    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00061    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00062    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00063 };


Function Documentation

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

Bridge a call, optionally allowing redirection.

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

References ast_channel::_state, 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_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, 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_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_bridge_config::end_sound, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_frame::frametype, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_bridge_config::play_warning, ast_channel::priority, ast_frame::ptr, 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_cdr::uniqueid, ast_cdr::userfield, ast_channel::visible_indication, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

02398 {
02399    /* Copy voice back and forth between the two channels.  Give the peer
02400       the ability to transfer calls with '#<extension' syntax. */
02401    struct ast_frame *f;
02402    struct ast_channel *who;
02403    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
02404    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
02405    char orig_channame[AST_MAX_EXTENSION];
02406    char orig_peername[AST_MAX_EXTENSION];
02407    int res;
02408    int diff;
02409    int hasfeatures=0;
02410    int hadfeatures=0;
02411    int autoloopflag;
02412    struct ast_option_header *aoh;
02413    struct ast_bridge_config backup_config;
02414    struct ast_cdr *bridge_cdr = NULL;
02415    struct ast_cdr *orig_peer_cdr = NULL;
02416    struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02417    struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02418    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02419    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02420 
02421    memset(&backup_config, 0, sizeof(backup_config));
02422 
02423    config->start_time = ast_tvnow();
02424 
02425    if (chan && peer) {
02426       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
02427       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
02428    } else if (chan) {
02429       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
02430    }
02431 
02432    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
02433    add_features_datastores(chan, peer, config);
02434 
02435    /* This is an interesting case.  One example is if a ringing channel gets redirected to
02436     * an extension that picks up a parked call.  This will make sure that the call taken
02437     * out of parking gets told that the channel it just got bridged to is still ringing. */
02438    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
02439       ast_indicate(peer, AST_CONTROL_RINGING);
02440    }
02441 
02442    if (monitor_ok) {
02443       const char *monitor_exec;
02444       struct ast_channel *src = NULL;
02445       if (!monitor_app) { 
02446          if (!(monitor_app = pbx_findapp("Monitor")))
02447             monitor_ok=0;
02448       }
02449       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
02450          src = chan;
02451       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
02452          src = peer;
02453       if (monitor_app && src) {
02454          char *tmp = ast_strdupa(monitor_exec);
02455          pbx_exec(src, monitor_app, tmp);
02456       }
02457    }
02458 
02459    set_config_flags(chan, peer, config);
02460    config->firstpass = 1;
02461 
02462    /* Answer if need be */
02463    if (chan->_state != AST_STATE_UP) {
02464       if (ast_raw_answer(chan, 1)) {
02465          return -1;
02466       }
02467    }
02468 
02469    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
02470    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
02471    orig_peer_cdr = peer_cdr;
02472    
02473    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
02474       
02475       if (chan_cdr) {
02476          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
02477          ast_cdr_update(chan);
02478          bridge_cdr = ast_cdr_dup(chan_cdr);
02479          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02480          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02481          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
02482             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02483          }
02484 
02485       } else {
02486          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
02487          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
02488          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
02489          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
02490          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
02491          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02492          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02493          ast_cdr_setcid(bridge_cdr, chan);
02494          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
02495          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
02496          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
02497          /* Destination information */
02498          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
02499          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
02500          if (peer_cdr) {
02501             bridge_cdr->start = peer_cdr->start;
02502             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02503          } else {
02504             ast_cdr_start(bridge_cdr);
02505          }
02506       }
02507       ast_debug(4,"bridge answer set, chan answer set\n");
02508       /* peer_cdr->answer will be set when a macro runs on the peer;
02509          in that case, the bridge answer will be delayed while the
02510          macro plays on the peer channel. The peer answered the call
02511          before the macro started playing. To the phone system,
02512          this is billable time for the call, even tho the caller
02513          hears nothing but ringing while the macro does its thing. */
02514 
02515       /* Another case where the peer cdr's time will be set, is when
02516          A self-parks by pickup up phone and dialing 700, then B
02517          picks up A by dialing its parking slot; there may be more 
02518          practical paths that get the same result, tho... in which
02519          case you get the previous answer time from the Park... which
02520          is before the bridge's start time, so I added in the 
02521          tvcmp check to the if below */
02522 
02523       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
02524          bridge_cdr->answer = peer_cdr->answer;
02525          bridge_cdr->disposition = peer_cdr->disposition;
02526          if (chan_cdr) {
02527             chan_cdr->answer = peer_cdr->answer;
02528             chan_cdr->disposition = peer_cdr->disposition;
02529          }
02530       } else {
02531          ast_cdr_answer(bridge_cdr);
02532          if (chan_cdr) {
02533             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
02534          }
02535       }
02536       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
02537          if (chan_cdr) {
02538             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
02539          }
02540          if (peer_cdr) {
02541             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
02542          }
02543       }
02544    }
02545    for (;;) {
02546       struct ast_channel *other; /* used later */
02547    
02548       res = ast_channel_bridge(chan, peer, config, &f, &who);
02549       
02550       /* When frame is not set, we are probably involved in a situation
02551          where we've timed out.
02552          When frame is set, we'll come this code twice; once for DTMF_BEGIN
02553          and also for DTMF_END. If we flow into the following 'if' for both, then 
02554          our wait times are cut in half, as both will subtract from the
02555          feature_timer. Not good!
02556       */
02557       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
02558          /* Update time limit for next pass */
02559          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
02560          if (res == AST_BRIDGE_RETRY) {
02561             /* The feature fully timed out but has not been updated. Skip
02562              * the potential round error from the diff calculation and
02563              * explicitly set to expired. */
02564             config->feature_timer = -1;
02565          } else {
02566             config->feature_timer -= diff;
02567          }
02568 
02569          if (hasfeatures) {
02570             /* Running on backup config, meaning a feature might be being
02571                activated, but that's no excuse to keep things going 
02572                indefinitely! */
02573             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
02574                ast_debug(1, "Timed out, realtime this time!\n");
02575                config->feature_timer = 0;
02576                who = chan;
02577                if (f)
02578                   ast_frfree(f);
02579                f = NULL;
02580                res = 0;
02581             } else if (config->feature_timer <= 0) {
02582                /* Not *really* out of time, just out of time for
02583                   digits to come in for features. */
02584                ast_debug(1, "Timed out for feature!\n");
02585                if (!ast_strlen_zero(peer_featurecode)) {
02586                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
02587                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
02588                }
02589                if (!ast_strlen_zero(chan_featurecode)) {
02590                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
02591                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
02592                }
02593                if (f)
02594                   ast_frfree(f);
02595                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02596                if (!hasfeatures) {
02597                   /* Restore original (possibly time modified) bridge config */
02598                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02599                   memset(&backup_config, 0, sizeof(backup_config));
02600                }
02601                hadfeatures = hasfeatures;
02602                /* Continue as we were */
02603                continue;
02604             } else if (!f) {
02605                /* The bridge returned without a frame and there is a feature in progress.
02606                 * However, we don't think the feature has quite yet timed out, so just
02607                 * go back into the bridge. */
02608                continue;
02609             }
02610          } else {
02611             if (config->feature_timer <=0) {
02612                /* We ran out of time */
02613                config->feature_timer = 0;
02614                who = chan;
02615                if (f)
02616                   ast_frfree(f);
02617                f = NULL;
02618                res = 0;
02619             }
02620          }
02621       }
02622       if (res < 0) {
02623          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
02624             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
02625          goto before_you_go;
02626       }
02627       
02628       if (!f || (f->frametype == AST_FRAME_CONTROL &&
02629             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
02630                f->subclass == AST_CONTROL_CONGESTION))) {
02631          res = -1;
02632          break;
02633       }
02634       /* many things should be sent to the 'other' channel */
02635       other = (who == chan) ? peer : chan;
02636       if (f->frametype == AST_FRAME_CONTROL) {
02637          switch (f->subclass) {
02638          case AST_CONTROL_RINGING:
02639          case AST_CONTROL_FLASH:
02640          case -1:
02641             ast_indicate(other, f->subclass);
02642             break;
02643          case AST_CONTROL_HOLD:
02644          case AST_CONTROL_UNHOLD:
02645             ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
02646             break;
02647          case AST_CONTROL_OPTION:
02648             aoh = f->data.ptr;
02649             /* Forward option Requests */
02650             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02651                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
02652                   f->datalen - sizeof(struct ast_option_header), 0);
02653             }
02654             break;
02655          }
02656       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02657          /* eat it */
02658       } else if (f->frametype == AST_FRAME_DTMF) {
02659          char *featurecode;
02660          int sense;
02661 
02662          hadfeatures = hasfeatures;
02663          /* This cannot overrun because the longest feature is one shorter than our buffer */
02664          if (who == chan) {
02665             sense = FEATURE_SENSE_CHAN;
02666             featurecode = chan_featurecode;
02667          } else  {
02668             sense = FEATURE_SENSE_PEER;
02669             featurecode = peer_featurecode;
02670          }
02671          /*! append the event to featurecode. we rely on the string being zero-filled, and
02672           * not overflowing it. 
02673           * \todo XXX how do we guarantee the latter ?
02674           */
02675          featurecode[strlen(featurecode)] = f->subclass;
02676          /* Get rid of the frame before we start doing "stuff" with the channels */
02677          ast_frfree(f);
02678          f = NULL;
02679          config->feature_timer = backup_config.feature_timer;
02680          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
02681          switch(res) {
02682          case AST_FEATURE_RETURN_PASSDIGITS:
02683             ast_dtmf_stream(other, who, featurecode, 0, 0);
02684             /* Fall through */
02685          case AST_FEATURE_RETURN_SUCCESS:
02686             memset(featurecode, 0, sizeof(chan_featurecode));
02687             break;
02688          }
02689          if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
02690             res = 0;
02691          } else 
02692             break;
02693          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02694          if (hadfeatures && !hasfeatures) {
02695             /* Restore backup */
02696             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02697             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02698          } else if (hasfeatures) {
02699             if (!hadfeatures) {
02700                /* Backup configuration */
02701                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02702                /* Setup temporary config options */
02703                config->play_warning = 0;
02704                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02705                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02706                config->warning_freq = 0;
02707                config->warning_sound = NULL;
02708                config->end_sound = NULL;
02709                config->start_sound = NULL;
02710                config->firstpass = 0;
02711             }
02712             config->start_time = ast_tvnow();
02713             config->feature_timer = featuredigittimeout;
02714             ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
02715          }
02716       }
02717       if (f)
02718          ast_frfree(f);
02719 
02720    }
02721    before_you_go:
02722 
02723    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02724       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
02725       if (bridge_cdr) {
02726          ast_cdr_discard(bridge_cdr);
02727          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
02728       }
02729       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
02730    }
02731 
02732    if (config->end_bridge_callback) {
02733       config->end_bridge_callback(config->end_bridge_callback_data);
02734    }
02735 
02736    /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 
02737     * if it were, then chan belongs to a different thread now, and might have been hung up long
02738      * ago.
02739     */
02740    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) &&
02741       ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02742       struct ast_cdr *swapper = NULL;
02743       char savelastapp[AST_MAX_EXTENSION];
02744       char savelastdata[AST_MAX_EXTENSION];
02745       char save_exten[AST_MAX_EXTENSION];
02746       int  save_prio;
02747       int  found = 0;   /* set if we find at least one match */
02748       int  spawn_error = 0;
02749       
02750       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02751       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02752       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02753          ast_cdr_end(bridge_cdr);
02754       }
02755       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
02756          dialplan code operate on it */
02757       ast_channel_lock(chan);
02758       if (bridge_cdr) {
02759          swapper = chan->cdr;
02760          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02761          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02762          chan->cdr = bridge_cdr;
02763       }
02764       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02765       save_prio = chan->priority;
02766       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02767       chan->priority = 1;
02768       ast_channel_unlock(chan);
02769       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) {
02770          chan->priority++;
02771       }
02772       if (spawn_error && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num) || ast_check_hangup(chan))) {
02773          /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */
02774          spawn_error = 0;
02775       }
02776       if (found && spawn_error) {
02777          /* Something bad happened, or a hangup has been requested. */
02778          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02779          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02780       }
02781       /* swap it back */
02782       ast_channel_lock(chan);
02783       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02784       chan->priority = save_prio;
02785       if (bridge_cdr) {
02786          if (chan->cdr == bridge_cdr) {
02787             chan->cdr = swapper;
02788          } else {
02789             bridge_cdr = NULL;
02790          }
02791       }
02792       if (!spawn_error) {
02793          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02794       }
02795       ast_channel_unlock(chan);
02796       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
02797       if (bridge_cdr) {
02798          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02799          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02800       }
02801       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02802    }
02803    
02804    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
02805    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02806    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
02807       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02808 
02809    /* we can post the bridge CDR at this point */
02810    if (bridge_cdr) {
02811       ast_cdr_end(bridge_cdr);
02812       ast_cdr_detach(bridge_cdr);
02813    }
02814    
02815    /* do a specialized reset on the beginning channel
02816       CDR's, if they still exist, so as not to mess up
02817       issues in future bridges;
02818       
02819       Here are the rules of the game:
02820       1. The chan and peer channel pointers will not change
02821          during the life of the bridge.
02822       2. But, in transfers, the channel names will change.
02823          between the time the bridge is started, and the
02824          time the channel ends. 
02825          Usually, when a channel changes names, it will
02826          also change CDR pointers.
02827       3. Usually, only one of the two channels (chan or peer)
02828          will change names.
02829       4. Usually, if a channel changes names during a bridge,
02830          it is because of a transfer. Usually, in these situations,
02831          it is normal to see 2 bridges running simultaneously, and
02832          it is not unusual to see the two channels that change
02833          swapped between bridges.
02834       5. After a bridge occurs, we have 2 or 3 channels' CDRs
02835          to attend to; if the chan or peer changed names,
02836          we have the before and after attached CDR's.
02837    */
02838    
02839    if (new_chan_cdr) {
02840       struct ast_channel *chan_ptr = NULL;
02841  
02842       if (strcasecmp(orig_channame, chan->name) != 0) { 
02843          /* old channel */
02844          chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02845          if (chan_ptr) {
02846             if (!ast_bridged_channel(chan_ptr)) {
02847                struct ast_cdr *cur;
02848                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02849                   if (cur == chan_cdr) {
02850                      break;
02851                   }
02852                }
02853                if (cur)
02854                   ast_cdr_specialized_reset(chan_cdr,0);
02855             }
02856             ast_channel_unlock(chan_ptr);
02857          }
02858          /* new channel */
02859          ast_cdr_specialized_reset(new_chan_cdr,0);
02860       } else {
02861          ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr  */
02862       }
02863    }
02864    
02865    {
02866       struct ast_channel *chan_ptr = NULL;
02867       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02868       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))
02869          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
02870       if (strcasecmp(orig_peername, peer->name) != 0) { 
02871          /* old channel */
02872          chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02873          if (chan_ptr) {
02874             if (!ast_bridged_channel(chan_ptr)) {
02875                struct ast_cdr *cur;
02876                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02877                   if (cur == peer_cdr) {
02878                      break;
02879                   }
02880                }
02881                if (cur)
02882                   ast_cdr_specialized_reset(peer_cdr,0);
02883             }
02884             ast_channel_unlock(chan_ptr);
02885          }
02886          /* new channel */
02887          ast_cdr_specialized_reset(new_peer_cdr,0);
02888       } else {
02889          ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr  */
02890       }
02891    }
02892    
02893    return res;
02894 }

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

References feature_interpret_helper().

Referenced by detect_disconnect().

02052                                                                                                                            {
02053 
02054    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02055 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4020 of file features.c.

References load_config().

Referenced by handle_features_reload().

04021 {
04022    int res;
04023    /* Release parking lot list */
04024    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04025    // TODO: I don't think any marking is necessary
04026 
04027    /* Reload configuration */
04028    res = load_config();
04029    
04030    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04031    return res;
04032 }

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

look for a call feature entry by its sname

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

Definition at line 1805 of file features.c.

References FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), handle_request_info(), and load_config().

01806 {
01807    int x;
01808    for (x = 0; x < FEATURES_COUNT; x++) {
01809       if (!strcasecmp(name, builtin_features[x].sname))
01810          return &builtin_features[x];
01811    }
01812    return NULL;
01813 }

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

References masq_park_call().

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

00819 {
00820    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00821 }

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

Park a call and read back parked location.

Parameters:
chan the channel to actually be parked
host the channel which will have the parked location read to.
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.

Park the channel chan, and read back the parked location to the host. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context)

Return values:
0 on success.
-1 on failure.

Definition at line 752 of file features.c.

References ast_park_call_full(), and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

00753 {
00754    struct ast_park_call_args args = {
00755       .timeout = timeout,
00756       .extout = extout,
00757    };
00758 
00759    return ast_park_call_full(chan, peer, &args);
00760 }

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

References parking_ext.

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

00244 {
00245    return parking_ext;
00246 }

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

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

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

04405 {
04406    struct ast_channel *cur = NULL;
04407    int res = -1;
04408 
04409    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04410       if (!cur->pbx && 
04411          (cur != chan) &&
04412          (chan->pickupgroup & cur->callgroup) &&
04413          ((cur->_state == AST_STATE_RINGING) ||
04414           (cur->_state == AST_STATE_RING))) {
04415             break;
04416       }
04417       ast_channel_unlock(cur);
04418    }
04419    if (cur) {
04420       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04421       res = ast_answer(chan);
04422       if (res)
04423          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04424       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04425       if (res)
04426          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04427       res = ast_channel_masquerade(cur, chan);
04428       if (res)
04429          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04430       ast_channel_unlock(cur);
04431    } else   {
04432       ast_debug(1, "No call pickup possible...\n");
04433    }
04434    return res;
04435 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 248 of file features.c.

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

00249 {
00250    return pickup_ext;
00251 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1795 of file features.c.

References ast_rwlock_rdlock().

Referenced by handle_request_info().

01796 {
01797    ast_rwlock_rdlock(&features_lock);
01798 }

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

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

Referenced by load_config().

01633 {
01634    if (!feature) {
01635       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01636       return;
01637    }
01638   
01639    AST_RWLIST_WRLOCK(&feature_list);
01640    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01641    AST_RWLIST_UNLOCK(&feature_list);
01642 
01643    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01644 }

void ast_unlock_call_features ( void   ) 

Definition at line 1800 of file features.c.

References ast_rwlock_unlock().

Referenced by handle_request_info().

01801 {
01802    ast_rwlock_unlock(&features_lock);
01803 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

01721 {
01722    if (!feature) {
01723       return;
01724    }
01725 
01726    AST_RWLIST_WRLOCK(&feature_list);
01727    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01728    AST_RWLIST_UNLOCK(&feature_list);
01729 
01730    ast_free(feature);
01731 }


Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1