Call Parking and Pickup API Includes code and algorithms from the Zapata library. More...
#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_PARKFAILED 25 |
| #define | AST_FEATURE_RETURN_PASSDIGITS 21 |
| #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_SNAME_LEN 32 |
| #define | PARK_APP_NAME "Park" |
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_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 | |
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
Definition in file features.h.
| #define AST_FEATURE_RETURN_HANGUP -1 |
Definition at line 64 of file features.h.
Referenced by builtin_disconnect().
| #define AST_FEATURE_RETURN_KEEPTRYING 24 |
Definition at line 69 of file features.h.
Referenced by feature_exec_app(), and feature_interpret().
| #define AST_FEATURE_RETURN_PARKFAILED 25 |
Definition at line 70 of file features.h.
Referenced by builtin_blindtransfer(), and masq_park_call().
| #define AST_FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 66 of file features.h.
Referenced by ast_bridge_call(), and feature_interpret().
| #define AST_FEATURE_RETURN_STOREDIGITS 22 |
Definition at line 67 of file features.h.
Referenced by feature_interpret().
| #define AST_FEATURE_RETURN_SUCCESS 23 |
Definition at line 68 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 |
Definition at line 65 of file features.h.
Referenced by feature_exec_app().
| #define FEATURE_APP_ARGS_LEN 256 |
Definition at line 32 of file features.h.
Referenced by load_config().
| #define FEATURE_APP_LEN 64 |
Definition at line 31 of file features.h.
Referenced by load_config().
| #define FEATURE_EXTEN_LEN 32 |
Definition at line 34 of file features.h.
Referenced by load_config().
| #define FEATURE_MAX_LEN 11 |
Definition at line 30 of file features.h.
Referenced by ast_bridge_call().
| #define FEATURE_MOH_LEN 80 |
Definition at line 35 of file features.h.
Referenced by load_config().
| #define FEATURE_SNAME_LEN 32 |
Definition at line 33 of file features.h.
Referenced by load_config().
| #define PARK_APP_NAME "Park" |
Definition at line 37 of file features.h.
Referenced by handle_exec().
| 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 41 of file features.h.
00041 { 00042 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00043 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00044 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00045 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00046 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00047 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00048 };
| 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 2441 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_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), 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_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_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_interpret(), 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(), bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), park_exec_full(), and try_calling().
02442 { 02443 /* Copy voice back and forth between the two channels. Give the peer 02444 the ability to transfer calls with '#<extension' syntax. */ 02445 struct ast_frame *f; 02446 struct ast_channel *who; 02447 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02448 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02449 char orig_channame[AST_MAX_EXTENSION]; 02450 char orig_peername[AST_MAX_EXTENSION]; 02451 int res; 02452 int diff; 02453 int hasfeatures=0; 02454 int hadfeatures=0; 02455 int autoloopflag; 02456 struct ast_option_header *aoh; 02457 struct ast_bridge_config backup_config; 02458 struct ast_cdr *bridge_cdr = NULL; 02459 struct ast_cdr *orig_peer_cdr = NULL; 02460 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02461 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02462 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02463 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02464 02465 memset(&backup_config, 0, sizeof(backup_config)); 02466 02467 config->start_time = ast_tvnow(); 02468 02469 if (chan && peer) { 02470 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02471 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02472 } else if (chan) { 02473 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02474 } 02475 02476 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02477 add_features_datastores(chan, peer, config); 02478 02479 /* This is an interesting case. One example is if a ringing channel gets redirected to 02480 * an extension that picks up a parked call. This will make sure that the call taken 02481 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02482 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02483 ast_indicate(peer, AST_CONTROL_RINGING); 02484 } 02485 02486 if (monitor_ok) { 02487 const char *monitor_exec; 02488 struct ast_channel *src = NULL; 02489 if (!monitor_app) { 02490 if (!(monitor_app = pbx_findapp("Monitor"))) 02491 monitor_ok=0; 02492 } 02493 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02494 src = chan; 02495 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02496 src = peer; 02497 if (monitor_app && src) { 02498 char *tmp = ast_strdupa(monitor_exec); 02499 pbx_exec(src, monitor_app, tmp); 02500 } 02501 } 02502 02503 set_config_flags(chan, peer, config); 02504 config->firstpass = 1; 02505 02506 /* Answer if need be */ 02507 if (chan->_state != AST_STATE_UP) { 02508 if (ast_raw_answer(chan, 1)) { 02509 return -1; 02510 } 02511 } 02512 02513 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02514 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02515 orig_peer_cdr = peer_cdr; 02516 02517 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02518 02519 if (chan_cdr) { 02520 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02521 ast_cdr_update(chan); 02522 bridge_cdr = ast_cdr_dup(chan_cdr); 02523 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02524 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02525 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 02526 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02527 } 02528 if (peer_cdr && ast_strlen_zero(peer->accountcode)) { 02529 ast_cdr_setaccount(peer, chan->accountcode); 02530 } 02531 02532 } else { 02533 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02534 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02535 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02536 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02537 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02538 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02539 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02540 ast_cdr_setcid(bridge_cdr, chan); 02541 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02542 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02543 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02544 /* Destination information */ 02545 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02546 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02547 if (peer_cdr) { 02548 bridge_cdr->start = peer_cdr->start; 02549 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02550 } else { 02551 ast_cdr_start(bridge_cdr); 02552 } 02553 } 02554 ast_debug(4,"bridge answer set, chan answer set\n"); 02555 /* peer_cdr->answer will be set when a macro runs on the peer; 02556 in that case, the bridge answer will be delayed while the 02557 macro plays on the peer channel. The peer answered the call 02558 before the macro started playing. To the phone system, 02559 this is billable time for the call, even tho the caller 02560 hears nothing but ringing while the macro does its thing. */ 02561 02562 /* Another case where the peer cdr's time will be set, is when 02563 A self-parks by pickup up phone and dialing 700, then B 02564 picks up A by dialing its parking slot; there may be more 02565 practical paths that get the same result, tho... in which 02566 case you get the previous answer time from the Park... which 02567 is before the bridge's start time, so I added in the 02568 tvcmp check to the if below */ 02569 02570 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 02571 bridge_cdr->answer = peer_cdr->answer; 02572 bridge_cdr->disposition = peer_cdr->disposition; 02573 if (chan_cdr) { 02574 chan_cdr->answer = peer_cdr->answer; 02575 chan_cdr->disposition = peer_cdr->disposition; 02576 } 02577 } else { 02578 ast_cdr_answer(bridge_cdr); 02579 if (chan_cdr) { 02580 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02581 } 02582 } 02583 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 02584 if (chan_cdr) { 02585 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02586 } 02587 if (peer_cdr) { 02588 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02589 } 02590 } 02591 } 02592 for (;;) { 02593 struct ast_channel *other; /* used later */ 02594 02595 res = ast_channel_bridge(chan, peer, config, &f, &who); 02596 02597 /* When frame is not set, we are probably involved in a situation 02598 where we've timed out. 02599 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02600 and also for DTMF_END. If we flow into the following 'if' for both, then 02601 our wait times are cut in half, as both will subtract from the 02602 feature_timer. Not good! 02603 */ 02604 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02605 /* Update time limit for next pass */ 02606 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02607 if (res == AST_BRIDGE_RETRY) { 02608 /* The feature fully timed out but has not been updated. Skip 02609 * the potential round error from the diff calculation and 02610 * explicitly set to expired. */ 02611 config->feature_timer = -1; 02612 } else { 02613 config->feature_timer -= diff; 02614 } 02615 02616 if (hasfeatures) { 02617 /* Running on backup config, meaning a feature might be being 02618 activated, but that's no excuse to keep things going 02619 indefinitely! */ 02620 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02621 ast_debug(1, "Timed out, realtime this time!\n"); 02622 config->feature_timer = 0; 02623 who = chan; 02624 if (f) 02625 ast_frfree(f); 02626 f = NULL; 02627 res = 0; 02628 } else if (config->feature_timer <= 0) { 02629 /* Not *really* out of time, just out of time for 02630 digits to come in for features. */ 02631 ast_debug(1, "Timed out for feature!\n"); 02632 if (!ast_strlen_zero(peer_featurecode)) { 02633 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02634 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02635 } 02636 if (!ast_strlen_zero(chan_featurecode)) { 02637 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02638 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02639 } 02640 if (f) 02641 ast_frfree(f); 02642 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02643 if (!hasfeatures) { 02644 /* Restore original (possibly time modified) bridge config */ 02645 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02646 memset(&backup_config, 0, sizeof(backup_config)); 02647 } 02648 hadfeatures = hasfeatures; 02649 /* Continue as we were */ 02650 continue; 02651 } else if (!f) { 02652 /* The bridge returned without a frame and there is a feature in progress. 02653 * However, we don't think the feature has quite yet timed out, so just 02654 * go back into the bridge. */ 02655 continue; 02656 } 02657 } else { 02658 if (config->feature_timer <=0) { 02659 /* We ran out of time */ 02660 config->feature_timer = 0; 02661 who = chan; 02662 if (f) 02663 ast_frfree(f); 02664 f = NULL; 02665 res = 0; 02666 } 02667 } 02668 } 02669 if (res < 0) { 02670 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02671 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02672 goto before_you_go; 02673 } 02674 02675 if (!f || (f->frametype == AST_FRAME_CONTROL && 02676 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02677 f->subclass == AST_CONTROL_CONGESTION))) { 02678 res = -1; 02679 break; 02680 } 02681 /* many things should be sent to the 'other' channel */ 02682 other = (who == chan) ? peer : chan; 02683 if (f->frametype == AST_FRAME_CONTROL) { 02684 switch (f->subclass) { 02685 case AST_CONTROL_RINGING: 02686 case AST_CONTROL_FLASH: 02687 case -1: 02688 ast_indicate(other, f->subclass); 02689 break; 02690 case AST_CONTROL_HOLD: 02691 case AST_CONTROL_UNHOLD: 02692 ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); 02693 break; 02694 case AST_CONTROL_OPTION: 02695 aoh = f->data.ptr; 02696 /* Forward option Requests */ 02697 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02698 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02699 f->datalen - sizeof(struct ast_option_header), 0); 02700 } 02701 break; 02702 } 02703 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02704 /* eat it */ 02705 } else if (f->frametype == AST_FRAME_DTMF) { 02706 char *featurecode; 02707 int sense; 02708 02709 hadfeatures = hasfeatures; 02710 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02711 if (who == chan) { 02712 sense = FEATURE_SENSE_CHAN; 02713 featurecode = chan_featurecode; 02714 } else { 02715 sense = FEATURE_SENSE_PEER; 02716 featurecode = peer_featurecode; 02717 } 02718 /*! append the event to featurecode. we rely on the string being zero-filled, and 02719 * not overflowing it. 02720 * \todo XXX how do we guarantee the latter ? 02721 */ 02722 featurecode[strlen(featurecode)] = f->subclass; 02723 /* Get rid of the frame before we start doing "stuff" with the channels */ 02724 ast_frfree(f); 02725 f = NULL; 02726 config->feature_timer = backup_config.feature_timer; 02727 res = feature_interpret(chan, peer, config, featurecode, sense); 02728 switch(res) { 02729 case AST_FEATURE_RETURN_PASSDIGITS: 02730 ast_dtmf_stream(other, who, featurecode, 0, 0); 02731 /* Fall through */ 02732 case AST_FEATURE_RETURN_SUCCESS: 02733 memset(featurecode, 0, sizeof(chan_featurecode)); 02734 break; 02735 } 02736 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 02737 res = 0; 02738 } else 02739 break; 02740 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02741 if (hadfeatures && !hasfeatures) { 02742 /* Restore backup */ 02743 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02744 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02745 } else if (hasfeatures) { 02746 if (!hadfeatures) { 02747 /* Backup configuration */ 02748 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02749 /* Setup temporary config options */ 02750 config->play_warning = 0; 02751 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02752 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02753 config->warning_freq = 0; 02754 config->warning_sound = NULL; 02755 config->end_sound = NULL; 02756 config->start_sound = NULL; 02757 config->firstpass = 0; 02758 } 02759 config->start_time = ast_tvnow(); 02760 config->feature_timer = featuredigittimeout; 02761 ast_debug(1, "Set time limit to %ld\n", config->feature_timer); 02762 } 02763 } 02764 if (f) 02765 ast_frfree(f); 02766 02767 } 02768 before_you_go: 02769 02770 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02771 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02772 if (bridge_cdr) { 02773 ast_cdr_discard(bridge_cdr); 02774 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02775 } 02776 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02777 } 02778 02779 if (config->end_bridge_callback) { 02780 config->end_bridge_callback(config->end_bridge_callback_data); 02781 } 02782 02783 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 02784 * if it were, then chan belongs to a different thread now, and might have been hung up long 02785 * ago. 02786 */ 02787 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02788 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02789 struct ast_cdr *swapper = NULL; 02790 char savelastapp[AST_MAX_EXTENSION]; 02791 char savelastdata[AST_MAX_EXTENSION]; 02792 char save_exten[AST_MAX_EXTENSION]; 02793 int save_prio; 02794 int found = 0; /* set if we find at least one match */ 02795 int spawn_error = 0; 02796 02797 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02798 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02799 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02800 ast_cdr_end(bridge_cdr); 02801 } 02802 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02803 dialplan code operate on it */ 02804 ast_channel_lock(chan); 02805 if (bridge_cdr) { 02806 swapper = chan->cdr; 02807 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02808 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02809 chan->cdr = bridge_cdr; 02810 } 02811 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02812 save_prio = chan->priority; 02813 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02814 chan->priority = 1; 02815 ast_channel_unlock(chan); 02816 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 02817 chan->priority++; 02818 } 02819 if (spawn_error && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num) || ast_check_hangup(chan))) { 02820 /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */ 02821 spawn_error = 0; 02822 } 02823 if (found && spawn_error) { 02824 /* Something bad happened, or a hangup has been requested. */ 02825 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02826 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02827 } 02828 /* swap it back */ 02829 ast_channel_lock(chan); 02830 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02831 chan->priority = save_prio; 02832 if (bridge_cdr) { 02833 if (chan->cdr == bridge_cdr) { 02834 chan->cdr = swapper; 02835 } else { 02836 bridge_cdr = NULL; 02837 } 02838 } 02839 if (!spawn_error) { 02840 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02841 } 02842 ast_channel_unlock(chan); 02843 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02844 if (bridge_cdr) { 02845 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02846 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02847 } 02848 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02849 } 02850 02851 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02852 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02853 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 02854 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02855 02856 /* we can post the bridge CDR at this point */ 02857 if (bridge_cdr) { 02858 ast_cdr_end(bridge_cdr); 02859 ast_cdr_detach(bridge_cdr); 02860 } 02861 02862 /* do a specialized reset on the beginning channel 02863 CDR's, if they still exist, so as not to mess up 02864 issues in future bridges; 02865 02866 Here are the rules of the game: 02867 1. The chan and peer channel pointers will not change 02868 during the life of the bridge. 02869 2. But, in transfers, the channel names will change. 02870 between the time the bridge is started, and the 02871 time the channel ends. 02872 Usually, when a channel changes names, it will 02873 also change CDR pointers. 02874 3. Usually, only one of the two channels (chan or peer) 02875 will change names. 02876 4. Usually, if a channel changes names during a bridge, 02877 it is because of a transfer. Usually, in these situations, 02878 it is normal to see 2 bridges running simultaneously, and 02879 it is not unusual to see the two channels that change 02880 swapped between bridges. 02881 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02882 to attend to; if the chan or peer changed names, 02883 we have the before and after attached CDR's. 02884 */ 02885 02886 if (new_chan_cdr) { 02887 struct ast_channel *chan_ptr = NULL; 02888 02889 if (strcasecmp(orig_channame, chan->name) != 0) { 02890 /* old channel */ 02891 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02892 if (chan_ptr) { 02893 if (!ast_bridged_channel(chan_ptr)) { 02894 struct ast_cdr *cur; 02895 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02896 if (cur == chan_cdr) { 02897 break; 02898 } 02899 } 02900 if (cur) 02901 ast_cdr_specialized_reset(chan_cdr,0); 02902 } 02903 ast_channel_unlock(chan_ptr); 02904 } 02905 /* new channel */ 02906 ast_cdr_specialized_reset(new_chan_cdr,0); 02907 } else { 02908 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02909 } 02910 } 02911 02912 { 02913 struct ast_channel *chan_ptr = NULL; 02914 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02915 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)) 02916 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02917 if (strcasecmp(orig_peername, peer->name) != 0) { 02918 /* old channel */ 02919 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02920 if (chan_ptr) { 02921 if (!ast_bridged_channel(chan_ptr)) { 02922 struct ast_cdr *cur; 02923 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02924 if (cur == peer_cdr) { 02925 break; 02926 } 02927 } 02928 if (cur) 02929 ast_cdr_specialized_reset(peer_cdr,0); 02930 } 02931 ast_channel_unlock(chan_ptr); 02932 } 02933 /* new channel */ 02934 if (new_peer_cdr) { 02935 ast_cdr_specialized_reset(new_peer_cdr, 0); 02936 } 02937 } else { 02938 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02939 } 02940 } 02941 02942 return res; 02943 }
| int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 4079 of file features.c.
References load_config().
Referenced by handle_features_reload().
04080 { 04081 int res; 04082 /* Release parking lot list */ 04083 //ASTOBJ_CONTAINER_MARKALL(&parkinglots); 04084 // TODO: I don't think any marking is necessary 04085 04086 /* Reload configuration */ 04087 res = load_config(); 04088 04089 //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy); 04090 return res; 04091 }
| 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 1884 of file features.c.
References FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), handle_request_info(), and load_config().
01885 { 01886 int x; 01887 for (x = 0; x < FEATURES_COUNT; x++) { 01888 if (!strcasecmp(name, builtin_features[x].sname)) 01889 return &builtin_features[x]; 01890 } 01891 return NULL; 01892 }
| 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. |
Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
| 0 | on success. | |
| -1 | on failure. |
Definition at line 894 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().
00895 { 00896 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00897 }
| 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. |
Park the channel chan, and read back the parked location to the host. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context)
| 0 | on success. | |
| -1 | on failure. |
Definition at line 823 of file features.c.
References park_call_full(), and ast_park_call_args::timeout.
Referenced by iax_park_thread(), and sip_park_thread().
00824 { 00825 struct ast_park_call_args args = { 00826 .timeout = timeout, 00827 .extout = extout, 00828 }; 00829 00830 return park_call_full(chan, peer, &args); 00831 }
| const char* ast_parking_ext | ( | void | ) |
Determine system parking extension.
Definition at line 315 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().
00316 { 00317 return parking_ext; 00318 }
| int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
| chan | channel that initiated pickup. |
Walk list of channels, checking it is not itself, channel is pbx one, check that the callgroup for both channels are the same and the channel is ringing. Answer calling channel, flag channel as answered on queue, masq channels together.
Definition at line 4475 of file features.c.
References ast_answer(), ast_channel_masquerade(), ast_channel_search_locked(), ast_channel_unlock, AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), ast_stream_and_wait(), ast_strlen_zero(), find_channel_by_group(), LOG_WARNING, ast_channel::name, pickupfailsound, and pickupsound.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), pickup_exec(), and ss_thread().
04476 { 04477 struct ast_channel *cur = ast_channel_search_locked(find_channel_by_group, chan); 04478 04479 if (cur) { 04480 int res = -1; 04481 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 04482 res = ast_answer(chan); 04483 if (res) 04484 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 04485 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 04486 if (res) 04487 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 04488 res = ast_channel_masquerade(cur, chan); 04489 if (res) 04490 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 04491 if (!ast_strlen_zero(pickupsound)) { 04492 ast_stream_and_wait(cur, pickupsound, ""); 04493 } 04494 ast_channel_unlock(cur); 04495 return res; 04496 } else { 04497 ast_debug(1, "No call pickup possible...\n"); 04498 if (!ast_strlen_zero(pickupfailsound)) { 04499 ast_stream_and_wait(chan, pickupfailsound, ""); 04500 } 04501 } 04502 return -1; 04503 }
| const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 320 of file features.c.
References pickup_ext.
Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().
00321 { 00322 return pickup_ext; 00323 }
| void ast_rdlock_call_features | ( | void | ) |
Definition at line 1874 of file features.c.
References ast_rwlock_rdlock(), and features_lock.
Referenced by handle_request_info().
01875 { 01876 ast_rwlock_rdlock(&features_lock); 01877 }
| 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 1711 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().
01712 { 01713 if (!feature) { 01714 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01715 return; 01716 } 01717 01718 AST_RWLIST_WRLOCK(&feature_list); 01719 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01720 AST_RWLIST_UNLOCK(&feature_list); 01721 01722 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 01723 }
| void ast_unlock_call_features | ( | void | ) |
Definition at line 1879 of file features.c.
References ast_rwlock_unlock(), and features_lock.
Referenced by handle_request_info().
01880 { 01881 ast_rwlock_unlock(&features_lock); 01882 }
| 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 1799 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
01800 { 01801 if (!feature) { 01802 return; 01803 } 01804 01805 AST_RWLIST_WRLOCK(&feature_list); 01806 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01807 AST_RWLIST_UNLOCK(&feature_list); 01808 01809 ast_free(feature); 01810 }
1.6.2