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