Wed Apr 6 11:30:04 2011

Asterisk developer's documentation


features.h File Reference

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

#include "asterisk/pbx.h"
#include "asterisk/linkedlists.h"

Go to the source code of this file.

Data Structures

struct  ast_call_feature

Defines

#define AST_FEATURE_RETURN_HANGUP   -1
#define AST_FEATURE_RETURN_KEEPTRYING   24
#define AST_FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
#define AST_FEATURE_RETURN_PARKFAILED   25
#define AST_FEATURE_RETURN_PASSDIGITS   21
#define AST_FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
#define AST_FEATURE_RETURN_STOREDIGITS   22
#define AST_FEATURE_RETURN_SUCCESS   23
#define AST_FEATURE_RETURN_SUCCESSBREAK   0
#define DEFAULT_PARKINGLOT   "default"
#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_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, const char *code, int sense, void *data)

Enumerations

enum  {
  AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
  AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3)
}
 main call feature structure More...

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_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit)
 parse L option and read associated channel variables to set warning, warning frequency, and timelimit
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature)
 detect a feature before bridging
int ast_features_reload (void)
 Reload call features from features.conf.
ast_call_featureast_find_call_feature (const char *name)
 look for a call feature entry by its sname
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, const char *parkexten, int *extout)
 Park a call and read back parked location.
int ast_parking_ext_valid (const char *exten_str, struct ast_channel *chan, const char *context)
 Determine if parking extension exists in a given context.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
const char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_rdlock_call_features (void)
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unlock_call_features (void)
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 AST_FEATURE_RETURN_HANGUP   -1

Definition at line 40 of file features.h.

Referenced by builtin_disconnect().

#define AST_FEATURE_RETURN_KEEPTRYING   24

Definition at line 47 of file features.h.

