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 |
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. | |
void | ast_bridge_end_dtmf (struct ast_channel *chan, char digit, struct timeval start, const char *why) |
Simulate a DTMF end on a broken bridge channel. | |
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_can_pickup (struct ast_channel *chan) |
Test if a channel can be picked up. | |
int | ast_do_pickup (struct ast_channel *chan, struct ast_channel *target) |
Pickup a call target. | |
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. | |
struct ast_call_feature * | ast_find_call_feature (const char *name) |
look for a call feature entry by its sname | |
int | ast_masq_park_call (struct ast_channel *park_me, struct ast_channel *parker, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
int | ast_masq_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
int | ast_park_call (struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout) |
Park a call and read back parked location. | |
int | ast_park_call_exten (struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, 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 |
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
Definition in file features.h.
#define AST_FEATURE_RETURN_HANGUP -1 |
Definition at line 39 of file features.h.
Referenced by builtin_disconnect().
#define AST_FEATURE_RETURN_KEEPTRYING 24 |
Definition at line 46 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 42 of file features.h.
#define AST_FEATURE_RETURN_PARKFAILED 25 |
Definition at line 47 of file features.h.
#define AST_FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 43 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 41 of file features.h.
#define AST_FEATURE_RETURN_STOREDIGITS 22 |
Definition at line 44 of file features.h.
Referenced by detect_disconnect(), and feature_interpret_helper().
#define AST_FEATURE_RETURN_SUCCESS 23 |
Definition at line 45 of file features.h.
Referenced by ast_bridge_call(), builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), builtin_parkcall(), feature_exec_app(), feature_interpret_helper(), and xfer_park_call_helper().
#define AST_FEATURE_RETURN_SUCCESSBREAK 0 |
Definition at line 40 of file features.h.
Referenced by builtin_blindtransfer(), and feature_exec_app().
#define DEFAULT_PARKINGLOT "default" |
Default parking lot
Definition at line 37 of file features.h.
Referenced by build_parkinglot(), load_config(), process_config(), and reload_config().
#define FEATURE_APP_ARGS_LEN 256 |
Definition at line 32 of file features.h.
Referenced by process_applicationmap_line().
#define FEATURE_APP_LEN 64 |
Definition at line 31 of file features.h.
Referenced by process_applicationmap_line().
#define FEATURE_EXTEN_LEN 32 |
Definition at line 34 of file features.h.
Referenced by process_applicationmap_line().
#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.
Referenced by process_applicationmap_line().
#define FEATURE_SENSE_CHAN (1 << 0) |
Definition at line 49 of file features.h.
Referenced by ast_bridge_call(), feature_exec_app(), and feature_interpret().
#define FEATURE_SENSE_PEER (1 << 1) |
Definition at line 50 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.
Referenced by process_applicationmap_line().
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 52 of file features.h.
anonymous enum |
main call feature structure
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 56 of file features.h.
00056 { 00057 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00058 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00059 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00060 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00061 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00062 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00063 };
int ast_bridge_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) |
Bridge a call, optionally allowing redirection.
Bridge a call, optionally allowing redirection.
chan | The bridge considers this channel the caller. | |
peer | The bridge considers this channel the callee. | |
config | Configuration for this bridge. |
Set start time, check for two channels,check if monitor on check for feature activation, create new CDR
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.
Definition at line 3938 of file features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, ast_bridge_end_dtmf(), AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_copy_vars(), 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_lock_both, ast_channel_log(), AST_CHANNEL_NAME, ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), 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_DUAL_REDIRECT_WAIT, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, ast_opt_transmit_silence, 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_softhangup(), AST_SOFTHANGUP_APPUNLOAD, AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_UNBRIDGE, 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_write(), ast_channel::caller, ast_channel::cdr, ast_cdr::channel, clear_dialed_interfaces(), ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_start_time, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_frame::frametype, ast_party_caller::id, ast_frame_subclass::integer, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, monitor_app, monitor_ok, ast_cdr::next, ast_party_id::number, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, ast_frame::ptr, S_COR, S_OR, ast_channel::sending_dtmf_digit, ast_channel::sending_dtmf_tv, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_party_number::str, ast_frame::subclass, ast_bridge_config::timelimit, ast_cdr::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(), parked_call_exec(), and try_calling().
03939 { 03940 /* Copy voice back and forth between the two channels. Give the peer 03941 the ability to transfer calls with '#<extension' syntax. */ 03942 struct ast_frame *f; 03943 struct ast_channel *who; 03944 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03945 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03946 char orig_channame[AST_CHANNEL_NAME]; 03947 char orig_peername[AST_CHANNEL_NAME]; 03948 int res; 03949 int diff; 03950 int hasfeatures=0; 03951 int hadfeatures=0; 03952 int autoloopflag; 03953 int sendingdtmfdigit = 0; 03954 int we_disabled_peer_cdr = 0; 03955 struct ast_option_header *aoh; 03956 struct ast_cdr *bridge_cdr = NULL; 03957 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03958 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03959 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03960 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03961 struct ast_silence_generator *silgen = NULL; 03962 const char *h_context; 03963 03964 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03965 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03966 03967 /* Clear any BLINDTRANSFER since the transfer has completed. */ 03968 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03969 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL); 03970 03971 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03972 add_features_datastores(chan, peer, config); 03973 03974 /* This is an interesting case. One example is if a ringing channel gets redirected to 03975 * an extension that picks up a parked call. This will make sure that the call taken 03976 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03977 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03978 ast_indicate(peer, AST_CONTROL_RINGING); 03979 } 03980 03981 if (monitor_ok) { 03982 const char *monitor_exec; 03983 struct ast_channel *src = NULL; 03984 if (!monitor_app) { 03985 if (!(monitor_app = pbx_findapp("Monitor"))) 03986 monitor_ok=0; 03987 } 03988 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03989 src = chan; 03990 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03991 src = peer; 03992 if (monitor_app && src) { 03993 char *tmp = ast_strdupa(monitor_exec); 03994 pbx_exec(src, monitor_app, tmp); 03995 } 03996 } 03997 03998 set_config_flags(chan, peer, config); 03999 04000 /* Answer if need be */ 04001 if (chan->_state != AST_STATE_UP) { 04002 if (ast_raw_answer(chan, 1)) { 04003 return -1; 04004 } 04005 } 04006 04007 #ifdef FOR_DEBUG 04008 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 04009 ast_channel_log("Pre-bridge CHAN Channel info", chan); 04010 ast_channel_log("Pre-bridge PEER Channel info", peer); 04011 #endif 04012 /* two channels are being marked as linked here */ 04013 ast_channel_set_linkgroup(chan,peer); 04014 04015 /* copy the userfield from the B-leg to A-leg if applicable */ 04016 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 04017 char tmp[256]; 04018 04019 ast_channel_lock(chan); 04020 if (!ast_strlen_zero(chan->cdr->userfield)) { 04021 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 04022 ast_cdr_appenduserfield(chan, tmp); 04023 } else { 04024 ast_cdr_setuserfield(chan, peer->cdr->userfield); 04025 } 04026 ast_channel_unlock(chan); 04027 /* Don't delete the CDR; just disable it. */ 04028 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04029 we_disabled_peer_cdr = 1; 04030 } 04031 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 04032 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 04033 04034 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 04035 ast_channel_lock_both(chan, peer); 04036 if (chan_cdr) { 04037 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 04038 ast_cdr_update(chan); 04039 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 04040 /* rip any forked CDR's off of the chan_cdr and attach 04041 * them to the bridge_cdr instead */ 04042 bridge_cdr->next = chan_cdr->next; 04043 chan_cdr->next = NULL; 04044 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04045 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04046 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 04047 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04048 } 04049 ast_cdr_setaccount(peer, chan->accountcode); 04050 } else { 04051 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 04052 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 04053 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 04054 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 04055 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 04056 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04057 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04058 ast_cdr_setcid(bridge_cdr, chan); 04059 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 04060 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 04061 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 04062 /* Destination information */ 04063 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 04064 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 04065 if (peer_cdr) { 04066 bridge_cdr->start = peer_cdr->start; 04067 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04068 } else { 04069 ast_cdr_start(bridge_cdr); 04070 } 04071 } 04072 ast_channel_unlock(chan); 04073 ast_channel_unlock(peer); 04074 04075 ast_debug(4,"bridge answer set, chan answer set\n"); 04076 /* peer_cdr->answer will be set when a macro runs on the peer; 04077 in that case, the bridge answer will be delayed while the 04078 macro plays on the peer channel. The peer answered the call 04079 before the macro started playing. To the phone system, 04080 this is billable time for the call, even tho the caller 04081 hears nothing but ringing while the macro does its thing. */ 04082 04083 /* Another case where the peer cdr's time will be set, is when 04084 A self-parks by pickup up phone and dialing 700, then B 04085 picks up A by dialing its parking slot; there may be more 04086 practical paths that get the same result, tho... in which 04087 case you get the previous answer time from the Park... which 04088 is before the bridge's start time, so I added in the 04089 tvcmp check to the if below */ 04090 04091 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 04092 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 04093 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 04094 if (chan_cdr) { 04095 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 04096 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 04097 } 04098 } else { 04099 ast_cdr_answer(bridge_cdr); 04100 if (chan_cdr) { 04101 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 04102 } 04103 } 04104 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 04105 if (chan_cdr) { 04106 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 04107 } 04108 if (peer_cdr) { 04109 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 04110 } 04111 } 04112 /* the DIALED flag may be set if a dialed channel is transfered 04113 * and then bridged to another channel. In order for the 04114 * bridge CDR to be written, the DIALED flag must not be 04115 * present. */ 04116 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04117 } 04118 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04119 04120 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04121 * a call is being bridged, that the humans in charge know what they're doing. If they 04122 * don't, well, what can we do about that? */ 04123 clear_dialed_interfaces(chan); 04124 clear_dialed_interfaces(peer); 04125 04126 for (;;) { 04127 struct ast_channel *other; /* used later */ 04128 04129 res = ast_channel_bridge(chan, peer, config, &f, &who); 04130 04131 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04132 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04133 /* Zombies are present time to leave! */ 04134 res = -1; 04135 if (f) { 04136 ast_frfree(f); 04137 } 04138 goto before_you_go; 04139 } 04140 04141 /* When frame is not set, we are probably involved in a situation 04142 where we've timed out. 04143 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04144 and also for DTMF_END. If we flow into the following 'if' for both, then 04145 our wait times are cut in half, as both will subtract from the 04146 feature_timer. Not good! 04147 */ 04148 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04149 /* Update feature timer for next pass */ 04150 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04151 if (res == AST_BRIDGE_RETRY) { 04152 /* The feature fully timed out but has not been updated. Skip 04153 * the potential round error from the diff calculation and 04154 * explicitly set to expired. */ 04155 config->feature_timer = -1; 04156 } else { 04157 config->feature_timer -= diff; 04158 } 04159 04160 if (hasfeatures) { 04161 if (config->feature_timer <= 0) { 04162 /* Not *really* out of time, just out of time for 04163 digits to come in for features. */ 04164 ast_debug(1, "Timed out for feature!\n"); 04165 if (!ast_strlen_zero(peer_featurecode)) { 04166 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 04167 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04168 } 04169 if (!ast_strlen_zero(chan_featurecode)) { 04170 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 04171 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04172 } 04173 if (f) 04174 ast_frfree(f); 04175 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04176 if (!hasfeatures) { 04177 /* No more digits expected - reset the timer */ 04178 config->feature_timer = 0; 04179 } 04180 hadfeatures = hasfeatures; 04181 /* Continue as we were */ 04182 continue; 04183 } else if (!f) { 04184 /* The bridge returned without a frame and there is a feature in progress. 04185 * However, we don't think the feature has quite yet timed out, so just 04186 * go back into the bridge. */ 04187 continue; 04188 } 04189 } else { 04190 if (config->feature_timer <=0) { 04191 /* We ran out of time */ 04192 config->feature_timer = 0; 04193 who = chan; 04194 if (f) 04195 ast_frfree(f); 04196 f = NULL; 04197 res = 0; 04198 } 04199 } 04200 } 04201 if (res < 0) { 04202 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04203 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 04204 } 04205 goto before_you_go; 04206 } 04207 04208 if (!f || (f->frametype == AST_FRAME_CONTROL && 04209 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04210 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04211 res = -1; 04212 break; 04213 } 04214 /* many things should be sent to the 'other' channel */ 04215 other = (who == chan) ? peer : chan; 04216 if (f->frametype == AST_FRAME_CONTROL) { 04217 switch (f->subclass.integer) { 04218 case AST_CONTROL_RINGING: 04219 case AST_CONTROL_FLASH: 04220 case -1: 04221 ast_indicate(other, f->subclass.integer); 04222 break; 04223 case AST_CONTROL_CONNECTED_LINE: 04224 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04225 break; 04226 } 04227 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04228 break; 04229 case AST_CONTROL_REDIRECTING: 04230 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04231 break; 04232 } 04233 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04234 break; 04235 case AST_CONTROL_AOC: 04236 case AST_CONTROL_HOLD: 04237 case AST_CONTROL_UNHOLD: 04238 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04239 break; 04240 case AST_CONTROL_OPTION: 04241 aoh = f->data.ptr; 04242 /* Forward option Requests, but only ones we know are safe 04243 * These are ONLY sent by chan_iax2 and I'm not convinced that 04244 * they are useful. I haven't deleted them entirely because I 04245 * just am not sure of the ramifications of removing them. */ 04246 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04247 switch (ntohs(aoh->option)) { 04248 case AST_OPTION_TONE_VERIFY: 04249 case AST_OPTION_TDD: 04250 case AST_OPTION_RELAXDTMF: 04251 case AST_OPTION_AUDIO_MODE: 04252 case AST_OPTION_DIGIT_DETECT: 04253 case AST_OPTION_FAX_DETECT: 04254 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04255 f->datalen - sizeof(struct ast_option_header), 0); 04256 } 04257 } 04258 break; 04259 } 04260 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04261 struct ast_flags *cfg; 04262 char dtmfcode[2] = { f->subclass.integer, }; 04263 size_t featurelen; 04264 04265 if (who == chan) { 04266 featurelen = strlen(chan_featurecode); 04267 cfg = &(config->features_caller); 04268 } else { 04269 featurelen = strlen(peer_featurecode); 04270 cfg = &(config->features_callee); 04271 } 04272 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04273 * DTMF along untouched. If this is not the first digit of a multi-digit code 04274 * then we need to fall through and stream the characters if it matches */ 04275 if (featurelen == 0 04276 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04277 if (option_debug > 3) { 04278 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04279 } 04280 ast_write(other, f); 04281 sendingdtmfdigit = 1; 04282 } else { 04283 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04284 * transmitting something while we hold on to the DTMF waiting for a 04285 * feature. */ 04286 if (!silgen && ast_opt_transmit_silence) { 04287 silgen = ast_channel_start_silence_generator(other); 04288 } 04289 if (option_debug > 3) { 04290 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04291 } 04292 } 04293 } else if (f->frametype == AST_FRAME_DTMF_END) { 04294 char *featurecode; 04295 int sense; 04296 04297 hadfeatures = hasfeatures; 04298 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04299 if (who == chan) { 04300 sense = FEATURE_SENSE_CHAN; 04301 featurecode = chan_featurecode; 04302 } else { 04303 sense = FEATURE_SENSE_PEER; 04304 featurecode = peer_featurecode; 04305 } 04306 04307 if (sendingdtmfdigit == 1) { 04308 /* We let the BEGIN go through happily, so let's not bother with the END, 04309 * since we already know it's not something we bother with */ 04310 ast_write(other, f); 04311 sendingdtmfdigit = 0; 04312 } else { 04313 /*! append the event to featurecode. we rely on the string being zero-filled, and 04314 * not overflowing it. 04315 * \todo XXX how do we guarantee the latter ? 04316 */ 04317 featurecode[strlen(featurecode)] = f->subclass.integer; 04318 /* Get rid of the frame before we start doing "stuff" with the channels */ 04319 ast_frfree(f); 04320 f = NULL; 04321 if (silgen) { 04322 ast_channel_stop_silence_generator(other, silgen); 04323 silgen = NULL; 04324 } 04325 config->feature_timer = 0; 04326 res = feature_interpret(chan, peer, config, featurecode, sense); 04327 switch(res) { 04328 case AST_FEATURE_RETURN_PASSDIGITS: 04329 ast_dtmf_stream(other, who, featurecode, 0, 0); 04330 /* Fall through */ 04331 case AST_FEATURE_RETURN_SUCCESS: 04332 memset(featurecode, 0, sizeof(chan_featurecode)); 04333 break; 04334 } 04335 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04336 res = 0; 04337 } else { 04338 break; 04339 } 04340 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04341 if (hadfeatures && !hasfeatures) { 04342 /* Feature completed or timed out */ 04343 config->feature_timer = 0; 04344 } else if (hasfeatures) { 04345 if (config->timelimit) { 04346 /* No warning next time - we are waiting for feature code */ 04347 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04348 } 04349 config->feature_start_time = ast_tvnow(); 04350 config->feature_timer = featuredigittimeout; 04351 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04352 } 04353 } 04354 } 04355 if (f) 04356 ast_frfree(f); 04357 } 04358 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04359 04360 before_you_go: 04361 if (chan->sending_dtmf_digit) { 04362 ast_bridge_end_dtmf(chan, chan->sending_dtmf_digit, chan->sending_dtmf_tv, 04363 "bridge end"); 04364 } 04365 if (peer->sending_dtmf_digit) { 04366 ast_bridge_end_dtmf(peer, peer->sending_dtmf_digit, peer->sending_dtmf_tv, 04367 "bridge end"); 04368 } 04369 04370 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04371 if (silgen) { 04372 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04373 silgen = NULL; 04374 } 04375 04376 /* Wait for any dual redirect to complete. */ 04377 while (ast_test_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) { 04378 sched_yield(); 04379 } 04380 04381 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04382 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04383 if (bridge_cdr) { 04384 ast_cdr_discard(bridge_cdr); 04385 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04386 } 04387 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04388 } 04389 04390 if (config->end_bridge_callback) { 04391 config->end_bridge_callback(config->end_bridge_callback_data); 04392 } 04393 04394 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04395 * if it were, then chan belongs to a different thread now, and might have been hung up long 04396 * ago. 04397 */ 04398 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04399 /* 04400 * If the bridge was broken for a hangup that isn't real, 04401 * then don't run the h extension, because the channel isn't 04402 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04403 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04404 */ 04405 h_context = NULL; 04406 } else if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04407 h_context = NULL; 04408 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04409 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04410 h_context = chan->context; 04411 } else if (!ast_strlen_zero(chan->macrocontext) 04412 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04413 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04414 h_context = chan->macrocontext; 04415 } else { 04416 h_context = NULL; 04417 } 04418 if (h_context) { 04419 struct ast_cdr *swapper = NULL; 04420 char savelastapp[AST_MAX_EXTENSION]; 04421 char savelastdata[AST_MAX_EXTENSION]; 04422 char save_context[AST_MAX_CONTEXT]; 04423 char save_exten[AST_MAX_EXTENSION]; 04424 int save_prio; 04425 int found = 0; /* set if we find at least one match */ 04426 int spawn_error = 0; 04427 04428 /* 04429 * Make sure that the channel is marked as hungup since we are 04430 * going to run the "h" exten on it. 04431 */ 04432 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04433 04434 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04435 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04436 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04437 ast_cdr_end(bridge_cdr); 04438 } 04439 04440 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04441 dialplan code operate on it */ 04442 ast_channel_lock(chan); 04443 if (bridge_cdr) { 04444 swapper = chan->cdr; 04445 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04446 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04447 chan->cdr = bridge_cdr; 04448 } 04449 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04450 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04451 save_prio = chan->priority; 04452 if (h_context != chan->context) { 04453 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04454 } 04455 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04456 chan->priority = 1; 04457 ast_channel_unlock(chan); 04458 04459 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04460 chan->priority, 04461 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04462 &found, 1)) == 0) { 04463 chan->priority++; 04464 } 04465 if (found && spawn_error) { 04466 /* Something bad happened, or a hangup has been requested. */ 04467 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04468 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04469 } 04470 04471 /* swap it back */ 04472 ast_channel_lock(chan); 04473 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04474 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04475 chan->priority = save_prio; 04476 if (bridge_cdr) { 04477 if (chan->cdr == bridge_cdr) { 04478 chan->cdr = swapper; 04479 } else { 04480 bridge_cdr = NULL; 04481 } 04482 } 04483 /* An "h" exten has been run, so indicate that one has been run. */ 04484 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04485 ast_channel_unlock(chan); 04486 04487 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04488 if (bridge_cdr) { 04489 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04490 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04491 } 04492 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04493 } 04494 04495 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04496 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04497 /* If the channel CDR has been modified during the call, record the changes in the bridge cdr, 04498 * BUT, if we've gone through the h extension block above, the CDR got swapped so don't overwrite 04499 * what was done in the h extension. What a mess. This is why you never touch CDR code. */ 04500 if (new_chan_cdr && bridge_cdr && !h_context) { 04501 ast_cdr_copy_vars(bridge_cdr, new_chan_cdr); 04502 ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield)); 04503 bridge_cdr->amaflags = new_chan_cdr->amaflags; 04504 ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode)); 04505 if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 04506 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04507 } 04508 } 04509 04510 /* we can post the bridge CDR at this point */ 04511 if (bridge_cdr) { 04512 ast_cdr_end(bridge_cdr); 04513 ast_cdr_detach(bridge_cdr); 04514 } 04515 04516 /* do a specialized reset on the beginning channel 04517 CDR's, if they still exist, so as not to mess up 04518 issues in future bridges; 04519 04520 Here are the rules of the game: 04521 1. The chan and peer channel pointers will not change 04522 during the life of the bridge. 04523 2. But, in transfers, the channel names will change. 04524 between the time the bridge is started, and the 04525 time the channel ends. 04526 Usually, when a channel changes names, it will 04527 also change CDR pointers. 04528 3. Usually, only one of the two channels (chan or peer) 04529 will change names. 04530 4. Usually, if a channel changes names during a bridge, 04531 it is because of a transfer. Usually, in these situations, 04532 it is normal to see 2 bridges running simultaneously, and 04533 it is not unusual to see the two channels that change 04534 swapped between bridges. 04535 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04536 to attend to; if the chan or peer changed names, 04537 we have the before and after attached CDR's. 04538 */ 04539 04540 if (new_chan_cdr) { 04541 struct ast_channel *chan_ptr = NULL; 04542 04543 if (strcasecmp(orig_channame, chan->name) != 0) { 04544 /* old channel */ 04545 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04546 ast_channel_lock(chan_ptr); 04547 if (!ast_bridged_channel(chan_ptr)) { 04548 struct ast_cdr *cur; 04549 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04550 if (cur == chan_cdr) { 04551 break; 04552 } 04553 } 04554 if (cur) { 04555 ast_cdr_specialized_reset(chan_cdr, 0); 04556 } 04557 } 04558 ast_channel_unlock(chan_ptr); 04559 chan_ptr = ast_channel_unref(chan_ptr); 04560 } 04561 /* new channel */ 04562 ast_cdr_specialized_reset(new_chan_cdr, 0); 04563 } else { 04564 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04565 } 04566 } 04567 04568 { 04569 struct ast_channel *chan_ptr = NULL; 04570 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04571 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)) 04572 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04573 if (strcasecmp(orig_peername, peer->name) != 0) { 04574 /* old channel */ 04575 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04576 ast_channel_lock(chan_ptr); 04577 if (!ast_bridged_channel(chan_ptr)) { 04578 struct ast_cdr *cur; 04579 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04580 if (cur == peer_cdr) { 04581 break; 04582 } 04583 } 04584 if (cur) { 04585 ast_cdr_specialized_reset(peer_cdr, 0); 04586 } 04587 } 04588 ast_channel_unlock(chan_ptr); 04589 chan_ptr = ast_channel_unref(chan_ptr); 04590 } 04591 /* new channel */ 04592 if (new_peer_cdr) { 04593 ast_cdr_specialized_reset(new_peer_cdr, 0); 04594 } 04595 } else { 04596 if (we_disabled_peer_cdr) { 04597 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04598 } 04599 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04600 } 04601 } 04602 04603 return res; 04604 }
void ast_bridge_end_dtmf | ( | struct ast_channel * | chan, | |
char | digit, | |||
struct timeval | start, | |||
const char * | why | |||
) |
Simulate a DTMF end on a broken bridge channel.
chan | Channel sending DTMF that has not ended. | |
digit | DTMF digit to stop. | |
start | DTMF digit start time. | |
why | Reason bridge broken. |
Definition at line 3905 of file features.c.
References ast_channel::_softhangup, ast_channel_lock, ast_channel_unlock, AST_FLAG_ZOMBIE, ast_log(), ast_senddigit_end(), AST_SOFTHANGUP_ASYNCGOTO, AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), and LOG_DTMF.
Referenced by ast_bridge_call(), and ast_do_masquerade().
03906 { 03907 int dead; 03908 long duration; 03909 03910 ast_channel_lock(chan); 03911 dead = ast_test_flag(chan, AST_FLAG_ZOMBIE) 03912 || (chan->_softhangup 03913 & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)); 03914 ast_channel_unlock(chan); 03915 if (dead) { 03916 /* Channel is a zombie or a real hangup. */ 03917 return; 03918 } 03919 03920 duration = ast_tvdiff_ms(ast_tvnow(), start); 03921 ast_senddigit_end(chan, digit, duration); 03922 ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n", 03923 digit, chan->name, why, duration); 03924 }
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
Definition at line 7486 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, ast_bridge_config::end_sound, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, pbx_builtin_getvar_helper(), ast_bridge_config::play_warning, S_OR, ast_bridge_config::start_sound, ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by bridge_exec(), and dial_exec_full().
07488 { 07489 char *stringp = ast_strdupa(parse); 07490 char *limit_str, *warning_str, *warnfreq_str; 07491 const char *var; 07492 int play_to_caller = 0, play_to_callee = 0; 07493 int delta; 07494 07495 limit_str = strsep(&stringp, ":"); 07496 warning_str = strsep(&stringp, ":"); 07497 warnfreq_str = strsep(&stringp, ":"); 07498 07499 config->timelimit = atol(limit_str); 07500 if (warning_str) 07501 config->play_warning = atol(warning_str); 07502 if (warnfreq_str) 07503 config->warning_freq = atol(warnfreq_str); 07504 07505 if (!config->timelimit) { 07506 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07507 config->timelimit = config->play_warning = config->warning_freq = 0; 07508 config->warning_sound = NULL; 07509 return -1; /* error */ 07510 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07511 int w = config->warning_freq; 07512 07513 /* 07514 * If the first warning is requested _after_ the entire call 07515 * would end, and no warning frequency is requested, then turn 07516 * off the warning. If a warning frequency is requested, reduce 07517 * the 'first warning' time by that frequency until it falls 07518 * within the call's total time limit. 07519 * 07520 * Graphically: 07521 * timelim->| delta |<-playwarning 07522 * 0__________________|_________________| 07523 * | w | | | | 07524 * 07525 * so the number of intervals to cut is 1+(delta-1)/w 07526 */ 07527 if (w == 0) { 07528 config->play_warning = 0; 07529 } else { 07530 config->play_warning -= w * ( 1 + (delta-1)/w ); 07531 if (config->play_warning < 1) 07532 config->play_warning = config->warning_freq = 0; 07533 } 07534 } 07535 07536 ast_channel_lock(chan); 07537 07538 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07539 play_to_caller = var ? ast_true(var) : 1; 07540 07541 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07542 play_to_callee = var ? ast_true(var) : 0; 07543 07544 if (!play_to_caller && !play_to_callee) 07545 play_to_caller = 1; 07546 07547 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07548 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07549 07550 /* The code looking at config wants a NULL, not just "", to decide 07551 * that the message should not be played, so we replace "" with NULL. 07552 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07553 * not found. 07554 */ 07555 07556 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07557 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07558 07559 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07560 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07561 07562 ast_channel_unlock(chan); 07563 07564 /* undo effect of S(x) in case they are both used */ 07565 calldurationlimit->tv_sec = 0; 07566 calldurationlimit->tv_usec = 0; 07567 07568 /* more efficient to do it like S(x) does since no advanced opts */ 07569 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07570 calldurationlimit->tv_sec = config->timelimit / 1000; 07571 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07572 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07573 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07574 config->timelimit = play_to_caller = play_to_callee = 07575 config->play_warning = config->warning_freq = 0; 07576 } else { 07577 ast_verb(4, "Limit Data for this call:\n"); 07578 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07579 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07580 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07581 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07582 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07583 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07584 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07585 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07586 } 07587 if (play_to_caller) 07588 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07589 if (play_to_callee) 07590 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07591 return 0; 07592 }
int ast_can_pickup | ( | struct ast_channel * | chan | ) |
Test if a channel can be picked up.
chan | Channel to test if can be picked up. |
Definition at line 7292 of file features.c.
References ast_channel::_state, ast_channel_datastore_find(), AST_FLAG_ZOMBIE, AST_STATE_DOWN, AST_STATE_RING, AST_STATE_RINGING, ast_test_flag, ast_channel::masq, and ast_channel::pbx.
Referenced by find_by_mark(), find_by_part(), find_channel_by_group(), pickup_by_exten(), and pickup_by_name_cb().
07293 { 07294 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07295 && (chan->_state == AST_STATE_RINGING 07296 || chan->_state == AST_STATE_RING 07297 /* 07298 * Check the down state as well because some SIP devices do not 07299 * give 180 ringing when they can just give 183 session progress 07300 * instead. Issue 14005. (Some ISDN switches as well for that 07301 * matter.) 07302 */ 07303 || chan->_state == AST_STATE_DOWN) 07304 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07305 return 1; 07306 } 07307 return 0; 07308 }
int ast_do_pickup | ( | struct ast_channel * | chan, | |
struct ast_channel * | target | |||
) |
Pickup a call target.
chan | channel that initiated pickup. | |
target | channel to be picked up. |
0 | on success. | |
-1 | on failure. |
< A masquerade changes channel names.
< A masquerade changes channel names.
Definition at line 7368 of file features.c.
References ast_answer(), AST_CEL_PICKUP, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_datastore_add(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_masquerade(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_datastore_alloc, ast_datastore_free(), ast_debug, ast_do_masquerade(), AST_FLAG_ANSWERED_ELSEWHERE, ast_log(), ast_manager_event_multichan, ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_queue_control(), ast_set_flag, ast_strdupa, ast_channel::caller, ast_channel::connected, EVENT_FLAG_CALL, LOG_WARNING, and ast_party_connected_line::source.
Referenced by ast_pickup_call(), pickup_by_channel(), pickup_by_exten(), pickup_by_group(), pickup_by_mark(), and pickup_by_part().
07369 { 07370 struct ast_party_connected_line connected_caller; 07371 struct ast_channel *chans[2] = { chan, target }; 07372 struct ast_datastore *ds_pickup; 07373 const char *chan_name;/*!< A masquerade changes channel names. */ 07374 const char *target_name;/*!< A masquerade changes channel names. */ 07375 int res = -1; 07376 07377 target_name = ast_strdupa(target->name); 07378 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name); 07379 07380 /* Mark the target to block any call pickup race. */ 07381 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07382 if (!ds_pickup) { 07383 ast_log(LOG_WARNING, 07384 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07385 return -1; 07386 } 07387 ast_channel_datastore_add(target, ds_pickup); 07388 07389 ast_party_connected_line_init(&connected_caller); 07390 ast_party_connected_line_copy(&connected_caller, &target->connected); 07391 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07392 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07393 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07394 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07395 } 07396 ast_party_connected_line_free(&connected_caller); 07397 07398 ast_channel_lock(chan); 07399 chan_name = ast_strdupa(chan->name); 07400 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07401 ast_channel_unlock(chan); 07402 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07403 07404 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07405 07406 if (ast_answer(chan)) { 07407 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07408 goto pickup_failed; 07409 } 07410 07411 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07412 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07413 goto pickup_failed; 07414 } 07415 07416 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07417 07418 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07419 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07420 07421 if (ast_channel_masquerade(target, chan)) { 07422 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07423 target_name); 07424 goto pickup_failed; 07425 } 07426 07427 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07428 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07429 "Channel: %s\r\n" 07430 "TargetChannel: %s\r\n", 07431 chan_name, target_name); 07432 07433 /* Do the masquerade manually to make sure that it is completed. */ 07434 ast_do_masquerade(target); 07435 res = 0; 07436 07437 pickup_failed: 07438 ast_channel_lock(target); 07439 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07440 ast_datastore_free(ds_pickup); 07441 } 07442 ast_party_connected_line_free(&connected_caller); 07443 07444 return res; 07445 }
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
chan | ||
features | an ast_flags ptr | |
code | ptr of input code | |
feature |
ast_call_feature | ptr to be set if found |
Definition at line 3412 of file features.c.
References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03412 { 03413 03414 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03415 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6833 of file features.c.
References ast_context_destroy(), ast_context_find(), ast_mutex_lock, ast_mutex_unlock, features_reload_lock, load_config(), parking_con_dial, and registrar.
Referenced by handle_features_reload().
06834 { 06835 struct ast_context *con; 06836 int res; 06837 06838 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06839 06840 /* 06841 * Always destroy the parking_con_dial context to remove buildup 06842 * of recalled extensions in the context. At worst, the parked 06843 * call gets hungup attempting to run an invalid extension when 06844 * we are trying to callback the parker or the preset return 06845 * extension. This is a small window of opportunity on an 06846 * execution chain that is not expected to happen very often. 06847 */ 06848 con = ast_context_find(parking_con_dial); 06849 if (con) { 06850 ast_context_destroy(con, registrar); 06851 } 06852 06853 res = load_config(1); 06854 ast_mutex_unlock(&features_reload_lock); 06855 06856 return res; 06857 }
struct ast_call_feature* ast_find_call_feature | ( | const char * | name | ) | [read] |
look for a call feature entry by its sname
name | a string ptr, should match "automon", "blindxfer", "atxfer", etc. |
Definition at line 3144 of file features.c.
References FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), handle_request_info(), and process_config().
03145 { 03146 int x; 03147 for (x = 0; x < FEATURES_COUNT; x++) { 03148 if (!strcasecmp(name, builtin_features[x].sname)) 03149 return &builtin_features[x]; 03150 } 03151 return NULL; 03152 }
int ast_masq_park_call | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call via a masqueraded channel.
park_me | Channel to be parked. | |
parker | Channel parking the call. | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
Masquerade the park_me channel into a new, empty channel which is then parked.
0 | on success. | |
-1 | on failure. |
Definition at line 1850 of file features.c.
References ast_strdupa, masq_park_call(), ast_park_call_args::orig_chan_name, and ast_park_call_args::timeout.
Referenced by handle_soft_key_event_message(), handle_stimulus_message(), and parkandannounce_exec().
01851 { 01852 struct ast_park_call_args args = { 01853 .timeout = timeout, 01854 .extout = extout, 01855 }; 01856 01857 if (peer) { 01858 args.orig_chan_name = ast_strdupa(peer->name); 01859 } 01860 return masq_park_call(rchan, peer, &args); 01861 }
int ast_masq_park_call_exten | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
const char * | park_exten, | |||
const char * | park_context, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call via a masqueraded channel.
park_me | Channel to be parked. | |
parker | Channel parking the call. | |
park_exten | Parking lot access extension | |
park_context | Parking lot context | |
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 park_me channel into a new, empty channel which is then parked.
0 | on success. | |
-1 | on failure. |
Definition at line 1796 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), find_parkinglot(), get_parking_exten(), masq_park_call(), ast_park_call_args::orig_chan_name, parkeddynamic, ast_park_call_args::parkinglot, parkinglot_unref(), parse(), park_app_args::pl_name, and ast_park_call_args::timeout.
Referenced by __analog_ss_thread(), analog_ss_thread(), and mgcp_ss().
01797 { 01798 int res; 01799 char *parse; 01800 const char *app_data; 01801 struct ast_exten *exten; 01802 struct park_app_args app_args; 01803 struct ast_park_call_args args = { 01804 .timeout = timeout, 01805 .extout = extout, 01806 }; 01807 01808 if (parker) { 01809 args.orig_chan_name = ast_strdupa(parker->name); 01810 } 01811 if (!park_exten || !park_context) { 01812 return masq_park_call(park_me, parker, &args); 01813 } 01814 01815 /* 01816 * Determiine if the specified park extension has an exclusive 01817 * parking lot to use. 01818 */ 01819 if (parker && parker != park_me) { 01820 ast_autoservice_start(park_me); 01821 } 01822 exten = get_parking_exten(park_exten, parker, park_context); 01823 if (exten) { 01824 app_data = ast_get_extension_app_data(exten); 01825 if (!app_data) { 01826 app_data = ""; 01827 } 01828 parse = ast_strdupa(app_data); 01829 AST_STANDARD_APP_ARGS(app_args, parse); 01830 01831 if (!ast_strlen_zero(app_args.pl_name)) { 01832 /* Find the specified exclusive parking lot */ 01833 args.parkinglot = find_parkinglot(app_args.pl_name); 01834 if (!args.parkinglot && parkeddynamic) { 01835 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01836 } 01837 } 01838 } 01839 if (parker && parker != park_me) { 01840 ast_autoservice_stop(park_me); 01841 } 01842 01843 res = masq_park_call(park_me, parker, &args); 01844 if (args.parkinglot) { 01845 parkinglot_unref(args.parkinglot); 01846 } 01847 return res; 01848 }
int ast_park_call | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
int | timeout, | |||
const char * | park_exten, | |||
int * | extout | |||
) |
Park a call and read back parked location.
park_me | Channel to be parked. | |
parker | Channel parking the call. | |
timeout | is a timeout in milliseconds | |
park_exten | Parking lot access extension (Not used) | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
Park the park_me channel, and read back the parked location to the parker channel. 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).
0 | on success. | |
-1 | on failure. |
Definition at line 1699 of file features.c.
References park_call_full(), and ast_park_call_args::timeout.
01700 { 01701 struct ast_park_call_args args = { 01702 .timeout = timeout, 01703 .extout = extout, 01704 }; 01705 01706 return park_call_full(park_me, parker, &args); 01707 }
int ast_park_call_exten | ( | struct ast_channel * | park_me, | |
struct ast_channel * | parker, | |||
const char * | park_exten, | |||
const char * | park_context, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call and read back parked location.
park_me | Channel to be parked. | |
parker | Channel parking the call. | |
park_exten | Parking lot access extension | |
park_context | Parking lot context | |
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 park_me channel, and read back the parked location to the parker channel. 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).
0 | on success. | |
-1 | on failure. |
Definition at line 1648 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), find_parkinglot(), get_parking_exten(), park_call_full(), parkeddynamic, ast_park_call_args::parkinglot, parkinglot_unref(), parse(), park_app_args::pl_name, and ast_park_call_args::timeout.
Referenced by iax_park_thread(), and sip_park_thread().
01649 { 01650 int res; 01651 char *parse; 01652 const char *app_data; 01653 struct ast_exten *exten; 01654 struct park_app_args app_args; 01655 struct ast_park_call_args args = { 01656 .timeout = timeout, 01657 .extout = extout, 01658 }; 01659 01660 if (!park_exten || !park_context) { 01661 return park_call_full(park_me, parker, &args); 01662 } 01663 01664 /* 01665 * Determiine if the specified park extension has an exclusive 01666 * parking lot to use. 01667 */ 01668 if (parker && parker != park_me) { 01669 ast_autoservice_start(park_me); 01670 } 01671 exten = get_parking_exten(park_exten, parker, park_context); 01672 if (exten) { 01673 app_data = ast_get_extension_app_data(exten); 01674 if (!app_data) { 01675 app_data = ""; 01676 } 01677 parse = ast_strdupa(app_data); 01678 AST_STANDARD_APP_ARGS(app_args, parse); 01679 01680 if (!ast_strlen_zero(app_args.pl_name)) { 01681 /* Find the specified exclusive parking lot */ 01682 args.parkinglot = find_parkinglot(app_args.pl_name); 01683 if (!args.parkinglot && parkeddynamic) { 01684 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01685 } 01686 } 01687 } 01688 if (parker && parker != park_me) { 01689 ast_autoservice_stop(park_me); 01690 } 01691 01692 res = park_call_full(park_me, parker, &args); 01693 if (args.parkinglot) { 01694 parkinglot_unref(args.parkinglot); 01695 } 01696 return res; 01697 }
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.
Definition at line 840 of file features.c.
References get_parking_exten().
Referenced by __analog_ss_thread(), analog_ss_thread(), dp_lookup(), handle_request_refer(), mgcp_ss(), and socket_process().
00841 { 00842 return get_parking_exten(exten_str, chan, context) ? 1 : 0; 00843 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
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.
< Potential pickup target
Definition at line 7334 of file features.c.
References ast_answer(), ast_channel_callback(), ast_channel_unlock, ast_channel_unref, ast_debug, ast_do_pickup(), ast_log(), ast_stream_and_wait(), ast_strlen_zero(), find_channel_by_group(), LOG_NOTICE, LOG_WARNING, pbx_builtin_setvar_helper(), pickupfailsound, and pickupsound.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), mgcp_ss(), and sip_pickup_thread().
07335 { 07336 struct ast_channel *target;/*!< Potential pickup target */ 07337 int res = -1; 07338 ast_debug(1, "pickup attempt by %s\n", chan->name); 07339 07340 /* The found channel is already locked. */ 07341 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07342 if (target) { 07343 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name); 07344 07345 res = ast_do_pickup(chan, target); 07346 ast_channel_unlock(target); 07347 if (!res) { 07348 if (!ast_strlen_zero(pickupsound)) { 07349 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07350 } 07351 } else { 07352 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name); 07353 } 07354 target = ast_channel_unref(target); 07355 } 07356 07357 if (res < 0) { 07358 ast_debug(1, "No call pickup possible... for %s\n", chan->name); 07359 if (!ast_strlen_zero(pickupfailsound)) { 07360 ast_answer(chan); 07361 ast_stream_and_wait(chan, pickupfailsound, ""); 07362 } 07363 } 07364 07365 return res; 07366 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 845 of file features.c.
Referenced by __analog_ss_thread(), analog_canmatch_featurecode(), analog_ss_thread(), canmatch_featurecode(), cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), and mgcp_ss().
00846 { 00847 return pickup_ext; 00848 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 3134 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
03135 { 03136 ast_rwlock_rdlock(&features_lock); 03137 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_set
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 2978 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, LOG_NOTICE, and ast_call_feature::sname.
Referenced by process_applicationmap_line().
02979 { 02980 if (!feature) { 02981 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02982 return; 02983 } 02984 02985 AST_RWLIST_WRLOCK(&feature_list); 02986 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 02987 AST_RWLIST_UNLOCK(&feature_list); 02988 02989 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 02990 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 3139 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
03140 { 03141 ast_rwlock_unlock(&features_lock); 03142 }
void ast_unregister_feature | ( | struct ast_call_feature * | feature | ) |
unregister feature from feature_set
feature | the ast_call_feature object which was registered before |
Definition at line 3058 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
03059 { 03060 if (!feature) { 03061 return; 03062 } 03063 03064 AST_RWLIST_WRLOCK(&feature_list); 03065 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 03066 AST_RWLIST_UNLOCK(&feature_list); 03067 03068 ast_free(feature); 03069 }