#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. | |
| 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 | |
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(), gtalk_load_config(), 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.
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 3851 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_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_accountcode(), 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_NAME, ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_uniqueid(), 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_MCID, 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(), 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, ast_frame::len, 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, 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().
03852 { 03853 /* Copy voice back and forth between the two channels. Give the peer 03854 the ability to transfer calls with '#<extension' syntax. */ 03855 struct ast_frame *f; 03856 struct ast_channel *who; 03857 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03858 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03859 char orig_channame[AST_CHANNEL_NAME]; 03860 char orig_peername[AST_CHANNEL_NAME]; 03861 int res; 03862 int diff; 03863 int hasfeatures=0; 03864 int hadfeatures=0; 03865 int autoloopflag; 03866 int sendingdtmfdigit = 0; 03867 int we_disabled_peer_cdr = 0; 03868 struct ast_option_header *aoh; 03869 struct ast_cdr *bridge_cdr = NULL; 03870 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03871 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03872 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03873 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03874 struct ast_silence_generator *silgen = NULL; 03875 const char *h_context; 03876 03877 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer)); 03878 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan)); 03879 03880 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03881 add_features_datastores(chan, peer, config); 03882 03883 /* This is an interesting case. One example is if a ringing channel gets redirected to 03884 * an extension that picks up a parked call. This will make sure that the call taken 03885 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03886 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03887 ast_indicate(peer, AST_CONTROL_RINGING); 03888 } 03889 03890 if (monitor_ok) { 03891 const char *monitor_exec; 03892 struct ast_channel *src = NULL; 03893 if (!monitor_app) { 03894 if (!(monitor_app = pbx_findapp("Monitor"))) 03895 monitor_ok=0; 03896 } 03897 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03898 src = chan; 03899 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03900 src = peer; 03901 if (monitor_app && src) { 03902 char *tmp = ast_strdupa(monitor_exec); 03903 pbx_exec(src, monitor_app, tmp); 03904 } 03905 } 03906 03907 set_config_flags(chan, config); 03908 03909 /* Answer if need be */ 03910 if (chan->_state != AST_STATE_UP) { 03911 if (ast_raw_answer(chan, 1)) { 03912 return -1; 03913 } 03914 } 03915 03916 #ifdef FOR_DEBUG 03917 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 03918 ast_channel_log("Pre-bridge CHAN Channel info", chan); 03919 ast_channel_log("Pre-bridge PEER Channel info", peer); 03920 #endif 03921 /* two channels are being marked as linked here */ 03922 ast_channel_set_linkgroup(chan,peer); 03923 03924 /* copy the userfield from the B-leg to A-leg if applicable */ 03925 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 03926 char tmp[256]; 03927 03928 ast_channel_lock(chan); 03929 if (!ast_strlen_zero(chan->cdr->userfield)) { 03930 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 03931 ast_cdr_appenduserfield(chan, tmp); 03932 } else { 03933 ast_cdr_setuserfield(chan, peer->cdr->userfield); 03934 } 03935 ast_channel_unlock(chan); 03936 /* Don't delete the CDR; just disable it. */ 03937 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03938 we_disabled_peer_cdr = 1; 03939 } 03940 ast_copy_string(orig_channame,ast_channel_name(chan),sizeof(orig_channame)); 03941 ast_copy_string(orig_peername,ast_channel_name(peer),sizeof(orig_peername)); 03942 03943 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 03944 ast_channel_lock_both(chan, peer); 03945 if (chan_cdr) { 03946 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 03947 ast_cdr_update(chan); 03948 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 03949 /* rip any forked CDR's off of the chan_cdr and attach 03950 * them to the bridge_cdr instead */ 03951 bridge_cdr->next = chan_cdr->next; 03952 chan_cdr->next = NULL; 03953 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03954 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03955 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 03956 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03957 } 03958 ast_cdr_setaccount(peer, ast_channel_accountcode(chan)); 03959 } else { 03960 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 03961 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 03962 ast_copy_string(bridge_cdr->channel, ast_channel_name(chan), sizeof(bridge_cdr->channel)); 03963 ast_copy_string(bridge_cdr->dstchannel, ast_channel_name(peer), sizeof(bridge_cdr->dstchannel)); 03964 ast_copy_string(bridge_cdr->uniqueid, ast_channel_uniqueid(chan), sizeof(bridge_cdr->uniqueid)); 03965 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03966 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03967 ast_cdr_setcid(bridge_cdr, chan); 03968 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 03969 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 03970 ast_copy_string(bridge_cdr->accountcode, ast_channel_accountcode(chan), sizeof(bridge_cdr->accountcode)); 03971 /* Destination information */ 03972 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 03973 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 03974 if (peer_cdr) { 03975 bridge_cdr->start = peer_cdr->start; 03976 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03977 } else { 03978 ast_cdr_start(bridge_cdr); 03979 } 03980 } 03981 ast_channel_unlock(chan); 03982 ast_channel_unlock(peer); 03983 03984 ast_debug(4, "bridge answer set, chan answer set\n"); 03985 /* peer_cdr->answer will be set when a macro runs on the peer; 03986 in that case, the bridge answer will be delayed while the 03987 macro plays on the peer channel. The peer answered the call 03988 before the macro started playing. To the phone system, 03989 this is billable time for the call, even tho the caller 03990 hears nothing but ringing while the macro does its thing. */ 03991 03992 /* Another case where the peer cdr's time will be set, is when 03993 A self-parks by pickup up phone and dialing 700, then B 03994 picks up A by dialing its parking slot; there may be more 03995 practical paths that get the same result, tho... in which 03996 case you get the previous answer time from the Park... which 03997 is before the bridge's start time, so I added in the 03998 tvcmp check to the if below */ 03999 04000 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 04001 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 04002 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 04003 if (chan_cdr) { 04004 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 04005 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 04006 } 04007 } else { 04008 ast_cdr_answer(bridge_cdr); 04009 if (chan_cdr) { 04010 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 04011 } 04012 } 04013 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 04014 if (chan_cdr) { 04015 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 04016 } 04017 if (peer_cdr) { 04018 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 04019 } 04020 } 04021 /* the DIALED flag may be set if a dialed channel is transfered 04022 * and then bridged to another channel. In order for the 04023 * bridge CDR to be written, the DIALED flag must not be 04024 * present. */ 04025 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 04026 } 04027 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer); 04028 04029 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 04030 * a call is being bridged, that the humans in charge know what they're doing. If they 04031 * don't, well, what can we do about that? */ 04032 clear_dialed_interfaces(chan); 04033 clear_dialed_interfaces(peer); 04034 04035 for (;;) { 04036 struct ast_channel *other; /* used later */ 04037 04038 res = ast_channel_bridge(chan, peer, config, &f, &who); 04039 04040 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) 04041 || ast_test_flag(peer, AST_FLAG_ZOMBIE)) { 04042 /* Zombies are present time to leave! */ 04043 res = -1; 04044 if (f) { 04045 ast_frfree(f); 04046 } 04047 goto before_you_go; 04048 } 04049 04050 /* When frame is not set, we are probably involved in a situation 04051 where we've timed out. 04052 When frame is set, we'll come this code twice; once for DTMF_BEGIN 04053 and also for DTMF_END. If we flow into the following 'if' for both, then 04054 our wait times are cut in half, as both will subtract from the 04055 feature_timer. Not good! 04056 */ 04057 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 04058 /* Update feature timer for next pass */ 04059 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 04060 if (res == AST_BRIDGE_RETRY) { 04061 /* The feature fully timed out but has not been updated. Skip 04062 * the potential round error from the diff calculation and 04063 * explicitly set to expired. */ 04064 config->feature_timer = -1; 04065 } else { 04066 config->feature_timer -= diff; 04067 } 04068 04069 if (hasfeatures) { 04070 if (config->feature_timer <= 0) { 04071 /* Not *really* out of time, just out of time for 04072 digits to come in for features. */ 04073 ast_debug(1, "Timed out for feature!\n"); 04074 if (!ast_strlen_zero(peer_featurecode)) { 04075 ast_dtmf_stream(chan, peer, peer_featurecode, 0, f ? f->len : 0); 04076 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 04077 } 04078 if (!ast_strlen_zero(chan_featurecode)) { 04079 ast_dtmf_stream(peer, chan, chan_featurecode, 0, f ? f->len : 0); 04080 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 04081 } 04082 if (f) 04083 ast_frfree(f); 04084 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04085 if (!hasfeatures) { 04086 /* No more digits expected - reset the timer */ 04087 config->feature_timer = 0; 04088 } 04089 hadfeatures = hasfeatures; 04090 /* Continue as we were */ 04091 continue; 04092 } else if (!f) { 04093 /* The bridge returned without a frame and there is a feature in progress. 04094 * However, we don't think the feature has quite yet timed out, so just 04095 * go back into the bridge. */ 04096 continue; 04097 } 04098 } else { 04099 if (config->feature_timer <=0) { 04100 /* We ran out of time */ 04101 config->feature_timer = 0; 04102 who = chan; 04103 if (f) 04104 ast_frfree(f); 04105 f = NULL; 04106 res = 0; 04107 } 04108 } 04109 } 04110 if (res < 0) { 04111 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 04112 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", ast_channel_name(chan), ast_channel_name(peer)); 04113 } 04114 goto before_you_go; 04115 } 04116 04117 if (!f || (f->frametype == AST_FRAME_CONTROL && 04118 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 04119 f->subclass.integer == AST_CONTROL_CONGESTION))) { 04120 /* 04121 * If the bridge was broken for a hangup that isn't real, 04122 * then don't run the h extension, because the channel isn't 04123 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO, 04124 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either. 04125 */ 04126 ast_channel_lock(chan); 04127 if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) { 04128 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 04129 } 04130 ast_channel_unlock(chan); 04131 res = -1; 04132 break; 04133 } 04134 /* many things should be sent to the 'other' channel */ 04135 other = (who == chan) ? peer : chan; 04136 if (f->frametype == AST_FRAME_CONTROL) { 04137 switch (f->subclass.integer) { 04138 case AST_CONTROL_RINGING: 04139 case AST_CONTROL_FLASH: 04140 case AST_CONTROL_MCID: 04141 case -1: 04142 ast_indicate(other, f->subclass.integer); 04143 break; 04144 case AST_CONTROL_CONNECTED_LINE: 04145 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 04146 break; 04147 } 04148 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04149 break; 04150 case AST_CONTROL_REDIRECTING: 04151 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 04152 break; 04153 } 04154 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04155 break; 04156 case AST_CONTROL_AOC: 04157 case AST_CONTROL_HOLD: 04158 case AST_CONTROL_UNHOLD: 04159 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 04160 break; 04161 case AST_CONTROL_OPTION: 04162 aoh = f->data.ptr; 04163 /* Forward option Requests, but only ones we know are safe 04164 * These are ONLY sent by chan_iax2 and I'm not convinced that 04165 * they are useful. I haven't deleted them entirely because I 04166 * just am not sure of the ramifications of removing them. */ 04167 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 04168 switch (ntohs(aoh->option)) { 04169 case AST_OPTION_TONE_VERIFY: 04170 case AST_OPTION_TDD: 04171 case AST_OPTION_RELAXDTMF: 04172 case AST_OPTION_AUDIO_MODE: 04173 case AST_OPTION_DIGIT_DETECT: 04174 case AST_OPTION_FAX_DETECT: 04175 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 04176 f->datalen - sizeof(struct ast_option_header), 0); 04177 } 04178 } 04179 break; 04180 } 04181 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 04182 struct ast_flags *cfg; 04183 char dtmfcode[2] = { f->subclass.integer, }; 04184 size_t featurelen; 04185 04186 if (who == chan) { 04187 featurelen = strlen(chan_featurecode); 04188 cfg = &(config->features_caller); 04189 } else { 04190 featurelen = strlen(peer_featurecode); 04191 cfg = &(config->features_callee); 04192 } 04193 /* Take a peek if this (possibly) matches a feature. If not, just pass this 04194 * DTMF along untouched. If this is not the first digit of a multi-digit code 04195 * then we need to fall through and stream the characters if it matches */ 04196 if (featurelen == 0 04197 && feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) { 04198 if (option_debug > 3) { 04199 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 04200 } 04201 ast_write(other, f); 04202 sendingdtmfdigit = 1; 04203 } else { 04204 /* If ast_opt_transmit_silence is set, then we need to make sure we are 04205 * transmitting something while we hold on to the DTMF waiting for a 04206 * feature. */ 04207 if (!silgen && ast_opt_transmit_silence) { 04208 silgen = ast_channel_start_silence_generator(other); 04209 } 04210 if (option_debug > 3) { 04211 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 04212 } 04213 } 04214 } else if (f->frametype == AST_FRAME_DTMF_END) { 04215 char *featurecode; 04216 int sense; 04217 unsigned int dtmfduration = f->len; 04218 04219 hadfeatures = hasfeatures; 04220 /* This cannot overrun because the longest feature is one shorter than our buffer */ 04221 if (who == chan) { 04222 sense = FEATURE_SENSE_CHAN; 04223 featurecode = chan_featurecode; 04224 } else { 04225 sense = FEATURE_SENSE_PEER; 04226 featurecode = peer_featurecode; 04227 } 04228 04229 if (sendingdtmfdigit == 1) { 04230 /* We let the BEGIN go through happily, so let's not bother with the END, 04231 * since we already know it's not something we bother with */ 04232 ast_write(other, f); 04233 sendingdtmfdigit = 0; 04234 } else { 04235 /*! append the event to featurecode. we rely on the string being zero-filled, and 04236 * not overflowing it. 04237 * \todo XXX how do we guarantee the latter ? 04238 */ 04239 featurecode[strlen(featurecode)] = f->subclass.integer; 04240 /* Get rid of the frame before we start doing "stuff" with the channels */ 04241 ast_frfree(f); 04242 f = NULL; 04243 if (silgen) { 04244 ast_channel_stop_silence_generator(other, silgen); 04245 silgen = NULL; 04246 } 04247 config->feature_timer = 0; 04248 res = feature_interpret(chan, peer, config, featurecode, sense); 04249 switch(res) { 04250 case AST_FEATURE_RETURN_PASSDIGITS: 04251 ast_dtmf_stream(other, who, featurecode, 0, dtmfduration); 04252 /* Fall through */ 04253 case AST_FEATURE_RETURN_SUCCESS: 04254 memset(featurecode, 0, sizeof(chan_featurecode)); 04255 break; 04256 } 04257 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 04258 res = 0; 04259 } else { 04260 break; 04261 } 04262 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 04263 if (hadfeatures && !hasfeatures) { 04264 /* Feature completed or timed out */ 04265 config->feature_timer = 0; 04266 } else if (hasfeatures) { 04267 if (config->timelimit) { 04268 /* No warning next time - we are waiting for feature code */ 04269 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 04270 } 04271 config->feature_start_time = ast_tvnow(); 04272 config->feature_timer = featuredigittimeout; 04273 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 04274 } 04275 } 04276 } 04277 if (f) 04278 ast_frfree(f); 04279 } 04280 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer); 04281 04282 before_you_go: 04283 /* Just in case something weird happened and we didn't clean up the silence generator... */ 04284 if (silgen) { 04285 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 04286 silgen = NULL; 04287 } 04288 04289 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 04290 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 04291 if (bridge_cdr) { 04292 ast_cdr_discard(bridge_cdr); 04293 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 04294 } 04295 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 04296 } 04297 04298 if (config->end_bridge_callback) { 04299 config->end_bridge_callback(config->end_bridge_callback_data); 04300 } 04301 04302 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 04303 * if it were, then chan belongs to a different thread now, and might have been hung up long 04304 * ago. 04305 */ 04306 if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) { 04307 h_context = NULL; 04308 } else if (ast_exists_extension(chan, chan->context, "h", 1, 04309 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04310 h_context = chan->context; 04311 } else if (!ast_strlen_zero(chan->macrocontext) 04312 && ast_exists_extension(chan, chan->macrocontext, "h", 1, 04313 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 04314 h_context = chan->macrocontext; 04315 } else { 04316 h_context = NULL; 04317 } 04318 if (h_context) { 04319 struct ast_cdr *swapper = NULL; 04320 char savelastapp[AST_MAX_EXTENSION]; 04321 char savelastdata[AST_MAX_EXTENSION]; 04322 char save_context[AST_MAX_CONTEXT]; 04323 char save_exten[AST_MAX_EXTENSION]; 04324 int save_prio; 04325 int found = 0; /* set if we find at least one match */ 04326 int spawn_error = 0; 04327 04328 /* 04329 * Make sure that the channel is marked as hungup since we are 04330 * going to run the "h" exten on it. 04331 */ 04332 ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD); 04333 04334 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 04335 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 04336 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 04337 ast_cdr_end(bridge_cdr); 04338 } 04339 04340 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 04341 dialplan code operate on it */ 04342 ast_channel_lock(chan); 04343 if (bridge_cdr) { 04344 swapper = chan->cdr; 04345 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 04346 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 04347 chan->cdr = bridge_cdr; 04348 } 04349 ast_copy_string(save_context, chan->context, sizeof(save_context)); 04350 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 04351 save_prio = chan->priority; 04352 if (h_context != chan->context) { 04353 ast_copy_string(chan->context, h_context, sizeof(chan->context)); 04354 } 04355 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 04356 chan->priority = 1; 04357 ast_channel_unlock(chan); 04358 04359 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 04360 chan->priority, 04361 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 04362 &found, 1)) == 0) { 04363 chan->priority++; 04364 } 04365 if (found && spawn_error) { 04366 /* Something bad happened, or a hangup has been requested. */ 04367 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, ast_channel_name(chan)); 04368 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, ast_channel_name(chan)); 04369 } 04370 04371 /* swap it back */ 04372 ast_channel_lock(chan); 04373 ast_copy_string(chan->context, save_context, sizeof(chan->context)); 04374 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 04375 chan->priority = save_prio; 04376 if (bridge_cdr) { 04377 if (chan->cdr == bridge_cdr) { 04378 chan->cdr = swapper; 04379 } else { 04380 bridge_cdr = NULL; 04381 } 04382 } 04383 /* An "h" exten has been run, so indicate that one has been run. */ 04384 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 04385 ast_channel_unlock(chan); 04386 04387 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 04388 if (bridge_cdr) { 04389 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 04390 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 04391 } 04392 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 04393 } 04394 04395 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 04396 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 04397 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 04398 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 04399 04400 /* we can post the bridge CDR at this point */ 04401 if (bridge_cdr) { 04402 ast_cdr_end(bridge_cdr); 04403 ast_cdr_detach(bridge_cdr); 04404 } 04405 04406 /* do a specialized reset on the beginning channel 04407 CDR's, if they still exist, so as not to mess up 04408 issues in future bridges; 04409 04410 Here are the rules of the game: 04411 1. The chan and peer channel pointers will not change 04412 during the life of the bridge. 04413 2. But, in transfers, the channel names will change. 04414 between the time the bridge is started, and the 04415 time the channel ends. 04416 Usually, when a channel changes names, it will 04417 also change CDR pointers. 04418 3. Usually, only one of the two channels (chan or peer) 04419 will change names. 04420 4. Usually, if a channel changes names during a bridge, 04421 it is because of a transfer. Usually, in these situations, 04422 it is normal to see 2 bridges running simultaneously, and 04423 it is not unusual to see the two channels that change 04424 swapped between bridges. 04425 5. After a bridge occurs, we have 2 or 3 channels' CDRs 04426 to attend to; if the chan or peer changed names, 04427 we have the before and after attached CDR's. 04428 */ 04429 04430 if (new_chan_cdr) { 04431 struct ast_channel *chan_ptr = NULL; 04432 04433 if (strcasecmp(orig_channame, ast_channel_name(chan)) != 0) { 04434 /* old channel */ 04435 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 04436 ast_channel_lock(chan_ptr); 04437 if (!ast_bridged_channel(chan_ptr)) { 04438 struct ast_cdr *cur; 04439 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04440 if (cur == chan_cdr) { 04441 break; 04442 } 04443 } 04444 if (cur) { 04445 ast_cdr_specialized_reset(chan_cdr, 0); 04446 } 04447 } 04448 ast_channel_unlock(chan_ptr); 04449 chan_ptr = ast_channel_unref(chan_ptr); 04450 } 04451 /* new channel */ 04452 ast_cdr_specialized_reset(new_chan_cdr, 0); 04453 } else { 04454 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 04455 } 04456 } 04457 04458 { 04459 struct ast_channel *chan_ptr = NULL; 04460 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 04461 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)) 04462 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 04463 if (strcasecmp(orig_peername, ast_channel_name(peer)) != 0) { 04464 /* old channel */ 04465 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 04466 ast_channel_lock(chan_ptr); 04467 if (!ast_bridged_channel(chan_ptr)) { 04468 struct ast_cdr *cur; 04469 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 04470 if (cur == peer_cdr) { 04471 break; 04472 } 04473 } 04474 if (cur) { 04475 ast_cdr_specialized_reset(peer_cdr, 0); 04476 } 04477 } 04478 ast_channel_unlock(chan_ptr); 04479 chan_ptr = ast_channel_unref(chan_ptr); 04480 } 04481 /* new channel */ 04482 if (new_peer_cdr) { 04483 ast_cdr_specialized_reset(new_peer_cdr, 0); 04484 } 04485 } else { 04486 if (we_disabled_peer_cdr) { 04487 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 04488 } 04489 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 04490 } 04491 } 04492 04493 return res; 04494 }
| 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 7390 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, strsep(), ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by bridge_exec(), and dial_exec_full().
07392 { 07393 char *stringp = ast_strdupa(parse); 07394 char *limit_str, *warning_str, *warnfreq_str; 07395 const char *var; 07396 int play_to_caller = 0, play_to_callee = 0; 07397 int delta; 07398 07399 limit_str = strsep(&stringp, ":"); 07400 warning_str = strsep(&stringp, ":"); 07401 warnfreq_str = strsep(&stringp, ":"); 07402 07403 config->timelimit = atol(limit_str); 07404 if (warning_str) 07405 config->play_warning = atol(warning_str); 07406 if (warnfreq_str) 07407 config->warning_freq = atol(warnfreq_str); 07408 07409 if (!config->timelimit) { 07410 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 07411 config->timelimit = config->play_warning = config->warning_freq = 0; 07412 config->warning_sound = NULL; 07413 return -1; /* error */ 07414 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 07415 int w = config->warning_freq; 07416 07417 /* 07418 * If the first warning is requested _after_ the entire call 07419 * would end, and no warning frequency is requested, then turn 07420 * off the warning. If a warning frequency is requested, reduce 07421 * the 'first warning' time by that frequency until it falls 07422 * within the call's total time limit. 07423 * 07424 * Graphically: 07425 * timelim->| delta |<-playwarning 07426 * 0__________________|_________________| 07427 * | w | | | | 07428 * 07429 * so the number of intervals to cut is 1+(delta-1)/w 07430 */ 07431 if (w == 0) { 07432 config->play_warning = 0; 07433 } else { 07434 config->play_warning -= w * ( 1 + (delta-1)/w ); 07435 if (config->play_warning < 1) 07436 config->play_warning = config->warning_freq = 0; 07437 } 07438 } 07439 07440 ast_channel_lock(chan); 07441 07442 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 07443 play_to_caller = var ? ast_true(var) : 1; 07444 07445 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 07446 play_to_callee = var ? ast_true(var) : 0; 07447 07448 if (!play_to_caller && !play_to_callee) 07449 play_to_caller = 1; 07450 07451 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 07452 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 07453 07454 /* The code looking at config wants a NULL, not just "", to decide 07455 * that the message should not be played, so we replace "" with NULL. 07456 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 07457 * not found. 07458 */ 07459 07460 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 07461 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07462 07463 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 07464 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 07465 07466 ast_channel_unlock(chan); 07467 07468 /* undo effect of S(x) in case they are both used */ 07469 calldurationlimit->tv_sec = 0; 07470 calldurationlimit->tv_usec = 0; 07471 07472 /* more efficient to do it like S(x) does since no advanced opts */ 07473 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 07474 calldurationlimit->tv_sec = config->timelimit / 1000; 07475 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 07476 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 07477 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 07478 config->timelimit = play_to_caller = play_to_callee = 07479 config->play_warning = config->warning_freq = 0; 07480 } else { 07481 ast_verb(4, "Limit Data for this call:\n"); 07482 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 07483 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 07484 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 07485 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 07486 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 07487 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 07488 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 07489 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 07490 } 07491 if (play_to_caller) 07492 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 07493 if (play_to_callee) 07494 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 07495 return 0; 07496 }
| 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 7197 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().
07198 { 07199 if (!chan->pbx && !chan->masq && !ast_test_flag(chan, AST_FLAG_ZOMBIE) 07200 && (chan->_state == AST_STATE_RINGING 07201 || chan->_state == AST_STATE_RING 07202 /* 07203 * Check the down state as well because some SIP devices do not 07204 * give 180 ringing when they can just give 183 session progress 07205 * instead. Issue 14005. (Some ISDN switches as well for that 07206 * matter.) 07207 */ 07208 || chan->_state == AST_STATE_DOWN) 07209 && !ast_channel_datastore_find(chan, &pickup_active, NULL)) { 07210 return 1; 07211 } 07212 return 0; 07213 }
| 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 7273 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_name(), 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().
07274 { 07275 struct ast_party_connected_line connected_caller; 07276 struct ast_channel *chans[2] = { chan, target }; 07277 struct ast_datastore *ds_pickup; 07278 const char *chan_name;/*!< A masquerade changes channel names. */ 07279 const char *target_name;/*!< A masquerade changes channel names. */ 07280 int res = -1; 07281 07282 target_name = ast_strdupa(ast_channel_name(target)); 07283 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan)); 07284 07285 /* Mark the target to block any call pickup race. */ 07286 ds_pickup = ast_datastore_alloc(&pickup_active, NULL); 07287 if (!ds_pickup) { 07288 ast_log(LOG_WARNING, 07289 "Unable to create channel datastore on '%s' for call pickup\n", target_name); 07290 return -1; 07291 } 07292 ast_channel_datastore_add(target, ds_pickup); 07293 07294 ast_party_connected_line_init(&connected_caller); 07295 ast_party_connected_line_copy(&connected_caller, &target->connected); 07296 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ 07297 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07298 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 07299 ast_channel_update_connected_line(chan, &connected_caller, NULL); 07300 } 07301 ast_party_connected_line_free(&connected_caller); 07302 07303 ast_channel_lock(chan); 07304 chan_name = ast_strdupa(ast_channel_name(chan)); 07305 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller); 07306 ast_channel_unlock(chan); 07307 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 07308 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 07309 ast_party_connected_line_free(&connected_caller); 07310 07311 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan); 07312 07313 if (ast_answer(chan)) { 07314 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 07315 goto pickup_failed; 07316 } 07317 07318 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 07319 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 07320 goto pickup_failed; 07321 } 07322 07323 /* setting this flag to generate a reason header in the cancel message to the ringing channel */ 07324 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE); 07325 07326 if (ast_channel_masquerade(target, chan)) { 07327 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, 07328 target_name); 07329 goto pickup_failed; 07330 } 07331 07332 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 07333 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 07334 "Channel: %s\r\n" 07335 "TargetChannel: %s\r\n", 07336 chan_name, target_name); 07337 07338 /* Do the masquerade manually to make sure that it is completed. */ 07339 ast_do_masquerade(target); 07340 res = 0; 07341 07342 pickup_failed: 07343 ast_channel_lock(target); 07344 if (!ast_channel_datastore_remove(target, ds_pickup)) { 07345 ast_datastore_free(ds_pickup); 07346 } 07347 07348 return res; 07349 }
| 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 3286 of file features.c.
References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
03286 { 03287 03288 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 03289 }
| int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 6759 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().
06760 { 06761 struct ast_context *con; 06762 int res; 06763 06764 ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */ 06765 06766 /* 06767 * Always destroy the parking_con_dial context to remove buildup 06768 * of recalled extensions in the context. At worst, the parked 06769 * call gets hungup attempting to run an invalid extension when 06770 * we are trying to callback the parker or the preset return 06771 * extension. This is a small window of opportunity on an 06772 * execution chain that is not expected to happen very often. 06773 */ 06774 con = ast_context_find(parking_con_dial); 06775 if (con) { 06776 ast_context_destroy(con, registrar); 06777 } 06778 06779 res = load_config(1); 06780 ast_mutex_unlock(&features_reload_lock); 06781 06782 return res; 06783 }
| 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 3019 of file features.c.
References FEATURES_COUNT, find_dynamic_feature(), and ast_call_feature::sname.
Referenced by action_atxfer(), handle_request_info(), and process_config().
03020 { 03021 int x; 03022 for (x = 0; x < FEATURES_COUNT; x++) { 03023 if (!strcasecmp(name, builtin_features[x].sname)) 03024 return &builtin_features[x]; 03025 } 03026 03027 return find_dynamic_feature(name); 03028 }
| 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 1764 of file features.c.
References ast_channel_name(), 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(), parkandannounce_exec(), and rpt_exec().
01765 { 01766 struct ast_park_call_args args = { 01767 .timeout = timeout, 01768 .extout = extout, 01769 }; 01770 01771 if (peer) { 01772 args.orig_chan_name = ast_strdupa(ast_channel_name(peer)); 01773 } 01774 return masq_park_call(rchan, peer, &args); 01775 }
| 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 1710 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), 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().
01711 { 01712 int res; 01713 char *parse; 01714 const char *app_data; 01715 struct ast_exten *exten; 01716 struct park_app_args app_args; 01717 struct ast_park_call_args args = { 01718 .timeout = timeout, 01719 .extout = extout, 01720 }; 01721 01722 if (parker) { 01723 args.orig_chan_name = ast_strdupa(ast_channel_name(parker)); 01724 } 01725 if (!park_exten || !park_context) { 01726 return masq_park_call(park_me, parker, &args); 01727 } 01728 01729 /* 01730 * Determiine if the specified park extension has an exclusive 01731 * parking lot to use. 01732 */ 01733 if (parker && parker != park_me) { 01734 ast_autoservice_start(park_me); 01735 } 01736 exten = get_parking_exten(park_exten, parker, park_context); 01737 if (exten) { 01738 app_data = ast_get_extension_app_data(exten); 01739 if (!app_data) { 01740 app_data = ""; 01741 } 01742 parse = ast_strdupa(app_data); 01743 AST_STANDARD_APP_ARGS(app_args, parse); 01744 01745 if (!ast_strlen_zero(app_args.pl_name)) { 01746 /* Find the specified exclusive parking lot */ 01747 args.parkinglot = find_parkinglot(app_args.pl_name); 01748 if (!args.parkinglot && parkeddynamic) { 01749 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01750 } 01751 } 01752 } 01753 if (parker && parker != park_me) { 01754 ast_autoservice_stop(park_me); 01755 } 01756 01757 res = masq_park_call(park_me, parker, &args); 01758 if (args.parkinglot) { 01759 parkinglot_unref(args.parkinglot); 01760 } 01761 return res; 01762 }
| 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 1613 of file features.c.
References park_call_full(), and ast_park_call_args::timeout.
01614 { 01615 struct ast_park_call_args args = { 01616 .timeout = timeout, 01617 .extout = extout, 01618 }; 01619 01620 return park_call_full(park_me, parker, &args); 01621 }
| 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 1562 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().
01563 { 01564 int res; 01565 char *parse; 01566 const char *app_data; 01567 struct ast_exten *exten; 01568 struct park_app_args app_args; 01569 struct ast_park_call_args args = { 01570 .timeout = timeout, 01571 .extout = extout, 01572 }; 01573 01574 if (!park_exten || !park_context) { 01575 return park_call_full(park_me, parker, &args); 01576 } 01577 01578 /* 01579 * Determiine if the specified park extension has an exclusive 01580 * parking lot to use. 01581 */ 01582 if (parker && parker != park_me) { 01583 ast_autoservice_start(park_me); 01584 } 01585 exten = get_parking_exten(park_exten, parker, park_context); 01586 if (exten) { 01587 app_data = ast_get_extension_app_data(exten); 01588 if (!app_data) { 01589 app_data = ""; 01590 } 01591 parse = ast_strdupa(app_data); 01592 AST_STANDARD_APP_ARGS(app_args, parse); 01593 01594 if (!ast_strlen_zero(app_args.pl_name)) { 01595 /* Find the specified exclusive parking lot */ 01596 args.parkinglot = find_parkinglot(app_args.pl_name); 01597 if (!args.parkinglot && parkeddynamic) { 01598 args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me); 01599 } 01600 } 01601 } 01602 if (parker && parker != park_me) { 01603 ast_autoservice_stop(park_me); 01604 } 01605 01606 res = park_call_full(park_me, parker, &args); 01607 if (args.parkinglot) { 01608 parkinglot_unref(args.parkinglot); 01609 } 01610 return res; 01611 }
| 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 801 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().
00802 { 00803 return get_parking_exten(exten_str, chan, context) ? 1 : 0; 00804 }
| int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
| chan | channel that initiated pickup. |
< Potential pickup target
Definition at line 7239 of file features.c.
References ast_answer(), ast_channel_callback(), ast_channel_name(), 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().
07240 { 07241 struct ast_channel *target;/*!< Potential pickup target */ 07242 int res = -1; 07243 ast_debug(1, "pickup attempt by %s\n", ast_channel_name(chan)); 07244 07245 /* The found channel is already locked. */ 07246 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0); 07247 if (target) { 07248 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan)); 07249 07250 res = ast_do_pickup(chan, target); 07251 ast_channel_unlock(target); 07252 if (!res) { 07253 if (!ast_strlen_zero(pickupsound)) { 07254 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound); 07255 } 07256 } else { 07257 ast_log(LOG_WARNING, "pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan)); 07258 } 07259 target = ast_channel_unref(target); 07260 } 07261 07262 if (res < 0) { 07263 ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan)); 07264 if (!ast_strlen_zero(pickupfailsound)) { 07265 ast_answer(chan); 07266 ast_stream_and_wait(chan, pickupfailsound, ""); 07267 } 07268 } 07269 07270 return res; 07271 }
| const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 806 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().
00807 { 00808 return pickup_ext; 00809 }
| void ast_rdlock_call_features | ( | void | ) |
Definition at line 3009 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
03010 { 03011 ast_rwlock_rdlock(&features_lock); 03012 }
| 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 2853 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
Referenced by process_applicationmap_line().
02854 { 02855 if (!feature) { 02856 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02857 return; 02858 } 02859 02860 AST_RWLIST_WRLOCK(&feature_list); 02861 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 02862 AST_RWLIST_UNLOCK(&feature_list); 02863 02864 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 02865 }
| void ast_unlock_call_features | ( | void | ) |
Definition at line 3014 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
03015 { 03016 ast_rwlock_unlock(&features_lock); 03017 }
| 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 2933 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
02934 { 02935 if (!feature) { 02936 return; 02937 } 02938 02939 AST_RWLIST_WRLOCK(&feature_list); 02940 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 02941 AST_RWLIST_UNLOCK(&feature_list); 02942 02943 ast_free(feature); 02944 }
1.5.6