#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 |
#define | PARK_APP_NAME "Park" |
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_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 *rchan, struct ast_channel *host, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
int | ast_park_call (struct ast_channel *chan, struct ast_channel *host, int timeout, const char *parkexten, 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 47 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 43 of file features.h.
#define AST_FEATURE_RETURN_PARKFAILED 25 |
Definition at line 48 of file features.h.
Referenced by builtin_blindtransfer(), and masq_park_call().
#define AST_FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 44 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 42 of file features.h.
#define AST_FEATURE_RETURN_STOREDIGITS 22 |
Definition at line 45 of file features.h.
Referenced by detect_disconnect(), and feature_interpret_helper().
#define AST_FEATURE_RETURN_SUCCESS 23 |
Definition at line 46 of file features.h.
Referenced by ast_bridge_call(), builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app().
#define AST_FEATURE_RETURN_SUCCESSBREAK 0 |
#define DEFAULT_PARKINGLOT "default" |
#define FEATURE_APP_ARGS_LEN 256 |
Definition at line 32 of file features.h.
#define FEATURE_APP_LEN 64 |
Definition at line 31 of file features.h.
#define FEATURE_EXTEN_LEN 32 |
Definition at line 34 of file features.h.
#define FEATURE_MAX_LEN 11 |
#define FEATURE_MOH_LEN 80 |
Definition at line 35 of file features.h.
#define FEATURE_SENSE_CHAN (1 << 0) |
Definition at line 50 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 |
Definition at line 33 of file features.h.
#define PARK_APP_NAME "Park" |
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 53 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 57 of file features.h.
00057 { 00058 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00059 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00060 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00061 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00062 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00063 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00064 };
int ast_bridge_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) |
Bridge a call, optionally allowing redirection.
chan,peer,config | Set start time, check for two channels,check if monitor on check for feature activation, create new CDR |
res | on success. | |
-1 | on failure to bridge. |
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 3387 of file features.c.
References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_channel::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_bridge(), ast_channel_connected_line_macro(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_log(), ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), 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, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, 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_channel::caller, ast_channel::cdr, ast_cdr::channel, config, ast_channel::context, ast_channel::data, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_party_caller::id, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, ast_party_id::number, 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_channel::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 park_exec_full().
03388 { 03389 /* Copy voice back and forth between the two channels. Give the peer 03390 the ability to transfer calls with '#<extension' syntax. */ 03391 struct ast_frame *f; 03392 struct ast_channel *who; 03393 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03394 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03395 char orig_channame[AST_MAX_EXTENSION]; 03396 char orig_peername[AST_MAX_EXTENSION]; 03397 int res; 03398 int diff; 03399 int hasfeatures=0; 03400 int hadfeatures=0; 03401 int autoloopflag; 03402 int we_disabled_peer_cdr = 0; 03403 struct ast_option_header *aoh; 03404 struct ast_cdr *bridge_cdr = NULL; 03405 struct ast_cdr *orig_peer_cdr = NULL; 03406 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03407 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03408 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03409 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03410 03411 if (chan && peer) { 03412 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03413 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03414 } else if (chan) { 03415 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03416 } 03417 03418 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03419 add_features_datastores(chan, peer, config); 03420 03421 /* This is an interesting case. One example is if a ringing channel gets redirected to 03422 * an extension that picks up a parked call. This will make sure that the call taken 03423 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03424 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03425 ast_indicate(peer, AST_CONTROL_RINGING); 03426 } 03427 03428 if (monitor_ok) { 03429 const char *monitor_exec; 03430 struct ast_channel *src = NULL; 03431 if (!monitor_app) { 03432 if (!(monitor_app = pbx_findapp("Monitor"))) 03433 monitor_ok=0; 03434 } 03435 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03436 src = chan; 03437 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03438 src = peer; 03439 if (monitor_app && src) { 03440 char *tmp = ast_strdupa(monitor_exec); 03441 pbx_exec(src, monitor_app, tmp); 03442 } 03443 } 03444 03445 set_config_flags(chan, peer, config); 03446 03447 /* Answer if need be */ 03448 if (chan->_state != AST_STATE_UP) { 03449 if (ast_raw_answer(chan, 1)) { 03450 return -1; 03451 } 03452 } 03453 03454 #ifdef FOR_DEBUG 03455 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 03456 ast_channel_log("Pre-bridge CHAN Channel info", chan); 03457 ast_channel_log("Pre-bridge PEER Channel info", peer); 03458 #endif 03459 /* two channels are being marked as linked here */ 03460 ast_channel_set_linkgroup(chan,peer); 03461 03462 /* copy the userfield from the B-leg to A-leg if applicable */ 03463 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 03464 char tmp[256]; 03465 if (!ast_strlen_zero(chan->cdr->userfield)) { 03466 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 03467 ast_cdr_appenduserfield(chan, tmp); 03468 } else 03469 ast_cdr_setuserfield(chan, peer->cdr->userfield); 03470 /* Don't delete the CDR; just disable it. */ 03471 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03472 we_disabled_peer_cdr = 1; 03473 } 03474 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 03475 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 03476 orig_peer_cdr = peer_cdr; 03477 03478 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 03479 03480 if (chan_cdr) { 03481 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 03482 ast_cdr_update(chan); 03483 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 03484 /* rip any forked CDR's off of the chan_cdr and attach 03485 * them to the bridge_cdr instead */ 03486 bridge_cdr->next = chan_cdr->next; 03487 chan_cdr->next = NULL; 03488 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03489 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03490 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 03491 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03492 } 03493 ast_cdr_setaccount(peer, chan->accountcode); 03494 03495 } else { 03496 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 03497 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 03498 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 03499 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 03500 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 03501 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03502 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03503 ast_cdr_setcid(bridge_cdr, chan); 03504 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 03505 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 03506 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 03507 /* Destination information */ 03508 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 03509 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 03510 if (peer_cdr) { 03511 bridge_cdr->start = peer_cdr->start; 03512 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03513 } else { 03514 ast_cdr_start(bridge_cdr); 03515 } 03516 } 03517 ast_debug(4,"bridge answer set, chan answer set\n"); 03518 /* peer_cdr->answer will be set when a macro runs on the peer; 03519 in that case, the bridge answer will be delayed while the 03520 macro plays on the peer channel. The peer answered the call 03521 before the macro started playing. To the phone system, 03522 this is billable time for the call, even tho the caller 03523 hears nothing but ringing while the macro does its thing. */ 03524 03525 /* Another case where the peer cdr's time will be set, is when 03526 A self-parks by pickup up phone and dialing 700, then B 03527 picks up A by dialing its parking slot; there may be more 03528 practical paths that get the same result, tho... in which 03529 case you get the previous answer time from the Park... which 03530 is before the bridge's start time, so I added in the 03531 tvcmp check to the if below */ 03532 03533 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 03534 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 03535 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 03536 if (chan_cdr) { 03537 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 03538 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 03539 } 03540 } else { 03541 ast_cdr_answer(bridge_cdr); 03542 if (chan_cdr) { 03543 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 03544 } 03545 } 03546 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 03547 if (chan_cdr) { 03548 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 03549 } 03550 if (peer_cdr) { 03551 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 03552 } 03553 } 03554 /* the DIALED flag may be set if a dialed channel is transfered 03555 * and then bridged to another channel. In order for the 03556 * bridge CDR to be written, the DIALED flag must not be 03557 * present. */ 03558 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 03559 } 03560 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL); 03561 for (;;) { 03562 struct ast_channel *other; /* used later */ 03563 03564 res = ast_channel_bridge(chan, peer, config, &f, &who); 03565 03566 /* When frame is not set, we are probably involved in a situation 03567 where we've timed out. 03568 When frame is set, we'll come this code twice; once for DTMF_BEGIN 03569 and also for DTMF_END. If we flow into the following 'if' for both, then 03570 our wait times are cut in half, as both will subtract from the 03571 feature_timer. Not good! 03572 */ 03573 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 03574 /* Update feature timer for next pass */ 03575 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 03576 if (res == AST_BRIDGE_RETRY) { 03577 /* The feature fully timed out but has not been updated. Skip 03578 * the potential round error from the diff calculation and 03579 * explicitly set to expired. */ 03580 config->feature_timer = -1; 03581 } else { 03582 config->feature_timer -= diff; 03583 } 03584 03585 if (hasfeatures) { 03586 if (config->feature_timer <= 0) { 03587 /* Not *really* out of time, just out of time for 03588 digits to come in for features. */ 03589 ast_debug(1, "Timed out for feature!\n"); 03590 if (!ast_strlen_zero(peer_featurecode)) { 03591 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 03592 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 03593 } 03594 if (!ast_strlen_zero(chan_featurecode)) { 03595 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 03596 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 03597 } 03598 if (f) 03599 ast_frfree(f); 03600 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 03601 if (!hasfeatures) { 03602 /* No more digits expected - reset the timer */ 03603 config->feature_timer = 0; 03604 } 03605 hadfeatures = hasfeatures; 03606 /* Continue as we were */ 03607 continue; 03608 } else if (!f) { 03609 /* The bridge returned without a frame and there is a feature in progress. 03610 * However, we don't think the feature has quite yet timed out, so just 03611 * go back into the bridge. */ 03612 continue; 03613 } 03614 } else { 03615 if (config->feature_timer <=0) { 03616 /* We ran out of time */ 03617 config->feature_timer = 0; 03618 who = chan; 03619 if (f) 03620 ast_frfree(f); 03621 f = NULL; 03622 res = 0; 03623 } 03624 } 03625 } 03626 if (res < 0) { 03627 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 03628 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 03629 } 03630 goto before_you_go; 03631 } 03632 03633 if (!f || (f->frametype == AST_FRAME_CONTROL && 03634 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 03635 f->subclass.integer == AST_CONTROL_CONGESTION))) { 03636 res = -1; 03637 break; 03638 } 03639 /* many things should be sent to the 'other' channel */ 03640 other = (who == chan) ? peer : chan; 03641 if (f->frametype == AST_FRAME_CONTROL) { 03642 switch (f->subclass.integer) { 03643 case AST_CONTROL_RINGING: 03644 case AST_CONTROL_FLASH: 03645 case -1: 03646 ast_indicate(other, f->subclass.integer); 03647 break; 03648 case AST_CONTROL_CONNECTED_LINE: 03649 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 03650 break; 03651 } 03652 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 03653 break; 03654 case AST_CONTROL_REDIRECTING: 03655 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 03656 break; 03657 } 03658 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 03659 break; 03660 case AST_CONTROL_AOC: 03661 case AST_CONTROL_HOLD: 03662 case AST_CONTROL_UNHOLD: 03663 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 03664 break; 03665 case AST_CONTROL_OPTION: 03666 aoh = f->data.ptr; 03667 /* Forward option Requests */ 03668 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 03669 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 03670 f->datalen - sizeof(struct ast_option_header), 0); 03671 } 03672 break; 03673 } 03674 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 03675 /* eat it */ 03676 } else if (f->frametype == AST_FRAME_DTMF) { 03677 char *featurecode; 03678 int sense; 03679 03680 hadfeatures = hasfeatures; 03681 /* This cannot overrun because the longest feature is one shorter than our buffer */ 03682 if (who == chan) { 03683 sense = FEATURE_SENSE_CHAN; 03684 featurecode = chan_featurecode; 03685 } else { 03686 sense = FEATURE_SENSE_PEER; 03687 featurecode = peer_featurecode; 03688 } 03689 /*! append the event to featurecode. we rely on the string being zero-filled, and 03690 * not overflowing it. 03691 * \todo XXX how do we guarantee the latter ? 03692 */ 03693 featurecode[strlen(featurecode)] = f->subclass.integer; 03694 /* Get rid of the frame before we start doing "stuff" with the channels */ 03695 ast_frfree(f); 03696 f = NULL; 03697 config->feature_timer = 0; 03698 res = feature_interpret(chan, peer, config, featurecode, sense); 03699 switch(res) { 03700 case AST_FEATURE_RETURN_PASSDIGITS: 03701 ast_dtmf_stream(other, who, featurecode, 0, 0); 03702 /* Fall through */ 03703 case AST_FEATURE_RETURN_SUCCESS: 03704 memset(featurecode, 0, sizeof(chan_featurecode)); 03705 break; 03706 } 03707 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 03708 res = 0; 03709 } else { 03710 break; 03711 } 03712 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 03713 if (hadfeatures && !hasfeatures) { 03714 /* Feature completed or timed out */ 03715 config->feature_timer = 0; 03716 } else if (hasfeatures) { 03717 if (config->timelimit) { 03718 /* No warning next time - we are waiting for future */ 03719 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 03720 } 03721 config->feature_start_time = ast_tvnow(); 03722 config->feature_timer = featuredigittimeout; 03723 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 03724 } 03725 } 03726 if (f) 03727 ast_frfree(f); 03728 03729 } 03730 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL); 03731 before_you_go: 03732 03733 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 03734 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 03735 if (bridge_cdr) { 03736 ast_cdr_discard(bridge_cdr); 03737 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 03738 } 03739 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 03740 } 03741 03742 if (config->end_bridge_callback) { 03743 config->end_bridge_callback(config->end_bridge_callback_data); 03744 } 03745 03746 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 03747 * if it were, then chan belongs to a different thread now, and might have been hung up long 03748 * ago. 03749 */ 03750 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) 03751 && ast_exists_extension(chan, chan->context, "h", 1, 03752 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 03753 struct ast_cdr *swapper = NULL; 03754 char savelastapp[AST_MAX_EXTENSION]; 03755 char savelastdata[AST_MAX_EXTENSION]; 03756 char save_exten[AST_MAX_EXTENSION]; 03757 int save_prio; 03758 int found = 0; /* set if we find at least one match */ 03759 int spawn_error = 0; 03760 03761 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 03762 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 03763 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 03764 ast_cdr_end(bridge_cdr); 03765 } 03766 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 03767 dialplan code operate on it */ 03768 ast_channel_lock(chan); 03769 if (bridge_cdr) { 03770 swapper = chan->cdr; 03771 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 03772 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 03773 chan->cdr = bridge_cdr; 03774 } 03775 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 03776 save_prio = chan->priority; 03777 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 03778 chan->priority = 1; 03779 ast_channel_unlock(chan); 03780 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 03781 chan->priority, 03782 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 03783 &found, 1)) == 0) { 03784 chan->priority++; 03785 } 03786 if (spawn_error 03787 && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, 03788 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL)) 03789 || ast_check_hangup(chan))) { 03790 /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */ 03791 spawn_error = 0; 03792 } 03793 if (found && spawn_error) { 03794 /* Something bad happened, or a hangup has been requested. */ 03795 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 03796 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 03797 } 03798 /* swap it back */ 03799 ast_channel_lock(chan); 03800 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 03801 chan->priority = save_prio; 03802 if (bridge_cdr) { 03803 if (chan->cdr == bridge_cdr) { 03804 chan->cdr = swapper; 03805 } else { 03806 bridge_cdr = NULL; 03807 } 03808 } 03809 if (!spawn_error) { 03810 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 03811 } 03812 ast_channel_unlock(chan); 03813 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 03814 if (bridge_cdr) { 03815 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 03816 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 03817 } 03818 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 03819 } 03820 03821 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 03822 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 03823 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 03824 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 03825 03826 /* we can post the bridge CDR at this point */ 03827 if (bridge_cdr) { 03828 ast_cdr_end(bridge_cdr); 03829 ast_cdr_detach(bridge_cdr); 03830 } 03831 03832 /* do a specialized reset on the beginning channel 03833 CDR's, if they still exist, so as not to mess up 03834 issues in future bridges; 03835 03836 Here are the rules of the game: 03837 1. The chan and peer channel pointers will not change 03838 during the life of the bridge. 03839 2. But, in transfers, the channel names will change. 03840 between the time the bridge is started, and the 03841 time the channel ends. 03842 Usually, when a channel changes names, it will 03843 also change CDR pointers. 03844 3. Usually, only one of the two channels (chan or peer) 03845 will change names. 03846 4. Usually, if a channel changes names during a bridge, 03847 it is because of a transfer. Usually, in these situations, 03848 it is normal to see 2 bridges running simultaneously, and 03849 it is not unusual to see the two channels that change 03850 swapped between bridges. 03851 5. After a bridge occurs, we have 2 or 3 channels' CDRs 03852 to attend to; if the chan or peer changed names, 03853 we have the before and after attached CDR's. 03854 */ 03855 03856 if (new_chan_cdr) { 03857 struct ast_channel *chan_ptr = NULL; 03858 03859 if (strcasecmp(orig_channame, chan->name) != 0) { 03860 /* old channel */ 03861 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 03862 ast_channel_lock(chan_ptr); 03863 if (!ast_bridged_channel(chan_ptr)) { 03864 struct ast_cdr *cur; 03865 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 03866 if (cur == chan_cdr) { 03867 break; 03868 } 03869 } 03870 if (cur) { 03871 ast_cdr_specialized_reset(chan_cdr, 0); 03872 } 03873 } 03874 ast_channel_unlock(chan_ptr); 03875 chan_ptr = ast_channel_unref(chan_ptr); 03876 } 03877 /* new channel */ 03878 ast_cdr_specialized_reset(new_chan_cdr, 0); 03879 } else { 03880 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 03881 } 03882 } 03883 03884 { 03885 struct ast_channel *chan_ptr = NULL; 03886 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 03887 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)) 03888 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 03889 if (strcasecmp(orig_peername, peer->name) != 0) { 03890 /* old channel */ 03891 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 03892 ast_channel_lock(chan_ptr); 03893 if (!ast_bridged_channel(chan_ptr)) { 03894 struct ast_cdr *cur; 03895 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 03896 if (cur == peer_cdr) { 03897 break; 03898 } 03899 } 03900 if (cur) { 03901 ast_cdr_specialized_reset(peer_cdr, 0); 03902 } 03903 } 03904 ast_channel_unlock(chan_ptr); 03905 chan_ptr = ast_channel_unref(chan_ptr); 03906 } 03907 /* new channel */ 03908 if (new_peer_cdr) { 03909 ast_cdr_specialized_reset(new_peer_cdr, 0); 03910 } 03911 } else { 03912 if (we_disabled_peer_cdr) { 03913 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03914 } 03915 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 03916 } 03917 } 03918 03919 return res; 03920 }
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 5680 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().
05682 { 05683 char *stringp = ast_strdupa(parse); 05684 char *limit_str, *warning_str, *warnfreq_str; 05685 const char *var; 05686 int play_to_caller = 0, play_to_callee = 0; 05687 int delta; 05688 05689 limit_str = strsep(&stringp, ":"); 05690 warning_str = strsep(&stringp, ":"); 05691 warnfreq_str = strsep(&stringp, ":"); 05692 05693 config->timelimit = atol(limit_str); 05694 if (warning_str) 05695 config->play_warning = atol(warning_str); 05696 if (warnfreq_str) 05697 config->warning_freq = atol(warnfreq_str); 05698 05699 if (!config->timelimit) { 05700 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 05701 config->timelimit = config->play_warning = config->warning_freq = 0; 05702 config->warning_sound = NULL; 05703 return -1; /* error */ 05704 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 05705 int w = config->warning_freq; 05706 05707 /* If the first warning is requested _after_ the entire call would end, 05708 and no warning frequency is requested, then turn off the warning. If 05709 a warning frequency is requested, reduce the 'first warning' time by 05710 that frequency until it falls within the call's total time limit. 05711 Graphically: 05712 timelim->| delta |<-playwarning 05713 0__________________|_________________| 05714 | w | | | | 05715 05716 so the number of intervals to cut is 1+(delta-1)/w 05717 */ 05718 05719 if (w == 0) { 05720 config->play_warning = 0; 05721 } else { 05722 config->play_warning -= w * ( 1 + (delta-1)/w ); 05723 if (config->play_warning < 1) 05724 config->play_warning = config->warning_freq = 0; 05725 } 05726 } 05727 05728 ast_channel_lock(chan); 05729 05730 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 05731 play_to_caller = var ? ast_true(var) : 1; 05732 05733 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 05734 play_to_callee = var ? ast_true(var) : 0; 05735 05736 if (!play_to_caller && !play_to_callee) 05737 play_to_caller = 1; 05738 05739 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 05740 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 05741 05742 /* The code looking at config wants a NULL, not just "", to decide 05743 * that the message should not be played, so we replace "" with NULL. 05744 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 05745 * not found. 05746 */ 05747 05748 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 05749 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 05750 05751 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 05752 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 05753 05754 ast_channel_unlock(chan); 05755 05756 /* undo effect of S(x) in case they are both used */ 05757 calldurationlimit->tv_sec = 0; 05758 calldurationlimit->tv_usec = 0; 05759 05760 /* more efficient to do it like S(x) does since no advanced opts */ 05761 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 05762 calldurationlimit->tv_sec = config->timelimit / 1000; 05763 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 05764 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 05765 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 05766 config->timelimit = play_to_caller = play_to_callee = 05767 config->play_warning = config->warning_freq = 0; 05768 } else { 05769 ast_verb(4, "Limit Data for this call:\n"); 05770 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 05771 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 05772 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 05773 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 05774 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 05775 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 05776 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 05777 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 05778 } 05779 if (play_to_caller) 05780 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 05781 if (play_to_callee) 05782 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 05783 return 0; 05784 }
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 2872 of file features.c.
References feature_group_exten::feature, and feature_interpret_helper().
Referenced by detect_disconnect().
02872 { 02873 02874 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 02875 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 5179 of file features.c.
References ao2_t_callback, load_config(), OBJ_NODATA, OBJ_UNLINK, parkinglot_is_marked_cb(), parkinglot_markall_cb(), and parkinglots.
Referenced by handle_features_reload().
05180 { 05181 int res; 05182 05183 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, "callback to mark all parkinglots"); 05184 res = load_config(); /* Reload configuration */ 05185 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, "callback to remove all marked parkinglots"); 05186 05187 return res; 05188 }
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 2614 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
02615 { 02616 int x; 02617 for (x = 0; x < FEATURES_COUNT; x++) { 02618 if (!strcasecmp(name, builtin_features[x].sname)) 02619 return &builtin_features[x]; 02620 } 02621 return NULL; 02622 }
int ast_masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call via a masqueraded channel.
rchan | the real channel to be parked | |
host | the channel to have the parking read to. | |
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 1299 of file features.c.
References masq_park_call().
Referenced by __analog_ss_thread(), analog_ss_thread(), handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), mgcp_ss(), parkandannounce_exec(), and rpt_exec().
01300 { 01301 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 01302 }
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
const char * | parkexten, | |||
int * | extout | |||
) |
Park a call and read back parked location.
chan | the channel to actually be parked | |
host | the channel which will have the parked location read to. | |
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 1225 of file features.c.
References ao2_callback, args, find_parkinglot_by_exten_cb(), park_call_full(), and parkinglots.
Referenced by iax_park_thread(), and sip_park_thread().
01226 { 01227 struct ast_parkinglot *found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, (void *) parkexten); 01228 01229 struct ast_park_call_args args = { 01230 .timeout = timeout, 01231 .extout = extout, 01232 .parkinglot = found_lot, 01233 }; 01234 01235 return park_call_full(chan, peer, &args); 01236 }
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 643 of file features.c.
References ast_get_extension_app(), E_MATCH, feature_group_exten::exten, PARK_APP_NAME, pbx_find_extension(), and pbx_find_info::stacklen.
Referenced by __analog_ss_thread(), analog_ss_thread(), dp_lookup(), handle_request_refer(), mgcp_ss(), and socket_process().
00644 { 00645 struct ast_exten *exten; 00646 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 00647 const char *app_at_exten; 00648 00649 exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, E_MATCH); 00650 if (!exten) { 00651 return 0; 00652 } 00653 00654 app_at_exten = ast_get_extension_app(exten); 00655 if (!app_at_exten || strcmp(PARK_APP_NAME, app_at_exten)) { 00656 return 0; 00657 } 00658 00659 return 1; 00660 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
Definition at line 5578 of file features.c.
References ast_answer(), ast_channel_callback(), ast_channel_connected_line_macro(), ast_channel_lock_both, ast_channel_masquerade(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_unref, ast_channel_update_connected_line(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_manager_event_multichan, ast_party_connected_line_collect_caller(), ast_queue_control(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_channel::caller, ast_channel::connected, EVENT_FLAG_CALL, find_channel_by_group(), LOG_WARNING, ast_channel::name, pickupfailsound, pickupsound, and ast_party_connected_line::source.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), handle_request_invite(), mgcp_ss(), and pickup_exec().
05579 { 05580 struct ast_channel *cur, *chans[2] = { chan, }; 05581 struct ast_party_connected_line connected_caller; 05582 int res; 05583 const char *chan_name; 05584 const char *cur_name; 05585 05586 if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) { 05587 ast_debug(1, "No call pickup possible...\n"); 05588 if (!ast_strlen_zero(pickupfailsound)) { 05589 ast_stream_and_wait(chan, pickupfailsound, ""); 05590 } 05591 return -1; 05592 } 05593 05594 chans[1] = cur; 05595 05596 ast_channel_lock_both(cur, chan); 05597 05598 cur_name = ast_strdupa(cur->name); 05599 chan_name = ast_strdupa(chan->name); 05600 05601 ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name); 05602 05603 connected_caller = cur->connected; 05604 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05605 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 05606 ast_channel_update_connected_line(chan, &connected_caller, NULL); 05607 } 05608 05609 ast_party_connected_line_collect_caller(&connected_caller, &chan->caller); 05610 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05611 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 05612 05613 ast_channel_unlock(cur); 05614 ast_channel_unlock(chan); 05615 05616 if (ast_answer(chan)) { 05617 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 05618 } 05619 05620 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 05621 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 05622 } 05623 05624 if ((res = ast_channel_masquerade(cur, chan))) { 05625 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name); 05626 } 05627 05628 if (!ast_strlen_zero(pickupsound)) { 05629 ast_stream_and_wait(cur, pickupsound, ""); 05630 } 05631 05632 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 05633 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 05634 "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, cur->name); 05635 05636 cur = ast_channel_unref(cur); 05637 05638 return res; 05639 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 662 of file features.c.
References pickup_ext.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), and mgcp_ss().
00663 { 00664 return pickup_ext; 00665 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 2604 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
02605 { 02606 ast_rwlock_rdlock(&features_lock); 02607 }
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 2448 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.
02449 { 02450 if (!feature) { 02451 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02452 return; 02453 } 02454 02455 AST_RWLIST_WRLOCK(&feature_list); 02456 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 02457 AST_RWLIST_UNLOCK(&feature_list); 02458 02459 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 02460 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 2609 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
02610 { 02611 ast_rwlock_unlock(&features_lock); 02612 }
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 2528 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
02529 { 02530 if (!feature) { 02531 return; 02532 } 02533 02534 AST_RWLIST_WRLOCK(&feature_list); 02535 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 02536 AST_RWLIST_UNLOCK(&feature_list); 02537 02538 ast_free(feature); 02539 }