Fri Feb 19 17:13:07 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/linkedlists.h"

Go to the source code of this file.

Data Structures

struct  ast_call_feature
 main call feature structure More...

Defines

#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_RETURN_HANGUP   -1
#define FEATURE_RETURN_KEEPTRYING   24
#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
#define FEATURE_RETURN_PARKFAILED   25
#define FEATURE_RETURN_PASSDIGITS   21
#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
#define FEATURE_RETURN_STOREDIGITS   22
#define FEATURE_RETURN_SUCCESS   23
#define FEATURE_RETURN_SUCCESSBREAK   0
#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)

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_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.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
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 FEATURE_APP_ARGS_LEN   256

Definition at line 31 of file features.h.

#define FEATURE_APP_LEN   64

Definition at line 30 of file features.h.

#define FEATURE_EXTEN_LEN   32

Definition at line 33 of file features.h.

#define FEATURE_MAX_LEN   11

Definition at line 29 of file features.h.

Referenced by ast_bridge_call(), and wait_for_answer().

#define FEATURE_MOH_LEN   80

Definition at line 34 of file features.h.

#define FEATURE_RETURN_HANGUP   -1

Definition at line 38 of file features.h.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 45 of file features.h.

Referenced by feature_exec_app(), and feature_interpret_helper().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 41 of file features.h.

#define FEATURE_RETURN_PARKFAILED   25

Definition at line 46 of file features.h.

Referenced by builtin_blindtransfer(), and masq_park_call().

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 42 of file features.h.

Referenced by ast_bridge_call(), and feature_interpret_helper().

#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 40 of file features.h.

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 43 of file features.h.

Referenced by detect_disconnect(), and feature_interpret_helper().

#define FEATURE_RETURN_SUCCESS   23

Definition at line 44 of file features.h.

Referenced by ast_bridge_call(), builtin_automonitor(), builtin_blindtransfer(), do_atxfer(), and feature_exec_app().

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 39 of file features.h.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 48 of file features.h.

Referenced by ast_bridge_call(), cmd_atxfer(), feature_exec_app(), and feature_interpret().

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 49 of file features.h.

Referenced by ast_bridge_call(), cmd_atxfer(), and set_peers().

#define FEATURE_SNAME_LEN   32

Definition at line 32 of file features.h.

#define PARK_APP_NAME   "Park"

Definition at line 36 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 51 of file features.h.


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.

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 1744 of file res_features.c.

