Sun Aug 15 20:33:39 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 1760 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().

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

01435                                                                                                                            {
01436 
01437    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01438 }

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

References masq_park_call().

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

00616 {
00617    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00618 }

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

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00560 {
00561    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00562 }

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

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

00212 {
00213    return parking_ext;
00214 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

02933 {
02934    struct ast_channel *cur = NULL;
02935    int res = -1;
02936 
02937    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02938       if (!cur->pbx && 
02939          (cur != chan) &&
02940          (chan->pickupgroup & cur->callgroup) &&
02941          ((cur->_state == AST_STATE_RINGING) ||
02942           (cur->_state == AST_STATE_RING))) {
02943             break;
02944       }
02945       ast_channel_unlock(cur);
02946    }
02947    if (cur) {
02948       if (option_debug)
02949          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02950       res = ast_answer(chan);
02951       if (res)
02952          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02953       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02954       if (res)
02955          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02956       res = ast_channel_masquerade(cur, chan);
02957       if (res)
02958          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02959       ast_channel_unlock(cur);
02960    } else   {
02961       if (option_debug)
02962          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02963    }
02964    return res;
02965 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 216 of file res_features.c.

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

00217 {
00218    return pickup_ext;
00219 }

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

01173 {
01174    if (!feature) {
01175       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01176          return;
01177    }
01178   
01179    AST_RWLIST_WRLOCK(&feature_list);
01180    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01181    AST_RWLIST_UNLOCK(&feature_list);
01182 
01183    if (option_verbose >= 2) {
01184       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01185    }
01186 }

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

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

01190 {
01191    if (!feature)
01192       return;
01193 
01194    AST_RWLIST_WRLOCK(&feature_list);
01195    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01196    AST_RWLIST_UNLOCK(&feature_list);
01197    
01198    free(feature);
01199 }


Generated on Sun Aug 15 20:33:39 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7