Referenced by feature_exec_app(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 43 of file features.h.

#define AST_FEATURE_RETURN_PARKFAILED   25

Definition at line 48 of file features.h.

Referenced by builtin_blindtransfer(), and masq_park_call().

#define AST_FEATURE_RETURN_PASSDIGITS   21

Definition at line 44 of file features.h.

Referenced by ast_bridge_call(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 42 of file features.h.

#define AST_FEATURE_RETURN_STOREDIGITS   22

Definition at line 45 of file features.h.

Referenced by detect_disconnect(), and feature_interpret_helper().

#define AST_FEATURE_RETURN_SUCCESS   23

Definition at line 46 of file features.h.

Referenced by ast_bridge_call(), builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app().

#define AST_FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 41 of file features.h.

Referenced by feature_exec_app().

#define DEFAULT_PARKINGLOT   "default"

Default parking lot

Definition at line 38 of file features.h.

Referenced by load_config().

#define FEATURE_APP_ARGS_LEN   256

Definition at line 32 of file features.h.

#define FEATURE_APP_LEN   64

Definition at line 31 of file features.h.

#define FEATURE_EXTEN_LEN   32

Definition at line 34 of file features.h.

#define FEATURE_MAX_LEN   11

Definition at line 30 of file features.h.

Referenced by ast_bridge_call(), and wait_for_answer().

#define FEATURE_MOH_LEN   80

Definition at line 35 of file features.h.

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 50 of file features.h.

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

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 51 of file features.h.

Referenced by ast_bridge_call(), and set_peers().

#define FEATURE_SNAME_LEN   32

Definition at line 33 of file features.h.

#define PARK_APP_NAME   "Park"

Definition at line 37 of file features.h.

Referenced by ast_parking_ext_valid(), and handle_exec().


Typedef Documentation

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

Definition at line 53 of file features.h.


Enumeration Type Documentation

anonymous enum

main call feature structure

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 57 of file features.h.

00057      {
00058    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00059    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00060    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00061    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00062    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00063    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00064 };


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.

Parameters:
chan,peer,config Set start time, check for two channels,check if monitor on check for feature activation, create new CDR
Return values:
res on success.
-1 on failure to bridge.

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 3387 of file features.c.

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_channel::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_bridge(), ast_channel_connected_line_macro(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_log(), ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_clear_flag, AST_CONTROL_AOC, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, 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_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), 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_verb, ast_channel::caller, ast_channel::cdr, ast_cdr::channel, 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_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_party_caller::id, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_COR, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_party_number::str, ast_cdr::uniqueid, ast_channel::uniqueid, ast_cdr::userfield, ast_party_number::valid, and ast_channel::visible_indication.

Referenced by app_exec(), bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), and park_exec_full().

03388 {
03389    /* Copy voice back and forth between the two channels.  Give the peer
03390       the ability to transfer calls with '#<extension' syntax. */
03391    struct ast_frame *f;
03392    struct ast_channel *who;
03393    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
03394    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
03395    char orig_channame[AST_MAX_EXTENSION];
03396    char orig_peername[AST_MAX_EXTENSION];
03397    int res;
03398    int diff;
03399    int hasfeatures=0;
03400    int hadfeatures=0;
03401    int autoloopflag;
03402    int we_disabled_peer_cdr = 0;
03403    struct ast_option_header *aoh;
03404    struct ast_cdr *bridge_cdr = NULL;
03405    struct ast_cdr *orig_peer_cdr = NULL;
03406    struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */
03407    struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */
03408    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
03409    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
03410 
03411    if (chan && peer) {
03412       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
03413       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
03414    } else if (chan) {
03415       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
03416    }
03417 
03418    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
03419    add_features_datastores(chan, peer, config);
03420 
03421    /* This is an interesting case.  One example is if a ringing channel gets redirected to
03422     * an extension that picks up a parked call.  This will make sure that the call taken
03423     * out of parking gets told that the channel it just got bridged to is still ringing. */
03424    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
03425       ast_indicate(peer, AST_CONTROL_RINGING);
03426    }
03427 
03428    if (monitor_ok) {
03429       const char *monitor_exec;
03430       struct ast_channel *src = NULL;
03431       if (!monitor_app) {
03432          if (!(monitor_app = pbx_findapp("Monitor")))
03433             monitor_ok=0;
03434       }
03435       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
03436          src = chan;
03437       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
03438          src = peer;
03439       if (monitor_app && src) {
03440          char *tmp = ast_strdupa(monitor_exec);
03441          pbx_exec(src, monitor_app, tmp);
03442       }
03443    }
03444 
03445    set_config_flags(chan, peer, config);
03446 
03447    /* Answer if need be */
03448    if (chan->_state != AST_STATE_UP) {
03449       if (ast_raw_answer(chan, 1)) {
03450          return -1;
03451       }
03452    }
03453 
03454 #ifdef FOR_DEBUG
03455    /* show the two channels and cdrs involved in the bridge for debug & devel purposes */
03456    ast_channel_log("Pre-bridge CHAN Channel info", chan);
03457    ast_channel_log("Pre-bridge PEER Channel info", peer);
03458 #endif
03459    /* two channels are being marked as linked here */
03460    ast_channel_set_linkgroup(chan,peer);
03461 
03462    /* copy the userfield from the B-leg to A-leg if applicable */
03463    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
03464       char tmp[256];
03465       if (!ast_strlen_zero(chan->cdr->userfield)) {
03466          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
03467          ast_cdr_appenduserfield(chan, tmp);
03468       } else
03469          ast_cdr_setuserfield(chan, peer->cdr->userfield);
03470       /* Don't delete the CDR; just disable it. */
03471       ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03472       we_disabled_peer_cdr = 1;
03473    }
03474    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
03475    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
03476    orig_peer_cdr = peer_cdr;
03477    
03478    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
03479       
03480       if (chan_cdr) {
03481          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
03482          ast_cdr_update(chan);
03483          bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
03484          /* rip any forked CDR's off of the chan_cdr and attach
03485           * them to the bridge_cdr instead */
03486          bridge_cdr->next = chan_cdr->next;
03487          chan_cdr->next = NULL;
03488          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03489          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03490          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
03491             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03492          }
03493          ast_cdr_setaccount(peer, chan->accountcode);
03494 
03495       } else {
03496          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
03497          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
03498          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
03499          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
03500          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
03501          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03502          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03503          ast_cdr_setcid(bridge_cdr, chan);
03504          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
03505          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
03506          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
03507          /* Destination information */
03508          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
03509          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
03510          if (peer_cdr) {
03511             bridge_cdr->start = peer_cdr->start;
03512             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03513          } else {
03514             ast_cdr_start(bridge_cdr);
03515          }
03516       }
03517       ast_debug(4,"bridge answer set, chan answer set\n");
03518       /* peer_cdr->answer will be set when a macro runs on the peer;
03519          in that case, the bridge answer will be delayed while the
03520          macro plays on the peer channel. The peer answered the call
03521          before the macro started playing. To the phone system,
03522          this is billable time for the call, even tho the caller
03523          hears nothing but ringing while the macro does its thing. */
03524 
03525       /* Another case where the peer cdr's time will be set, is when
03526          A self-parks by pickup up phone and dialing 700, then B
03527          picks up A by dialing its parking slot; there may be more 
03528          practical paths that get the same result, tho... in which
03529          case you get the previous answer time from the Park... which
03530          is before the bridge's start time, so I added in the 
03531          tvcmp check to the if below */
03532 
03533       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
03534          ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
03535          ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
03536          if (chan_cdr) {
03537             ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
03538             ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
03539          }
03540       } else {
03541          ast_cdr_answer(bridge_cdr);
03542          if (chan_cdr) {
03543             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
03544          }
03545       }
03546       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
03547          if (chan_cdr) {
03548             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
03549          }
03550          if (peer_cdr) {
03551             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
03552          }
03553       }
03554       /* the DIALED flag may be set if a dialed channel is transfered
03555        * and then bridged to another channel.  In order for the
03556        * bridge CDR to be written, the DIALED flag must not be
03557        * present. */
03558       ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
03559    }
03560    ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL);
03561    for (;;) {
03562       struct ast_channel *other; /* used later */
03563    
03564       res = ast_channel_bridge(chan, peer, config, &f, &who);
03565       
03566       /* When frame is not set, we are probably involved in a situation
03567          where we've timed out.
03568          When frame is set, we'll come this code twice; once for DTMF_BEGIN
03569          and also for DTMF_END. If we flow into the following 'if' for both, then 
03570          our wait times are cut in half, as both will subtract from the
03571          feature_timer. Not good!
03572       */
03573       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
03574          /* Update feature timer for next pass */
03575          diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
03576          if (res == AST_BRIDGE_RETRY) {
03577             /* The feature fully timed out but has not been updated. Skip
03578              * the potential round error from the diff calculation and
03579              * explicitly set to expired. */
03580             config->feature_timer = -1;
03581          } else {
03582             config->feature_timer -= diff;
03583          }
03584 
03585          if (hasfeatures) {
03586             if (config->feature_timer <= 0) {
03587                /* Not *really* out of time, just out of time for
03588                   digits to come in for features. */
03589                ast_debug(1, "Timed out for feature!\n");
03590                if (!ast_strlen_zero(peer_featurecode)) {
03591                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
03592                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
03593                }
03594                if (!ast_strlen_zero(chan_featurecode)) {
03595                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
03596                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
03597                }
03598                if (f)
03599                   ast_frfree(f);
03600                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03601                if (!hasfeatures) {
03602                   /* No more digits expected - reset the timer */
03603                   config->feature_timer = 0;
03604                }
03605                hadfeatures = hasfeatures;
03606                /* Continue as we were */
03607                continue;
03608             } else if (!f) {
03609                /* The bridge returned without a frame and there is a feature in progress.
03610                 * However, we don't think the feature has quite yet timed out, so just
03611                 * go back into the bridge. */
03612                continue;
03613             }
03614          } else {
03615             if (config->feature_timer <=0) {
03616                /* We ran out of time */
03617                config->feature_timer = 0;
03618                who = chan;
03619                if (f)
03620                   ast_frfree(f);
03621                f = NULL;
03622                res = 0;
03623             }
03624          }
03625       }
03626       if (res < 0) {
03627          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
03628             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
03629          }
03630          goto before_you_go;
03631       }
03632       
03633       if (!f || (f->frametype == AST_FRAME_CONTROL &&
03634             (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
03635                f->subclass.integer == AST_CONTROL_CONGESTION))) {
03636          res = -1;
03637          break;
03638       }
03639       /* many things should be sent to the 'other' channel */
03640       other = (who == chan) ? peer : chan;
03641       if (f->frametype == AST_FRAME_CONTROL) {
03642          switch (f->subclass.integer) {
03643          case AST_CONTROL_RINGING:
03644          case AST_CONTROL_FLASH:
03645          case -1:
03646             ast_indicate(other, f->subclass.integer);
03647             break;
03648          case AST_CONTROL_CONNECTED_LINE:
03649             if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
03650                break;
03651             }
03652             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03653             break;
03654          case AST_CONTROL_REDIRECTING:
03655             if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
03656                break;
03657             }
03658             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03659             break;
03660          case AST_CONTROL_AOC:
03661          case AST_CONTROL_HOLD:
03662          case AST_CONTROL_UNHOLD:
03663             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03664             break;
03665          case AST_CONTROL_OPTION:
03666             aoh = f->data.ptr;
03667             /* Forward option Requests */
03668             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
03669                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
03670                   f->datalen - sizeof(struct ast_option_header), 0);
03671             }
03672             break;
03673          }
03674       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
03675          /* eat it */
03676       } else if (f->frametype == AST_FRAME_DTMF) {
03677          char *featurecode;
03678          int sense;
03679 
03680          hadfeatures = hasfeatures;
03681          /* This cannot overrun because the longest feature is one shorter than our buffer */
03682          if (who == chan) {
03683             sense = FEATURE_SENSE_CHAN;
03684             featurecode = chan_featurecode;
03685          } else  {
03686             sense = FEATURE_SENSE_PEER;
03687             featurecode = peer_featurecode;
03688          }
03689          /*! append the event to featurecode. we rely on the string being zero-filled, and
03690           * not overflowing it. 
03691           * \todo XXX how do we guarantee the latter ?
03692           */
03693          featurecode[strlen(featurecode)] = f->subclass.integer;
03694          /* Get rid of the frame before we start doing "stuff" with the channels */
03695          ast_frfree(f);
03696          f = NULL;
03697          config->feature_timer = 0;
03698          res = feature_interpret(chan, peer, config, featurecode, sense);
03699          switch(res) {
03700          case AST_FEATURE_RETURN_PASSDIGITS:
03701             ast_dtmf_stream(other, who, featurecode, 0, 0);
03702             /* Fall through */
03703          case AST_FEATURE_RETURN_SUCCESS:
03704             memset(featurecode, 0, sizeof(chan_featurecode));
03705             break;
03706          }
03707          if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
03708             res = 0;
03709          } else {
03710             break;
03711          }
03712          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03713          if (hadfeatures && !hasfeatures) {
03714             /* Feature completed or timed out */
03715             config->feature_timer = 0;
03716          } else if (hasfeatures) {
03717             if (config->timelimit) {
03718                /* No warning next time - we are waiting for future */
03719                ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
03720             }
03721             config->feature_start_time = ast_tvnow();
03722             config->feature_timer = featuredigittimeout;
03723             ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
03724          }
03725       }
03726       if (f)
03727          ast_frfree(f);
03728 
03729    }
03730    ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL);
03731    before_you_go:
03732 
03733    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
03734       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
03735       if (bridge_cdr) {
03736          ast_cdr_discard(bridge_cdr);
03737          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
03738       }
03739       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
03740    }
03741 
03742    if (config->end_bridge_callback) {
03743       config->end_bridge_callback(config->end_bridge_callback_data);
03744    }
03745 
03746    /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 
03747     * if it were, then chan belongs to a different thread now, and might have been hung up long
03748      * ago.
03749     */
03750    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN)
03751       && ast_exists_extension(chan, chan->context, "h", 1,
03752          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
03753       struct ast_cdr *swapper = NULL;
03754       char savelastapp[AST_MAX_EXTENSION];
03755       char savelastdata[AST_MAX_EXTENSION];
03756       char save_exten[AST_MAX_EXTENSION];
03757       int  save_prio;
03758       int  found = 0;   /* set if we find at least one match */
03759       int  spawn_error = 0;
03760       
03761       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
03762       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
03763       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
03764          ast_cdr_end(bridge_cdr);
03765       }
03766       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
03767          dialplan code operate on it */
03768       ast_channel_lock(chan);
03769       if (bridge_cdr) {
03770          swapper = chan->cdr;
03771          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
03772          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
03773          chan->cdr = bridge_cdr;
03774       }
03775       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
03776       save_prio = chan->priority;
03777       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
03778       chan->priority = 1;
03779       ast_channel_unlock(chan);
03780       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten,
03781          chan->priority,
03782          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
03783          &found, 1)) == 0) {
03784          chan->priority++;
03785       }
03786       if (spawn_error
03787          && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority,
03788             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
03789             || ast_check_hangup(chan))) {
03790          /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */
03791          spawn_error = 0;
03792       }
03793       if (found && spawn_error) {
03794          /* Something bad happened, or a hangup has been requested. */
03795          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03796          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03797       }
03798       /* swap it back */
03799       ast_channel_lock(chan);
03800       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
03801       chan->priority = save_prio;
03802       if (bridge_cdr) {
03803          if (chan->cdr == bridge_cdr) {
03804             chan->cdr = swapper;
03805          } else {
03806             bridge_cdr = NULL;
03807          }
03808       }
03809       if (!spawn_error) {
03810          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
03811       }
03812       ast_channel_unlock(chan);
03813       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
03814       if (bridge_cdr) {
03815          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
03816          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
03817       }
03818       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03819    }
03820    
03821    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
03822    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
03823    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
03824       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
03825 
03826    /* we can post the bridge CDR at this point */
03827    if (bridge_cdr) {
03828       ast_cdr_end(bridge_cdr);
03829       ast_cdr_detach(bridge_cdr);
03830    }
03831    
03832    /* do a specialized reset on the beginning channel
03833       CDR's, if they still exist, so as not to mess up
03834       issues in future bridges;
03835       
03836       Here are the rules of the game:
03837       1. The chan and peer channel pointers will not change
03838          during the life of the bridge.
03839       2. But, in transfers, the channel names will change.
03840          between the time the bridge is started, and the
03841          time the channel ends. 
03842          Usually, when a channel changes names, it will
03843          also change CDR pointers.
03844       3. Usually, only one of the two channels (chan or peer)
03845          will change names.
03846       4. Usually, if a channel changes names during a bridge,
03847          it is because of a transfer. Usually, in these situations,
03848          it is normal to see 2 bridges running simultaneously, and
03849          it is not unusual to see the two channels that change
03850          swapped between bridges.
03851       5. After a bridge occurs, we have 2 or 3 channels' CDRs
03852          to attend to; if the chan or peer changed names,
03853          we have the before and after attached CDR's.
03854    */
03855 
03856    if (new_chan_cdr) {
03857       struct ast_channel *chan_ptr = NULL;
03858 
03859       if (strcasecmp(orig_channame, chan->name) != 0) { 
03860          /* old channel */
03861          if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
03862             ast_channel_lock(chan_ptr);
03863             if (!ast_bridged_channel(chan_ptr)) {
03864                struct ast_cdr *cur;
03865                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03866                   if (cur == chan_cdr) {
03867                      break;
03868                   }
03869                }
03870                if (cur) {
03871                   ast_cdr_specialized_reset(chan_cdr, 0);
03872                }
03873             }
03874             ast_channel_unlock(chan_ptr);
03875             chan_ptr = ast_channel_unref(chan_ptr);
03876          }
03877          /* new channel */
03878          ast_cdr_specialized_reset(new_chan_cdr, 0);
03879       } else {
03880          ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr  */
03881       }
03882    }
03883 
03884    {
03885       struct ast_channel *chan_ptr = NULL;
03886       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
03887       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))
03888          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
03889       if (strcasecmp(orig_peername, peer->name) != 0) { 
03890          /* old channel */
03891          if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
03892             ast_channel_lock(chan_ptr);
03893             if (!ast_bridged_channel(chan_ptr)) {
03894                struct ast_cdr *cur;
03895                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03896                   if (cur == peer_cdr) {
03897                      break;
03898                   }
03899                }
03900                if (cur) {
03901                   ast_cdr_specialized_reset(peer_cdr, 0);
03902                }
03903             }
03904             ast_channel_unlock(chan_ptr);
03905             chan_ptr = ast_channel_unref(chan_ptr);
03906          }
03907          /* new channel */
03908          if (new_peer_cdr) {
03909             ast_cdr_specialized_reset(new_peer_cdr, 0);
03910          }
03911       } else {
03912          if (we_disabled_peer_cdr) {
03913             ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03914          }
03915          ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr  */
03916       }
03917    }
03918    
03919    return res;
03920 }

