Wed Aug 18 22:34:23 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"

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

Definition at line 45 of file features.h.

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

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

#define FEATURE_APP_LEN   64

Definition at line 31 of file features.h.

#define FEATURE_EXTEN_LEN   32

Definition at line 34 of file features.h.

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

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

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

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

References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_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_NULL, 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_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_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, chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.

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

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

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

References chan, feature_group_exten::feature, and feature_interpret_helper().

Referenced by detect_disconnect().

02059                                                                                                                            {
02060 
02061    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02062 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4052 of file features.c.

References load_config().

Referenced by handle_features_reload().

04053 {
04054    int res;
04055    /* Release parking lot list */
04056    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04057    // TODO: I don't think any marking is necessary
04058 
04059    /* Reload configuration */
04060    res = load_config();
04061    
04062    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04063    return res;
04064 }

struct ast_call_feature* ast_find_call_feature ( const char *  name  ) 

look for a call feature entry by its sname

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

Definition at line 1812 of file features.c.

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

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

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

00826 {
00827    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00828 }

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

Park a call and read back parked location.

Parameters:
chan the channel to actually be parked
host the channel which will have the parked location read to.
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.
Park the channel chan, and read back the parked location to the host. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context)
Return values:
0 on success.
-1 on failure.

Definition at line 754 of file features.c.

References ast_park_call_full(), chan, and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

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

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

References parking_ext.

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

00245 {
00246    return parking_ext;
00247 }

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

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

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

04437 {
04438    struct ast_channel *cur = NULL;
04439    int res = -1;
04440 
04441    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04442       if (!cur->pbx && 
04443          (cur != chan) &&
04444          (chan->pickupgroup & cur->callgroup) &&
04445          ((cur->_state == AST_STATE_RINGING) ||
04446           (cur->_state == AST_STATE_RING))) {
04447             break;
04448       }
04449       ast_channel_unlock(cur);
04450    }
04451    if (cur) {
04452       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04453       res = ast_answer(chan);
04454       if (res)
04455          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04456       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04457       if (res)
04458          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04459       res = ast_channel_masquerade(cur, chan);
04460       if (res)
04461          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04462       ast_channel_unlock(cur);
04463    } else   {
04464       ast_debug(1, "No call pickup possible...\n");
04465    }
04466    return res;
04467 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 249 of file features.c.

References pickup_ext.

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

00250 {
00251    return pickup_ext;
00252 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1802 of file features.c.

References ast_rwlock_rdlock(), and features_lock.

Referenced by handle_request_info().

01803 {
01804    ast_rwlock_rdlock(&features_lock);
01805 }

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

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

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

void ast_unlock_call_features ( void   ) 

Definition at line 1807 of file features.c.

References ast_rwlock_unlock(), and features_lock.

Referenced by handle_request_info().

01808 {
01809    ast_rwlock_unlock(&features_lock);
01810 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.

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


Generated on Wed Aug 18 22:34:23 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7