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 3960 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().
03961 { 03962 /* Copy voice back and forth between the two channels. Give the peer 03963 the ability to transfer calls with '#<extension' syntax. */ 03964 struct ast_frame *f; 03965 struct ast_channel *who; 03966 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03967 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03968 char orig_channame[AST_CHANNEL_NAME]; 03969 char orig_peername[AST_CHANNEL_NAME]; 03970 int res; 03971 int diff; 03972 int hasfeatures=0; 03973 int hadfeatures=0; 03974 int autoloopflag; 03975 int sendingdtmfdigit = 0; 03976 int we_disabled_peer_cdr = 0; 03977 struct ast_option_header *aoh; 03978 struct ast_cdr *bridge_cdr = NULL; 03979 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03980 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03981 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03982 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03983 struct ast_silence_generator *silgen = NULL; 03984 const char *h_context; 03985 03986 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03987 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03988 03989 /* Clear any BLINDTRANSFER since the transfer has completed. */ 03990 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03991 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL); 03992 03993 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03994 add_features_datastores(chan, peer, config); 03995 03996 /* This is an interesting case. One example is if a ringing channel gets redirected to 03997 * an extension that picks up a parked call. This will make sure that the call taken 03998 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03999 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 04000 ast_indicate(peer, AST_CONTROL_RINGING); 04001 } 04002 04003 if (monitor_ok) { 04004 const char *monitor_exec; 04005 struct ast_channel *src = NULL; 04006 if (!monitor_app) { 04007 if (!(monitor_app = pbx_findapp("Monitor"))) 04008 monitor_ok=0; 04009 } 04010 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 04011 src = chan; 04012 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 04013 src = peer; 04014 if (monitor_app && src) { 04015 char *tmp = ast_strdupa(monitor_exec); 04016 pbx_exec(src, monitor_app, tmp); 04017 } 04018 } 04019 04020 set_config_flags(chan, peer, config); 04021 04022 /* Answer if need be */ 04023 if (chan->_state != AST_STATE_UP) { 04024 if (ast_raw_answer(chan, 1)) { 04025 return -1; 04026 } 04027 } 04028 04029 #ifdef FOR_DEBUG 04030 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 04031 ast_channel_log("Pre-bridge CHAN Channel info", chan); 04032 ast_channel_log("Pre-bridge PEER Channel info", peer); 04033 #endif 04034 /* two channels are being marked as linked here */ 04035 ast_channel_set_linkgroup(chan,peer); 04036 04037 /* copy the userfield from the B-leg to A-leg if applicable */ 04038 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 04039 char tmp[256]; 04040 04041 ast_channel_lock(chan); 04042 if (!ast_strlen_zero(chan->cdr->userfield)) { 04043 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 04044 ast_cdr_appenduserfield(chan, tmp); 04045 } else { 04046 ast_cdr_setuserfield(chan, peer->cdr->userfield); 04047 } 04048 ast_channel_unlock(chan); 04049 /* Don't delete the CDR; just disable it. */ 04050 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04051 we_disabled_peer_cdr = 1; 04052 } 04053 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 04054 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 04055 04056 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 04057 ast_channel_lock_both(chan, peer); 04058 if (chan_cdr) { 04059 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 04060 ast_cdr_update(chan); 04061 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 04062 /* rip any forked CDR's off of the chan_cdr and attach 04063 * them to the bridge_cdr instead */ 04064 bridge_cdr->next = chan_cdr->next; 04065 chan_cdr->next = NULL; 04066 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04067 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04068 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 04069 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04070 } 04071 ast_cdr_setaccount(peer, chan->accountcode); 04072 } else { 04073 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 04074 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 04075 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 04076 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 04077 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 04078 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04079 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04080 ast_cdr_setcid(bridge_cdr, chan); 04081 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 04082 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 04083 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 04084 /* Destination information */ 04085 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 04086 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 04087 if (peer_cdr) { 04088 bridge_cdr->start = peer_cdr->start; 04089 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04090 } else { 04091 ast_cdr_start(bridge_cdr); 04092 } 04093 } 04094 ast_channel_unlock(chan); 04095 ast_channel_unlock(peer); 04096 04097 ast_debug(4,"bridge answer set, chan answer set\n"); 04098 /* peer_cdr->answer will be set when a macro runs on the peer; 04099 in that case, the bridge answer will be delayed while the 04100 macro plays on the peer channel. The peer answered the call 04101 before the macro started playing. To the phone system, 04102 this is billable time for the call, even tho the caller 04103 hears nothing but ringing while the macro does its thing. */ 04104 04105 /* Another case where the peer cdr's time will be set, is when 04106 A self-parks by pickup up phone and dialing 700, then B 04107 picks up A by dialing its parking slot; there may be more 04108 practical paths that get the same result, tho... in which 04109 case you get the previous answer time from the Park... which 04110 is before the bridge's start time, so I added in the 04111 tvcmp check to the if below */ 04112 04113 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 04114 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 04115 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 04116 if (chan_cdr) { 04117 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 04118 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 04119 } 04120 } else { 04121 ast_cdr_answer(bridge_cdr); 04122 if (chan_cdr) { 04123 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 04124 } 04125 } 04126 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 04127 if (chan_cdr) { 04128 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 04129 } 04130 if (peer_cdr) { 04131 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 04132 } 04133 } 04134 /* the DIALED flag may be set if a dialed channel is transferred 04135 * and then bridged to another channel. In order for the 04136 * bridge CDR to be written, the DIALED flag must not be 04137 * present. */ 04138 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04139 } 04140 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04141 04142 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04143 * a call is being bridged, that the humans in charge know what they're doing. If they 04144 * don't, well, what can we do about that? */ 04145 clear_dialed_interfaces(chan); 04146 clear_dialed_interfaces(peer); 04147 04148 for (;;) { 04149 struct ast_channel *other; /* used later */ 04150 04151 res = ast_channel_bridge(chan, peer, config, &f, &who); 04152 04153 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04154 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04155 /* Zombies are present time to leave! */ 04156 res = -1; 04157 if (f) { 04158 ast_frfree(f); 04159 } 04160 goto before_you_go; 04161 } 04162 04163 /* When frame is not set, we are probably involved in a situation 04164 where we've timed out. 04165 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04166 and also for DTMF_END. If we flow into the following 'if' for both, then 04167 our wait times are cut in half, as both will subtract from the 04168 feature_timer. Not good! 04169 */ 04170 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04171 /* Update feature timer for next pass */ 04172 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04173 if (res == AST_BRIDGE_RETRY) { 04174 /* The feature fully timed out but has not been updated. Skip 04175 * the potential round error from the diff calculation and 04176 * explicitly set to expired. */ 04177 config->feature_timer = -1; 04178 } else { 04179 config->feature_timer -= diff; 04180 } 04181 04182 if (hasfeatures) { 04183 if (config->feature_timer <= 0) { 04184 /* Not *really* out of time, just out of time for 04185 digits to come in for features. */ 04186 ast_debug(1, "Timed out for feature!\n"); 04187 if (!ast_strlen_zero(peer_featurecode)) { 04188 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 04189 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04190 } 04191 if (!ast_strlen_zero(chan_featurecode)) { 04192 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 04193 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04194 } 04195 if (f) 04196 ast_frfree(f); 04197 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04198 if (!hasfeatures) { 04199 /* No more digits expected - reset the timer */ 04200 config->feature_timer = 0; 04201 } 04202 hadfeatures = hasfeatures; 04203 /* Continue as we were */ 04204 continue; 04205 } else if (!f) { 04206 /* The bridge returned without a frame and there is a feature in progress. 04207 * However, we don't think the feature has quite yet timed out, so just 04208 * go back into the bridge. */ 04209 continue; 04210 } 04211 } else { 04212 if (config->feature_timer <=0) { 04213 /* We ran out of time */ 04214 config->feature_timer = 0; 04215 who = chan; 04216 if (f) 04217 ast_frfree(f); 04218 f = NULL; 04219 res = 0; 04220 } 04221 } 04222 } 04223 if (res < 0) { 04224 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04225 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 04226 } 04227 goto before_you_go; 04228 } 04229 04230 if (!f || (f->frametype == AST_FRAME_CONTROL && 04231 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04232 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04233 res = -1; 04234 break; 04235 } 04236 /* many things should be sent to the 'other' channel */ 04237 other = (who == chan) ? peer : chan; 04238 if (f->frametype == AST_FRAME_CONTROL) { 04239 switch (f->subclass.integer) { 04240 case AST_CONTROL_RINGING: 04241 case AST_CONTROL_FLASH: 04242 case -1: 04243 ast_indicate(other, f->subclass.integer); 04244 break; 04245 case AST_CONTROL_CONNECTED_LINE: 04246 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04247 break; 04248 } 04249 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04250 break; 04251 case AST_CONTROL_REDIRECTING: 04252 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04253 break; 04254 } 04255 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04256 break; 04257 case AST_CONTROL_AOC: 04258 case AST_CONTROL_HOLD: 04259 case AST_CONTROL_UNHOLD: 04260 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04261 break; 04262 case AST_CONTROL_OPTION: 04263 aoh = f->data.ptr; 04264 /* Forward option Requests, but only ones we know are safe 04265 * These are ONLY sent by chan_iax2 and I'm not convinced that 04266 * they are useful. I haven't deleted them entirely because I 04267 * just am not sure of the ramifications of removing them. */ 04268 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04269 switch (ntohs(aoh->option)) { 04270 case AST_OPTION_TONE_VERIFY: 04271 case AST_OPTION_TDD: 04272 case AST_OPTION_RELAXDTMF: 04273 case AST_OPTION_AUDIO_MODE: 04274 case AST_OPTION_DIGIT_DETECT: 04275 case AST_OPTION_FAX_DETECT: 04276 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04277 f->datalen - sizeof(struct ast_option_header), 0); 04278 } 04279 } 04280 break; 04281 } 04282 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04283 struct ast_flags *cfg; 04284 char dtmfcode[2] = { f->subclass.integer, }; 04285 size_t featurelen; 04286 04287 if (who == chan) { 04288 featurelen = strlen(chan_featurecode); 04289 cfg = &(config->features_caller); 04290 } else { 04291 featurelen = strlen(peer_featurecode); 04292 cfg = &(config->features_callee); 04293 } 04294 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04295 * DTMF along untouched. If this is not the first digit of a multi-digit code 04296 * then we need to fall through and stream the characters if it matches */ 04297 if (featurelen == 0 04298 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04299 if (option_debug > 3) { 04300 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04301 } 04302 ast_write(other, f); 04303 sendingdtmfdigit = 1; 04304 } else { 04305 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04306 * transmitting something while we hold on to the DTMF waiting for a 04307 * feature. */ 04308 if (!silgen && ast_opt_transmit_silence) { 04309 silgen = ast_channel_start_silence_generator(other); 04310 } 04311 if (option_debug > 3) { 04312 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04313 } 04314 } 04315 } else if (f->frametype == AST_FRAME_DTMF_END) { 04316 char *featurecode; 04317 int sense; 04318 04319 hadfeatures = hasfeatures; 04320 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04321 if (who == chan) { 04322 sense = FEATURE_SENSE_CHAN; 04323 featurecode = chan_featurecode; 04324 } else { 04325 sense = FEATURE_SENSE_PEER; 04326 featurecode = peer_featurecode; 04327 } 04328 04329 if (sendingdtmfdigit == 1) { 04330 /* We let the BEGIN go through happily, so let's not bother with the END, 04331 * since we already know it's not something we bother with */ 04332 ast_write(other, f); 04333 sendingdtmfdigit = 0; 04334 } else { 04335 /*! append the event to featurecode. we rely on the string being zero-filled, and 04336 * not overflowing it. 04337 * \todo XXX how do we guarantee the latter ? 04338 */ 04339 featurecode[strlen(featurecode)] = f->subclass.integer; 04340 /* Get rid of the frame before we start doing "stuff" with the channels */ 04341 ast_frfree(f); 04342 f = NULL; 04343 if (silgen) { 04344 ast_channel_stop_silence_generator(other, silgen); 04345 silgen = NULL; 04346 } 04347 config->feature_timer = 0; 04348 res = feature_interpret(chan, peer, config, featurecode, sense); 04349 switch(res) { 04350 case AST_FEATURE_RETURN_PASSDIGITS: 04351 ast_dtmf_stream(other, who, featurecode, 0, 0); 04352 /* Fall through */ 04353 case AST_FEATURE_RETURN_SUCCESS: 04354 memset(featurecode, 0, sizeof(chan_featurecode)); 04355 break; 04356 } 04357 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04358 res = 0; 04359 } else { 04360 break; 04361 } 04362 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04363 if (hadfeatures && !hasfeatures) { 04364 /* Feature completed or timed out */ 04365 config->feature_timer = 0; 04366 } else if (hasfeatures) { 04367 if (config->timelimit) { 04368 /* No warning next time - we are waiting for feature code */ 04369 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04370 } 04371 config->feature_start_time = ast_tvnow(); 04372 config->feature_timer = featuredigittimeout; 04373 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04374 } 04375 } 04376 } 04377 if (f) 04378 ast_frfree(f); 04379 } 04380 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04381 04382 before_you_go: 04383 if (chan->sending_dtmf_digit) { 04384 ast_bridge_end_dtmf(chan, chan->sending_dtmf_digit, chan->sending_dtmf_tv, 04385 "bridge end"); 04386 } 04387 if (peer->sending_dtmf_digit) { 04388 ast_bridge_end_dtmf(peer, peer->sending_dtmf_digit, peer->sending_dtmf_tv, 04389 "bridge end"); 04390 } 04391 04392 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04393 if (silgen) { 04394 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04395 silgen = NULL; 04396 } 04397 04398 /* Wait for any dual redirect to complete. */ 04399 while (ast_test_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) { 04400 sched_yield(); 04401 } 04402 04403 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04404 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04405 if (bridge_cdr) { 04406 ast_cdr_discard(bridge_cdr); 04407 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04408 } 04409 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04410 } 04411 04412 if (config->end_bridge_callback) { 04413 config->end_bridge_callback(config->end_bridge_callback_data); 04414 } 04415 04416 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04417 * if it were, then chan belongs to a different thread now, and might have been hung up long 04418 * ago. 04419 */ 04420 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04421 /* 04422 * If the bridge was broken for a hangup that isn't real, 04423 * then don't run the h extension, because the channel isn't 04424 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04425 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04426 */ 04427 h_context = NULL; 04428 } else if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04429 h_context = NULL; 04430 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04431 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04432 h_context = chan->context; 04433 } else if (!ast_strlen_zero(chan->macrocontext) 04434 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04435 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04436 h_context = chan->macrocontext; 04437 } else { 04438 h_context = NULL; 04439 } 04440 if (h_context) { 04441 struct ast_cdr *swapper = NULL; 04442 char savelastapp[AST_MAX_EXTENSION]; 04443 char savelastdata[AST_MAX_EXTENSION]; 04444 char save_context[AST_MAX_CONTEXT]; 04445 char save_exten[AST_MAX_EXTENSION]; 04446 int save_prio; 04447 int found = 0; /* set if we find at least one match */ 04448 int spawn_error = 0; 04449 04450 /* 04451 * Make sure that the channel is marked as hungup since we are 04452 * going to run the "h" exten on it. 04453 */ 04454 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04455 04456 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04457 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04458 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04459 ast_cdr_end(bridge_cdr); 04460 } 04461 04462 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04463 dialplan code operate on it */ 04464 ast_channel_lock(chan); 04465 if (bridge_cdr) { 04466 swapper = chan->cdr; 04467 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04468 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04469 chan->cdr = bridge_cdr; 04470 } 04471 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04472 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04473 save_prio = chan->priority; 04474 if (h_context != chan->context) { 04475 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04476 } 04477 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04478 chan->priority = 1; 04479 ast_channel_unlock(chan); 04480 04481 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04482 chan->priority, 04483 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04484 &found, 1)) == 0) { 04485 chan->priority++; 04486 } 04487 if (found && spawn_error) { 04488 /* Something bad happened, or a hangup has been requested. */ 04489 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04490 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04491 } 04492 04493 /* swap it back */ 04494 ast_channel_lock(chan); 04495 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04496 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04497 chan->priority = save_prio; 04498 if (bridge_cdr) { 04499 if (chan->cdr == bridge_cdr) { 04500 chan->cdr = swapper; 04501 } else { 04502 bridge_cdr = NULL; 04503 } 04504 } 04505 /* An "h" exten has been run, so indicate that one has been run. */ 04506 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04507 ast_channel_unlock(chan); 04508 04509 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04510 if (bridge_cdr) { 04511 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04512 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04513 } 04514 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04515 } 04516 04517 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04518 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04519 /* If the channel CDR has been modified during the call, record the changes in the bridge cdr, 04520 * BUT, if we've gone through the h extension block above, the CDR got swapped so don't overwrite 04521 * what was done in the h extension. What a mess. This is why you never touch CDR code. */ 04522 if (new_chan_cdr && bridge_cdr && !h_context) { 04523 ast_cdr_copy_vars(bridge_cdr, new_chan_cdr); 04524 ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield)); 04525 bridge_cdr->amaflags = new_chan_cdr->amaflags; 04526 ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode)); 04527 if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 04528 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04529 } 04530 } 04531 04532 /* we can post the bridge CDR at this point */ 04533 if (bridge_cdr) { 04534 ast_cdr_end(bridge_cdr); 04535 ast_cdr_detach(bridge_cdr); 04536 } 04537 04538 /* do a specialized reset on the beginning channel 04539 CDR's, if they still exist, so as not to mess up 04540 issues in future bridges; 04541 04542 Here are the rules of the game: 04543 1. The chan and peer channel pointers will not change 04544 during the life of the bridge. 04545 2. But, in transfers, the channel names will change. 04546 between the time the bridge is started, and the 04547 time the channel ends. 04548 Usually, when a channel changes names, it will 04549 also change CDR pointers. 04550 3. Usually, only one of the two channels (chan or peer) 04551 will change names. 04552 4. Usually, if a channel changes names during a bridge, 04553 it is because of a transfer. Usually, in these situations, 04554 it is normal to see 2 bridges running simultaneously, and 04555 it is not unusual to see the two channels that change 04556 swapped between bridges. 04557 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04558 to attend to; if the chan or peer changed names, 04559 we have the before and after attached CDR's. 04560 */ 04561 04562 if (new_chan_cdr) { 04563 struct ast_channel *chan_ptr = NULL; 04564 04565 if (strcasecmp(orig_channame, chan->name) != 0) { 04566 /* old channel */ 04567 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04568 ast_channel_lock(chan_ptr); 04569 if (!ast_bridged_channel(chan_ptr)) { 04570 struct ast_cdr *cur; 04571 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04572 if (cur == chan_cdr) { 04573 break; 04574 } 04575 } 04576 if (cur) { 04577 ast_cdr_specialized_reset(chan_cdr, 0); 04578 } 04579 } 04580 ast_channel_unlock(chan_ptr); 04581 chan_ptr = ast_channel_unref(chan_ptr); 04582 } 04583 /* new channel */ 04584 ast_cdr_specialized_reset(new_chan_cdr, 0); 04585 } else { 04586 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04587 } 04588 } 04589 04590 { 04591 struct ast_channel *chan_ptr = NULL; 04592 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04593 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)) 04594 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04595 if (strcasecmp(orig_peername, peer->name) != 0) { 04596 /* old channel */ 04597 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04598 ast_channel_lock(chan_ptr); 04599 if (!ast_bridged_channel(chan_ptr)) { 04600 struct ast_cdr *cur; 04601 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04602 if (cur == peer_cdr) { 04603 break; 04604 } 04605 } 04606 if (cur) { 04607 ast_cdr_specialized_reset(peer_cdr, 0); 04608 } 04609 } 04610 ast_channel_unlock(chan_ptr); 04611 chan_ptr = ast_channel_unref(chan_ptr); 04612 } 04613 /* new channel */ 04614 if (new_peer_cdr) { 04615 ast_cdr_specialized_reset(new_peer_cdr, 0); 04616 } 04617 } else { 04618 if (we_disabled_peer_cdr) { 04619 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04620 } 04621 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04622 } 04623 } 04624 04625 return res; 04626 }
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 3927 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().
03928 { 03929 int dead; 03930 long duration; 03931 03932 ast_channel_lock(chan); 03933 dead = ast_test_flag(chan, AST_FLAG_ZOMBIE) 03934 || (chan->_softhangup 03935 & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)); 03936 ast_channel_unlock(chan); 03937 if (dead) { 03938 /* Channel is a zombie or a real hangup. */ 03939 return; 03940 } 03941 03942 duration = ast_tvdiff_ms(ast_tvnow(), start); 03943 ast_senddigit_end(chan, digit, duration); 03944 ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n", 03945 digit, chan->name, why, duration); 03946 }
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 7532 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().
07534 { 07535 char *stringp = ast_strdupa(parse); 07536 char *limit_str, *warning_str, *warnfreq_str; 07537 const char *var; 07538 int play_to_caller = 0, play_to_callee = 0; 07539 int delta; 07540 07541 limit_str = strsep(&stringp, ":"); 07542 warning_str = strsep(&stringp, ":"); 07543 warnfreq_str = strsep(&stringp, ":"); 07544 07545 config->timelimit = atol(limit_str); 07546 if (warning_str) 07547 config->play_warning = atol(warning_str); 07548 if (warnfreq_str) 07549 config->warning_freq = atol(warnfreq_str); 07550 07551 if (!config->timelimit) { 07552 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07553 config->timelimit = config->play_warning = config->warning_freq = 0; 07554 config->warning_sound = NULL; 07555 return -1; /* error */ 07556 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07557 int w = config->warning_freq; 07558 07559 /* 07560 * If the first warning is requested _after_ the entire call 07561 * would end, and no warning frequency is requested, then turn 07562 * off the warning. If a warning frequency is requested, reduce 07563 * the 'first warning' time by that frequency until it falls 07564 * within the call's total time limit. 07565 * 07566 * Graphically: 07567 * timelim->| delta |<-playwarning 07568 * 0__________________|_________________| 07569 * | w | | | | 07570 * 07571 * so the number of intervals to cut is 1+(delta-1)/w 07572 */ 07573 if (w == 0) { 07574 config->play_warning = 0; 07575 } else { 07576 config->play_warning -= w * ( 1 + (delta-1)/w ); 07577 if (config->play_warning < 1) 07578 config->play_warning = config->warning_freq = 0; 07579 } 07580 } 07581 07582 ast_channel_lock(chan); 07583 07584 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07585 play_to_caller = var ? ast_true(var) : 1; 07586 07587 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07588 play_to_callee = var ? ast_true(var) : 0; 07589 07590 if (!play_to_caller && !play_to_callee) 07591 play_to_caller = 1; 07592 07593 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07594 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07595 07596 /* The code looking at config wants a NULL, not just "", to decide 07597 * that the message should not be played, so we replace "" with NULL. 07598 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07599 * not found. 07600 */ 07601 07602 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07603 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07604 07605 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07606 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07607 07608 ast_channel_unlock(chan); 07609 07610 /* undo effect of S(x) in case they are both used */ 07611 calldurationlimit->tv_sec = 0; 07612 calldurationlimit->tv_usec = 0; 07613 07614 /* more efficient to do it like S(x) does since no advanced opts */ 07615 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07616 calldurationlimit->tv_sec = config->timelimit / 1000; 07617 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07618 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07619 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07620 config->timelimit = play_to_caller = play_to_callee = 07621 config->play_warning = config->warning_freq = 0; 07622 } else { 07623 ast_verb(4, "Limit Data for this call:\n"); 07624 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07625 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07626 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07627 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07628 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07629 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07630 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07631 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07632 } 07633 if (play_to_caller) 07634 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07635 if (play_to_callee) 07636 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07637 return 0; 07638 }
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 7338 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().
07339 { 07340 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07341 && (chan->_state == AST_STATE_RINGING 07342 || chan->_state == AST_STATE_RING 07343 /* 07344 * Check the down state as well because some SIP devices do not 07345 * give 180 ringing when they can just give 183 session progress 07346 * instead. Issue 14005. (Some ISDN switches as well for that 07347 * matter.) 07348 */ 07349 || chan->_state == AST_STATE_DOWN) 07350 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07351 return 1; 07352 } 07353 return 0; 07354 }
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 7414 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().
07415 { 07416 struct ast_party_connected_line connected_caller; 07417 struct ast_channel *chans[2] = { chan, target }; 07418 struct ast_datastore *ds_pickup; 07419 const char *chan_name;/*!< A masquerade changes channel names. */ 07420 const char *target_name;/*!< A masquerade changes channel names. */ 07421 int res = -1; 07422 07423 target_name = ast_strdupa(target->name); 07424 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name); 07425 07426 /* Mark the target to block any call pickup race. */ 07427 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07428 if (!ds_pickup) { 07429 ast_log(LOG_WARNING, 07430 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07431 return -1; 07432 } 07433 ast_channel_datastore_add(target, ds_pickup); 07434 07435 ast_party_connected_line_init(&connected_caller); 07436 ast_party_connected_line_copy(&connected_caller, &target->connected); 07437 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07438 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07439 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07440 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07441 } 07442 ast_party_connected_line_free(&connected_caller); 07443 07444 ast_channel_lock(chan); 07445 chan_name = ast_strdupa(chan->name); 07446 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07447 ast_channel_unlock(chan); 07448 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07449 07450 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07451 07452 if (ast_answer(chan)) { 07453 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07454 goto pickup_failed; 07455 } 07456 07457 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07458 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07459 goto pickup_failed; 07460 } 07461 07462 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07463 07464 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07465 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07466 07467 if (ast_channel_masquerade(target, chan)) { 07468 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07469 target_name); 07470 goto pickup_failed; 07471 } 07472 07473 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07474 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07475 "Channel: %s\r\n" 07476 "TargetChannel: %s\r\n", 07477 chan_name, target_name); 07478 07479 /* Do the masquerade manually to make sure that it is completed. */ 07480 ast_do_masquerade(target); 07481 res = 0; 07482 07483 pickup_failed: 07484 ast_channel_lock(target); 07485 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07486 ast_datastore_free(ds_pickup); 07487 } 07488 ast_party_connected_line_free(&connected_caller); 07489 07490 return res; 07491 }
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 3434 of file features.c.
References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03434 { 03435 03436 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03437 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6879 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().
06880 { 06881 struct ast_context *con; 06882 int res; 06883 06884 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06885 06886 /* 06887 * Always destroy the parking_con_dial context to remove buildup 06888 * of recalled extensions in the context. At worst, the parked 06889 * call gets hungup attempting to run an invalid extension when 06890 * we are trying to callback the parker or the preset return 06891 * extension. This is a small window of opportunity on an 06892 * execution chain that is not expected to happen very often. 06893 */ 06894 con = ast_context_find(parking_con_dial); 06895 if (con) { 06896 ast_context_destroy(con, registrar); 06897 } 06898 06899 res = load_config(1); 06900 ast_mutex_unlock(&features_reload_lock); 06901 06902 return res; 06903 }
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 3160 of file features.c.
References FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), handle_request_info(), and process_config().
03161 { 03162 int x; 03163 for (x = 0; x < FEATURES_COUNT; x++) { 03164 if (!strcasecmp(name, builtin_features[x].sname)) 03165 return &builtin_features[x]; 03166 } 03167 return NULL; 03168 }
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 1857 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().
01858 { 01859 struct ast_park_call_args args = { 01860 .timeout = timeout, 01861 .extout = extout, 01862 }; 01863 01864 if (peer) { 01865 args.orig_chan_name = ast_strdupa(peer->name); 01866 } 01867 return masq_park_call(rchan, peer, &args); 01868 }
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 1803 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().
01804 { 01805 int res; 01806 char *parse; 01807 const char *app_data; 01808 struct ast_exten *exten; 01809 struct park_app_args app_args; 01810 struct ast_park_call_args args = { 01811 .timeout = timeout, 01812 .extout = extout, 01813 }; 01814 01815 if (parker) { 01816 args.orig_chan_name = ast_strdupa(parker->name); 01817 } 01818 if (!park_exten || !park_context) { 01819 return masq_park_call(park_me, parker, &args); 01820 } 01821 01822 /* 01823 * Determiine if the specified park extension has an exclusive 01824 * parking lot to use. 01825 */ 01826 if (parker && parker != park_me) { 01827 ast_autoservice_start(park_me); 01828 } 01829 exten = get_parking_exten(park_exten, parker, park_context); 01830 if (exten) { 01831 app_data = ast_get_extension_app_data(exten); 01832 if (!app_data) { 01833 app_data = ""; 01834 } 01835 parse = ast_strdupa(app_data); 01836 AST_STANDARD_APP_ARGS(app_args, parse); 01837 01838 if (!ast_strlen_zero(app_args.pl_name)) { 01839 /* Find the specified exclusive parking lot */ 01840 args.parkinglot = find_parkinglot(app_args.pl_name); 01841 if (!args.parkinglot && parkeddynamic) { 01842 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01843 } 01844 } 01845 } 01846 if (parker && parker != park_me) { 01847 ast_autoservice_stop(park_me); 01848 } 01849 01850 res = masq_park_call(park_me, parker, &args); 01851 if (args.parkinglot) { 01852 parkinglot_unref(args.parkinglot); 01853 } 01854 return res; 01855 }
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 1706 of file features.c.
References park_call_full(), and ast_park_call_args::timeout.
01707 { 01708 struct ast_park_call_args args = { 01709 .timeout = timeout, 01710 .extout = extout, 01711 }; 01712 01713 return park_call_full(park_me, parker, &args); 01714 }
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 1655 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().
01656 { 01657 int res; 01658 char *parse; 01659 const char *app_data; 01660 struct ast_exten *exten; 01661 struct park_app_args app_args; 01662 struct ast_park_call_args args = { 01663 .timeout = timeout, 01664 .extout = extout, 01665 }; 01666 01667 if (!park_exten || !park_context) { 01668 return park_call_full(park_me, parker, &args); 01669 } 01670 01671 /* 01672 * Determiine if the specified park extension has an exclusive 01673 * parking lot to use. 01674 */ 01675 if (parker && parker != park_me) { 01676 ast_autoservice_start(park_me); 01677 } 01678 exten = get_parking_exten(park_exten, parker, park_context); 01679 if (exten) { 01680 app_data = ast_get_extension_app_data(exten); 01681 if (!app_data) { 01682 app_data = ""; 01683 } 01684 parse = ast_strdupa(app_data); 01685 AST_STANDARD_APP_ARGS(app_args, parse); 01686 01687 if (!ast_strlen_zero(app_args.pl_name)) { 01688 /* Find the specified exclusive parking lot */ 01689 args.parkinglot = find_parkinglot(app_args.pl_name); 01690 if (!args.parkinglot && parkeddynamic) { 01691 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01692 } 01693 } 01694 } 01695 if (parker && parker != park_me) { 01696 ast_autoservice_stop(park_me); 01697 } 01698 01699 res = park_call_full(park_me, parker, &args); 01700 if (args.parkinglot) { 01701 parkinglot_unref(args.parkinglot); 01702 } 01703 return res; 01704 }
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 844 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().
00845 { 00846 return get_parking_exten(exten_str, chan, context) ? 1 : 0; 00847 }
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 7380 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().
07381 { 07382 struct ast_channel *target;/*!< Potential pickup target */ 07383 int res = -1; 07384 ast_debug(1, "pickup attempt by %s\n", chan->name); 07385 07386 /* The found channel is already locked. */ 07387 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07388 if (target) { 07389 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name); 07390 07391 res = ast_do_pickup(chan, target); 07392 ast_channel_unlock(target); 07393 if (!res) { 07394 if (!ast_strlen_zero(pickupsound)) { 07395 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07396 } 07397 } else { 07398 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name); 07399 } 07400 target = ast_channel_unref(target); 07401 } 07402 07403 if (res < 0) { 07404 ast_debug(1, "No call pickup possible... for %s\n", chan->name); 07405 if (!ast_strlen_zero(pickupfailsound)) { 07406 ast_answer(chan); 07407 ast_stream_and_wait(chan, pickupfailsound, ""); 07408 } 07409 } 07410 07411 return res; 07412 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 849 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().
00850 { 00851 return pickup_ext; 00852 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 3150 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
03151 { 03152 ast_rwlock_rdlock(&features_lock); 03153 }
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 2994 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().
02995 { 02996 if (!feature) { 02997 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02998 return; 02999 } 03000 03001 AST_RWLIST_WRLOCK(&feature_list); 03002 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 03003 AST_RWLIST_UNLOCK(&feature_list); 03004 03005 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 03006 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 3155 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
03156 { 03157 ast_rwlock_unlock(&features_lock); 03158 }
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 3074 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
03075 { 03076 if (!feature) { 03077 return; 03078 } 03079 03080 AST_RWLIST_WRLOCK(&feature_list); 03081 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 03082 AST_RWLIST_UNLOCK(&feature_list); 03083 03084 ast_free(feature); 03085 }