Mon Jun 27 16:51:14 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 3395 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_AUDIO_MODE, AST_OPTION_DIGIT_DETECT, AST_OPTION_FAX_DETECT, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, 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().

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

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

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

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

References feature_group_exten::feature, and feature_interpret_helper().

Referenced by detect_disconnect().

02881                                                                                                                                  {
02882 
02883    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02884 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

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

05199 {
05200    int res;
05201 
05202    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, "callback to mark all parkinglots");
05203    res = load_config(); /* Reload configuration */
05204    ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, "callback to remove all marked parkinglots");
05205    
05206    return res;
05207 }

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

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

02624 {
02625    int x;
02626    for (x = 0; x < FEATURES_COUNT; x++) {
02627       if (!strcasecmp(name, builtin_features[x].sname))
02628          return &builtin_features[x];
02629    }
02630    return NULL;
02631 }

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

05599 {
05600    struct ast_channel *cur, *chans[2] = { chan, };
05601    struct ast_party_connected_line connected_caller;
05602    int res;
05603    const char *chan_name;
05604    const char *cur_name;
05605 
05606    if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
05607       ast_debug(1, "No call pickup possible...\n");
05608       if (!ast_strlen_zero(pickupfailsound)) {
05609          ast_stream_and_wait(chan, pickupfailsound, "");
05610       }
05611       return -1;
05612    }
05613 
05614    chans[1] = cur;
05615 
05616    ast_channel_lock_both(cur, chan);
05617 
05618    cur_name = ast_strdupa(cur->name);
05619    chan_name = ast_strdupa(chan->name);
05620 
05621    ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name);
05622 
05623    connected_caller = cur->connected;
05624    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05625    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
05626       ast_channel_update_connected_line(chan, &connected_caller, NULL);
05627    }
05628 
05629    ast_party_connected_line_collect_caller(&connected_caller, &chan->caller);
05630    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05631    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
05632 
05633    ast_channel_unlock(cur);
05634    ast_channel_unlock(chan);
05635 
05636    if (ast_answer(chan)) {
05637       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
05638    }
05639 
05640    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
05641       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
05642    }
05643 
05644    if ((res = ast_channel_masquerade(cur, chan))) {
05645       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name);
05646    }
05647 
05648    if (!ast_strlen_zero(pickupsound)) {
05649       ast_stream_and_wait(cur, pickupsound, "");
05650    }
05651 
05652    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
05653    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
05654       "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, cur->name);
05655 
05656    cur = ast_channel_unref(cur);
05657 
05658    return res;
05659 }

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

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

02614 {
02615    ast_rwlock_rdlock(&features_lock);
02616 }

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

02458 {
02459    if (!feature) {
02460       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02461       return;
02462    }
02463   
02464    AST_RWLIST_WRLOCK(&feature_list);
02465    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02466    AST_RWLIST_UNLOCK(&feature_list);
02467 
02468    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02469 }

void ast_unlock_call_features ( void   ) 

Definition at line 2618 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

02619 {
02620    ast_rwlock_unlock(&features_lock);
02621 }

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

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

02538 {
02539    if (!feature) {
02540       return;
02541    }
02542 
02543    AST_RWLIST_WRLOCK(&feature_list);
02544    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02545    AST_RWLIST_UNLOCK(&feature_list);
02546 
02547    ast_free(feature);
02548 }


Generated on Mon Jun 27 16:51:14 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7