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