Fri Sep 11 13:45:30 2009

Asterisk developer's documentation


features.h File Reference

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

#include "asterisk/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 1706 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().

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

01385                                                                                                                            {
01386 
01387    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01388 }

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

References masq_park_call().

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

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

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

02861 {
02862    struct ast_channel *cur = NULL;
02863    int res = -1;
02864 
02865    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02866       if (!cur->pbx && 
02867          (cur != chan) &&
02868          (chan->pickupgroup & cur->callgroup) &&
02869          ((cur->_state == AST_STATE_RINGING) ||
02870           (cur->_state == AST_STATE_RING))) {
02871             break;
02872       }
02873       ast_channel_unlock(cur);
02874    }
02875    if (cur) {
02876       if (option_debug)
02877          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02878       res = ast_answer(chan);
02879       if (res)
02880          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02881       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02882       if (res)
02883          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02884       res = ast_channel_masquerade(cur, chan);
02885       if (res)
02886          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02887       ast_channel_unlock(cur);
02888    } else   {
02889       if (option_debug)
02890          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02891    }
02892    return res;
02893 }

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

01123 {
01124    if (!feature) {
01125       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01126          return;
01127    }
01128   
01129    AST_RWLIST_WRLOCK(&feature_list);
01130    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01131    AST_RWLIST_UNLOCK(&feature_list);
01132 
01133    if (option_verbose >= 2) {
01134       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01135    }
01136 }

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

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

01140 {
01141    if (!feature)
01142       return;
01143 
01144    AST_RWLIST_WRLOCK(&feature_list);
01145    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01146    AST_RWLIST_UNLOCK(&feature_list);
01147    
01148    free(feature);
01149 }


Generated on Fri Sep 11 13:45:30 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7