Thu Dec 17 15:36:03 2009

Asterisk developer's documentation


features.h File Reference

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

#include "asterisk/linkedlists.h"

Go to the source code of this file.

Data Structures

struct  ast_call_feature
 main call feature structure More...

Defines

#define FEATURE_APP_ARGS_LEN   256
#define FEATURE_APP_LEN   64
#define FEATURE_EXTEN_LEN   32
#define FEATURE_MAX_LEN   11
#define FEATURE_MOH_LEN   80
#define FEATURE_RETURN_HANGUP   -1
#define FEATURE_RETURN_KEEPTRYING   24
#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
#define FEATURE_RETURN_PARKFAILED   25
#define FEATURE_RETURN_PASSDIGITS   21
#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
#define FEATURE_RETURN_STOREDIGITS   22
#define FEATURE_RETURN_SUCCESS   23
#define FEATURE_RETURN_SUCCESSBREAK   0
#define FEATURE_SENSE_CHAN   (1 << 0)
#define FEATURE_SENSE_PEER   (1 << 1)
#define FEATURE_SNAME_LEN   32
#define PARK_APP_NAME   "Park"

Typedefs

typedef int(*) ast_feature_operation (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)

Functions

int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature)
 detect a feature before bridging
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *host, int timeout, int *extout)
 Park a call and read back parked location.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set


Detailed Description

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

Definition in file features.h.


Define Documentation

#define FEATURE_APP_ARGS_LEN   256

Definition at line 31 of file features.h.

#define FEATURE_APP_LEN   64

Definition at line 30 of file features.h.

#define FEATURE_EXTEN_LEN   32

Definition at line 33 of file features.h.

#define FEATURE_MAX_LEN   11

Definition at line 29 of file features.h.

Referenced by ast_bridge_call(), and wait_for_answer().

#define FEATURE_MOH_LEN   80

Definition at line 34 of file features.h.

#define FEATURE_RETURN_HANGUP   -1

Definition at line 38 of file features.h.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 45 of file features.h.

Referenced by feature_exec_app(), and feature_interpret_helper().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 41 of file features.h.

#define FEATURE_RETURN_PARKFAILED   25

Definition at line 46 of file features.h.

Referenced by builtin_blindtransfer(), and masq_park_call().

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 42 of file features.h.

Referenced by ast_bridge_call(), and feature_interpret_helper().

#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 40 of file features.h.

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 43 of file features.h.

Referenced by detect_disconnect(), and feature_interpret_helper().

#define FEATURE_RETURN_SUCCESS   23

Definition at line 44 of file features.h.

Referenced by ast_bridge_call(), builtin_automonitor(), builtin_blindtransfer(), do_atxfer(), and feature_exec_app().

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 39 of file features.h.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 48 of file features.h.

Referenced by ast_bridge_call(), cmd_atxfer(), feature_exec_app(), and feature_interpret().

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 49 of file features.h.

Referenced by ast_bridge_call(), cmd_atxfer(), and set_peers().

#define FEATURE_SNAME_LEN   32

Definition at line 32 of file features.h.

#define PARK_APP_NAME   "Park"

Definition at line 36 of file features.h.

Referenced by handle_exec().


Typedef Documentation

typedef int(*) ast_feature_operation(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)

Definition at line 51 of file features.h.


Function Documentation

int ast_bridge_call ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config 
)

Bridge a call, optionally allowing redirection.

append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.

Todo:
XXX how do we guarantee the latter ?

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

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

int ast_feature_detect ( struct ast_channel chan,
struct ast_flags features,
char *  code,
struct ast_call_feature feature 
)

detect a feature before bridging

Parameters:
chan 
ast_flags ptr
char ptr of input code
Return values:
ast_call_feature ptr to be set if found
Returns:
result, was feature found or not

Definition at line 1385 of file res_features.c.

References feature_interpret_helper().

Referenced by detect_disconnect().

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

int ast_masq_park_call ( struct ast_channel rchan,
struct ast_channel host,
int  timeout,
int *  extout 
)

Park a call via a masqueraded channel.

Parameters:
rchan the real channel to be parked
host the channel to have the parking read to Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want

Definition at line 607 of file res_features.c.

References masq_park_call().

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

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

int ast_park_call ( struct ast_channel chan,
struct ast_channel peer,
int  timeout,
int *  extout 
)

Park a call and read back parked location.

Note:
We put the user in the parking list, then wake up the parking thread to be sure it looks after these channels too

Definition at line 552 of file res_features.c.

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00553 {
00554    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00555 }

char* ast_parking_ext ( void   ) 

Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.

Definition at line 207 of file res_features.c.

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

00208 {
00209    return parking_ext;
00210 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

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

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 212 of file res_features.c.

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

00213 {
00214    return pickup_ext;
00215 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_set

Parameters:
feature an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call.

Definition at line 1122 of file res_features.c.

References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verbose(), ast_call_feature::feature_entry, LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.

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

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 1139 of file res_features.c.

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

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


Generated on Thu Dec 17 15:36:03 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7