Fri Apr 24 16:26: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_SNAME_LEN   32
#define PARK_APP_NAME   "Park"

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

#define FEATURE_MOH_LEN   80

Definition at line 34 of file features.h.

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


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 1647 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_NULL, ast_cdr_setcid(), 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_interpret(), 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_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_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, 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(), park_exec(), and try_calling().

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

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

02781 {
02782    struct ast_channel *cur = NULL;
02783    int res = -1;
02784 
02785    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02786       if (!cur->pbx && 
02787          (cur != chan) &&
02788          (chan->pickupgroup & cur->callgroup) &&
02789          ((cur->_state == AST_STATE_RINGING) ||
02790           (cur->_state == AST_STATE_RING))) {
02791             break;
02792       }
02793       ast_channel_unlock(cur);
02794    }
02795    if (cur) {
02796       if (option_debug)
02797          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02798       res = ast_answer(chan);
02799       if (res)
02800          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02801       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02802       if (res)
02803          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02804       res = ast_channel_masquerade(cur, chan);
02805       if (res)
02806          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02807       ast_channel_unlock(cur);
02808    } else   {
02809       if (option_debug)
02810          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02811    }
02812    return res;
02813 }

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

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

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

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

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


Generated on Fri Apr 24 16:26:30 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7