Tue Apr 6 15:45:55 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 1751 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().

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

01426                                                                                                                            {
01427 
01428    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01429 }

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

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

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

01164 {
01165    if (!feature) {
01166       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01167          return;
01168    }
01169   
01170    AST_RWLIST_WRLOCK(&feature_list);
01171    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01172    AST_RWLIST_UNLOCK(&feature_list);
01173 
01174    if (option_verbose >= 2) {
01175       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01176    }
01177 }

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

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

01181 {
01182    if (!feature)
01183       return;
01184 
01185    AST_RWLIST_WRLOCK(&feature_list);
01186    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01187    AST_RWLIST_UNLOCK(&feature_list);
01188    
01189    free(feature);
01190 }


Generated on Tue Apr 6 15:45:55 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7