Thu Jan 28 17:36:04 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 1711 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().

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

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

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

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

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

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

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

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

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


Generated on Thu Jan 28 17:36:04 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7