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