int ast_bridge_timelimit ( struct ast_channel chan,
struct ast_bridge_config config,
char *  parse,
struct timeval *  calldurationlimit 
)

parse L option and read associated channel variables to set warning, warning frequency, and timelimit

Note:
caller must be aware of freeing memory for warning_sound, end_sound, and start_sound

Definition at line 5680 of file features.c.

References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, config, LOG_WARNING, pbx_builtin_getvar_helper(), S_OR, strsep(), and var.

Referenced by bridge_exec(), and dial_exec_full().

05682 {
05683    char *stringp = ast_strdupa(parse);
05684    char *limit_str, *warning_str, *warnfreq_str;
05685    const char *var;
05686    int play_to_caller = 0, play_to_callee = 0;
05687    int delta;
05688 
05689    limit_str = strsep(&stringp, ":");
05690    warning_str = strsep(&stringp, ":");
05691    warnfreq_str = strsep(&stringp, ":");
05692 
05693    config->timelimit = atol(limit_str);
05694    if (warning_str)
05695       config->play_warning = atol(warning_str);
05696    if (warnfreq_str)
05697       config->warning_freq = atol(warnfreq_str);
05698 
05699    if (!config->timelimit) {
05700       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
05701       config->timelimit = config->play_warning = config->warning_freq = 0;
05702       config->warning_sound = NULL;
05703       return -1; /* error */
05704    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
05705       int w = config->warning_freq;
05706 
05707       /* If the first warning is requested _after_ the entire call would end,
05708          and no warning frequency is requested, then turn off the warning. If
05709          a warning frequency is requested, reduce the 'first warning' time by
05710          that frequency until it falls within the call's total time limit.
05711          Graphically:
05712               timelim->|    delta        |<-playwarning
05713          0__________________|_________________|
05714                 | w  |    |    |    |
05715 
05716          so the number of intervals to cut is 1+(delta-1)/w
05717       */
05718 
05719       if (w == 0) {
05720          config->play_warning = 0;
05721       } else {
05722          config->play_warning -= w * ( 1 + (delta-1)/w );
05723          if (config->play_warning < 1)
05724             config->play_warning = config->warning_freq = 0;
05725       }
05726    }
05727    
05728    ast_channel_lock(chan);
05729 
05730    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
05731    play_to_caller = var ? ast_true(var) : 1;
05732 
05733    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
05734    play_to_callee = var ? ast_true(var) : 0;
05735 
05736    if (!play_to_caller && !play_to_callee)
05737       play_to_caller = 1;
05738 
05739    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
05740    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
05741 
05742    /* The code looking at config wants a NULL, not just "", to decide
05743     * that the message should not be played, so we replace "" with NULL.
05744     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
05745     * not found.
05746     */
05747 
05748    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
05749    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05750 
05751    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
05752    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05753 
05754    ast_channel_unlock(chan);
05755 
05756    /* undo effect of S(x) in case they are both used */
05757    calldurationlimit->tv_sec = 0;
05758    calldurationlimit->tv_usec = 0;
05759 
05760    /* more efficient to do it like S(x) does since no advanced opts */
05761    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
05762       calldurationlimit->tv_sec = config->timelimit / 1000;
05763       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
05764       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
05765          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
05766       config->timelimit = play_to_caller = play_to_callee =
05767       config->play_warning = config->warning_freq = 0;
05768    } else {
05769       ast_verb(4, "Limit Data for this call:\n");
05770       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
05771       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
05772       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
05773       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
05774       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
05775       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
05776       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
05777       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
05778    }
05779    if (play_to_caller)
05780       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
05781    if (play_to_callee)
05782       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
05783    return 0;
05784 }

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

