Fri Jun 19 12:10:34 2009

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

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), ast_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_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, 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(), park_exec_full(), and try_calling().

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

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

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

Referenced by detect_disconnect().

02042                                                                                                                            {
02043 
02044    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02045 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 3969 of file features.c.

References load_config().

Referenced by handle_features_reload().

03970 {
03971    int res;
03972    /* Release parking lot list */
03973    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
03974    // TODO: I don't think any marking is necessary
03975 
03976    /* Reload configuration */
03977    res = load_config();
03978    
03979    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
03980    return res;
03981 }

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

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

01796 {
01797    int x;
01798    for (x = 0; x < FEATURES_COUNT; x++) {
01799       if (!strcasecmp(name, builtin_features[x].sname))
01800          return &builtin_features[x];
01801    }
01802    return NULL;
01803 }

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

00809 {
00810    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00811 }

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

00743 {
00744    struct ast_park_call_args args = {
00745       .timeout = timeout,
00746       .extout = extout,
00747    };
00748 
00749    return ast_park_call_full(chan, peer, &args);
00750 }

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

00243 {
00244    return parking_ext;
00245 }

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

04354 {
04355    struct ast_channel *cur = NULL;
04356    int res = -1;
04357 
04358    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04359       if (!cur->pbx && 
04360          (cur != chan) &&
04361          (chan->pickupgroup & cur->callgroup) &&
04362          ((cur->_state == AST_STATE_RINGING) ||
04363           (cur->_state == AST_STATE_RING))) {
04364             break;
04365       }
04366       ast_channel_unlock(cur);
04367    }
04368    if (cur) {
04369       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04370       res = ast_answer(chan);
04371       if (res)
04372          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04373       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04374       if (res)
04375          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04376       res = ast_channel_masquerade(cur, chan);
04377       if (res)
04378          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04379       ast_channel_unlock(cur);
04380    } else   {
04381       ast_debug(1, "No call pickup possible...\n");
04382    }
04383    return res;
04384 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 247 of file features.c.

References pickup_ext.

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

00248 {
00249    return pickup_ext;
00250 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1785 of file features.c.

References ast_rwlock_rdlock(), and features_lock.

Referenced by handle_request_info().

01786 {
01787    ast_rwlock_rdlock(&features_lock);
01788 }

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

01623 {
01624    if (!feature) {
01625       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01626       return;
01627    }
01628   
01629    AST_RWLIST_WRLOCK(&feature_list);
01630    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01631    AST_RWLIST_UNLOCK(&feature_list);
01632 
01633    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01634 }

void ast_unlock_call_features ( void   ) 

Definition at line 1790 of file features.c.

References ast_rwlock_unlock(), and features_lock.

Referenced by handle_request_info().

01791 {
01792    ast_rwlock_unlock(&features_lock);
01793 }

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

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

01711 {
01712    if (!feature) {
01713       return;
01714    }
01715 
01716    AST_RWLIST_WRLOCK(&feature_list);
01717    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01718    AST_RWLIST_UNLOCK(&feature_list);
01719 
01720    ast_free(feature);
01721 }


Generated on Fri Jun 19 12:10:34 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7