#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. | |
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. | |
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 |
Definition in file features.h.
#define AST_FEATURE_RETURN_HANGUP -1 |
#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 |
#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) |
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) |
#define FEATURE_SNAME_LEN 32 |
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.
chan | The bridge considers this channel the caller. | |
peer | The bridge considers this channel the callee. | |
config | Configuration for this bridge. |
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 3906 of file features.c.
References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_cdr::answer, 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_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(), config, ast_channel::context, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_party_caller::id, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, monitor_app, monitor_ok, ast_channel::name, 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, S_COR, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_party_number::str, 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(), and parked_call_exec().
03907 { 03908 /* Copy voice back and forth between the two channels. Give the peer 03909 the ability to transfer calls with '#<extension' syntax. */ 03910 struct ast_frame *f; 03911 struct ast_channel *who; 03912 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03913 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03914 char orig_channame[AST_CHANNEL_NAME]; 03915 char orig_peername[AST_CHANNEL_NAME]; 03916 int res; 03917 int diff; 03918 int hasfeatures=0; 03919 int hadfeatures=0; 03920 int autoloopflag; 03921 int sendingdtmfdigit = 0; 03922 int we_disabled_peer_cdr = 0; 03923 struct ast_option_header *aoh; 03924 struct ast_cdr *bridge_cdr = NULL; 03925 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03926 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03927 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03928 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03929 struct ast_silence_generator *silgen = NULL; 03930 const char *h_context; 03931 03932 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03933 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03934 03935 /* Clear any BLINDTRANSFER since the transfer has completed. */ 03936 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03937 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL); 03938 03939 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03940 add_features_datastores(chan, peer, config); 03941 03942 /* This is an interesting case. One example is if a ringing channel gets redirected to 03943 * an extension that picks up a parked call. This will make sure that the call taken 03944 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03945 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03946 ast_indicate(peer, AST_CONTROL_RINGING); 03947 } 03948 03949 if (monitor_ok) { 03950 const char *monitor_exec; 03951 struct ast_channel *src = NULL; 03952 if (!monitor_app) { 03953 if (!(monitor_app = pbx_findapp("Monitor"))) 03954 monitor_ok=0; 03955 } 03956 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03957 src = chan; 03958 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03959 src = peer; 03960 if (monitor_app && src) { 03961 char *tmp = ast_strdupa(monitor_exec); 03962 pbx_exec(src, monitor_app, tmp); 03963 } 03964 } 03965 03966 set_config_flags(chan, peer, config); 03967 03968 /* Answer if need be */ 03969 if (chan->_state != AST_STATE_UP) { 03970 if (ast_raw_answer(chan, 1)) { 03971 return -1; 03972 } 03973 } 03974 03975 #ifdef FOR_DEBUG 03976 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 03977 ast_channel_log("Pre-bridge CHAN Channel info", chan); 03978 ast_channel_log("Pre-bridge PEER Channel info", peer); 03979 #endif 03980 /* two channels are being marked as linked here */ 03981 ast_channel_set_linkgroup(chan,peer); 03982 03983 /* copy the userfield from the B-leg to A-leg if applicable */ 03984 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 03985 char tmp[256]; 03986 03987 ast_channel_lock(chan); 03988 if (!ast_strlen_zero(chan->cdr->userfield)) { 03989 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 03990 ast_cdr_appenduserfield(chan, tmp); 03991 } else { 03992 ast_cdr_setuserfield(chan, peer->cdr->userfield); 03993 } 03994 ast_channel_unlock(chan); 03995 /* Don't delete the CDR; just disable it. */ 03996 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03997 we_disabled_peer_cdr = 1; 03998 } 03999 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 04000 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 04001 04002 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 04003 ast_channel_lock_both(chan, peer); 04004 if (chan_cdr) { 04005 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 04006 ast_cdr_update(chan); 04007 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 04008 /* rip any forked CDR's off of the chan_cdr and attach 04009 * them to the bridge_cdr instead */ 04010 bridge_cdr->next = chan_cdr->next; 04011 chan_cdr->next = NULL; 04012 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04013 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04014 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 04015 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04016 } 04017 ast_cdr_setaccount(peer, chan->accountcode); 04018 } else { 04019 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 04020 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 04021 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 04022 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 04023 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 04024 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 04025 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 04026 ast_cdr_setcid(bridge_cdr, chan); 04027 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 04028 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 04029 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 04030 /* Destination information */ 04031 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 04032 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 04033 if (peer_cdr) { 04034 bridge_cdr->start = peer_cdr->start; 04035 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 04036 } else { 04037 ast_cdr_start(bridge_cdr); 04038 } 04039 } 04040 ast_channel_unlock(chan); 04041 ast_channel_unlock(peer); 04042 04043 ast_debug(4,"bridge answer set, chan answer set\n"); 04044 /* peer_cdr->answer will be set when a macro runs on the peer; 04045 in that case, the bridge answer will be delayed while the 04046 macro plays on the peer channel. The peer answered the call 04047 before the macro started playing. To the phone system, 04048 this is billable time for the call, even tho the caller 04049 hears nothing but ringing while the macro does its thing. */ 04050 04051 /* Another case where the peer cdr's time will be set, is when 04052 A self-parks by pickup up phone and dialing 700, then B 04053 picks up A by dialing its parking slot; there may be more 04054 practical paths that get the same result, tho... in which 04055 case you get the previous answer time from the Park... which 04056 is before the bridge's start time, so I added in the 04057 tvcmp check to the if below */ 04058 04059 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 04060 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 04061 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 04062 if (chan_cdr) { 04063 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 04064 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 04065 } 04066 } else { 04067 ast_cdr_answer(bridge_cdr); 04068 if (chan_cdr) { 04069 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 04070 } 04071 } 04072 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 04073 if (chan_cdr) { 04074 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 04075 } 04076 if (peer_cdr) { 04077 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 04078 } 04079 } 04080 /* the DIALED flag may be set if a dialed channel is transfered 04081 * and then bridged to another channel. In order for the 04082 * bridge CDR to be written, the DIALED flag must not be 04083 * present. */ 04084 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04085 } 04086 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04087 04088 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04089 * a call is being bridged, that the humans in charge know what they're doing. If they 04090 * don't, well, what can we do about that? */ 04091 clear_dialed_interfaces(chan); 04092 clear_dialed_interfaces(peer); 04093 04094 for (;;) { 04095 struct ast_channel *other; /* used later */ 04096 04097 res = ast_channel_bridge(chan, peer, config, &f, &who); 04098 04099 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04100 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04101 /* Zombies are present time to leave! */ 04102 res = -1; 04103 if (f) { 04104 ast_frfree(f); 04105 } 04106 goto before_you_go; 04107 } 04108 04109 /* When frame is not set, we are probably involved in a situation 04110 where we've timed out. 04111 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04112 and also for DTMF_END. If we flow into the following 'if' for both, then 04113 our wait times are cut in half, as both will subtract from the 04114 feature_timer. Not good! 04115 */ 04116 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04117 /* Update feature timer for next pass */ 04118 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04119 if (res == AST_BRIDGE_RETRY) { 04120 /* The feature fully timed out but has not been updated. Skip 04121 * the potential round error from the diff calculation and 04122 * explicitly set to expired. */ 04123 config->feature_timer = -1; 04124 } else { 04125 config->feature_timer -= diff; 04126 } 04127 04128 if (hasfeatures) { 04129 if (config->feature_timer <= 0) { 04130 /* Not *really* out of time, just out of time for 04131 digits to come in for features. */ 04132 ast_debug(1, "Timed out for feature!\n"); 04133 if (!ast_strlen_zero(peer_featurecode)) { 04134 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 04135 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04136 } 04137 if (!ast_strlen_zero(chan_featurecode)) { 04138 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 04139 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04140 } 04141 if (f) 04142 ast_frfree(f); 04143 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04144 if (!hasfeatures) { 04145 /* No more digits expected - reset the timer */ 04146 config->feature_timer = 0; 04147 } 04148 hadfeatures = hasfeatures; 04149 /* Continue as we were */ 04150 continue; 04151 } else if (!f) { 04152 /* The bridge returned without a frame and there is a feature in progress. 04153 * However, we don't think the feature has quite yet timed out, so just 04154 * go back into the bridge. */ 04155 continue; 04156 } 04157 } else { 04158 if (config->feature_timer <=0) { 04159 /* We ran out of time */ 04160 config->feature_timer = 0; 04161 who = chan; 04162 if (f) 04163 ast_frfree(f); 04164 f = NULL; 04165 res = 0; 04166 } 04167 } 04168 } 04169 if (res < 0) { 04170 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04171 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 04172 } 04173 goto before_you_go; 04174 } 04175 04176 if (!f || (f->frametype == AST_FRAME_CONTROL && 04177 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04178 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04179 /* 04180 * If the bridge was broken for a hangup that isn't real, 04181 * then don't run the h extension, because the channel isn't 04182 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04183 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04184 */ 04185 ast_channel_lock(chan); 04186 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04187 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 04188 } 04189 ast_channel_unlock(chan); 04190 res = -1; 04191 break; 04192 } 04193 /* many things should be sent to the 'other' channel */ 04194 other = (who == chan) ? peer : chan; 04195 if (f->frametype == AST_FRAME_CONTROL) { 04196 switch (f->subclass.integer) { 04197 case AST_CONTROL_RINGING: 04198 case AST_CONTROL_FLASH: 04199 case -1: 04200 ast_indicate(other, f->subclass.integer); 04201 break; 04202 case AST_CONTROL_CONNECTED_LINE: 04203 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04204 break; 04205 } 04206 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04207 break; 04208 case AST_CONTROL_REDIRECTING: 04209 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04210 break; 04211 } 04212 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04213 break; 04214 case AST_CONTROL_AOC: 04215 case AST_CONTROL_HOLD: 04216 case AST_CONTROL_UNHOLD: 04217 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04218 break; 04219 case AST_CONTROL_OPTION: 04220 aoh = f->data.ptr; 04221 /* Forward option Requests, but only ones we know are safe 04222 * These are ONLY sent by chan_iax2 and I'm not convinced that 04223 * they are useful. I haven't deleted them entirely because I 04224 * just am not sure of the ramifications of removing them. */ 04225 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04226 switch (ntohs(aoh->option)) { 04227 case AST_OPTION_TONE_VERIFY: 04228 case AST_OPTION_TDD: 04229 case AST_OPTION_RELAXDTMF: 04230 case AST_OPTION_AUDIO_MODE: 04231 case AST_OPTION_DIGIT_DETECT: 04232 case AST_OPTION_FAX_DETECT: 04233 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04234 f->datalen - sizeof(struct ast_option_header), 0); 04235 } 04236 } 04237 break; 04238 } 04239 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04240 struct ast_flags *cfg; 04241 char dtmfcode[2] = { f->subclass.integer, }; 04242 size_t featurelen; 04243 04244 if (who == chan) { 04245 featurelen = strlen(chan_featurecode); 04246 cfg = &(config->features_caller); 04247 } else { 04248 featurelen = strlen(peer_featurecode); 04249 cfg = &(config->features_callee); 04250 } 04251 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04252 * DTMF along untouched. If this is not the first digit of a multi-digit code 04253 * then we need to fall through and stream the characters if it matches */ 04254 if (featurelen == 0 04255 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04256 if (option_debug > 3) { 04257 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04258 } 04259 ast_write(other, f); 04260 sendingdtmfdigit = 1; 04261 } else { 04262 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04263 * transmitting something while we hold on to the DTMF waiting for a 04264 * feature. */ 04265 if (!silgen && ast_opt_transmit_silence) { 04266 silgen = ast_channel_start_silence_generator(other); 04267 } 04268 if (option_debug > 3) { 04269 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04270 } 04271 } 04272 } else if (f->frametype == AST_FRAME_DTMF_END) { 04273 char *featurecode; 04274 int sense; 04275 04276 hadfeatures = hasfeatures; 04277 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04278 if (who == chan) { 04279 sense = FEATURE_SENSE_CHAN; 04280 featurecode = chan_featurecode; 04281 } else { 04282 sense = FEATURE_SENSE_PEER; 04283 featurecode = peer_featurecode; 04284 } 04285 04286 if (sendingdtmfdigit == 1) { 04287 /* We let the BEGIN go through happily, so let's not bother with the END, 04288 * since we already know it's not something we bother with */ 04289 ast_write(other, f); 04290 sendingdtmfdigit = 0; 04291 } else { 04292 /*! append the event to featurecode. we rely on the string being zero-filled, and 04293 * not overflowing it. 04294 * \todo XXX how do we guarantee the latter ? 04295 */ 04296 featurecode[strlen(featurecode)] = f->subclass.integer; 04297 /* Get rid of the frame before we start doing "stuff" with the channels */ 04298 ast_frfree(f); 04299 f = NULL; 04300 if (silgen) { 04301 ast_channel_stop_silence_generator(other, silgen); 04302 silgen = NULL; 04303 } 04304 config->feature_timer = 0; 04305 res = feature_interpret(chan, peer, config, featurecode, sense); 04306 switch(res) { 04307 case AST_FEATURE_RETURN_PASSDIGITS: 04308 ast_dtmf_stream(other, who, featurecode, 0, 0); 04309 /* Fall through */ 04310 case AST_FEATURE_RETURN_SUCCESS: 04311 memset(featurecode, 0, sizeof(chan_featurecode)); 04312 break; 04313 } 04314 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04315 res = 0; 04316 } else { 04317 break; 04318 } 04319 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04320 if (hadfeatures && !hasfeatures) { 04321 /* Feature completed or timed out */ 04322 config->feature_timer = 0; 04323 } else if (hasfeatures) { 04324 if (config->timelimit) { 04325 /* No warning next time - we are waiting for feature code */ 04326 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04327 } 04328 config->feature_start_time = ast_tvnow(); 04329 config->feature_timer = featuredigittimeout; 04330 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04331 } 04332 } 04333 } 04334 if (f) 04335 ast_frfree(f); 04336 } 04337 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04338 04339 before_you_go: 04340 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04341 if (silgen) { 04342 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04343 silgen = NULL; 04344 } 04345 04346 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04347 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04348 if (bridge_cdr) { 04349 ast_cdr_discard(bridge_cdr); 04350 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04351 } 04352 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04353 } 04354 04355 if (config->end_bridge_callback) { 04356 config->end_bridge_callback(config->end_bridge_callback_data); 04357 } 04358 04359 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04360 * if it were, then chan belongs to a different thread now, and might have been hung up long 04361 * ago. 04362 */ 04363 if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04364 h_context = NULL; 04365 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04366 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04367 h_context = chan->context; 04368 } else if (!ast_strlen_zero(chan->macrocontext) 04369 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04370 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04371 h_context = chan->macrocontext; 04372 } else { 04373 h_context = NULL; 04374 } 04375 if (h_context) { 04376 struct ast_cdr *swapper = NULL; 04377 char savelastapp[AST_MAX_EXTENSION]; 04378 char savelastdata[AST_MAX_EXTENSION]; 04379 char save_context[AST_MAX_CONTEXT]; 04380 char save_exten[AST_MAX_EXTENSION]; 04381 int save_prio; 04382 int found = 0; /* set if we find at least one match */ 04383 int spawn_error = 0; 04384 04385 /* 04386 * Make sure that the channel is marked as hungup since we are 04387 * going to run the "h" exten on it. 04388 */ 04389 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04390 04391 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04392 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04393 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04394 ast_cdr_end(bridge_cdr); 04395 } 04396 04397 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04398 dialplan code operate on it */ 04399 ast_channel_lock(chan); 04400 if (bridge_cdr) { 04401 swapper = chan->cdr; 04402 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04403 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04404 chan->cdr = bridge_cdr; 04405 } 04406 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04407 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04408 save_prio = chan->priority; 04409 if (h_context != chan->context) { 04410 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04411 } 04412 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04413 chan->priority = 1; 04414 ast_channel_unlock(chan); 04415 04416 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04417 chan->priority, 04418 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04419 &found, 1)) == 0) { 04420 chan->priority++; 04421 } 04422 if (found && spawn_error) { 04423 /* Something bad happened, or a hangup has been requested. */ 04424 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04425 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04426 } 04427 04428 /* swap it back */ 04429 ast_channel_lock(chan); 04430 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04431 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04432 chan->priority = save_prio; 04433 if (bridge_cdr) { 04434 if (chan->cdr == bridge_cdr) { 04435 chan->cdr = swapper; 04436 } else { 04437 bridge_cdr = NULL; 04438 } 04439 } 04440 /* An "h" exten has been run, so indicate that one has been run. */ 04441 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04442 ast_channel_unlock(chan); 04443 04444 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04445 if (bridge_cdr) { 04446 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04447 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04448 } 04449 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04450 } 04451 04452 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04453 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04454 /* If the channel CDR has been modified during the call, record the changes in the bridge cdr, 04455 * BUT, if we've gone through the h extension block above, the CDR got swapped so don't overwrite 04456 * what was done in the h extension. What a mess. This is why you never touch CDR code. */ 04457 if (new_chan_cdr && bridge_cdr && !h_context) { 04458 ast_cdr_copy_vars(bridge_cdr, new_chan_cdr); 04459 ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield)); 04460 bridge_cdr->amaflags = new_chan_cdr->amaflags; 04461 ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode)); 04462 if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 04463 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04464 } 04465 } 04466 04467 /* we can post the bridge CDR at this point */ 04468 if (bridge_cdr) { 04469 ast_cdr_end(bridge_cdr); 04470 ast_cdr_detach(bridge_cdr); 04471 } 04472 04473 /* do a specialized reset on the beginning channel 04474 CDR's, if they still exist, so as not to mess up 04475 issues in future bridges; 04476 04477 Here are the rules of the game: 04478 1. The chan and peer channel pointers will not change 04479 during the life of the bridge. 04480 2. But, in transfers, the channel names will change. 04481 between the time the bridge is started, and the 04482 time the channel ends. 04483 Usually, when a channel changes names, it will 04484 also change CDR pointers. 04485 3. Usually, only one of the two channels (chan or peer) 04486 will change names. 04487 4. Usually, if a channel changes names during a bridge, 04488 it is because of a transfer. Usually, in these situations, 04489 it is normal to see 2 bridges running simultaneously, and 04490 it is not unusual to see the two channels that change 04491 swapped between bridges. 04492 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04493 to attend to; if the chan or peer changed names, 04494 we have the before and after attached CDR's. 04495 */ 04496 04497 if (new_chan_cdr) { 04498 struct ast_channel *chan_ptr = NULL; 04499 04500 if (strcasecmp(orig_channame, chan->name) != 0) { 04501 /* old channel */ 04502 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04503 ast_channel_lock(chan_ptr); 04504 if (!ast_bridged_channel(chan_ptr)) { 04505 struct ast_cdr *cur; 04506 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04507 if (cur == chan_cdr) { 04508 break; 04509 } 04510 } 04511 if (cur) { 04512 ast_cdr_specialized_reset(chan_cdr, 0); 04513 } 04514 } 04515 ast_channel_unlock(chan_ptr); 04516 chan_ptr = ast_channel_unref(chan_ptr); 04517 } 04518 /* new channel */ 04519 ast_cdr_specialized_reset(new_chan_cdr, 0); 04520 } else { 04521 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04522 } 04523 } 04524 04525 { 04526 struct ast_channel *chan_ptr = NULL; 04527 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04528 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)) 04529 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04530 if (strcasecmp(orig_peername, peer->name) != 0) { 04531 /* old channel */ 04532 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04533 ast_channel_lock(chan_ptr); 04534 if (!ast_bridged_channel(chan_ptr)) { 04535 struct ast_cdr *cur; 04536 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04537 if (cur == peer_cdr) { 04538 break; 04539 } 04540 } 04541 if (cur) { 04542 ast_cdr_specialized_reset(peer_cdr, 0); 04543 } 04544 } 04545 ast_channel_unlock(chan_ptr); 04546 chan_ptr = ast_channel_unref(chan_ptr); 04547 } 04548 /* new channel */ 04549 if (new_peer_cdr) { 04550 ast_cdr_specialized_reset(new_peer_cdr, 0); 04551 } 04552 } else { 04553 if (we_disabled_peer_cdr) { 04554 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04555 } 04556 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04557 } 04558 } 04559 04560 return res; 04561 }
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 7444 of file features.c.
References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, config, LOG_WARNING, pbx_builtin_getvar_helper(), S_OR, strsep(), and var.
Referenced by bridge_exec(), and dial_exec_full().
07446 { 07447 char *stringp = ast_strdupa(parse); 07448 char *limit_str, *warning_str, *warnfreq_str; 07449 const char *var; 07450 int play_to_caller = 0, play_to_callee = 0; 07451 int delta; 07452 07453 limit_str = strsep(&stringp, ":"); 07454 warning_str = strsep(&stringp, ":"); 07455 warnfreq_str = strsep(&stringp, ":"); 07456 07457 config->timelimit = atol(limit_str); 07458 if (warning_str) 07459 config->play_warning = atol(warning_str); 07460 if (warnfreq_str) 07461 config->warning_freq = atol(warnfreq_str); 07462 07463 if (!config->timelimit) { 07464 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07465 config->timelimit = config->play_warning = config->warning_freq = 0; 07466 config->warning_sound = NULL; 07467 return -1; /* error */ 07468 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07469 int w = config->warning_freq; 07470 07471 /* 07472 * If the first warning is requested _after_ the entire call 07473 * would end, and no warning frequency is requested, then turn 07474 * off the warning. If a warning frequency is requested, reduce 07475 * the 'first warning' time by that frequency until it falls 07476 * within the call's total time limit. 07477 * 07478 * Graphically: 07479 * timelim->| delta |<-playwarning 07480 * 0__________________|_________________| 07481 * | w | | | | 07482 * 07483 * so the number of intervals to cut is 1+(delta-1)/w 07484 */ 07485 if (w == 0) { 07486 config->play_warning = 0; 07487 } else { 07488 config->play_warning -= w * ( 1 + (delta-1)/w ); 07489 if (config->play_warning < 1) 07490 config->play_warning = config->warning_freq = 0; 07491 } 07492 } 07493 07494 ast_channel_lock(chan); 07495 07496 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07497 play_to_caller = var ? ast_true(var) : 1; 07498 07499 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07500 play_to_callee = var ? ast_true(var) : 0; 07501 07502 if (!play_to_caller && !play_to_callee) 07503 play_to_caller = 1; 07504 07505 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07506 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07507 07508 /* The code looking at config wants a NULL, not just "", to decide 07509 * that the message should not be played, so we replace "" with NULL. 07510 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07511 * not found. 07512 */ 07513 07514 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07515 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07516 07517 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07518 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07519 07520 ast_channel_unlock(chan); 07521 07522 /* undo effect of S(x) in case they are both used */ 07523 calldurationlimit->tv_sec = 0; 07524 calldurationlimit->tv_usec = 0; 07525 07526 /* more efficient to do it like S(x) does since no advanced opts */ 07527 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07528 calldurationlimit->tv_sec = config->timelimit / 1000; 07529 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07530 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07531 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07532 config->timelimit = play_to_caller = play_to_callee = 07533 config->play_warning = config->warning_freq = 0; 07534 } else { 07535 ast_verb(4, "Limit Data for this call:\n"); 07536 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07537 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07538 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07539 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07540 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07541 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07542 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07543 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07544 } 07545 if (play_to_caller) 07546 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07547 if (play_to_callee) 07548 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07549 return 0; 07550 }
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 7250 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, ast_channel::pbx, and pickup_active.
Referenced by find_by_mark(), find_by_part(), find_channel_by_group(), pickup_by_exten(), and pickup_by_name_cb().
07251 { 07252 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07253 && (chan->_state == AST_STATE_RINGING 07254 || chan->_state == AST_STATE_RING 07255 /* 07256 * Check the down state as well because some SIP devices do not 07257 * give 180 ringing when they can just give 183 session progress 07258 * instead. Issue 14005. (Some ISDN switches as well for that 07259 * matter.) 07260 */ 07261 || chan->_state == AST_STATE_DOWN) 07262 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07263 return 1; 07264 } 07265 return 0; 07266 }
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 7326 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, EVENT_FLAG_CALL, LOG_WARNING, ast_channel::name, pickup_active, 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().
07327 { 07328 struct ast_party_connected_line connected_caller; 07329 struct ast_channel *chans[2] = { chan, target }; 07330 struct ast_datastore *ds_pickup; 07331 const char *chan_name;/*!< A masquerade changes channel names. */ 07332 const char *target_name;/*!< A masquerade changes channel names. */ 07333 int res = -1; 07334 07335 target_name = ast_strdupa(target->name); 07336 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name); 07337 07338 /* Mark the target to block any call pickup race. */ 07339 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07340 if (!ds_pickup) { 07341 ast_log(LOG_WARNING, 07342 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07343 return -1; 07344 } 07345 ast_channel_datastore_add(target, ds_pickup); 07346 07347 ast_party_connected_line_init(&connected_caller); 07348 ast_party_connected_line_copy(&connected_caller, &target->connected); 07349 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07350 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07351 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07352 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07353 } 07354 ast_party_connected_line_free(&connected_caller); 07355 07356 ast_channel_lock(chan); 07357 chan_name = ast_strdupa(chan->name); 07358 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07359 ast_channel_unlock(chan); 07360 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07361 07362 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07363 07364 if (ast_answer(chan)) { 07365 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07366 goto pickup_failed; 07367 } 07368 07369 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07370 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07371 goto pickup_failed; 07372 } 07373 07374 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07375 07376 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07377 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07378 07379 if (ast_channel_masquerade(target, chan)) { 07380 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07381 target_name); 07382 goto pickup_failed; 07383 } 07384 07385 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07386 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07387 "Channel: %s\r\n" 07388 "TargetChannel: %s\r\n", 07389 chan_name, target_name); 07390 07391 /* Do the masquerade manually to make sure that it is completed. */ 07392 ast_do_masquerade(target); 07393 res = 0; 07394 07395 pickup_failed: 07396 ast_channel_lock(target); 07397 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07398 ast_datastore_free(ds_pickup); 07399 } 07400 ast_party_connected_line_free(&connected_caller); 07401 07402 return res; 07403 }
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 3401 of file features.c.
References feature_group_exten::feature, FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03401 { 03402 03403 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03404 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6791 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().
06792 { 06793 struct ast_context *con; 06794 int res; 06795 06796 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06797 06798 /* 06799 * Always destroy the parking_con_dial context to remove buildup 06800 * of recalled extensions in the context. At worst, the parked 06801 * call gets hungup attempting to run an invalid extension when 06802 * we are trying to callback the parker or the preset return 06803 * extension. This is a small window of opportunity on an 06804 * execution chain that is not expected to happen very often. 06805 */ 06806 con = ast_context_find(parking_con_dial); 06807 if (con) { 06808 ast_context_destroy(con, registrar); 06809 } 06810 06811 res = load_config(1); 06812 ast_mutex_unlock(&features_reload_lock); 06813 06814 return res; 06815 }
struct ast_call_feature* ast_find_call_feature | ( | const char * | name | ) |
look for a call feature entry by its sname
name | a string ptr, should match "automon", "blindxfer", "atxfer", etc. |
Definition at line 3133 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
03134 { 03135 int x; 03136 for (x = 0; x < FEATURES_COUNT; x++) { 03137 if (!strcasecmp(name, builtin_features[x].sname)) 03138 return &builtin_features[x]; 03139 } 03140 return NULL; 03141 }
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. |
0 | on success. | |
-1 | on failure. |
Definition at line 1845 of file features.c.
References args, ast_strdupa, masq_park_call(), and ast_channel::name.
Referenced by handle_soft_key_event_message(), handle_stimulus_message(), and parkandannounce_exec().
01846 { 01847 struct ast_park_call_args args = { 01848 .timeout = timeout, 01849 .extout = extout, 01850 }; 01851 01852 if (peer) { 01853 args.orig_chan_name = ast_strdupa(peer->name); 01854 } 01855 return masq_park_call(rchan, peer, &args); 01856 }
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. |
0 | on success. | |
-1 | on failure. |
Definition at line 1791 of file features.c.
References args, ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), feature_group_exten::exten, find_parkinglot(), get_parking_exten(), masq_park_call(), ast_channel::name, parkeddynamic, parkinglot_unref(), parse(), and park_app_args::pl_name.
Referenced by __analog_ss_thread(), analog_ss_thread(), and mgcp_ss().
01792 { 01793 int res; 01794 char *parse; 01795 const char *app_data; 01796 struct ast_exten *exten; 01797 struct park_app_args app_args; 01798 struct ast_park_call_args args = { 01799 .timeout = timeout, 01800 .extout = extout, 01801 }; 01802 01803 if (parker) { 01804 args.orig_chan_name = ast_strdupa(parker->name); 01805 } 01806 if (!park_exten || !park_context) { 01807 return masq_park_call(park_me, parker, &args); 01808 } 01809 01810 /* 01811 * Determiine if the specified park extension has an exclusive 01812 * parking lot to use. 01813 */ 01814 if (parker && parker != park_me) { 01815 ast_autoservice_start(park_me); 01816 } 01817 exten = get_parking_exten(park_exten, parker, park_context); 01818 if (exten) { 01819 app_data = ast_get_extension_app_data(exten); 01820 if (!app_data) { 01821 app_data = ""; 01822 } 01823 parse = ast_strdupa(app_data); 01824 AST_STANDARD_APP_ARGS(app_args, parse); 01825 01826 if (!ast_strlen_zero(app_args.pl_name)) { 01827 /* Find the specified exclusive parking lot */ 01828 args.parkinglot = find_parkinglot(app_args.pl_name); 01829 if (!args.parkinglot && parkeddynamic) { 01830 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01831 } 01832 } 01833 } 01834 if (parker && parker != park_me) { 01835 ast_autoservice_stop(park_me); 01836 } 01837 01838 res = masq_park_call(park_me, parker, &args); 01839 if (args.parkinglot) { 01840 parkinglot_unref(args.parkinglot); 01841 } 01842 return res; 01843 }
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. |
0 | on success. | |
-1 | on failure. |
Definition at line 1694 of file features.c.
References args, and park_call_full().
01695 { 01696 struct ast_park_call_args args = { 01697 .timeout = timeout, 01698 .extout = extout, 01699 }; 01700 01701 return park_call_full(park_me, parker, &args); 01702 }
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. |
0 | on success. | |
-1 | on failure. |
Definition at line 1643 of file features.c.
References args, ast_autoservice_start(), ast_autoservice_stop(), ast_get_extension_app_data(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), create_dynamic_parkinglot(), feature_group_exten::exten, find_parkinglot(), get_parking_exten(), park_call_full(), parkeddynamic, parkinglot_unref(), parse(), and park_app_args::pl_name.
Referenced by iax_park_thread(), and sip_park_thread().
01644 { 01645 int res; 01646 char *parse; 01647 const char *app_data; 01648 struct ast_exten *exten; 01649 struct park_app_args app_args; 01650 struct ast_park_call_args args = { 01651 .timeout = timeout, 01652 .extout = extout, 01653 }; 01654 01655 if (!park_exten || !park_context) { 01656 return park_call_full(park_me, parker, &args); 01657 } 01658 01659 /* 01660 * Determiine if the specified park extension has an exclusive 01661 * parking lot to use. 01662 */ 01663 if (parker && parker != park_me) { 01664 ast_autoservice_start(park_me); 01665 } 01666 exten = get_parking_exten(park_exten, parker, park_context); 01667 if (exten) { 01668 app_data = ast_get_extension_app_data(exten); 01669 if (!app_data) { 01670 app_data = ""; 01671 } 01672 parse = ast_strdupa(app_data); 01673 AST_STANDARD_APP_ARGS(app_args, parse); 01674 01675 if (!ast_strlen_zero(app_args.pl_name)) { 01676 /* Find the specified exclusive parking lot */ 01677 args.parkinglot = find_parkinglot(app_args.pl_name); 01678 if (!args.parkinglot && parkeddynamic) { 01679 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01680 } 01681 } 01682 } 01683 if (parker && parker != park_me) { 01684 ast_autoservice_stop(park_me); 01685 } 01686 01687 res = park_call_full(park_me, parker, &args); 01688 if (args.parkinglot) { 01689 parkinglot_unref(args.parkinglot); 01690 } 01691 return res; 01692 }
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.
0 | if extension does not exist | |
1 | if extension does exist |
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. |
< Potential pickup target
Definition at line 7292 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, ast_channel::name, pbx_builtin_setvar_helper(), pickupfailsound, and pickupsound.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), mgcp_ss(), and sip_pickup_thread().
07293 { 07294 struct ast_channel *target;/*!< Potential pickup target */ 07295 int res = -1; 07296 ast_debug(1, "pickup attempt by %s\n", chan->name); 07297 07298 /* The found channel is already locked. */ 07299 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07300 if (target) { 07301 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name); 07302 07303 res = ast_do_pickup(chan, target); 07304 ast_channel_unlock(target); 07305 if (!res) { 07306 if (!ast_strlen_zero(pickupsound)) { 07307 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07308 } 07309 } else { 07310 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name); 07311 } 07312 target = ast_channel_unref(target); 07313 } 07314 07315 if (res < 0) { 07316 ast_debug(1, "No call pickup possible... for %s\n", chan->name); 07317 if (!ast_strlen_zero(pickupfailsound)) { 07318 ast_answer(chan); 07319 ast_stream_and_wait(chan, pickupfailsound, ""); 07320 } 07321 } 07322 07323 return res; 07324 }
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 3123 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
03124 { 03125 ast_rwlock_rdlock(&features_lock); 03126 }
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 2967 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, feature_group_exten::feature, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
Referenced by process_applicationmap_line().
02968 { 02969 if (!feature) { 02970 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02971 return; 02972 } 02973 02974 AST_RWLIST_WRLOCK(&feature_list); 02975 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 02976 AST_RWLIST_UNLOCK(&feature_list); 02977 02978 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 02979 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 3128 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
03129 { 03130 ast_rwlock_unlock(&features_lock); 03131 }
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 3047 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
03048 { 03049 if (!feature) { 03050 return; 03051 } 03052 03053 AST_RWLIST_WRLOCK(&feature_list); 03054 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 03055 AST_RWLIST_UNLOCK(&feature_list); 03056 03057 ast_free(feature); 03058 }