Fri Nov 12 12:00:31 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_PARKFAILED   25
#define AST_FEATURE_RETURN_PASSDIGITS   21
#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_SNAME_LEN   32
#define PARK_APP_NAME   "Park"

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_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 64 of file features.h.

Referenced by builtin_disconnect().

#define AST_FEATURE_RETURN_KEEPTRYING   24

Definition at line 69 of file features.h.

Referenced by feature_exec_app(), and feature_interpret().

#define AST_FEATURE_RETURN_PARKFAILED   25

Definition at line 70 of file features.h.

Referenced by builtin_blindtransfer(), and masq_park_call().

#define AST_FEATURE_RETURN_PASSDIGITS   21

Definition at line 66 of file features.h.

Referenced by ast_bridge_call(), and feature_interpret().

#define AST_FEATURE_RETURN_STOREDIGITS   22

Definition at line 67 of file features.h.

Referenced by feature_interpret().

#define AST_FEATURE_RETURN_SUCCESS   23
#define AST_FEATURE_RETURN_SUCCESSBREAK   0

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

#define FEATURE_MOH_LEN   80

Definition at line 35 of file features.h.

Referenced by load_config().

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


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 41 of file features.h.

00041      {
00042    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00043    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00044    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00045    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00046    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00047    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00048 };


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 2441 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_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_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_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_interpret(), 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_channel::name, 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_channel::uniqueid, 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(), bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), park_exec_full(), and try_calling().

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

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4079 of file features.c.

References load_config().

Referenced by handle_features_reload().

04080 {
04081    int res;
04082    /* Release parking lot list */
04083    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04084    // TODO: I don't think any marking is necessary
04085 
04086    /* Reload configuration */
04087    res = load_config();
04088    
04089    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04090    return res;
04091 }

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

References FEATURES_COUNT, and ast_call_feature::sname.

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

01885 {
01886    int x;
01887    for (x = 0; x < FEATURES_COUNT; x++) {
01888       if (!strcasecmp(name, builtin_features[x].sname))
01889          return &builtin_features[x];
01890    }
01891    return NULL;
01892 }

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

00895 {
00896    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00897 }

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

References park_call_full(), and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

00824 {
00825    struct ast_park_call_args args = {
00826       .timeout = timeout,
00827       .extout = extout,
00828    };
00829 
00830    return park_call_full(chan, peer, &args);
00831 }

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

00316 {
00317    return parking_ext;
00318 }

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

References ast_answer(), ast_channel_masquerade(), ast_channel_search_locked(), ast_channel_unlock, AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), ast_stream_and_wait(), ast_strlen_zero(), find_channel_by_group(), LOG_WARNING, ast_channel::name, pickupfailsound, and pickupsound.

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

04476 {
04477    struct ast_channel *cur = ast_channel_search_locked(find_channel_by_group, chan);
04478 
04479    if (cur) {
04480       int res = -1;
04481       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04482       res = ast_answer(chan);
04483       if (res)
04484          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04485       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04486       if (res)
04487          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04488       res = ast_channel_masquerade(cur, chan);
04489       if (res)
04490          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04491       if (!ast_strlen_zero(pickupsound)) {
04492          ast_stream_and_wait(cur, pickupsound, "");
04493       }
04494       ast_channel_unlock(cur);
04495       return res;
04496    } else   {
04497       ast_debug(1, "No call pickup possible...\n");
04498       if (!ast_strlen_zero(pickupfailsound)) {
04499          ast_stream_and_wait(chan, pickupfailsound, "");
04500       }
04501    }
04502    return -1;
04503 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 320 of file features.c.

References pickup_ext.

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

00321 {
00322    return pickup_ext;
00323 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1874 of file features.c.

References ast_rwlock_rdlock(), and features_lock.

Referenced by handle_request_info().

01875 {
01876    ast_rwlock_rdlock(&features_lock);
01877 }

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

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

Referenced by load_config().

01712 {
01713    if (!feature) {
01714       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01715       return;
01716    }
01717   
01718    AST_RWLIST_WRLOCK(&feature_list);
01719    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01720    AST_RWLIST_UNLOCK(&feature_list);
01721 
01722    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01723 }

void ast_unlock_call_features ( void   ) 

Definition at line 1879 of file features.c.

References ast_rwlock_unlock(), and features_lock.

Referenced by handle_request_info().

01880 {
01881    ast_rwlock_unlock(&features_lock);
01882 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

01800 {
01801    if (!feature) {
01802       return;
01803    }
01804 
01805    AST_RWLIST_WRLOCK(&feature_list);
01806    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01807    AST_RWLIST_UNLOCK(&feature_list);
01808 
01809    ast_free(feature);
01810 }


Generated by  doxygen 1.6.2