detect a feature before bridging

Parameters:
chan 
features an ast_flags ptr
code ptr of input code
feature 
Return values:
ast_call_feature ptr to be set if found

Definition at line 2872 of file features.c.

References feature_group_exten::feature, and feature_interpret_helper().

Referenced by detect_disconnect().

02872                                                                                                                                  {
02873 
02874    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02875 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 5179 of file features.c.

References ao2_t_callback, load_config(), OBJ_NODATA, OBJ_UNLINK, parkinglot_is_marked_cb(), parkinglot_markall_cb(), and parkinglots.

Referenced by handle_features_reload().

05180 {
05181    int res;
05182 
05183    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, "callback to mark all parkinglots");
05184    res = load_config(); /* Reload configuration */
05185    ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, "callback to remove all marked parkinglots");
05186    
05187    return res;
05188 }

struct ast_call_feature* ast_find_call_feature ( const char *  name  ) 

look for a call feature entry by its sname

Parameters:
name a string ptr, should match "automon", "blindxfer", "atxfer", etc.

Definition at line 2614 of file features.c.

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

02615 {
02616    int x;
02617    for (x = 0; x < FEATURES_COUNT; x++) {
02618       if (!strcasecmp(name, builtin_features[x].sname))
02619          return &builtin_features[x];
02620    }
02621    return NULL;
02622 }

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.
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.
Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
Return values:
0 on success.
-1 on failure.

