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 2397 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_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().
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 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 02482 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02483 } 02484 02485 } else { 02486 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02487 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02488 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02489 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02490 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02491 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02492 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02493 ast_cdr_setcid(bridge_cdr, chan); 02494 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02495 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02496 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02497 /* Destination information */ 02498 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02499 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02500 if (peer_cdr) { 02501 bridge_cdr->start = peer_cdr->start; 02502 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02503 } else { 02504 ast_cdr_start(bridge_cdr); 02505 } 02506 } 02507 ast_debug(4,"bridge answer set, chan answer set\n"); 02508 /* peer_cdr->answer will be set when a macro runs on the peer; 02509 in that case, the bridge answer will be delayed while the 02510 macro plays on the peer channel. The peer answered the call 02511 before the macro started playing. To the phone system, 02512 this is billable time for the call, even tho the caller 02513 hears nothing but ringing while the macro does its thing. */ 02514 02515 /* Another case where the peer cdr's time will be set, is when 02516 A self-parks by pickup up phone and dialing 700, then B 02517 picks up A by dialing its parking slot; there may be more 02518 practical paths that get the same result, tho... in which 02519 case you get the previous answer time from the Park... which 02520 is before the bridge's start time, so I added in the 02521 tvcmp check to the if below */ 02522 02523 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 02524 bridge_cdr->answer = peer_cdr->answer; 02525 bridge_cdr->disposition = peer_cdr->disposition; 02526 if (chan_cdr) { 02527 chan_cdr->answer = peer_cdr->answer; 02528 chan_cdr->disposition = peer_cdr->disposition; 02529 } 02530 } else { 02531 ast_cdr_answer(bridge_cdr); 02532 if (chan_cdr) { 02533 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02534 } 02535 } 02536 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 02537 if (chan_cdr) { 02538 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02539 } 02540 if (peer_cdr) { 02541 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02542 } 02543 } 02544 } 02545 for (;;) { 02546 struct ast_channel *other; /* used later */ 02547 02548 res = ast_channel_bridge(chan, peer, config, &f, &who); 02549 02550 /* When frame is not set, we are probably involved in a situation 02551 where we've timed out. 02552 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02553 and also for DTMF_END. If we flow into the following 'if' for both, then 02554 our wait times are cut in half, as both will subtract from the 02555 feature_timer. Not good! 02556 */ 02557 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02558 /* Update time limit for next pass */ 02559 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02560 if (res == AST_BRIDGE_RETRY) { 02561 /* The feature fully timed out but has not been updated. Skip 02562 * the potential round error from the diff calculation and 02563 * explicitly set to expired. */ 02564 config->feature_timer = -1; 02565 } else { 02566 config->feature_timer -= diff; 02567 } 02568 02569 if (hasfeatures) { 02570 /* Running on backup config, meaning a feature might be being 02571 activated, but that's no excuse to keep things going 02572 indefinitely! */ 02573 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02574 ast_debug(1, "Timed out, realtime this time!\n"); 02575 config->feature_timer = 0; 02576 who = chan; 02577 if (f) 02578 ast_frfree(f); 02579 f = NULL; 02580 res = 0; 02581 } else if (config->feature_timer <= 0) { 02582 /* Not *really* out of time, just out of time for 02583 digits to come in for features. */ 02584 ast_debug(1, "Timed out for feature!\n"); 02585 if (!ast_strlen_zero(peer_featurecode)) { 02586 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02587 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02588 } 02589 if (!ast_strlen_zero(chan_featurecode)) { 02590 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02591 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02592 } 02593 if (f) 02594 ast_frfree(f); 02595 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02596 if (!hasfeatures) { 02597 /* Restore original (possibly time modified) bridge config */ 02598 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02599 memset(&backup_config, 0, sizeof(backup_config)); 02600 } 02601 hadfeatures = hasfeatures; 02602 /* Continue as we were */ 02603 continue; 02604 } else if (!f) { 02605 /* The bridge returned without a frame and there is a feature in progress. 02606 * However, we don't think the feature has quite yet timed out, so just 02607 * go back into the bridge. */ 02608 continue; 02609 } 02610 } else { 02611 if (config->feature_timer <=0) { 02612 /* We ran out of time */ 02613 config->feature_timer = 0; 02614 who = chan; 02615 if (f) 02616 ast_frfree(f); 02617 f = NULL; 02618 res = 0; 02619 } 02620 } 02621 } 02622 if (res < 0) { 02623 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02624 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02625 goto before_you_go; 02626 } 02627 02628 if (!f || (f->frametype == AST_FRAME_CONTROL && 02629 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02630 f->subclass == AST_CONTROL_CONGESTION))) { 02631 res = -1; 02632 break; 02633 } 02634 /* many things should be sent to the 'other' channel */ 02635 other = (who == chan) ? peer : chan; 02636 if (f->frametype == AST_FRAME_CONTROL) { 02637 switch (f->subclass) { 02638 case AST_CONTROL_RINGING: 02639 case AST_CONTROL_FLASH: 02640 case -1: 02641 ast_indicate(other, f->subclass); 02642 break; 02643 case AST_CONTROL_HOLD: 02644 case AST_CONTROL_UNHOLD: 02645 ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); 02646 break; 02647 case AST_CONTROL_OPTION: 02648 aoh = f->data.ptr; 02649 /* Forward option Requests */ 02650 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02651 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02652 f->datalen - sizeof(struct ast_option_header), 0); 02653 } 02654 break; 02655 } 02656 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02657 /* eat it */ 02658 } else if (f->frametype == AST_FRAME_DTMF) { 02659 char *featurecode; 02660 int sense; 02661 02662 hadfeatures = hasfeatures; 02663 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02664 if (who == chan) { 02665 sense = FEATURE_SENSE_CHAN; 02666 featurecode = chan_featurecode; 02667 } else { 02668 sense = FEATURE_SENSE_PEER; 02669 featurecode = peer_featurecode; 02670 } 02671 /*! append the event to featurecode. we rely on the string being zero-filled, and 02672 * not overflowing it. 02673 * \todo XXX how do we guarantee the latter ? 02674 */ 02675 featurecode[strlen(featurecode)] = f->subclass; 02676 /* Get rid of the frame before we start doing "stuff" with the channels */ 02677 ast_frfree(f); 02678 f = NULL; 02679 config->feature_timer = backup_config.feature_timer; 02680 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 02681 switch(res) { 02682 case AST_FEATURE_RETURN_PASSDIGITS: 02683 ast_dtmf_stream(other, who, featurecode, 0, 0); 02684 /* Fall through */ 02685 case AST_FEATURE_RETURN_SUCCESS: 02686 memset(featurecode, 0, sizeof(chan_featurecode)); 02687 break; 02688 } 02689 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 02690 res = 0; 02691 } else 02692 break; 02693 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02694 if (hadfeatures && !hasfeatures) { 02695 /* Restore backup */ 02696 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02697 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02698 } else if (hasfeatures) { 02699 if (!hadfeatures) { 02700 /* Backup configuration */ 02701 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02702 /* Setup temporary config options */ 02703 config->play_warning = 0; 02704 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02705 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02706 config->warning_freq = 0; 02707 config->warning_sound = NULL; 02708 config->end_sound = NULL; 02709 config->start_sound = NULL; 02710 config->firstpass = 0; 02711 } 02712 config->start_time = ast_tvnow(); 02713 config->feature_timer = featuredigittimeout; 02714 ast_debug(1, "Set time limit to %ld\n", config->feature_timer); 02715 } 02716 } 02717 if (f) 02718 ast_frfree(f); 02719 02720 } 02721 before_you_go: 02722 02723 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02724 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02725 if (bridge_cdr) { 02726 ast_cdr_discard(bridge_cdr); 02727 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02728 } 02729 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02730 } 02731 02732 if (config->end_bridge_callback) { 02733 config->end_bridge_callback(config->end_bridge_callback_data); 02734 } 02735 02736 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 02737 * if it were, then chan belongs to a different thread now, and might have been hung up long 02738 * ago. 02739 */ 02740 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02741 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02742 struct ast_cdr *swapper = NULL; 02743 char savelastapp[AST_MAX_EXTENSION]; 02744 char savelastdata[AST_MAX_EXTENSION]; 02745 char save_exten[AST_MAX_EXTENSION]; 02746 int save_prio; 02747 int found = 0; /* set if we find at least one match */ 02748 int spawn_error = 0; 02749 02750 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02751 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02752 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02753 ast_cdr_end(bridge_cdr); 02754 } 02755 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02756 dialplan code operate on it */ 02757 ast_channel_lock(chan); 02758 if (bridge_cdr) { 02759 swapper = chan->cdr; 02760 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02761 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02762 chan->cdr = bridge_cdr; 02763 } 02764 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02765 save_prio = chan->priority; 02766 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02767 chan->priority = 1; 02768 ast_channel_unlock(chan); 02769 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 02770 chan->priority++; 02771 } 02772 if (spawn_error && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num) || ast_check_hangup(chan))) { 02773 /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */ 02774 spawn_error = 0; 02775 } 02776 if (found && spawn_error) { 02777 /* Something bad happened, or a hangup has been requested. */ 02778 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02779 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02780 } 02781 /* swap it back */ 02782 ast_channel_lock(chan); 02783 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02784 chan->priority = save_prio; 02785 if (bridge_cdr) { 02786 if (chan->cdr == bridge_cdr) { 02787 chan->cdr = swapper; 02788 } else { 02789 bridge_cdr = NULL; 02790 } 02791 } 02792 if (!spawn_error) { 02793 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02794 } 02795 ast_channel_unlock(chan); 02796 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02797 if (bridge_cdr) { 02798 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02799 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02800 } 02801 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02802 } 02803 02804 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02805 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02806 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 02807 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02808 02809 /* we can post the bridge CDR at this point */ 02810 if (bridge_cdr) { 02811 ast_cdr_end(bridge_cdr); 02812 ast_cdr_detach(bridge_cdr); 02813 } 02814 02815 /* do a specialized reset on the beginning channel 02816 CDR's, if they still exist, so as not to mess up 02817 issues in future bridges; 02818 02819 Here are the rules of the game: 02820 1. The chan and peer channel pointers will not change 02821 during the life of the bridge. 02822 2. But, in transfers, the channel names will change. 02823 between the time the bridge is started, and the 02824 time the channel ends. 02825 Usually, when a channel changes names, it will 02826 also change CDR pointers. 02827 3. Usually, only one of the two channels (chan or peer) 02828 will change names. 02829 4. Usually, if a channel changes names during a bridge, 02830 it is because of a transfer. Usually, in these situations, 02831 it is normal to see 2 bridges running simultaneously, and 02832 it is not unusual to see the two channels that change 02833 swapped between bridges. 02834 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02835 to attend to; if the chan or peer changed names, 02836 we have the before and after attached CDR's. 02837 */ 02838 02839 if (new_chan_cdr) { 02840 struct ast_channel *chan_ptr = NULL; 02841 02842 if (strcasecmp(orig_channame, chan->name) != 0) { 02843 /* old channel */ 02844 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02845 if (chan_ptr) { 02846 if (!ast_bridged_channel(chan_ptr)) { 02847 struct ast_cdr *cur; 02848 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02849 if (cur == chan_cdr) { 02850 break; 02851 } 02852 } 02853 if (cur) 02854 ast_cdr_specialized_reset(chan_cdr,0); 02855 } 02856 ast_channel_unlock(chan_ptr); 02857 } 02858 /* new channel */ 02859 ast_cdr_specialized_reset(new_chan_cdr,0); 02860 } else { 02861 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02862 } 02863 } 02864 02865 { 02866 struct ast_channel *chan_ptr = NULL; 02867 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02868 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)) 02869 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02870 if (strcasecmp(orig_peername, peer->name) != 0) { 02871 /* old channel */ 02872 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02873 if (chan_ptr) { 02874 if (!ast_bridged_channel(chan_ptr)) { 02875 struct ast_cdr *cur; 02876 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02877 if (cur == peer_cdr) { 02878 break; 02879 } 02880 } 02881 if (cur) 02882 ast_cdr_specialized_reset(peer_cdr,0); 02883 } 02884 ast_channel_unlock(chan_ptr); 02885 } 02886 /* new channel */ 02887 ast_cdr_specialized_reset(new_peer_cdr,0); 02888 } else { 02889 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02890 } 02891 } 02892 02893 return res; 02894 }
| 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 4020 of file features.c.
References load_config().
Referenced by handle_features_reload().
04021 { 04022 int res; 04023 /* Release parking lot list */ 04024 //ASTOBJ_CONTAINER_MARKALL(&parkinglots); 04025 // TODO: I don't think any marking is necessary 04026 04027 /* Reload configuration */ 04028 res = load_config(); 04029 04030 //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy); 04031 return res; 04032 }
| 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. |
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 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. |
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 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. |
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 4404 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().
04405 { 04406 struct ast_channel *cur = NULL; 04407 int res = -1; 04408 04409 while ((cur = ast_channel_walk_locked(cur)) != NULL) { 04410 if (!cur->pbx && 04411 (cur != chan) && 04412 (chan->pickupgroup & cur->callgroup) && 04413 ((cur->_state == AST_STATE_RINGING) || 04414 (cur->_state == AST_STATE_RING))) { 04415 break; 04416 } 04417 ast_channel_unlock(cur); 04418 } 04419 if (cur) { 04420 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 04421 res = ast_answer(chan); 04422 if (res) 04423 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 04424 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 04425 if (res) 04426 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 04427 res = ast_channel_masquerade(cur, chan); 04428 if (res) 04429 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 04430 ast_channel_unlock(cur); 04431 } else { 04432 ast_debug(1, "No call pickup possible...\n"); 04433 } 04434 return res; 04435 }
| 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 1795 of file features.c.
References ast_rwlock_rdlock().
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, 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().
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.6.1