Thu Apr 8 01:22:32 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 2401 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_setaccount(), 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().

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

02056                                                                                                                            {
02057 
02058    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02059 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4031 of file features.c.

References load_config().

Referenced by handle_features_reload().

04032 {
04033    int res;
04034    /* Release parking lot list */
04035    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04036    // TODO: I don't think any marking is necessary
04037 
04038    /* Reload configuration */
04039    res = load_config();
04040    
04041    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04042    return res;
04043 }

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

References FEATURES_COUNT, and ast_call_feature::sname.

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

01810 {
01811    int x;
01812    for (x = 0; x < FEATURES_COUNT; x++) {
01813       if (!strcasecmp(name, builtin_features[x].sname))
01814          return &builtin_features[x];
01815    }
01816    return NULL;
01817 }

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 822 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().

00823 {
00824    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00825 }

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

References ast_park_call_full(), and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

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

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 4415 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().

04416 {
04417    struct ast_channel *cur = NULL;
04418    int res = -1;
04419 
04420    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04421       if (!cur->pbx && 
04422          (cur != chan) &&
04423          (chan->pickupgroup & cur->callgroup) &&
04424          ((cur->_state == AST_STATE_RINGING) ||
04425           (cur->_state == AST_STATE_RING))) {
04426             break;
04427       }
04428       ast_channel_unlock(cur);
04429    }
04430    if (cur) {
04431       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04432       res = ast_answer(chan);
04433       if (res)
04434          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04435       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04436       if (res)
04437          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04438       res = ast_channel_masquerade(cur, chan);
04439       if (res)
04440          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04441       ast_channel_unlock(cur);
04442    } else   {
04443       ast_debug(1, "No call pickup possible...\n");
04444    }
04445    return res;
04446 }

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

References ast_rwlock_rdlock().

Referenced by handle_request_info().

01800 {
01801    ast_rwlock_rdlock(&features_lock);
01802 }

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 1636 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().

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

void ast_unlock_call_features ( void   ) 

Definition at line 1804 of file features.c.

References ast_rwlock_unlock().

Referenced by handle_request_info().

01805 {
01806    ast_rwlock_unlock(&features_lock);
01807 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

01725 {
01726    if (!feature) {
01727       return;
01728    }
01729 
01730    AST_RWLIST_WRLOCK(&feature_list);
01731    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01732    AST_RWLIST_UNLOCK(&feature_list);
01733 
01734    ast_free(feature);
01735 }


Generated on 8 Apr 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1