Definition at line 1299 of file features.c.

References masq_park_call().

Referenced by __analog_ss_thread(), analog_ss_thread(), handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), mgcp_ss(), parkandannounce_exec(), and rpt_exec().

01300 {
01301    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
01302 }

int ast_park_call ( struct ast_channel chan,
struct ast_channel host,
int  timeout,
const char *  parkexten,
int *  extout 
)

Park a call and read back parked location.

Parameters:
chan the channel to actually be parked
host the channel which will have the parked location read to.
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.
Park the channel chan, and read back the parked location to the host. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context)
Return values:
0 on success.
-1 on failure.

Definition at line 1225 of file features.c.

References ao2_callback, args, find_parkinglot_by_exten_cb(), park_call_full(), and parkinglots.

Referenced by iax_park_thread(), and sip_park_thread().

01226 {
01227    struct ast_parkinglot *found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, (void *) parkexten);
01228 
01229    struct ast_park_call_args args = {
01230       .timeout = timeout,
01231       .extout = extout,
01232       .parkinglot = found_lot,
01233    };
01234 
01235    return park_call_full(chan, peer, &args);
01236 }

int ast_parking_ext_valid ( const char *  exten_str,
struct ast_channel chan,
const char *  context 
)

Determine if parking extension exists in a given context.