References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_channel::amaflags, ast_cdr::answer, ast_channel::appl, ast_answer(), 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_NOANSWER, ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_ATXFERCMD, 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_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, 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_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_verbose(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, cmd_atxfer(), config, ast_channel::context, ast_channel::data, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_interpret(), FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, ast_option_header::option, option_debug, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_cdr::uniqueid, ast_channel::uniqueid, ast_cdr::userfield, VERBOSE_PREFIX_2, and ast_channel::visible_indication.

Referenced by app_exec(), ast_bridge_call_thread(), do_atxfer(), and park_exec().

01745 {
01746    /* Copy voice back and forth between the two channels.  Give the peer
01747       the ability to transfer calls with '#<extension' syntax. */
01748    struct ast_frame *f;
01749    struct ast_channel *who;
01750    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01751    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01752    char orig_channame[AST_MAX_EXTENSION];
01753    char orig_peername[AST_MAX_EXTENSION];
01754 
01755    int res;
01756    int diff;
01757    int hasfeatures=0;
01758    int hadfeatures=0;
01759    int autoloopflag;
01760    struct ast_option_header *aoh;
01761    struct ast_bridge_config backup_config;
01762    struct ast_cdr *bridge_cdr = NULL;
01763    struct ast_cdr *orig_peer_cdr = NULL;
01764    struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */
01765    struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */
01766    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
01767    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
01768 
01769    memset(&backup_config, 0, sizeof(backup_config));
01770 
01771    config->start_time = ast_tvnow();
01772 
01773    if (chan && peer) {
01774       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01775       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01776    } else if (chan) {
01777       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01778    }
01779 
01780    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
01781    add_features_datastores(chan, peer, config);
01782 
01783    /* This is an interesting case.  One example is if a ringing channel gets redirected to
01784     * an extension that picks up a parked call.  This will make sure that the call taken
01785     * out of parking gets told that the channel it just got bridged to is still ringing. */
01786    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
01787       ast_indicate(peer, AST_CONTROL_RINGING);
01788    }
01789 
01790    if (monitor_ok) {
01791       const char *monitor_exec;
01792       struct ast_channel *src = NULL;
01793       if (!monitor_app) { 
01794          if (!(monitor_app = pbx_findapp("Monitor")))
01795             monitor_ok=0;
01796       }
01797       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01798          src = chan;
01799       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01800          src = peer;
01801       if (monitor_app && src) {
01802          char *tmp = ast_strdupa(monitor_exec);
01803          pbx_exec(src, monitor_app, tmp);
01804       }
01805    }
01806 
01807    set_config_flags(chan, peer, config);
01808    config->firstpass = 1;
01809 
01810    /* Answer if need be */
01811    if (ast_answer(chan))
01812       return -1;
01813 
01814    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
01815    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
01816    orig_peer_cdr = peer_cdr;
01817    
01818    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
01819          
01820       if (chan_cdr) {
01821          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
01822          ast_cdr_update(chan);
01823          bridge_cdr = ast_cdr_dup(chan_cdr);
01824          /* rip any forked CDR's off of the chan_cdr and attach
01825           * them to the bridge_cdr instead */
01826          bridge_cdr->next = chan_cdr->next;
01827          chan_cdr->next = NULL;
01828          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
01829          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
01830          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
01831             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
01832          }
01833       } else {
01834          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
01835          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
01836          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
01837          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
01838          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
01839          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
01840          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
01841          ast_cdr_setcid(bridge_cdr, chan);
01842          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
01843          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
01844          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
01845          /* Destination information */
01846          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
01847          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
01848          if (peer_cdr) {
01849             bridge_cdr->start = peer_cdr->start;
01850             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
01851          } else {
01852             ast_cdr_start(bridge_cdr);
01853          }
01854       }
01855       /* peer_cdr->answer will be set when a macro runs on the peer;
01856          in that case, the bridge answer will be delayed while the
01857          macro plays on the peer channel. The peer answered the call
01858          before the macro started playing. To the phone system,
01859          this is billable time for the call, even tho the caller
01860          hears nothing but ringing while the macro does its thing. */
01861 
01862       /* Another case where the peer cdr's time will be set, is when
01863          A self-parks by pickup up phone and dialing 700, then B
01864          picks up A by dialing its parking slot; there may be more 
01865          practical paths that get the same result, tho... in which
01866          case you get the previous answer time from the Park... which
01867          is before the bridge's start time, so I added in the 
01868          tvcmp check to the if below */
01869 
01870       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
01871          ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
01872          ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
01873          if (chan_cdr) {
01874             ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
01875             ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
01876          }
01877       } else {
01878          ast_cdr_answer(bridge_cdr);
01879          if (chan_cdr) {
01880             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
01881          }
01882       }
01883       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
01884          if (chan_cdr) {
01885             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
01886          }
01887          if (peer_cdr) {
01888             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
01889          }
01890       }
01891    }
01892 
01893    for (;;) {
01894       struct ast_channel *other; /* used later */
01895 
01896       res = ast_channel_bridge(chan, peer, config, &f, &who);
01897       
01898       /* When frame is not set, we are probably involved in a situation
01899          where we've timed out.
01900          When frame is set, we'll come thru this code twice; once for DTMF_BEGIN
01901          and also for DTMF_END. If we flow into the following 'if' for both, then 
01902          our wait times are cut in half, as both will subtract from the
01903          feature_timer. Not good!
01904       */
01905       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
01906          /* Update time limit for next pass */
01907          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01908          if (res == AST_BRIDGE_RETRY) {
01909             /* The feature fully timed out but has not been updated. Skip
01910              * the potential round error from the diff calculation and
01911              * explicitly set to expired. */
01912             config->feature_timer = -1;
01913          } else {
01914             config->feature_timer -= diff;
01915          }
01916 
01917          if (hasfeatures) {
01918             /* Running on backup config, meaning a feature might be being
01919                activated, but that's no excuse to keep things going 
01920                indefinitely! */
01921             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01922                if (option_debug)
01923                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01924                config->feature_timer = 0;
01925                who = chan;
01926                if (f)
01927                   ast_frfree(f);
01928                f = NULL;
01929                res = 0;
01930             } else if (config->feature_timer <= 0) {
01931                /* Not *really* out of time, just out of time for
01932                   digits to come in for features. */
01933                if (option_debug)
01934                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01935                if (!ast_strlen_zero(peer_featurecode)) {
01936                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01937                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01938                }
01939                if (!ast_strlen_zero(chan_featurecode)) {
01940                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01941                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01942                }
01943                if (f)
01944                   ast_frfree(f);
01945                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01946                if (!hasfeatures) {
01947                   /* Restore original (possibly time modified) bridge config */
01948                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01949                   memset(&backup_config, 0, sizeof(backup_config));
01950                }
01951                hadfeatures = hasfeatures;
01952                /* Continue as we were */
01953                continue;
01954             } else if (!f) {
01955                /* The bridge returned without a frame and there is a feature in progress.
01956                 * However, we don't think the feature has quite yet timed out, so just
01957                 * go back into the bridge. */
01958                continue;
01959             }
01960          } else {
01961             if (config->feature_timer <=0) {
01962                /* We ran out of time */
01963                config->feature_timer = 0;
01964                who = chan;
01965                if (f)
01966                   ast_frfree(f);
01967                f = NULL;
01968                res = 0;
01969             }
01970          }
01971       }
01972       if (res < 0) {
01973          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01974             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01975          goto before_you_go;
01976       }
01977       
01978       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01979             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01980                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01981          res = -1;
01982          break;
01983       }
01984       /* many things should be sent to the 'other' channel */
01985       other = (who == chan) ? peer : chan;
01986       if (f->frametype == AST_FRAME_CONTROL) {
01987          switch (f->subclass) {
01988          case AST_CONTROL_RINGING:
01989          case AST_CONTROL_FLASH:
01990          case -1:
01991             ast_indicate(other, f->subclass);
01992             break;
01993          case AST_CONTROL_HOLD:
01994          case AST_CONTROL_UNHOLD:
01995             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01996             break;
01997          case AST_CONTROL_OPTION:
01998             aoh = f->data;
01999             /* Forward option Requests */
02000             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02001                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
02002                   f->datalen - sizeof(struct ast_option_header), 0);
02003             }
02004             break;
02005          case AST_CONTROL_ATXFERCMD:
02006             cmd_atxfer(chan, peer, config, who, f->data);
02007             break;
02008          }
02009       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02010          /* eat it */
02011       } else if (f->frametype == AST_FRAME_DTMF) {
02012          char *featurecode;
02013          int sense;
02014 
02015          hadfeatures = hasfeatures;
02016          /* This cannot overrun because the longest feature is one shorter than our buffer */
02017          if (who == chan) {
02018             sense = FEATURE_SENSE_CHAN;
02019             featurecode = chan_featurecode;
02020          } else  {
02021             sense = FEATURE_SENSE_PEER;
02022             featurecode = peer_featurecode;
02023          }
02024          /*! append the event to featurecode. we rely on the string being zero-filled, and
02025           * not overflowing it. 
02026           * \todo XXX how do we guarantee the latter ?
02027           */
02028          featurecode[strlen(featurecode)] = f->subclass;
02029          /* Get rid of the frame before we start doing "stuff" with the channels */
02030          ast_frfree(f);
02031          f = NULL;
02032          config->feature_timer = backup_config.feature_timer;
02033          res = feature_interpret(chan, peer, config, featurecode, sense);
02034          switch(res) {
02035          case FEATURE_RETURN_PASSDIGITS:
02036             ast_dtmf_stream(other, who, featurecode, 0);
02037             /* Fall through */
02038          case FEATURE_RETURN_SUCCESS:
02039             memset(featurecode, 0, sizeof(chan_featurecode));
02040             break;
02041          }
02042          if (res >= FEATURE_RETURN_PASSDIGITS) {
02043             res = 0;
02044          } else 
02045             break;
02046          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02047          if (hadfeatures && !hasfeatures) {
02048             /* Restore backup */
02049             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02050             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02051          } else if (hasfeatures) {
02052             if (!hadfeatures) {
02053                /* Backup configuration */
02054                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02055                /* Setup temporary config options */
02056                config->play_warning = 0;
02057                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02058                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02059                config->warning_freq = 0;
02060                config->warning_sound = NULL;
02061                config->end_sound = NULL;
02062                config->start_sound = NULL;
02063                config->firstpass = 0;
02064             }
02065             config->start_time = ast_tvnow();
02066             config->feature_timer = featuredigittimeout;
02067             if (option_debug)
02068                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
02069          }
02070       }
02071       if (f)
02072          ast_frfree(f);
02073 
02074    }
02075   before_you_go:
02076 
02077    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02078       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
02079       if (bridge_cdr) {
02080          ast_cdr_discard(bridge_cdr);
02081          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
02082       }
02083       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
02084    }
02085 
02086    if (config->end_bridge_callback) {
02087       config->end_bridge_callback(config->end_bridge_callback_data);
02088    }
02089 
02090    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 
02091        ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02092       struct ast_cdr *swapper = NULL;
02093       char savelastapp[AST_MAX_EXTENSION];
02094       char savelastdata[AST_MAX_EXTENSION];
02095       char save_exten[AST_MAX_EXTENSION];
02096       int  save_prio, spawn_error = 0;
02097       
02098       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02099       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02100       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02101          ast_cdr_end(bridge_cdr);
02102       }
02103       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
02104          dialplan code operate on it */
02105       ast_channel_lock(chan);
02106       if (bridge_cdr) {
02107          swapper = chan->cdr;
02108          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02109          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02110          chan->cdr = bridge_cdr;
02111       }
02112       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02113       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02114       save_prio = chan->priority;
02115       chan->priority = 1;
02116       ast_channel_unlock(chan);
02117       while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
02118          if ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) {
02119             /* Something bad happened, or a hangup has been requested. */
02120             if (option_debug)
02121                ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02122             if (option_verbose > 1)
02123                ast_verbose( VERBOSE_PREFIX_2 "Spawn h extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02124             break;
02125          }
02126          chan->priority++;
02127       }
02128       /* swap it back */
02129       ast_channel_lock(chan);
02130       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02131       chan->priority = save_prio;
02132       if (bridge_cdr) {
02133          if (chan->cdr == bridge_cdr) {
02134             chan->cdr = swapper;
02135          } else {
02136             bridge_cdr = NULL;
02137          }
02138       }
02139       if (chan->priority != 1 || !spawn_error) {
02140          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02141       }
02142       ast_channel_unlock(chan);
02143       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
02144       if (bridge_cdr) {
02145          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02146          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02147       }
02148       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02149    }
02150    
02151    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
02152    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02153    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
02154       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02155    }
02156 
02157    /* we can post the bridge CDR at this point */
02158    if (bridge_cdr) {
02159       ast_cdr_end(bridge_cdr);
02160       ast_cdr_detach(bridge_cdr);
02161    }
02162    
02163    /* do a specialized reset on the beginning channel
02164       CDR's, if they still exist, so as not to mess up
02165       issues in future bridges;
02166       
02167       Here are the rules of the game:
02168       1. The chan and peer channel pointers will not change
02169          during the life of the bridge.
02170       2. But, in transfers, the channel names will change.
02171          between the time the bridge is started, and the
02172          time the channel ends. 
02173          Usually, when a channel changes names, it will
02174          also change CDR pointers.
02175       3. Usually, only one of the two channels (chan or peer)
02176          will change names.
02177       4. Usually, if a channel changes names during a bridge,
02178          it is because of a transfer. Usually, in these situations,
02179          it is normal to see 2 bridges running simultaneously, and
02180          it is not unusual to see the two channels that change
02181          swapped between bridges.
02182       5. After a bridge occurs, we have 2 or 3 channels' CDRs
02183          to attend to; if the chan or peer changed names,
02184          we have the before and after attached CDR's.
02185    */
02186    
02187    if (new_chan_cdr) {
02188       struct ast_channel *chan_ptr = NULL;
02189       
02190       if (strcasecmp(orig_channame, chan->name) != 0) { 
02191          /* old channel */
02192          chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02193          if (chan_ptr) {
02194             if (!ast_bridged_channel(chan_ptr)) {
02195                struct ast_cdr *cur;
02196                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02197                   if (cur == chan_cdr) {
02198                      break;
02199                   }
02200                }
02201                if (cur)
02202                   ast_cdr_specialized_reset(chan_cdr,0);
02203             }
02204             ast_channel_unlock(chan_ptr);
02205          }
02206          /* new channel */
02207          ast_cdr_specialized_reset(new_chan_cdr,0);
02208       } else {
02209          ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr  */
02210       }
02211    }
02212 
02213    {
02214       struct ast_channel *chan_ptr = NULL;
02215       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02216       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))
02217          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
02218       if (strcasecmp(orig_peername, peer->name) != 0) { 
02219          /* old channel */
02220          chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02221          if (chan_ptr) {
02222             if (!ast_bridged_channel(chan_ptr)) {
02223                struct ast_cdr *cur;
02224                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02225                   if (cur == peer_cdr) {
02226                      break;
02227                   }
02228                }
02229                if (cur)
02230                   ast_cdr_specialized_reset(peer_cdr,0);
02231             }
02232             ast_channel_unlock(chan_ptr);
02233          }
02234          /* new channel */
02235          ast_cdr_specialized_reset(new_peer_cdr,0);
02236       } else {
02237          ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr  */
02238       }
02239    }
02240    
02241    return res;
02242 }

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 1419 of file res_features.c.

