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