Wed Mar 3 22:55:01 2010

Asterisk developer's documentation


features.h File Reference

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

#include "asterisk/pbx.h"
#include "asterisk/linkedlists.h"
Include dependency graph for features.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_call_feature

Defines

#define AST_FEATURE_RETURN_HANGUP   -1
#define AST_FEATURE_RETURN_KEEPTRYING   24
#define AST_FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
#define AST_FEATURE_RETURN_PARKFAILED   25
#define AST_FEATURE_RETURN_PASSDIGITS   21
#define AST_FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
#define AST_FEATURE_RETURN_STOREDIGITS   22
#define AST_FEATURE_RETURN_SUCCESS   23
#define AST_FEATURE_RETURN_SUCCESSBREAK   0
#define FEATURE_APP_ARGS_LEN   256
#define FEATURE_APP_LEN   64
#define FEATURE_EXTEN_LEN   32
#define FEATURE_MAX_LEN   11
#define FEATURE_MOH_LEN   80
#define FEATURE_SENSE_CHAN   (1 << 0)
#define FEATURE_SENSE_PEER   (1 << 1)
#define FEATURE_SNAME_LEN   32
#define PARK_APP_NAME   "Park"

Typedefs

typedef int(* ast_feature_operation )(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)

Enumerations

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

main call feature structure

More...

Functions

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

Detailed Description

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

Definition in file features.h.


Define Documentation

#define AST_FEATURE_RETURN_HANGUP   -1

Definition at line 39 of file features.h.

Referenced by builtin_disconnect().

#define AST_FEATURE_RETURN_KEEPTRYING   24

Definition at line 46 of file features.h.

Referenced by feature_exec_app(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 42 of file features.h.

#define AST_FEATURE_RETURN_PARKFAILED   25

Definition at line 47 of file features.h.

Referenced by builtin_blindtransfer(), and masq_park_call().

#define AST_FEATURE_RETURN_PASSDIGITS   21

Definition at line 43 of file features.h.

Referenced by ast_bridge_call(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 41 of file features.h.

#define AST_FEATURE_RETURN_STOREDIGITS   22

Definition at line 44 of file features.h.

Referenced by detect_disconnect(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_SUCCESS   23
#define AST_FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 40 of file features.h.

Referenced by feature_exec_app().

#define FEATURE_APP_ARGS_LEN   256

Definition at line 32 of file features.h.

Referenced by load_config().

#define FEATURE_APP_LEN   64

Definition at line 31 of file features.h.

Referenced by load_config().

#define FEATURE_EXTEN_LEN   32

Definition at line 34 of file features.h.

Referenced by load_config().

#define FEATURE_MAX_LEN   11

Definition at line 30 of file features.h.

Referenced by ast_bridge_call(), and wait_for_answer().

#define FEATURE_MOH_LEN   80

Definition at line 35 of file features.h.

Referenced by load_config().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 49 of file features.h.

Referenced by ast_bridge_call(), ast_feature_interpret(), and feature_exec_app().

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 50 of file features.h.

Referenced by ast_bridge_call(), and set_peers().

#define FEATURE_SNAME_LEN   32

Definition at line 33 of file features.h.

Referenced by load_config().

#define PARK_APP_NAME   "Park"

Definition at line 37 of file features.h.

Referenced by handle_exec().


Typedef Documentation

typedef int(* ast_feature_operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)

Definition at line 52 of file features.h.


Enumeration Type Documentation

anonymous enum

main call feature structure

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 56 of file features.h.

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


Function Documentation

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

Bridge a call, optionally allowing redirection.

Bridge a call, optionally allowing redirection.

Parameters:
chan,peer,config Set start time, check for two channels,check if monitor on check for feature activation, create new CDR
Return values:
res on success.
-1 on failure to bridge.

append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.

Todo:
XXX how do we guarantee the latter ?

Definition at line 2391 of file features.c.

References ast_channel::_state, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_bridge_config::end_sound, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_frame::frametype, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_bridge_config::play_warning, ast_channel::priority, ast_frame::ptr, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::uniqueid, ast_cdr::userfield, ast_channel::visible_indication, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

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

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4005 of file features.c.

References load_config().

Referenced by handle_features_reload().

04006 {
04007    int res;
04008    /* Release parking lot list */
04009    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04010    // TODO: I don't think any marking is necessary
04011 
04012    /* Reload configuration */
04013    res = load_config();
04014    
04015    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04016    return res;
04017 }

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

References FEATURES_COUNT, and ast_call_feature::sname.

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

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

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

00817 {
00818    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00819 }

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

References ast_park_call_full(), and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

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

const char* ast_parking_ext ( void   ) 

Determine system parking extension.

Returns:
the call parking extension for drivers that provide special call parking help

Definition at line 243 of file features.c.

References parking_ext.

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

00244 {
00245    return parking_ext;
00246 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Parameters:
chan channel that initiated pickup.

Walk list of channels, checking it is not itself, channel is pbx one, check that the callgroup for both channels are the same and the channel is ringing. Answer calling channel, flag channel as answered on queue, masq channels together.

Definition at line 4389 of file features.c.

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

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

04390 {
04391    struct ast_channel *cur = NULL;
04392    int res = -1;
04393 
04394    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04395       if (!cur->pbx && 
04396          (cur != chan) &&
04397          (chan->pickupgroup & cur->callgroup) &&
04398          ((cur->_state == AST_STATE_RINGING) ||
04399           (cur->_state == AST_STATE_RING))) {
04400             break;
04401       }
04402       ast_channel_unlock(cur);
04403    }
04404    if (cur) {
04405       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04406       res = ast_answer(chan);
04407       if (res)
04408          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04409       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04410       if (res)
04411          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04412       res = ast_channel_masquerade(cur, chan);
04413       if (res)
04414          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04415       ast_channel_unlock(cur);
04416    } else   {
04417       ast_debug(1, "No call pickup possible...\n");
04418    }
04419    return res;
04420 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 248 of file features.c.

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

00249 {
00250    return pickup_ext;
00251 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1793 of file features.c.

References ast_rwlock_rdlock().

Referenced by handle_request_info().

01794 {
01795    ast_rwlock_rdlock(&features_lock);
01796 }

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

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

Referenced by load_config().

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

void ast_unlock_call_features ( void   ) 

Definition at line 1798 of file features.c.

References ast_rwlock_unlock().

Referenced by handle_request_info().

01799 {
01800    ast_rwlock_unlock(&features_lock);
01801 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

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


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