References feature_interpret_helper().

Referenced by detect_disconnect().

01419                                                                                                                            {
01420 
01421    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01422 }

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 Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want

Definition at line 608 of file res_features.c.

References masq_park_call().

Referenced by handle_exec(), manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().

00609 {
00610    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00611 }

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

Park a call and read back parked location.

Note:
We put the user in the parking list, then wake up the parking thread to be sure it looks after these channels too

Definition at line 552 of file res_features.c.

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00553 {
00554    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00555 }

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 207 of file res_features.c.

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

00208 {
00209    return parking_ext;
00210 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2901 of file res_features.c.

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

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

02902 {
02903    struct ast_channel *cur = NULL;
02904    int res = -1;
02905 
02906    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02907       if (!cur->pbx && 
02908          (cur != chan) &&
02909          (chan->pickupgroup & cur->callgroup) &&
02910          ((cur->_state == AST_STATE_RINGING) ||
02911           (cur->_state == AST_STATE_RING))) {
02912             break;
02913       }
02914       ast_channel_unlock(cur);
02915    }
02916    if (cur) {
02917       if (option_debug)
02918          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02919       res = ast_answer(chan);
02920       if (res)
02921          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02922       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02923       if (res)
02924          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02925       res = ast_channel_masquerade(cur, chan);
02926       if (res)
02927          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02928       ast_channel_unlock(cur);
02929    } else   {
02930       if (option_debug)
02931          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02932    }
02933    return res;
02934 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 212 of file res_features.c.

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

00213 {
00214    return pickup_ext;
00215 }

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 1156 of file res_features.c.

References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verbose(), ast_call_feature::feature_entry, LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.

01157 {
01158    if (!feature) {
01159       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01160          return;
01161    }
01162   
01163    AST_RWLIST_WRLOCK(&feature_list);
01164    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01165    AST_RWLIST_UNLOCK(&feature_list);
01166 
01167    if (option_verbose >= 2) {
01168       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01169    }
01170 }

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 1173 of file res_features.c.

References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.

01174 {
01175    if (!feature)
01176       return;
01177 
01178    AST_RWLIST_WRLOCK(&feature_list);
01179    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01180    AST_RWLIST_UNLOCK(&feature_list);
01181    
01182    free(feature);
01183 }


Generated on Fri Feb 19 17:13:07 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7