#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 | 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, 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_feature_detect (struct ast_channel *chan, struct ast_flags *features, 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, int *extout) |
Park a call and read back parked location. | |
const char * | ast_parking_ext (void) |
Determine system parking extension. | |
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.
Referenced by builtin_blindtransfer(), and masq_park_call().
#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(), and feature_exec_app().
#define AST_FEATURE_RETURN_SUCCESSBREAK 0 |
#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 49 of file features.h.
Referenced by ast_bridge_call(), ast_feature_interpret(), and feature_exec_app().
#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, char *code, int sense, void *data) |
Definition at line 52 of file features.h.
anonymous enum |
main call feature structure
AST_FEATURE_FLAG_NEEDSDTMF | |
AST_FEATURE_FLAG_ONPEER | |
AST_FEATURE_FLAG_ONSELF | |
AST_FEATURE_FLAG_BYCALLEE | |
AST_FEATURE_FLAG_BYCALLER | |
AST_FEATURE_FLAG_BYBOTH |
Definition at line 56 of file features.h.
00056 { 00057 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00058 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00059 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00060 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00061 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00062 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00063 };
int ast_bridge_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) |
Bridge a call, optionally allowing redirection.
chan,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 2404 of file features.c.
References ast_channel::_state, ast_cdr::accountcode, ast_channel::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_detach(), ast_cdr_discard(), ast_cdr_dup(), 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_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, 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_get_channel_by_name_locked(), 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::cdr, chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.
Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), and park_exec_full().
02405 { 02406 /* Copy voice back and forth between the two channels. Give the peer 02407 the ability to transfer calls with '#<extension' syntax. */ 02408 struct ast_frame *f; 02409 struct ast_channel *who; 02410 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02411 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02412 char orig_channame[AST_MAX_EXTENSION]; 02413 char orig_peername[AST_MAX_EXTENSION]; 02414 int res; 02415 int diff; 02416 int hasfeatures=0; 02417 int hadfeatures=0; 02418 int autoloopflag; 02419 struct ast_option_header *aoh; 02420 struct ast_bridge_config backup_config; 02421 struct ast_cdr *bridge_cdr = NULL; 02422 struct ast_cdr *orig_peer_cdr = NULL; 02423 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 02424 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 02425 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02426 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02427 02428 memset(&backup_config, 0, sizeof(backup_config)); 02429 02430 config->start_time = ast_tvnow(); 02431 02432 if (chan && peer) { 02433 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02434 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02435 } else if (chan) { 02436 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02437 } 02438 02439 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02440 add_features_datastores(chan, peer, config); 02441 02442 /* This is an interesting case. One example is if a ringing channel gets redirected to 02443 * an extension that picks up a parked call. This will make sure that the call taken 02444 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02445 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02446 ast_indicate(peer, AST_CONTROL_RINGING); 02447 } 02448 02449 if (monitor_ok) { 02450 const char *monitor_exec; 02451 struct ast_channel *src = NULL; 02452 if (!monitor_app) { 02453 if (!(monitor_app = pbx_findapp("Monitor"))) 02454 monitor_ok=0; 02455 } 02456 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02457 src = chan; 02458 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02459 src = peer; 02460 if (monitor_app && src) { 02461 char *tmp = ast_strdupa(monitor_exec); 02462 pbx_exec(src, monitor_app, tmp); 02463 } 02464 } 02465 02466 set_config_flags(chan, peer, config); 02467 config->firstpass = 1; 02468 02469 /* Answer if need be */ 02470 if (chan->_state != AST_STATE_UP) { 02471 if (ast_raw_answer(chan, 1)) { 02472 return -1; 02473 } 02474 } 02475 02476 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02477 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02478 orig_peer_cdr = peer_cdr; 02479 02480 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02481 02482 if (chan_cdr) { 02483 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02484 ast_cdr_update(chan); 02485 bridge_cdr = ast_cdr_dup(chan_cdr); 02486 /* rip any forked CDR's off of the chan_cdr and attach 02487 * them to the bridge_cdr instead */ 02488 bridge_cdr->next = chan_cdr->next; 02489 chan_cdr->next = NULL; 02490 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02491 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02492 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 02493 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02494 } 02495 ast_cdr_setaccount(peer, chan->accountcode); 02496 02497 } else { 02498 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02499 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02500 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02501 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02502 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02503 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02504 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02505 ast_cdr_setcid(bridge_cdr, chan); 02506 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02507 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02508 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02509 /* Destination information */ 02510 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02511 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02512 if (peer_cdr) { 02513 bridge_cdr->start = peer_cdr->start; 02514 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02515 } else { 02516 ast_cdr_start(bridge_cdr); 02517 } 02518 } 02519 ast_debug(4,"bridge answer set, chan answer set\n"); 02520 /* peer_cdr->answer will be set when a macro runs on the peer; 02521 in that case, the bridge answer will be delayed while the 02522 macro plays on the peer channel. The peer answered the call 02523 before the macro started playing. To the phone system, 02524 this is billable time for the call, even tho the caller 02525 hears nothing but ringing while the macro does its thing. */ 02526 02527 /* Another case where the peer cdr's time will be set, is when 02528 A self-parks by pickup up phone and dialing 700, then B 02529 picks up A by dialing its parking slot; there may be more 02530 practical paths that get the same result, tho... in which 02531 case you get the previous answer time from the Park... which 02532 is before the bridge's start time, so I added in the 02533 tvcmp check to the if below */ 02534 02535 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 02536 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 02537 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 02538 if (chan_cdr) { 02539 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 02540 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 02541 } 02542 } else { 02543 ast_cdr_answer(bridge_cdr); 02544 if (chan_cdr) { 02545 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02546 } 02547 } 02548 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 02549 if (chan_cdr) { 02550 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02551 } 02552 if (peer_cdr) { 02553 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02554 } 02555 } 02556 /* the DIALED flag may be set if a dialed channel is transfered 02557 * and then bridged to another channel. In order for the 02558 * bridge CDR to be written, the DIALED flag must not be 02559 * present. */ 02560 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 02561 } 02562 for (;;) { 02563 struct ast_channel *other; /* used later */ 02564 02565 res = ast_channel_bridge(chan, peer, config, &f, &who); 02566 02567 /* When frame is not set, we are probably involved in a situation 02568 where we've timed out. 02569 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02570 and also for DTMF_END. If we flow into the following 'if' for both, then 02571 our wait times are cut in half, as both will subtract from the 02572 feature_timer. Not good! 02573 */ 02574 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02575 /* Update time limit for next pass */ 02576 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02577 if (res == AST_BRIDGE_RETRY) { 02578 /* The feature fully timed out but has not been updated. Skip 02579 * the potential round error from the diff calculation and 02580 * explicitly set to expired. */ 02581 config->feature_timer = -1; 02582 } else { 02583 config->feature_timer -= diff; 02584 } 02585 02586 if (hasfeatures) { 02587 /* Running on backup config, meaning a feature might be being 02588 activated, but that's no excuse to keep things going 02589 indefinitely! */ 02590 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02591 ast_debug(1, "Timed out, realtime this time!\n"); 02592 config->feature_timer = 0; 02593 who = chan; 02594 if (f) 02595 ast_frfree(f); 02596 f = NULL; 02597 res = 0; 02598 } else if (config->feature_timer <= 0) { 02599 /* Not *really* out of time, just out of time for 02600 digits to come in for features. */ 02601 ast_debug(1, "Timed out for feature!\n"); 02602 if (!ast_strlen_zero(peer_featurecode)) { 02603 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02604 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02605 } 02606 if (!ast_strlen_zero(chan_featurecode)) { 02607 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02608 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02609 } 02610 if (f) 02611 ast_frfree(f); 02612 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02613 if (!hasfeatures) { 02614 /* Restore original (possibly time modified) bridge config */ 02615 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02616 memset(&backup_config, 0, sizeof(backup_config)); 02617 } 02618 hadfeatures = hasfeatures; 02619 /* Continue as we were */ 02620 continue; 02621 } else if (!f) { 02622 /* The bridge returned without a frame and there is a feature in progress. 02623 * However, we don't think the feature has quite yet timed out, so just 02624 * go back into the bridge. */ 02625 continue; 02626 } 02627 } else { 02628 if (config->feature_timer <=0) { 02629 /* We ran out of time */ 02630 config->feature_timer = 0; 02631 who = chan; 02632 if (f) 02633 ast_frfree(f); 02634 f = NULL; 02635 res = 0; 02636 } 02637 } 02638 } 02639 if (res < 0) { 02640 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02641 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02642 goto before_you_go; 02643 } 02644 02645 if (!f || (f->frametype == AST_FRAME_CONTROL && 02646 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02647 f->subclass == AST_CONTROL_CONGESTION))) { 02648 res = -1; 02649 break; 02650 } 02651 /* many things should be sent to the 'other' channel */ 02652 other = (who == chan) ? peer : chan; 02653 if (f->frametype == AST_FRAME_CONTROL) { 02654 switch (f->subclass) { 02655 case AST_CONTROL_RINGING: 02656 case AST_CONTROL_FLASH: 02657 case -1: 02658 ast_indicate(other, f->subclass); 02659 break; 02660 case AST_CONTROL_HOLD: 02661 case AST_CONTROL_UNHOLD: 02662 ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); 02663 break; 02664 case AST_CONTROL_OPTION: 02665 aoh = f->data.ptr; 02666 /* Forward option Requests */ 02667 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02668 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02669 f->datalen - sizeof(struct ast_option_header), 0); 02670 } 02671 break; 02672 } 02673 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02674 /* eat it */ 02675 } else if (f->frametype == AST_FRAME_DTMF) { 02676 char *featurecode; 02677 int sense; 02678 02679 hadfeatures = hasfeatures; 02680 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02681 if (who == chan) { 02682 sense = FEATURE_SENSE_CHAN; 02683 featurecode = chan_featurecode; 02684 } else { 02685 sense = FEATURE_SENSE_PEER; 02686 featurecode = peer_featurecode; 02687 } 02688 /*! append the event to featurecode. we rely on the string being zero-filled, and 02689 * not overflowing it. 02690 * \todo XXX how do we guarantee the latter ? 02691 */ 02692 featurecode[strlen(featurecode)] = f->subclass; 02693 /* Get rid of the frame before we start doing "stuff" with the channels */ 02694 ast_frfree(f); 02695 f = NULL; 02696 config->feature_timer = backup_config.feature_timer; 02697 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 02698 switch(res) { 02699 case AST_FEATURE_RETURN_PASSDIGITS: 02700 ast_dtmf_stream(other, who, featurecode, 0, 0); 02701 /* Fall through */ 02702 case AST_FEATURE_RETURN_SUCCESS: 02703 memset(featurecode, 0, sizeof(chan_featurecode)); 02704 break; 02705 } 02706 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 02707 res = 0; 02708 } else 02709 break; 02710 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02711 if (hadfeatures && !hasfeatures) { 02712 /* Restore backup */ 02713 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02714 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02715 } else if (hasfeatures) { 02716 if (!hadfeatures) { 02717 /* Backup configuration */ 02718 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02719 /* Setup temporary config options */ 02720 config->play_warning = 0; 02721 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02722 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02723 config->warning_freq = 0; 02724 config->warning_sound = NULL; 02725 config->end_sound = NULL; 02726 config->start_sound = NULL; 02727 config->firstpass = 0; 02728 } 02729 config->start_time = ast_tvnow(); 02730 config->feature_timer = featuredigittimeout; 02731 ast_debug(1, "Set time limit to %ld\n", config->feature_timer); 02732 } 02733 } 02734 if (f) 02735 ast_frfree(f); 02736 02737 } 02738 before_you_go: 02739 02740 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02741 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02742 if (bridge_cdr) { 02743 ast_cdr_discard(bridge_cdr); 02744 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02745 } 02746 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02747 } 02748 02749 if (config->end_bridge_callback) { 02750 config->end_bridge_callback(config->end_bridge_callback_data); 02751 } 02752 02753 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 02754 * if it were, then chan belongs to a different thread now, and might have been hung up long 02755 * ago. 02756 */ 02757 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02758 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02759 struct ast_cdr *swapper = NULL; 02760 char savelastapp[AST_MAX_EXTENSION]; 02761 char savelastdata[AST_MAX_EXTENSION]; 02762 char save_exten[AST_MAX_EXTENSION]; 02763 int save_prio; 02764 int found = 0; /* set if we find at least one match */ 02765 int spawn_error = 0; 02766 02767 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02768 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02769 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02770 ast_cdr_end(bridge_cdr); 02771 } 02772 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02773 dialplan code operate on it */ 02774 ast_channel_lock(chan); 02775 if (bridge_cdr) { 02776 swapper = chan->cdr; 02777 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02778 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02779 chan->cdr = bridge_cdr; 02780 } 02781 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02782 save_prio = chan->priority; 02783 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02784 chan->priority = 1; 02785 ast_channel_unlock(chan); 02786 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 02787 chan->priority++; 02788 } 02789 if (spawn_error && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num) || ast_check_hangup(chan))) { 02790 /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */ 02791 spawn_error = 0; 02792 } 02793 if (found && spawn_error) { 02794 /* Something bad happened, or a hangup has been requested. */ 02795 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02796 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02797 } 02798 /* swap it back */ 02799 ast_channel_lock(chan); 02800 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02801 chan->priority = save_prio; 02802 if (bridge_cdr) { 02803 if (chan->cdr == bridge_cdr) { 02804 chan->cdr = swapper; 02805 } else { 02806 bridge_cdr = NULL; 02807 } 02808 } 02809 if (!spawn_error) { 02810 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02811 } 02812 ast_channel_unlock(chan); 02813 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02814 if (bridge_cdr) { 02815 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02816 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02817 } 02818 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02819 } 02820 02821 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02822 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02823 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 02824 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02825 02826 /* we can post the bridge CDR at this point */ 02827 if (bridge_cdr) { 02828 ast_cdr_end(bridge_cdr); 02829 ast_cdr_detach(bridge_cdr); 02830 } 02831 02832 /* do a specialized reset on the beginning channel 02833 CDR's, if they still exist, so as not to mess up 02834 issues in future bridges; 02835 02836 Here are the rules of the game: 02837 1. The chan and peer channel pointers will not change 02838 during the life of the bridge. 02839 2. But, in transfers, the channel names will change. 02840 between the time the bridge is started, and the 02841 time the channel ends. 02842 Usually, when a channel changes names, it will 02843 also change CDR pointers. 02844 3. Usually, only one of the two channels (chan or peer) 02845 will change names. 02846 4. Usually, if a channel changes names during a bridge, 02847 it is because of a transfer. Usually, in these situations, 02848 it is normal to see 2 bridges running simultaneously, and 02849 it is not unusual to see the two channels that change 02850 swapped between bridges. 02851 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02852 to attend to; if the chan or peer changed names, 02853 we have the before and after attached CDR's. 02854 */ 02855 02856 if (new_chan_cdr) { 02857 struct ast_channel *chan_ptr = NULL; 02858 02859 if (strcasecmp(orig_channame, chan->name) != 0) { 02860 /* old channel */ 02861 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02862 if (chan_ptr) { 02863 if (!ast_bridged_channel(chan_ptr)) { 02864 struct ast_cdr *cur; 02865 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02866 if (cur == chan_cdr) { 02867 break; 02868 } 02869 } 02870 if (cur) 02871 ast_cdr_specialized_reset(chan_cdr,0); 02872 } 02873 ast_channel_unlock(chan_ptr); 02874 } 02875 /* new channel */ 02876 ast_cdr_specialized_reset(new_chan_cdr,0); 02877 } else { 02878 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02879 } 02880 } 02881 02882 { 02883 struct ast_channel *chan_ptr = NULL; 02884 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02885 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)) 02886 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02887 if (strcasecmp(orig_peername, peer->name) != 0) { 02888 /* old channel */ 02889 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02890 if (chan_ptr) { 02891 if (!ast_bridged_channel(chan_ptr)) { 02892 struct ast_cdr *cur; 02893 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02894 if (cur == peer_cdr) { 02895 break; 02896 } 02897 } 02898 if (cur) 02899 ast_cdr_specialized_reset(peer_cdr,0); 02900 } 02901 ast_channel_unlock(chan_ptr); 02902 } 02903 /* new channel */ 02904 ast_cdr_specialized_reset(new_peer_cdr,0); 02905 } else { 02906 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02907 } 02908 } 02909 02910 return res; 02911 }
int ast_feature_detect | ( | struct ast_channel * | chan, | |
struct ast_flags * | features, | |||
char * | code, | |||
struct ast_call_feature * | feature | |||
) |
detect a feature before bridging
chan | ||
ast_flags | ptr | |
char | ptr of input code |
ast_call_feature | ptr to be set if found |
Definition at line 2059 of file features.c.
References chan, feature_group_exten::feature, and feature_interpret_helper().
Referenced by detect_disconnect().
02059 { 02060 02061 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 02062 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 4052 of file features.c.
References load_config().
Referenced by handle_features_reload().
04053 { 04054 int res; 04055 /* Release parking lot list */ 04056 //ASTOBJ_CONTAINER_MARKALL(&parkinglots); 04057 // TODO: I don't think any marking is necessary 04058 04059 /* Reload configuration */ 04060 res = load_config(); 04061 04062 //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy); 04063 return res; 04064 }
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 1812 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
01813 { 01814 int x; 01815 for (x = 0; x < FEATURES_COUNT; x++) { 01816 if (!strcasecmp(name, builtin_features[x].sname)) 01817 return &builtin_features[x]; 01818 } 01819 return NULL; 01820 }
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 825 of file features.c.
References masq_park_call().
Referenced by handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().
00826 { 00827 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00828 }
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
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 754 of file features.c.
References ast_park_call_full(), chan, and ast_park_call_args::timeout.
Referenced by iax_park_thread(), and sip_park_thread().
00755 { 00756 struct ast_park_call_args args = { 00757 .timeout = timeout, 00758 .extout = extout, 00759 }; 00760 00761 return ast_park_call_full(chan, peer, &args); 00762 }
const char* ast_parking_ext | ( | void | ) |
Determine system parking extension.
Definition at line 244 of file features.c.
References parking_ext.
Referenced by build_parkinglot(), builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00245 { 00246 return parking_ext; 00247 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
Definition at line 4436 of file features.c.
References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, chan, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), pickup_exec(), and ss_thread().
04437 { 04438 struct ast_channel *cur = NULL; 04439 int res = -1; 04440 04441 while ((cur = ast_channel_walk_locked(cur)) != NULL) { 04442 if (!cur->pbx && 04443 (cur != chan) && 04444 (chan->pickupgroup & cur->callgroup) && 04445 ((cur->_state == AST_STATE_RINGING) || 04446 (cur->_state == AST_STATE_RING))) { 04447 break; 04448 } 04449 ast_channel_unlock(cur); 04450 } 04451 if (cur) { 04452 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 04453 res = ast_answer(chan); 04454 if (res) 04455 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 04456 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 04457 if (res) 04458 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 04459 res = ast_channel_masquerade(cur, chan); 04460 if (res) 04461 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 04462 ast_channel_unlock(cur); 04463 } else { 04464 ast_debug(1, "No call pickup possible...\n"); 04465 } 04466 return res; 04467 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 249 of file features.c.
References pickup_ext.
Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().
00250 { 00251 return pickup_ext; 00252 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 1802 of file features.c.
References ast_rwlock_rdlock(), and features_lock.
Referenced by handle_request_info().
01803 { 01804 ast_rwlock_rdlock(&features_lock); 01805 }
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 1639 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.
01640 { 01641 if (!feature) { 01642 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01643 return; 01644 } 01645 01646 AST_RWLIST_WRLOCK(&feature_list); 01647 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01648 AST_RWLIST_UNLOCK(&feature_list); 01649 01650 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 01651 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 1807 of file features.c.
References ast_rwlock_unlock(), and features_lock.
Referenced by handle_request_info().
01808 { 01809 ast_rwlock_unlock(&features_lock); 01810 }
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 1727 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
01728 { 01729 if (!feature) { 01730 return; 01731 } 01732 01733 AST_RWLIST_WRLOCK(&feature_list); 01734 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01735 AST_RWLIST_UNLOCK(&feature_list); 01736 01737 ast_free(feature); 01738 }