#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 3826 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_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().
03827 { 03828 /* Copy voice back and forth between the two channels. Give the peer 03829 the ability to transfer calls with '#<extension' syntax. */ 03830 struct ast_frame *f; 03831 struct ast_channel *who; 03832 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03833 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03834 char orig_channame[AST_CHANNEL_NAME]; 03835 char orig_peername[AST_CHANNEL_NAME]; 03836 int res; 03837 int diff; 03838 int hasfeatures=0; 03839 int hadfeatures=0; 03840 int autoloopflag; 03841 int sendingdtmfdigit = 0; 03842 int we_disabled_peer_cdr = 0; 03843 struct ast_option_header *aoh; 03844 struct ast_cdr *bridge_cdr = NULL; 03845 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03846 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03847 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03848 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03849 struct ast_silence_generator *silgen = NULL; 03850 const char *h_context; 03851 03852 if (chan && peer) { 03853 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03854 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03855 } else if (chan) { 03856 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03857 } 03858 03859 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03860 add_features_datastores(chan, peer, config); 03861 03862 /* This is an interesting case. One example is if a ringing channel gets redirected to 03863 * an extension that picks up a parked call. This will make sure that the call taken 03864 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03865 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03866 ast_indicate(peer, AST_CONTROL_RINGING); 03867 } 03868 03869 if (monitor_ok) { 03870 const char *monitor_exec; 03871 struct ast_channel *src = NULL; 03872 if (!monitor_app) { 03873 if (!(monitor_app = pbx_findapp("Monitor"))) 03874 monitor_ok=0; 03875 } 03876 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03877 src = chan; 03878 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03879 src = peer; 03880 if (monitor_app && src) { 03881 char *tmp = ast_strdupa(monitor_exec); 03882 pbx_exec(src, monitor_app, tmp); 03883 } 03884 } 03885 03886 set_config_flags(chan, peer, config); 03887 03888 /* Answer if need be */ 03889 if (chan->_state != AST_STATE_UP) { 03890 if (ast_raw_answer(chan, 1)) { 03891 return -1; 03892 } 03893 } 03894 03895 #ifdef FOR_DEBUG 03896 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 03897 ast_channel_log("Pre-bridge CHAN Channel info", chan); 03898 ast_channel_log("Pre-bridge PEER Channel info", peer); 03899 #endif 03900 /* two channels are being marked as linked here */ 03901 ast_channel_set_linkgroup(chan,peer); 03902 03903 /* copy the userfield from the B-leg to A-leg if applicable */ 03904 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 03905 char tmp[256]; 03906 03907 ast_channel_lock(chan); 03908 if (!ast_strlen_zero(chan->cdr->userfield)) { 03909 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 03910 ast_cdr_appenduserfield(chan, tmp); 03911 } else { 03912 ast_cdr_setuserfield(chan, peer->cdr->userfield); 03913 } 03914 ast_channel_unlock(chan); 03915 /* Don't delete the CDR; just disable it. */ 03916 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03917 we_disabled_peer_cdr = 1; 03918 } 03919 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 03920 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 03921 03922 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 03923 ast_channel_lock_both(chan, peer); 03924 if (chan_cdr) { 03925 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 03926 ast_cdr_update(chan); 03927 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 03928 /* rip any forked CDR's off of the chan_cdr and attach 03929 * them to the bridge_cdr instead */ 03930 bridge_cdr->next = chan_cdr->next; 03931 chan_cdr->next = NULL; 03932 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03933 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03934 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 03935 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03936 } 03937 ast_cdr_setaccount(peer, chan->accountcode); 03938 } else { 03939 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 03940 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 03941 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 03942 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 03943 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 03944 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03945 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03946 ast_cdr_setcid(bridge_cdr, chan); 03947 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 03948 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 03949 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 03950 /* Destination information */ 03951 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 03952 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 03953 if (peer_cdr) { 03954 bridge_cdr->start = peer_cdr->start; 03955 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03956 } else { 03957 ast_cdr_start(bridge_cdr); 03958 } 03959 } 03960 ast_channel_unlock(chan); 03961 ast_channel_unlock(peer); 03962 03963 ast_debug(4,"bridge answer set, chan answer set\n"); 03964 /* peer_cdr->answer will be set when a macro runs on the peer; 03965 in that case, the bridge answer will be delayed while the 03966 macro plays on the peer channel. The peer answered the call 03967 before the macro started playing. To the phone system, 03968 this is billable time for the call, even tho the caller 03969 hears nothing but ringing while the macro does its thing. */ 03970 03971 /* Another case where the peer cdr's time will be set, is when 03972 A self-parks by pickup up phone and dialing 700, then B 03973 picks up A by dialing its parking slot; there may be more 03974 practical paths that get the same result, tho... in which 03975 case you get the previous answer time from the Park... which 03976 is before the bridge's start time, so I added in the 03977 tvcmp check to the if below */ 03978 03979 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 03980 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 03981 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 03982 if (chan_cdr) { 03983 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 03984 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 03985 } 03986 } else { 03987 ast_cdr_answer(bridge_cdr); 03988 if (chan_cdr) { 03989 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 03990 } 03991 } 03992 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 03993 if (chan_cdr) { 03994 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 03995 } 03996 if (peer_cdr) { 03997 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 03998 } 03999 } 04000 /* the DIALED flag may be set if a dialed channel is transfered 04001 * and then bridged to another channel. In order for the 04002 * bridge CDR to be written, the DIALED flag must not be 04003 * present. */ 04004 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04005 } 04006 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04007 04008 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04009 * a call is being bridged, that the humans in charge know what they're doing. If they 04010 * don't, well, what can we do about that? */ 04011 clear_dialed_interfaces(chan); 04012 clear_dialed_interfaces(peer); 04013 04014 for (;;) { 04015 struct ast_channel *other; /* used later */ 04016 04017 res = ast_channel_bridge(chan, peer, config, &f, &who); 04018 04019 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04020 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04021 /* Zombies are present time to leave! */ 04022 res = -1; 04023 if (f) { 04024 ast_frfree(f); 04025 } 04026 goto before_you_go; 04027 } 04028 04029 /* When frame is not set, we are probably involved in a situation 04030 where we've timed out. 04031 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04032 and also for DTMF_END. If we flow into the following 'if' for both, then 04033 our wait times are cut in half, as both will subtract from the 04034 feature_timer. Not good! 04035 */ 04036 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04037 /* Update feature timer for next pass */ 04038 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04039 if (res == AST_BRIDGE_RETRY) { 04040 /* The feature fully timed out but has not been updated. Skip 04041 * the potential round error from the diff calculation and 04042 * explicitly set to expired. */ 04043 config->feature_timer = -1; 04044 } else { 04045 config->feature_timer -= diff; 04046 } 04047 04048 if (hasfeatures) { 04049 if (config->feature_timer <= 0) { 04050 /* Not *really* out of time, just out of time for 04051 digits to come in for features. */ 04052 ast_debug(1, "Timed out for feature!\n"); 04053 if (!ast_strlen_zero(peer_featurecode)) { 04054 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 04055 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04056 } 04057 if (!ast_strlen_zero(chan_featurecode)) { 04058 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 04059 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04060 } 04061 if (f) 04062 ast_frfree(f); 04063 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04064 if (!hasfeatures) { 04065 /* No more digits expected - reset the timer */ 04066 config->feature_timer = 0; 04067 } 04068 hadfeatures = hasfeatures; 04069 /* Continue as we were */ 04070 continue; 04071 } else if (!f) { 04072 /* The bridge returned without a frame and there is a feature in progress. 04073 * However, we don't think the feature has quite yet timed out, so just 04074 * go back into the bridge. */ 04075 continue; 04076 } 04077 } else { 04078 if (config->feature_timer <=0) { 04079 /* We ran out of time */ 04080 config->feature_timer = 0; 04081 who = chan; 04082 if (f) 04083 ast_frfree(f); 04084 f = NULL; 04085 res = 0; 04086 } 04087 } 04088 } 04089 if (res < 0) { 04090 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04091 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 04092 } 04093 goto before_you_go; 04094 } 04095 04096 if (!f || (f->frametype == AST_FRAME_CONTROL && 04097 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04098 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04099 /* 04100 * If the bridge was broken for a hangup that isn't real, 04101 * then don't run the h extension, because the channel isn't 04102 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04103 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04104 */ 04105 ast_channel_lock(chan); 04106 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04107 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 04108 } 04109 ast_channel_unlock(chan); 04110 res = -1; 04111 break; 04112 } 04113 /* many things should be sent to the 'other' channel */ 04114 other = (who == chan) ? peer : chan; 04115 if (f->frametype == AST_FRAME_CONTROL) { 04116 switch (f->subclass.integer) { 04117 case AST_CONTROL_RINGING: 04118 case AST_CONTROL_FLASH: 04119 case -1: 04120 ast_indicate(other, f->subclass.integer); 04121 break; 04122 case AST_CONTROL_CONNECTED_LINE: 04123 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04124 break; 04125 } 04126 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04127 break; 04128 case AST_CONTROL_REDIRECTING: 04129 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04130 break; 04131 } 04132 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04133 break; 04134 case AST_CONTROL_AOC: 04135 case AST_CONTROL_HOLD: 04136 case AST_CONTROL_UNHOLD: 04137 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04138 break; 04139 case AST_CONTROL_OPTION: 04140 aoh = f->data.ptr; 04141 /* Forward option Requests, but only ones we know are safe 04142 * These are ONLY sent by chan_iax2 and I'm not convinced that 04143 * they are useful. I haven't deleted them entirely because I 04144 * just am not sure of the ramifications of removing them. */ 04145 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04146 switch (ntohs(aoh->option)) { 04147 case AST_OPTION_TONE_VERIFY: 04148 case AST_OPTION_TDD: 04149 case AST_OPTION_RELAXDTMF: 04150 case AST_OPTION_AUDIO_MODE: 04151 case AST_OPTION_DIGIT_DETECT: 04152 case AST_OPTION_FAX_DETECT: 04153 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04154 f->datalen - sizeof(struct ast_option_header), 0); 04155 } 04156 } 04157 break; 04158 } 04159 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04160 struct ast_flags *cfg; 04161 char dtmfcode[2] = { f->subclass.integer, }; 04162 size_t featurelen; 04163 04164 if (who == chan) { 04165 featurelen = strlen(chan_featurecode); 04166 cfg = &(config->features_caller); 04167 } else { 04168 featurelen = strlen(peer_featurecode); 04169 cfg = &(config->features_callee); 04170 } 04171 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04172 * DTMF along untouched. If this is not the first digit of a multi-digit code 04173 * then we need to fall through and stream the characters if it matches */ 04174 if (featurelen == 0 04175 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04176 if (option_debug > 3) { 04177 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04178 } 04179 ast_write(other, f); 04180 sendingdtmfdigit = 1; 04181 } else { 04182 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04183 * transmitting something while we hold on to the DTMF waiting for a 04184 * feature. */ 04185 if (!silgen && ast_opt_transmit_silence) { 04186 silgen = ast_channel_start_silence_generator(other); 04187 } 04188 if (option_debug > 3) { 04189 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04190 } 04191 } 04192 } else if (f->frametype == AST_FRAME_DTMF_END) { 04193 char *featurecode; 04194 int sense; 04195 04196 hadfeatures = hasfeatures; 04197 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04198 if (who == chan) { 04199 sense = FEATURE_SENSE_CHAN; 04200 featurecode = chan_featurecode; 04201 } else { 04202 sense = FEATURE_SENSE_PEER; 04203 featurecode = peer_featurecode; 04204 } 04205 04206 if (sendingdtmfdigit == 1) { 04207 /* We let the BEGIN go through happily, so let's not bother with the END, 04208 * since we already know it's not something we bother with */ 04209 ast_write(other, f); 04210 sendingdtmfdigit = 0; 04211 } else { 04212 /*! append the event to featurecode. we rely on the string being zero-filled, and 04213 * not overflowing it. 04214 * \todo XXX how do we guarantee the latter ? 04215 */ 04216 featurecode[strlen(featurecode)] = f->subclass.integer; 04217 /* Get rid of the frame before we start doing "stuff" with the channels */ 04218 ast_frfree(f); 04219 f = NULL; 04220 if (silgen) { 04221 ast_channel_stop_silence_generator(other, silgen); 04222 silgen = NULL; 04223 } 04224 config->feature_timer = 0; 04225 res = feature_interpret(chan, peer, config, featurecode, sense); 04226 switch(res) { 04227 case AST_FEATURE_RETURN_PASSDIGITS: 04228 ast_dtmf_stream(other, who, featurecode, 0, 0); 04229 /* Fall through */ 04230 case AST_FEATURE_RETURN_SUCCESS: 04231 memset(featurecode, 0, sizeof(chan_featurecode)); 04232 break; 04233 } 04234 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04235 res = 0; 04236 } else { 04237 break; 04238 } 04239 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04240 if (hadfeatures && !hasfeatures) { 04241 /* Feature completed or timed out */ 04242 config->feature_timer = 0; 04243 } else if (hasfeatures) { 04244 if (config->timelimit) { 04245 /* No warning next time - we are waiting for feature code */ 04246 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04247 } 04248 config->feature_start_time = ast_tvnow(); 04249 config->feature_timer = featuredigittimeout; 04250 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04251 } 04252 } 04253 } 04254 if (f) 04255 ast_frfree(f); 04256 } 04257 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04258 04259 before_you_go: 04260 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04261 if (silgen) { 04262 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04263 silgen = NULL; 04264 } 04265 04266 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04267 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04268 if (bridge_cdr) { 04269 ast_cdr_discard(bridge_cdr); 04270 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04271 } 04272 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04273 } 04274 04275 if (config->end_bridge_callback) { 04276 config->end_bridge_callback(config->end_bridge_callback_data); 04277 } 04278 04279 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04280 * if it were, then chan belongs to a different thread now, and might have been hung up long 04281 * ago. 04282 */ 04283 if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04284 h_context = NULL; 04285 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04286 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04287 h_context = chan->context; 04288 } else if (!ast_strlen_zero(chan->macrocontext) 04289 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04290 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04291 h_context = chan->macrocontext; 04292 } else { 04293 h_context = NULL; 04294 } 04295 if (h_context) { 04296 struct ast_cdr *swapper = NULL; 04297 char savelastapp[AST_MAX_EXTENSION]; 04298 char savelastdata[AST_MAX_EXTENSION]; 04299 char save_context[AST_MAX_CONTEXT]; 04300 char save_exten[AST_MAX_EXTENSION]; 04301 int save_prio; 04302 int found = 0; /* set if we find at least one match */ 04303 int spawn_error = 0; 04304 04305 /* 04306 * Make sure that the channel is marked as hungup since we are 04307 * going to run the "h" exten on it. 04308 */ 04309 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04310 04311 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04312 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04313 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04314 ast_cdr_end(bridge_cdr); 04315 } 04316 04317 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04318 dialplan code operate on it */ 04319 ast_channel_lock(chan); 04320 if (bridge_cdr) { 04321 swapper = chan->cdr; 04322 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04323 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04324 chan->cdr = bridge_cdr; 04325 } 04326 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04327 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04328 save_prio = chan->priority; 04329 if (h_context != chan->context) { 04330 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04331 } 04332 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04333 chan->priority = 1; 04334 ast_channel_unlock(chan); 04335 04336 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04337 chan->priority, 04338 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04339 &found, 1)) == 0) { 04340 chan->priority++; 04341 } 04342 if (found && spawn_error) { 04343 /* Something bad happened, or a hangup has been requested. */ 04344 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04345 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 04346 } 04347 04348 /* swap it back */ 04349 ast_channel_lock(chan); 04350 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04351 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04352 chan->priority = save_prio; 04353 if (bridge_cdr) { 04354 if (chan->cdr == bridge_cdr) { 04355 chan->cdr = swapper; 04356 } else { 04357 bridge_cdr = NULL; 04358 } 04359 } 04360 /* An "h" exten has been run, so indicate that one has been run. */ 04361 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04362 ast_channel_unlock(chan); 04363 04364 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04365 if (bridge_cdr) { 04366 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04367 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04368 } 04369 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04370 } 04371 04372 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04373 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04374 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 04375 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04376 04377 /* we can post the bridge CDR at this point */ 04378 if (bridge_cdr) { 04379 ast_cdr_end(bridge_cdr); 04380 ast_cdr_detach(bridge_cdr); 04381 } 04382 04383 /* do a specialized reset on the beginning channel 04384 CDR's, if they still exist, so as not to mess up 04385 issues in future bridges; 04386 04387 Here are the rules of the game: 04388 1. The chan and peer channel pointers will not change 04389 during the life of the bridge. 04390 2. But, in transfers, the channel names will change. 04391 between the time the bridge is started, and the 04392 time the channel ends. 04393 Usually, when a channel changes names, it will 04394 also change CDR pointers. 04395 3. Usually, only one of the two channels (chan or peer) 04396 will change names. 04397 4. Usually, if a channel changes names during a bridge, 04398 it is because of a transfer. Usually, in these situations, 04399 it is normal to see 2 bridges running simultaneously, and 04400 it is not unusual to see the two channels that change 04401 swapped between bridges. 04402 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04403 to attend to; if the chan or peer changed names, 04404 we have the before and after attached CDR's. 04405 */ 04406 04407 if (new_chan_cdr) { 04408 struct ast_channel *chan_ptr = NULL; 04409 04410 if (strcasecmp(orig_channame, chan->name) != 0) { 04411 /* old channel */ 04412 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04413 ast_channel_lock(chan_ptr); 04414 if (!ast_bridged_channel(chan_ptr)) { 04415 struct ast_cdr *cur; 04416 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04417 if (cur == chan_cdr) { 04418 break; 04419 } 04420 } 04421 if (cur) { 04422 ast_cdr_specialized_reset(chan_cdr, 0); 04423 } 04424 } 04425 ast_channel_unlock(chan_ptr); 04426 chan_ptr = ast_channel_unref(chan_ptr); 04427 } 04428 /* new channel */ 04429 ast_cdr_specialized_reset(new_chan_cdr, 0); 04430 } else { 04431 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04432 } 04433 } 04434 04435 { 04436 struct ast_channel *chan_ptr = NULL; 04437 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04438 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)) 04439 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04440 if (strcasecmp(orig_peername, peer->name) != 0) { 04441 /* old channel */ 04442 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04443 ast_channel_lock(chan_ptr); 04444 if (!ast_bridged_channel(chan_ptr)) { 04445 struct ast_cdr *cur; 04446 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04447 if (cur == peer_cdr) { 04448 break; 04449 } 04450 } 04451 if (cur) { 04452 ast_cdr_specialized_reset(peer_cdr, 0); 04453 } 04454 } 04455 ast_channel_unlock(chan_ptr); 04456 chan_ptr = ast_channel_unref(chan_ptr); 04457 } 04458 /* new channel */ 04459 if (new_peer_cdr) { 04460 ast_cdr_specialized_reset(new_peer_cdr, 0); 04461 } 04462 } else { 04463 if (we_disabled_peer_cdr) { 04464 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04465 } 04466 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04467 } 04468 } 04469 04470 return res; 04471 }
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 7327 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().
07329 { 07330 char *stringp = ast_strdupa(parse); 07331 char *limit_str, *warning_str, *warnfreq_str; 07332 const char *var; 07333 int play_to_caller = 0, play_to_callee = 0; 07334 int delta; 07335 07336 limit_str = strsep(&stringp, ":"); 07337 warning_str = strsep(&stringp, ":"); 07338 warnfreq_str = strsep(&stringp, ":"); 07339 07340 config->timelimit = atol(limit_str); 07341 if (warning_str) 07342 config->play_warning = atol(warning_str); 07343 if (warnfreq_str) 07344 config->warning_freq = atol(warnfreq_str); 07345 07346 if (!config->timelimit) { 07347 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07348 config->timelimit = config->play_warning = config->warning_freq = 0; 07349 config->warning_sound = NULL; 07350 return -1; /* error */ 07351 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07352 int w = config->warning_freq; 07353 07354 /* 07355 * If the first warning is requested _after_ the entire call 07356 * would end, and no warning frequency is requested, then turn 07357 * off the warning. If a warning frequency is requested, reduce 07358 * the 'first warning' time by that frequency until it falls 07359 * within the call's total time limit. 07360 * 07361 * Graphically: 07362 * timelim->| delta |<-playwarning 07363 * 0__________________|_________________| 07364 * | w | | | | 07365 * 07366 * so the number of intervals to cut is 1+(delta-1)/w 07367 */ 07368 if (w == 0) { 07369 config->play_warning = 0; 07370 } else { 07371 config->play_warning -= w * ( 1 + (delta-1)/w ); 07372 if (config->play_warning < 1) 07373 config->play_warning = config->warning_freq = 0; 07374 } 07375 } 07376 07377 ast_channel_lock(chan); 07378 07379 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07380 play_to_caller = var ? ast_true(var) : 1; 07381 07382 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07383 play_to_callee = var ? ast_true(var) : 0; 07384 07385 if (!play_to_caller && !play_to_callee) 07386 play_to_caller = 1; 07387 07388 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07389 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07390 07391 /* The code looking at config wants a NULL, not just "", to decide 07392 * that the message should not be played, so we replace "" with NULL. 07393 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07394 * not found. 07395 */ 07396 07397 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07398 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07399 07400 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07401 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07402 07403 ast_channel_unlock(chan); 07404 07405 /* undo effect of S(x) in case they are both used */ 07406 calldurationlimit->tv_sec = 0; 07407 calldurationlimit->tv_usec = 0; 07408 07409 /* more efficient to do it like S(x) does since no advanced opts */ 07410 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07411 calldurationlimit->tv_sec = config->timelimit / 1000; 07412 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07413 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07414 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07415 config->timelimit = play_to_caller = play_to_callee = 07416 config->play_warning = config->warning_freq = 0; 07417 } else { 07418 ast_verb(4, "Limit Data for this call:\n"); 07419 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07420 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07421 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07422 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07423 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07424 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07425 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07426 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07427 } 07428 if (play_to_caller) 07429 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07430 if (play_to_callee) 07431 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07432 return 0; 07433 }
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 7134 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().
07135 { 07136 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07137 && (chan->_state == AST_STATE_RINGING 07138 || chan->_state == AST_STATE_RING 07139 /* 07140 * Check the down state as well because some SIP devices do not 07141 * give 180 ringing when they can just give 183 session progress 07142 * instead. Issue 14005. (Some ISDN switches as well for that 07143 * matter.) 07144 */ 07145 || chan->_state == AST_STATE_DOWN) 07146 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07147 return 1; 07148 } 07149 return 0; 07150 }
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 7210 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().
07211 { 07212 struct ast_party_connected_line connected_caller; 07213 struct ast_channel *chans[2] = { chan, target }; 07214 struct ast_datastore *ds_pickup; 07215 const char *chan_name;/*!< A masquerade changes channel names. */ 07216 const char *target_name;/*!< A masquerade changes channel names. */ 07217 int res = -1; 07218 07219 target_name = ast_strdupa(target->name); 07220 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, chan->name); 07221 07222 /* Mark the target to block any call pickup race. */ 07223 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07224 if (!ds_pickup) { 07225 ast_log(LOG_WARNING, 07226 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07227 return -1; 07228 } 07229 ast_channel_datastore_add(target, ds_pickup); 07230 07231 ast_party_connected_line_init(&connected_caller); 07232 ast_party_connected_line_copy(&connected_caller, &target->connected); 07233 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07234 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07235 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07236 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07237 } 07238 ast_party_connected_line_free(&connected_caller); 07239 07240 ast_channel_lock(chan); 07241 chan_name = ast_strdupa(chan->name); 07242 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07243 ast_channel_unlock(chan); 07244 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07245 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07246 ast_party_connected_line_free(&connected_caller); 07247 07248 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07249 07250 if (ast_answer(chan)) { 07251 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07252 goto pickup_failed; 07253 } 07254 07255 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07256 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07257 goto pickup_failed; 07258 } 07259 07260 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07261 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07262 07263 if (ast_channel_masquerade(target, chan)) { 07264 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07265 target_name); 07266 goto pickup_failed; 07267 } 07268 07269 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07270 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07271 "Channel: %s\r\n" 07272 "TargetChannel: %s\r\n", 07273 chan_name, target_name); 07274 07275 /* Do the masquerade manually to make sure that it is completed. */ 07276 ast_do_masquerade(target); 07277 res = 0; 07278 07279 pickup_failed: 07280 ast_channel_lock(target); 07281 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07282 ast_datastore_free(ds_pickup); 07283 } 07284 07285 return res; 07286 }
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 3277 of file features.c.
References feature_group_exten::feature, FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03277 { 03278 03279 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03280 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6696 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().
06697 { 06698 struct ast_context *con; 06699 int res; 06700 06701 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06702 06703 /* 06704 * Always destroy the parking_con_dial context to remove buildup 06705 * of recalled extensions in the context. At worst, the parked 06706 * call gets hungup attempting to run an invalid extension when 06707 * we are trying to callback the parker or the preset return 06708 * extension. This is a small window of opportunity on an 06709 * execution chain that is not expected to happen very often. 06710 */ 06711 con = ast_context_find(parking_con_dial); 06712 if (con) { 06713 ast_context_destroy(con, registrar); 06714 } 06715 06716 res = load_config(1); 06717 ast_mutex_unlock(&features_reload_lock); 06718 06719 return res; 06720 }
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 3011 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
03012 { 03013 int x; 03014 for (x = 0; x < FEATURES_COUNT; x++) { 03015 if (!strcasecmp(name, builtin_features[x].sname)) 03016 return &builtin_features[x]; 03017 } 03018 return NULL; 03019 }
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 1756 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(), parkandannounce_exec(), and rpt_exec().
01757 { 01758 struct ast_park_call_args args = { 01759 .timeout = timeout, 01760 .extout = extout, 01761 }; 01762 01763 if (peer) { 01764 args.orig_chan_name = ast_strdupa(peer->name); 01765 } 01766 return masq_park_call(rchan, peer, &args); 01767 }
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 1702 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().
01703 { 01704 int res; 01705 char *parse; 01706 const char *app_data; 01707 struct ast_exten *exten; 01708 struct park_app_args app_args; 01709 struct ast_park_call_args args = { 01710 .timeout = timeout, 01711 .extout = extout, 01712 }; 01713 01714 if (parker) { 01715 args.orig_chan_name = ast_strdupa(parker->name); 01716 } 01717 if (!park_exten || !park_context) { 01718 return masq_park_call(park_me, parker, &args); 01719 } 01720 01721 /* 01722 * Determiine if the specified park extension has an exclusive 01723 * parking lot to use. 01724 */ 01725 if (parker && parker != park_me) { 01726 ast_autoservice_start(park_me); 01727 } 01728 exten = get_parking_exten(park_exten, parker, park_context); 01729 if (exten) { 01730 app_data = ast_get_extension_app_data(exten); 01731 if (!app_data) { 01732 app_data = ""; 01733 } 01734 parse = ast_strdupa(app_data); 01735 AST_STANDARD_APP_ARGS(app_args, parse); 01736 01737 if (!ast_strlen_zero(app_args.pl_name)) { 01738 /* Find the specified exclusive parking lot */ 01739 args.parkinglot = find_parkinglot(app_args.pl_name); 01740 if (!args.parkinglot && parkeddynamic) { 01741 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01742 } 01743 } 01744 } 01745 if (parker && parker != park_me) { 01746 ast_autoservice_stop(park_me); 01747 } 01748 01749 res = masq_park_call(park_me, parker, &args); 01750 if (args.parkinglot) { 01751 parkinglot_unref(args.parkinglot); 01752 } 01753 return res; 01754 }
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 1605 of file features.c.
References args, and park_call_full().
01606 { 01607 struct ast_park_call_args args = { 01608 .timeout = timeout, 01609 .extout = extout, 01610 }; 01611 01612 return park_call_full(park_me, parker, &args); 01613 }
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 1554 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().
01555 { 01556 int res; 01557 char *parse; 01558 const char *app_data; 01559 struct ast_exten *exten; 01560 struct park_app_args app_args; 01561 struct ast_park_call_args args = { 01562 .timeout = timeout, 01563 .extout = extout, 01564 }; 01565 01566 if (!park_exten || !park_context) { 01567 return park_call_full(park_me, parker, &args); 01568 } 01569 01570 /* 01571 * Determiine if the specified park extension has an exclusive 01572 * parking lot to use. 01573 */ 01574 if (parker && parker != park_me) { 01575 ast_autoservice_start(park_me); 01576 } 01577 exten = get_parking_exten(park_exten, parker, park_context); 01578 if (exten) { 01579 app_data = ast_get_extension_app_data(exten); 01580 if (!app_data) { 01581 app_data = ""; 01582 } 01583 parse = ast_strdupa(app_data); 01584 AST_STANDARD_APP_ARGS(app_args, parse); 01585 01586 if (!ast_strlen_zero(app_args.pl_name)) { 01587 /* Find the specified exclusive parking lot */ 01588 args.parkinglot = find_parkinglot(app_args.pl_name); 01589 if (!args.parkinglot && parkeddynamic) { 01590 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01591 } 01592 } 01593 } 01594 if (parker && parker != park_me) { 01595 ast_autoservice_stop(park_me); 01596 } 01597 01598 res = park_call_full(park_me, parker, &args); 01599 if (args.parkinglot) { 01600 parkinglot_unref(args.parkinglot); 01601 } 01602 return res; 01603 }
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 793 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().
00794 { 00795 return get_parking_exten(exten_str, chan, context) ? 1 : 0; 00796 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
< Potential pickup target
Definition at line 7176 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().
07177 { 07178 struct ast_channel *target;/*!< Potential pickup target */ 07179 int res = -1; 07180 ast_debug(1, "pickup attempt by %s\n", chan->name); 07181 07182 /* The found channel is already locked. */ 07183 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07184 if (target) { 07185 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name); 07186 07187 res = ast_do_pickup(chan, target); 07188 ast_channel_unlock(target); 07189 if (!res) { 07190 if (!ast_strlen_zero(pickupsound)) { 07191 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07192 } 07193 } else { 07194 ast_log(LOG_WARNING, "pickup %s failed by %s\n", target->name, chan->name); 07195 } 07196 target = ast_channel_unref(target); 07197 } 07198 07199 if (res < 0) { 07200 ast_debug(1, "No call pickup possible... for %s\n", chan->name); 07201 if (!ast_strlen_zero(pickupfailsound)) { 07202 ast_answer(chan); 07203 ast_stream_and_wait(chan, pickupfailsound, ""); 07204 } 07205 } 07206 07207 return res; 07208 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 798 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().
00799 { 00800 return pickup_ext; 00801 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 3001 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
03002 { 03003 ast_rwlock_rdlock(&features_lock); 03004 }
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 2845 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().
02846 { 02847 if (!feature) { 02848 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02849 return; 02850 } 02851 02852 AST_RWLIST_WRLOCK(&feature_list); 02853 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 02854 AST_RWLIST_UNLOCK(&feature_list); 02855 02856 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 02857 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 3006 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
03007 { 03008 ast_rwlock_unlock(&features_lock); 03009 }
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 2925 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
02926 { 02927 if (!feature) { 02928 return; 02929 } 02930 02931 AST_RWLIST_WRLOCK(&feature_list); 02932 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 02933 AST_RWLIST_UNLOCK(&feature_list); 02934 02935 ast_free(feature); 02936 }