Return values:
0 if extension does not exist
1 if extension does exist

Definition at line 643 of file features.c.

References ast_get_extension_app(), E_MATCH, feature_group_exten::exten, PARK_APP_NAME, pbx_find_extension(), and pbx_find_info::stacklen.

Referenced by __analog_ss_thread(), analog_ss_thread(), dp_lookup(), handle_request_refer(), mgcp_ss(), and socket_process().

00644 {
00645    struct ast_exten *exten;
00646    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
00647    const char *app_at_exten;
00648 
00649    exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, E_MATCH);
00650    if (!exten) {
00651       return 0;
00652    }
00653 
00654    app_at_exten = ast_get_extension_app(exten);
00655    if (!app_at_exten || strcmp(PARK_APP_NAME, app_at_exten)) {
00656       return 0;
00657    }
00658 
00659    return 1;
00660 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Parameters:
chan channel that initiated pickup.
Walk list of channels, checking it is not itself, channel is pbx one, check that the callgroup for both channels are the same and the channel is ringing. Answer calling channel, flag channel as answered on queue, masq channels together.

Definition at line 5578 of file features.c.

References ast_answer(), ast_channel_callback(), ast_channel_connected_line_macro(), ast_channel_lock_both, ast_channel_masquerade(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_unref, ast_channel_update_connected_line(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_manager_event_multichan, ast_party_connected_line_collect_caller(), ast_queue_control(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_channel::caller, ast_channel::connected, EVENT_FLAG_CALL, find_channel_by_group(), LOG_WARNING, ast_channel::name, pickupfailsound, pickupsound, and ast_party_connected_line::source.

Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), handle_request_invite(), mgcp_ss(), and pickup_exec().

05579 {
05580    struct ast_channel *cur, *chans[2] = { chan, };
05581    struct ast_party_connected_line connected_caller;
05582    int res;
05583    const char *chan_name;
05584    const char *cur_name;
05585 
05586    if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
05587       ast_debug(1, "No call pickup possible...\n");
05588       if (!ast_strlen_zero(pickupfailsound)) {
05589          ast_stream_and_wait(chan, pickupfailsound, "");
05590       }
05591       return -1;
05592    }
05593 
05594    chans[1] = cur;
05595 
05596    ast_channel_lock_both(cur, chan);
05597 
05598    cur_name = ast_strdupa(cur->name);
05599    chan_name = ast_strdupa(chan->name);
05600 
05601    ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name);
05602 
05603    connected_caller = cur->connected;
05604    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05605    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
05606       ast_channel_update_connected_line(chan, &connected_caller, NULL);
05607    }
05608 
05609    ast_party_connected_line_collect_caller(&connected_caller, &chan->caller);
05610    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05611    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
05612 
05613    ast_channel_unlock(cur);
05614    ast_channel_unlock(chan);
05615 
05616    if (ast_answer(chan)) {
05617       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
05618    }
05619 
05620    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
05621       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
05622    }
05623 
05624    if ((res = ast_channel_masquerade(cur, chan))) {
05625       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name);
05626    }
05627 
05628    if (!ast_strlen_zero(pickupsound)) {
05629       ast_stream_and_wait(cur, pickupsound, "");
05630    }
05631 
05632    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
05633    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
05634       "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, cur->name);
05635 
05636    cur = ast_channel_unref(cur);
05637 
05638    return res;
05639 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 662 of file features.c.

References pickup_ext.

Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), and mgcp_ss().

00663 {
00664    return pickup_ext;
00665 }

void ast_rdlock_call_features ( void   ) 

Definition at line 2604 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

02605 {
02606    ast_rwlock_rdlock(&features_lock);
02607 }

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 2448 of file features.c.

References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, feature_group_exten::feature, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.

02449 {
02450    if (!feature) {
02451       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02452       return;
02453    }
02454   
02455    AST_RWLIST_WRLOCK(&feature_list);
02456    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02457    AST_RWLIST_UNLOCK(&feature_list);
02458 
02459    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02460 }

void ast_unlock_call_features ( void   ) 

Definition at line 2609 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

02610 {
02611    ast_rwlock_unlock(&features_lock);
02612 }

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 2528 of file features.c.

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.

02529 {
02530    if (!feature) {
02531       return;
02532    }
02533 
02534    AST_RWLIST_WRLOCK(&feature_list);
02535    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02536    AST_RWLIST_UNLOCK(&feature_list);
02537 
02538    ast_free(feature);
02539 }


Generated on Wed Apr 6 11:30:04 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7