#include "asterisk/pbx.h"
#include "asterisk/linkedlists.h"
Go to the source code of this file.
Data Structures | |
struct | ast_call_feature |
Defines | |
#define | AST_FEATURE_RETURN_HANGUP -1 |
#define | AST_FEATURE_RETURN_KEEPTRYING 24 |
#define | AST_FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
#define | AST_FEATURE_RETURN_PARKFAILED 25 |
#define | AST_FEATURE_RETURN_PASSDIGITS 21 |
#define | AST_FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
#define | AST_FEATURE_RETURN_STOREDIGITS 22 |
#define | AST_FEATURE_RETURN_SUCCESS 23 |
#define | AST_FEATURE_RETURN_SUCCESSBREAK 0 |
#define | FEATURE_APP_ARGS_LEN 256 |
#define | FEATURE_APP_LEN 64 |
#define | FEATURE_EXTEN_LEN 32 |
#define | FEATURE_MAX_LEN 11 |
#define | FEATURE_MOH_LEN 80 |
#define | FEATURE_SENSE_CHAN (1 << 0) |
#define | FEATURE_SENSE_PEER (1 << 1) |
#define | FEATURE_SNAME_LEN 32 |
#define | PARK_APP_NAME "Park" |
Typedefs | |
typedef int(*) | ast_feature_operation (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Enumerations | |
enum | { AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3), AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3) } |
main call feature structure More... | |
Functions | |
int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
Bridge a call, optionally allowing redirection. | |
int | ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature) |
detect a feature before bridging | |
int | ast_features_reload (void) |
Reload call features from features.conf. | |
ast_call_feature * | ast_find_call_feature (const char *name) |
look for a call feature entry by its sname | |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
int | ast_park_call (struct ast_channel *chan, struct ast_channel *host, int timeout, int *extout) |
Park a call and read back parked location. | |
const char * | ast_parking_ext (void) |
Determine system parking extension. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
const char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_rdlock_call_features (void) |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
void | ast_unlock_call_features (void) |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set |
Definition in file features.h.
#define AST_FEATURE_RETURN_HANGUP -1 |
#define AST_FEATURE_RETURN_KEEPTRYING 24 |
Definition at line 46 of file features.h.
Referenced by feature_exec_app(), and feature_interpret_helper().
#define AST_FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
Definition at line 42 of file features.h.
#define AST_FEATURE_RETURN_PARKFAILED 25 |
Definition at line 47 of file features.h.
Referenced by builtin_blindtransfer(), and masq_park_call().
#define AST_FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 43 of file features.h.
Referenced by ast_bridge_call(), and feature_interpret_helper().
#define AST_FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
Definition at line 41 of file features.h.
#define AST_FEATURE_RETURN_STOREDIGITS 22 |
Definition at line 44 of file features.h.
Referenced by detect_disconnect(), and feature_interpret_helper().
#define AST_FEATURE_RETURN_SUCCESS 23 |
Definition at line 45 of file features.h.
Referenced by ast_bridge_call(), builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app().
#define AST_FEATURE_RETURN_SUCCESSBREAK 0 |
#define FEATURE_APP_ARGS_LEN 256 |
Definition at line 32 of file features.h.
#define FEATURE_APP_LEN 64 |
Definition at line 31 of file features.h.
#define FEATURE_EXTEN_LEN 32 |
Definition at line 34 of file features.h.
#define FEATURE_MAX_LEN 11 |
#define FEATURE_MOH_LEN 80 |
Definition at line 35 of file features.h.
#define FEATURE_SENSE_CHAN (1 << 0) |
Definition at line 49 of file features.h.
Referenced by ast_bridge_call(), ast_feature_interpret(), and feature_exec_app().
#define FEATURE_SENSE_PEER (1 << 1) |
#define FEATURE_SNAME_LEN 32 |
Definition at line 33 of file features.h.
#define PARK_APP_NAME "Park" |
typedef int(*) ast_feature_operation(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Definition at line 52 of file features.h.
anonymous enum |
main call feature structure
AST_FEATURE_FLAG_NEEDSDTMF | |
AST_FEATURE_FLAG_ONPEER | |
AST_FEATURE_FLAG_ONSELF | |
AST_FEATURE_FLAG_BYCALLEE | |
AST_FEATURE_FLAG_BYCALLER | |
AST_FEATURE_FLAG_BYBOTH |
Definition at line 56 of file features.h.
00056 { 00057 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00058 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00059 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00060 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00061 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00062 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00063 };
int ast_bridge_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) |
Bridge a call, optionally allowing redirection.
chan,peer,config | Set start time, check for two channels,check if monitor on check for feature activation, create new CDR |
res | on success. | |
-1 | on failure to bridge. |
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 2377 of file features.c.
References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.
Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), park_exec_full(), and try_calling().
02378 { 02379 /* Copy voice back and forth between the two channels. Give the peer 02380 the ability to transfer calls with '#<extension' syntax. */ 02381 struct ast_frame *f; 02382 struct ast_channel *who; 02383 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02384 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02385 char orig_channame[AST_MAX_EXTENSION]; 02386 char orig_peername[AST_MAX_EXTENSION]; 02387 int res; 02388 int diff; 02389 int hasfeatures=0; 02390 int hadfeatures=0; 02391 int autoloopflag; 02392 struct ast_option_header *aoh; 02393 struct ast_bridge_config backup_config; 02394 struct ast_cdr *bridge_cdr = NULL; 02395 struct ast_cdr *orig_peer_cdr = NULL; 02396 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02397 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02398 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02399 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02400 02401 memset(&backup_config, 0, sizeof(backup_config)); 02402 02403 config->start_time = ast_tvnow(); 02404 02405 if (chan && peer) { 02406 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02407 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02408 } else if (chan) { 02409 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02410 } 02411 02412 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02413 add_features_datastores(chan, peer, config); 02414 02415 /* This is an interesting case. One example is if a ringing channel gets redirected to 02416 * an extension that picks up a parked call. This will make sure that the call taken 02417 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02418 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02419 ast_indicate(peer, AST_CONTROL_RINGING); 02420 } 02421 02422 if (monitor_ok) { 02423 const char *monitor_exec; 02424 struct ast_channel *src = NULL; 02425 if (!monitor_app) { 02426 if (!(monitor_app = pbx_findapp("Monitor"))) 02427 monitor_ok=0; 02428 } 02429 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02430 src = chan; 02431 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02432 src = peer; 02433 if (monitor_app && src) { 02434 char *tmp = ast_strdupa(monitor_exec); 02435 pbx_exec(src, monitor_app, tmp); 02436 } 02437 } 02438 02439 set_config_flags(chan, peer, config); 02440 config->firstpass = 1; 02441 02442 /* Answer if need be */ 02443 if (chan->_state != AST_STATE_UP) { 02444 if (ast_raw_answer(chan, 1)) { 02445 return -1; 02446 } 02447 } 02448 02449 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02450 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02451 orig_peer_cdr = peer_cdr; 02452 02453 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02454 02455 if (chan_cdr) { 02456 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02457 ast_cdr_update(chan); 02458 bridge_cdr = ast_cdr_dup(chan_cdr); 02459 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 02460 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 02461 } else { 02462 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02463 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02464 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02465 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02466 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02467 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 02468 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 02469 ast_cdr_setcid(bridge_cdr, chan); 02470 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02471 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02472 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02473 /* Destination information */ 02474 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02475 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02476 if (peer_cdr) { 02477 bridge_cdr->start = peer_cdr->start; 02478 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02479 } else { 02480 ast_cdr_start(bridge_cdr); 02481 } 02482 } 02483 ast_debug(4,"bridge answer set, chan answer set\n"); 02484 /* peer_cdr->answer will be set when a macro runs on the peer; 02485 in that case, the bridge answer will be delayed while the 02486 macro plays on the peer channel. The peer answered the call 02487 before the macro started playing. To the phone system, 02488 this is billable time for the call, even tho the caller 02489 hears nothing but ringing while the macro does its thing. */ 02490 if (peer_cdr && !ast_tvzero(peer_cdr->answer)) { 02491 bridge_cdr->answer = peer_cdr->answer; 02492 chan_cdr->answer = peer_cdr->answer; 02493 bridge_cdr->disposition = peer_cdr->disposition; 02494 chan_cdr->disposition = peer_cdr->disposition; 02495 } else { 02496 ast_cdr_answer(bridge_cdr); 02497 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02498 } 02499 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02500 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02501 if (peer_cdr) { 02502 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02503 } 02504 } 02505 } 02506 for (;;) { 02507 struct ast_channel *other; /* used later */ 02508 02509 res = ast_channel_bridge(chan, peer, config, &f, &who); 02510 02511 /* When frame is not set, we are probably involved in a situation 02512 where we've timed out. 02513 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02514 and also for DTMF_END. If we flow into the following 'if' for both, then 02515 our wait times are cut in half, as both will subtract from the 02516 feature_timer. Not good! 02517 */ 02518 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02519 /* Update time limit for next pass */ 02520 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02521 if (res == AST_BRIDGE_RETRY) { 02522 /* The feature fully timed out but has not been updated. Skip 02523 * the potential round error from the diff calculation and 02524 * explicitly set to expired. */ 02525 config->feature_timer = -1; 02526 } else { 02527 config->feature_timer -= diff; 02528 } 02529 02530 if (hasfeatures) { 02531 /* Running on backup config, meaning a feature might be being 02532 activated, but that's no excuse to keep things going 02533 indefinitely! */ 02534 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02535 ast_debug(1, "Timed out, realtime this time!\n"); 02536 config->feature_timer = 0; 02537 who = chan; 02538 if (f) 02539 ast_frfree(f); 02540 f = NULL; 02541 res = 0; 02542 } else if (config->feature_timer <= 0) { 02543 /* Not *really* out of time, just out of time for 02544 digits to come in for features. */ 02545 ast_debug(1, "Timed out for feature!\n"); 02546 if (!ast_strlen_zero(peer_featurecode)) { 02547 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02548 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02549 } 02550 if (!ast_strlen_zero(chan_featurecode)) { 02551 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02552 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02553 } 02554 if (f) 02555 ast_frfree(f); 02556 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02557 if (!hasfeatures) { 02558 /* Restore original (possibly time modified) bridge config */ 02559 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02560 memset(&backup_config, 0, sizeof(backup_config)); 02561 } 02562 hadfeatures = hasfeatures; 02563 /* Continue as we were */ 02564 continue; 02565 } else if (!f) { 02566 /* The bridge returned without a frame and there is a feature in progress. 02567 * However, we don't think the feature has quite yet timed out, so just 02568 * go back into the bridge. */ 02569 continue; 02570 } 02571 } else { 02572 if (config->feature_timer <=0) { 02573 /* We ran out of time */ 02574 config->feature_timer = 0; 02575 who = chan; 02576 if (f) 02577 ast_frfree(f); 02578 f = NULL; 02579 res = 0; 02580 } 02581 } 02582 } 02583 if (res < 0) { 02584 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02585 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02586 goto before_you_go; 02587 } 02588 02589 if (!f || (f->frametype == AST_FRAME_CONTROL && 02590 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02591 f->subclass == AST_CONTROL_CONGESTION))) { 02592 res = -1; 02593 break; 02594 } 02595 /* many things should be sent to the 'other' channel */ 02596 other = (who == chan) ? peer : chan; 02597 if (f->frametype == AST_FRAME_CONTROL) { 02598 switch (f->subclass) { 02599 case AST_CONTROL_RINGING: 02600 case AST_CONTROL_FLASH: 02601 case -1: 02602 ast_indicate(other, f->subclass); 02603 break; 02604 case AST_CONTROL_HOLD: 02605 case AST_CONTROL_UNHOLD: 02606 ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); 02607 break; 02608 case AST_CONTROL_OPTION: 02609 aoh = f->data.ptr; 02610 /* Forward option Requests */ 02611 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02612 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02613 f->datalen - sizeof(struct ast_option_header), 0); 02614 } 02615 break; 02616 } 02617 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02618 /* eat it */ 02619 } else if (f->frametype == AST_FRAME_DTMF) { 02620 char *featurecode; 02621 int sense; 02622 02623 hadfeatures = hasfeatures; 02624 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02625 if (who == chan) { 02626 sense = FEATURE_SENSE_CHAN; 02627 featurecode = chan_featurecode; 02628 } else { 02629 sense = FEATURE_SENSE_PEER; 02630 featurecode = peer_featurecode; 02631 } 02632 /*! append the event to featurecode. we rely on the string being zero-filled, and 02633 * not overflowing it. 02634 * \todo XXX how do we guarantee the latter ? 02635 */ 02636 featurecode[strlen(featurecode)] = f->subclass; 02637 /* Get rid of the frame before we start doing "stuff" with the channels */ 02638 ast_frfree(f); 02639 f = NULL; 02640 config->feature_timer = backup_config.feature_timer; 02641 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 02642 switch(res) { 02643 case AST_FEATURE_RETURN_PASSDIGITS: 02644 ast_dtmf_stream(other, who, featurecode, 0, 0); 02645 /* Fall through */ 02646 case AST_FEATURE_RETURN_SUCCESS: 02647 memset(featurecode, 0, sizeof(chan_featurecode)); 02648 break; 02649 } 02650 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 02651 res = 0; 02652 } else 02653 break; 02654 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02655 if (hadfeatures && !hasfeatures) { 02656 /* Restore backup */ 02657 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02658 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02659 } else if (hasfeatures) { 02660 if (!hadfeatures) { 02661 /* Backup configuration */ 02662 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02663 /* Setup temporary config options */ 02664 config->play_warning = 0; 02665 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02666 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02667 config->warning_freq = 0; 02668 config->warning_sound = NULL; 02669 config->end_sound = NULL; 02670 config->start_sound = NULL; 02671 config->firstpass = 0; 02672 } 02673 config->start_time = ast_tvnow(); 02674 config->feature_timer = featuredigittimeout; 02675 ast_debug(1, "Set time limit to %ld\n", config->feature_timer); 02676 } 02677 } 02678 if (f) 02679 ast_frfree(f); 02680 02681 } 02682 before_you_go: 02683 02684 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02685 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02686 if (bridge_cdr) { 02687 ast_cdr_discard(bridge_cdr); 02688 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02689 } 02690 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02691 } 02692 02693 if (config->end_bridge_callback) { 02694 config->end_bridge_callback(config->end_bridge_callback_data); 02695 } 02696 02697 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 02698 * if it were, then chan belongs to a different thread now, and might have been hung up long 02699 * ago. 02700 */ 02701 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02702 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02703 struct ast_cdr *swapper = NULL; 02704 char savelastapp[AST_MAX_EXTENSION]; 02705 char savelastdata[AST_MAX_EXTENSION]; 02706 char save_exten[AST_MAX_EXTENSION]; 02707 int save_prio; 02708 int found = 0; /* set if we find at least one match */ 02709 int spawn_error = 0; 02710 02711 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02712 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02713 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02714 ast_cdr_end(bridge_cdr); 02715 } 02716 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02717 dialplan code operate on it */ 02718 ast_channel_lock(chan); 02719 if (bridge_cdr) { 02720 swapper = chan->cdr; 02721 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02722 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02723 chan->cdr = bridge_cdr; 02724 } 02725 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02726 save_prio = chan->priority; 02727 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02728 chan->priority = 1; 02729 ast_channel_unlock(chan); 02730 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 02731 chan->priority++; 02732 } 02733 if (found && spawn_error) { 02734 /* Something bad happened, or a hangup has been requested. */ 02735 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02736 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02737 } 02738 /* swap it back */ 02739 ast_channel_lock(chan); 02740 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02741 chan->priority = save_prio; 02742 if (bridge_cdr) { 02743 if (chan->cdr == bridge_cdr) { 02744 chan->cdr = swapper; 02745 } else { 02746 bridge_cdr = NULL; 02747 } 02748 } 02749 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02750 ast_channel_unlock(chan); 02751 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02752 if (bridge_cdr) { 02753 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02754 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02755 } 02756 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02757 } 02758 02759 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02760 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02761 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 02762 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02763 02764 /* we can post the bridge CDR at this point */ 02765 if (bridge_cdr) { 02766 ast_cdr_end(bridge_cdr); 02767 ast_cdr_detach(bridge_cdr); 02768 } 02769 02770 /* do a specialized reset on the beginning channel 02771 CDR's, if they still exist, so as not to mess up 02772 issues in future bridges; 02773 02774 Here are the rules of the game: 02775 1. The chan and peer channel pointers will not change 02776 during the life of the bridge. 02777 2. But, in transfers, the channel names will change. 02778 between the time the bridge is started, and the 02779 time the channel ends. 02780 Usually, when a channel changes names, it will 02781 also change CDR pointers. 02782 3. Usually, only one of the two channels (chan or peer) 02783 will change names. 02784 4. Usually, if a channel changes names during a bridge, 02785 it is because of a transfer. Usually, in these situations, 02786 it is normal to see 2 bridges running simultaneously, and 02787 it is not unusual to see the two channels that change 02788 swapped between bridges. 02789 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02790 to attend to; if the chan or peer changed names, 02791 we have the before and after attached CDR's. 02792 */ 02793 02794 if (new_chan_cdr) { 02795 struct ast_channel *chan_ptr = NULL; 02796 02797 if (strcasecmp(orig_channame, chan->name) != 0) { 02798 /* old channel */ 02799 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02800 if (chan_ptr) { 02801 if (!ast_bridged_channel(chan_ptr)) { 02802 struct ast_cdr *cur; 02803 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02804 if (cur == chan_cdr) { 02805 break; 02806 } 02807 } 02808 if (cur) 02809 ast_cdr_specialized_reset(chan_cdr,0); 02810 } 02811 ast_channel_unlock(chan_ptr); 02812 } 02813 /* new channel */ 02814 ast_cdr_specialized_reset(new_chan_cdr,0); 02815 } else { 02816 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02817 } 02818 } 02819 02820 { 02821 struct ast_channel *chan_ptr = NULL; 02822 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02823 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)) 02824 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02825 if (strcasecmp(orig_peername, peer->name) != 0) { 02826 /* old channel */ 02827 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02828 if (chan_ptr) { 02829 if (!ast_bridged_channel(chan_ptr)) { 02830 struct ast_cdr *cur; 02831 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02832 if (cur == peer_cdr) { 02833 break; 02834 } 02835 } 02836 if (cur) 02837 ast_cdr_specialized_reset(peer_cdr,0); 02838 } 02839 ast_channel_unlock(chan_ptr); 02840 } 02841 /* new channel */ 02842 ast_cdr_specialized_reset(new_peer_cdr,0); 02843 } else { 02844 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02845 } 02846 } 02847 02848 return res; 02849 }
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 2042 of file features.c.
References chan, feature_group_exten::feature, and feature_interpret_helper().
Referenced by detect_disconnect().
02042 { 02043 02044 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 02045 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 3969 of file features.c.
References load_config().
Referenced by handle_features_reload().
03970 { 03971 int res; 03972 /* Release parking lot list */ 03973 //ASTOBJ_CONTAINER_MARKALL(&parkinglots); 03974 // TODO: I don't think any marking is necessary 03975 03976 /* Reload configuration */ 03977 res = load_config(); 03978 03979 //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy); 03980 return res; 03981 }
struct ast_call_feature* ast_find_call_feature | ( | const char * | name | ) |
look for a call feature entry by its sname
name | a string ptr, should match "automon", "blindxfer", "atxfer", etc. |
Definition at line 1795 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
01796 { 01797 int x; 01798 for (x = 0; x < FEATURES_COUNT; x++) { 01799 if (!strcasecmp(name, builtin_features[x].sname)) 01800 return &builtin_features[x]; 01801 } 01802 return NULL; 01803 }
int ast_masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call via a masqueraded channel.
rchan | the real channel to be parked | |
host | the channel to have the parking read to. | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
0 | on success. | |
-1 | on failure. |
Definition at line 808 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().
00809 { 00810 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00811 }
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call and read back parked location.
chan | the channel to actually be parked | |
host | the channel which will have the parked location read to. | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
0 | on success. | |
-1 | on failure. |
Definition at line 742 of file features.c.
References ast_park_call_full(), chan, and ast_park_call_args::timeout.
Referenced by iax_park_thread(), and sip_park_thread().
00743 { 00744 struct ast_park_call_args args = { 00745 .timeout = timeout, 00746 .extout = extout, 00747 }; 00748 00749 return ast_park_call_full(chan, peer, &args); 00750 }
const char* ast_parking_ext | ( | void | ) |
Determine system parking extension.
Definition at line 242 of file features.c.
References parking_ext.
Referenced by build_parkinglot(), builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00243 { 00244 return parking_ext; 00245 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
Definition at line 4353 of file features.c.
References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, chan, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), pickup_exec(), and ss_thread().
04354 { 04355 struct ast_channel *cur = NULL; 04356 int res = -1; 04357 04358 while ((cur = ast_channel_walk_locked(cur)) != NULL) { 04359 if (!cur->pbx && 04360 (cur != chan) && 04361 (chan->pickupgroup & cur->callgroup) && 04362 ((cur->_state == AST_STATE_RINGING) || 04363 (cur->_state == AST_STATE_RING))) { 04364 break; 04365 } 04366 ast_channel_unlock(cur); 04367 } 04368 if (cur) { 04369 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 04370 res = ast_answer(chan); 04371 if (res) 04372 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 04373 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 04374 if (res) 04375 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 04376 res = ast_channel_masquerade(cur, chan); 04377 if (res) 04378 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 04379 ast_channel_unlock(cur); 04380 } else { 04381 ast_debug(1, "No call pickup possible...\n"); 04382 } 04383 return res; 04384 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 247 of file features.c.
References pickup_ext.
Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().
00248 { 00249 return pickup_ext; 00250 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 1785 of file features.c.
References ast_rwlock_rdlock(), and features_lock.
Referenced by handle_request_info().
01786 { 01787 ast_rwlock_rdlock(&features_lock); 01788 }
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 1622 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, feature_group_exten::feature, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
01623 { 01624 if (!feature) { 01625 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01626 return; 01627 } 01628 01629 AST_RWLIST_WRLOCK(&feature_list); 01630 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01631 AST_RWLIST_UNLOCK(&feature_list); 01632 01633 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 01634 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 1790 of file features.c.
References ast_rwlock_unlock(), and features_lock.
Referenced by handle_request_info().
01791 { 01792 ast_rwlock_unlock(&features_lock); 01793 }
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 1710 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
01711 { 01712 if (!feature) { 01713 return; 01714 } 01715 01716 AST_RWLIST_WRLOCK(&feature_list); 01717 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01718 AST_RWLIST_UNLOCK(&feature_list); 01719 01720 ast_free(feature); 01721 }