Go to the source code of this file.
Data Structures | |
struct | ast_call_feature |
main call feature structure More... | |
Defines | |
#define | FEATURE_APP_ARGS_LEN 256 |
#define | FEATURE_APP_LEN 64 |
#define | FEATURE_EXTEN_LEN 32 |
#define | FEATURE_MAX_LEN 11 |
#define | FEATURE_MOH_LEN 80 |
#define | FEATURE_SNAME_LEN 32 |
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_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. | |
char * | ast_parking_ext (void) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set |
Definition in file features.h.
#define FEATURE_APP_ARGS_LEN 256 |
Definition at line 29 of file features.h.
#define FEATURE_APP_LEN 64 |
Definition at line 28 of file features.h.
#define FEATURE_EXTEN_LEN 32 |
Definition at line 31 of file features.h.
#define FEATURE_MAX_LEN 11 |
#define FEATURE_MOH_LEN 80 |
Definition at line 32 of file features.h.
#define FEATURE_SNAME_LEN 32 |
Definition at line 30 of file features.h.
int ast_bridge_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) |
Bridge a call, optionally allowing redirection.
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 1446 of file res_features.c.
References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_answer(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, ast_cdr_isset_unanswered(), 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_ATXFERCMD, 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_default_amaflags, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_OPTION_FLAG_REQUEST, ast_set_flag, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, ast_cdr::channel, cmd_atxfer(), config, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::end, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, ast_cdr::next, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.
Referenced by app_exec(), ast_bridge_call_thread(), do_atxfer(), park_exec(), and try_calling().
01447 { 01448 /* Copy voice back and forth between the two channels. Give the peer 01449 the ability to transfer calls with '#<extension' syntax. */ 01450 struct ast_frame *f; 01451 struct ast_channel *who; 01452 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01453 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01454 char orig_channame[AST_MAX_EXTENSION]; 01455 char orig_peername[AST_MAX_EXTENSION]; 01456 01457 int res; 01458 int diff; 01459 int hasfeatures=0; 01460 int hadfeatures=0; 01461 struct ast_option_header *aoh; 01462 struct ast_bridge_config backup_config; 01463 struct ast_cdr *bridge_cdr = NULL; 01464 struct ast_cdr *orig_peer_cdr = NULL; 01465 01466 memset(&backup_config, 0, sizeof(backup_config)); 01467 01468 config->start_time = ast_tvnow(); 01469 01470 if (chan && peer) { 01471 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01472 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01473 } else if (chan) 01474 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01475 01476 if (monitor_ok) { 01477 const char *monitor_exec; 01478 struct ast_channel *src = NULL; 01479 if (!monitor_app) { 01480 if (!(monitor_app = pbx_findapp("Monitor"))) 01481 monitor_ok=0; 01482 } 01483 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01484 src = chan; 01485 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01486 src = peer; 01487 if (monitor_app && src) { 01488 char *tmp = ast_strdupa(monitor_exec); 01489 pbx_exec(src, monitor_app, tmp); 01490 } 01491 } 01492 01493 set_config_flags(chan, peer, config); 01494 config->firstpass = 1; 01495 01496 /* Answer if need be */ 01497 if (ast_answer(chan)) 01498 return -1; 01499 01500 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 01501 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 01502 orig_peer_cdr = peer->cdr; 01503 01504 if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) { 01505 01506 if (chan->cdr) { 01507 ast_set_flag(chan->cdr, AST_CDR_FLAG_MAIN); 01508 ast_cdr_update(chan); 01509 bridge_cdr = ast_cdr_dup(chan->cdr); 01510 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 01511 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 01512 } else { 01513 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 01514 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 01515 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 01516 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 01517 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 01518 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 01519 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 01520 ast_cdr_setcid(bridge_cdr, chan); 01521 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 01522 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 01523 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 01524 /* Destination information */ 01525 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 01526 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 01527 if (peer->cdr) { 01528 bridge_cdr->start = peer->cdr->start; 01529 ast_copy_string(bridge_cdr->userfield, peer->cdr->userfield, sizeof(bridge_cdr->userfield)); 01530 } else { 01531 ast_cdr_start(bridge_cdr); 01532 } 01533 } 01534 /* peer->cdr->answer will be set when a macro runs on the peer; 01535 in that case, the bridge answer will be delayed while the 01536 macro plays on the peer channel. The peer answered the call 01537 before the macro started playing. To the phone system, 01538 this is billable time for the call, even tho the caller 01539 hears nothing but ringing while the macro does its thing. */ 01540 if (peer->cdr && !ast_tvzero(peer->cdr->answer)) { 01541 bridge_cdr->answer = peer->cdr->answer; 01542 chan->cdr->answer = peer->cdr->answer; 01543 } else { 01544 ast_cdr_answer(bridge_cdr); 01545 ast_cdr_answer(chan->cdr); /* for the sake of cli status checks */ 01546 } 01547 ast_set_flag(chan->cdr, AST_CDR_FLAG_BRIDGED); 01548 if (peer->cdr) { 01549 ast_set_flag(peer->cdr, AST_CDR_FLAG_BRIDGED); 01550 } 01551 } 01552 01553 for (;;) { 01554 struct ast_channel *other; /* used later */ 01555 01556 res = ast_channel_bridge(chan, peer, config, &f, &who); 01557 01558 if (config->feature_timer) { 01559 /* Update time limit for next pass */ 01560 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01561 config->feature_timer -= diff; 01562 if (hasfeatures) { 01563 /* Running on backup config, meaning a feature might be being 01564 activated, but that's no excuse to keep things going 01565 indefinitely! */ 01566 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01567 if (option_debug) 01568 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01569 config->feature_timer = 0; 01570 who = chan; 01571 if (f) 01572 ast_frfree(f); 01573 f = NULL; 01574 res = 0; 01575 } else if (config->feature_timer <= 0) { 01576 /* Not *really* out of time, just out of time for 01577 digits to come in for features. */ 01578 if (option_debug) 01579 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01580 if (!ast_strlen_zero(peer_featurecode)) { 01581 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01582 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01583 } 01584 if (!ast_strlen_zero(chan_featurecode)) { 01585 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01586 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01587 } 01588 if (f) 01589 ast_frfree(f); 01590 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01591 if (!hasfeatures) { 01592 /* Restore original (possibly time modified) bridge config */ 01593 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01594 memset(&backup_config, 0, sizeof(backup_config)); 01595 } 01596 hadfeatures = hasfeatures; 01597 /* Continue as we were */ 01598 continue; 01599 } else if (!f) { 01600 /* The bridge returned without a frame and there is a feature in progress. 01601 * However, we don't think the feature has quite yet timed out, so just 01602 * go back into the bridge. */ 01603 continue; 01604 } 01605 } else { 01606 if (config->feature_timer <=0) { 01607 /* We ran out of time */ 01608 config->feature_timer = 0; 01609 who = chan; 01610 if (f) 01611 ast_frfree(f); 01612 f = NULL; 01613 res = 0; 01614 } 01615 } 01616 } 01617 if (res < 0) { 01618 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01619 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01620 goto before_you_go; 01621 } 01622 01623 if (!f || (f->frametype == AST_FRAME_CONTROL && 01624 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01625 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01626 res = -1; 01627 break; 01628 } 01629 /* many things should be sent to the 'other' channel */ 01630 other = (who == chan) ? peer : chan; 01631 if (f->frametype == AST_FRAME_CONTROL) { 01632 switch (f->subclass) { 01633 case AST_CONTROL_RINGING: 01634 case AST_CONTROL_FLASH: 01635 case -1: 01636 ast_indicate(other, f->subclass); 01637 break; 01638 case AST_CONTROL_HOLD: 01639 case AST_CONTROL_UNHOLD: 01640 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01641 break; 01642 case AST_CONTROL_OPTION: 01643 aoh = f->data; 01644 /* Forward option Requests */ 01645 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01646 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01647 f->datalen - sizeof(struct ast_option_header), 0); 01648 } 01649 break; 01650 case AST_CONTROL_ATXFERCMD: 01651 cmd_atxfer(chan, peer, config, who, f->data); 01652 break; 01653 } 01654 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01655 /* eat it */ 01656 } else if (f->frametype == AST_FRAME_DTMF) { 01657 char *featurecode; 01658 int sense; 01659 01660 hadfeatures = hasfeatures; 01661 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01662 if (who == chan) { 01663 sense = FEATURE_SENSE_CHAN; 01664 featurecode = chan_featurecode; 01665 } else { 01666 sense = FEATURE_SENSE_PEER; 01667 featurecode = peer_featurecode; 01668 } 01669 /*! append the event to featurecode. we rely on the string being zero-filled, and 01670 * not overflowing it. 01671 * \todo XXX how do we guarantee the latter ? 01672 */ 01673 featurecode[strlen(featurecode)] = f->subclass; 01674 /* Get rid of the frame before we start doing "stuff" with the channels */ 01675 ast_frfree(f); 01676 f = NULL; 01677 config->feature_timer = backup_config.feature_timer; 01678 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01679 switch(res) { 01680 case FEATURE_RETURN_PASSDIGITS: 01681 ast_dtmf_stream(other, who, featurecode, 0); 01682 /* Fall through */ 01683 case FEATURE_RETURN_SUCCESS: 01684 memset(featurecode, 0, sizeof(chan_featurecode)); 01685 break; 01686 } 01687 if (res >= FEATURE_RETURN_PASSDIGITS) { 01688 res = 0; 01689 } else 01690 break; 01691 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01692 if (hadfeatures && !hasfeatures) { 01693 /* Restore backup */ 01694 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01695 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01696 } else if (hasfeatures) { 01697 if (!hadfeatures) { 01698 /* Backup configuration */ 01699 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01700 /* Setup temporary config options */ 01701 config->play_warning = 0; 01702 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01703 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01704 config->warning_freq = 0; 01705 config->warning_sound = NULL; 01706 config->end_sound = NULL; 01707 config->start_sound = NULL; 01708 config->firstpass = 0; 01709 } 01710 config->start_time = ast_tvnow(); 01711 config->feature_timer = featuredigittimeout; 01712 if (option_debug) 01713 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01714 } 01715 } 01716 if (f) 01717 ast_frfree(f); 01718 01719 } 01720 before_you_go: 01721 /* obey the NoCDR() wishes. */ 01722 if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) { 01723 01724 ast_cdr_end(bridge_cdr); 01725 01726 ast_cdr_detach(bridge_cdr); 01727 01728 /* just in case, these channels get bridged again before hangup */ 01729 if (chan->cdr) { 01730 ast_cdr_specialized_reset(chan->cdr,0); 01731 } 01732 if (peer->cdr) { 01733 struct ast_cdr *cur; 01734 01735 ast_channel_lock(peer); 01736 for (cur = peer->cdr; cur; cur = cur->next) { 01737 if (cur == orig_peer_cdr) { 01738 break; 01739 } 01740 } 01741 01742 if (!cur) { 01743 /* orig_peer_cdr is gone, probably because of a masquerade 01744 * during the bridge. */ 01745 ast_channel_unlock(peer); 01746 return res; 01747 } 01748 01749 /* before resetting the peer cdr, throw a copy of it to the 01750 backend, just in case the cdr.conf file is calling for 01751 unanswered CDR's. */ 01752 01753 /* When peer->cdr isn't the same addr as orig_peer_cdr, 01754 this can only happen if there was a transfer, methinks; 01755 at any rate, only pay attention to the original*/ 01756 if (ast_cdr_isset_unanswered()) { 01757 struct ast_cdr *dupd = ast_cdr_dup(orig_peer_cdr); 01758 if (dupd) { 01759 if (ast_tvzero(dupd->end) && ast_cdr_isset_unanswered()) 01760 ast_cdr_end(dupd); 01761 ast_cdr_detach(dupd); 01762 } 01763 } 01764 ast_cdr_specialized_reset(orig_peer_cdr,0); 01765 ast_channel_unlock(peer); 01766 } 01767 } 01768 return res; 01769 }
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 Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want |
Definition at line 481 of file res_features.c.
References ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_channel::context, ast_channel::exten, f, LOG_WARNING, park_call_full(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.
Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().
00482 { 00483 struct ast_channel *chan; 00484 struct ast_frame *f; 00485 char *orig_chan_name = NULL; 00486 int park_status; 00487 00488 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00489 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00490 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00491 return -1; 00492 } 00493 00494 /* Make formats okay */ 00495 chan->readformat = rchan->readformat; 00496 chan->writeformat = rchan->writeformat; 00497 ast_channel_masquerade(chan, rchan); 00498 00499 /* Setup the extensions and such */ 00500 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00501 00502 /* Make the masq execute */ 00503 f = ast_read(chan); 00504 if (f) 00505 ast_frfree(f); 00506 00507 orig_chan_name = ast_strdupa(chan->name); 00508 00509 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name); 00510 if (park_status == 1) { 00511 /* would be nice to play: "invalid parking extension" */ 00512 ast_hangup(chan); 00513 return -1; 00514 } 00515 00516 return 0; 00517 }
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call and read back parked location.
Definition at line 476 of file res_features.c.
References park_call_full().
Referenced by builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), and sip_park_thread().
00477 { 00478 return park_call_full(chan, peer, timeout, extout, NULL); 00479 }
char* ast_parking_ext | ( | void | ) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
Definition at line 160 of file res_features.c.
Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00161 { 00162 return parking_ext; 00163 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2333 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), and ss_thread().
02334 { 02335 struct ast_channel *cur = NULL; 02336 int res = -1; 02337 02338 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02339 if (!cur->pbx && 02340 (cur != chan) && 02341 (chan->pickupgroup & cur->callgroup) && 02342 ((cur->_state == AST_STATE_RINGING) || 02343 (cur->_state == AST_STATE_RING))) { 02344 break; 02345 } 02346 ast_channel_unlock(cur); 02347 } 02348 if (cur) { 02349 if (option_debug) 02350 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02351 res = ast_answer(chan); 02352 if (res) 02353 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02354 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02355 if (res) 02356 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02357 res = ast_channel_masquerade(cur, chan); 02358 if (res) 02359 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02360 ast_channel_unlock(cur); 02361 } else { 02362 if (option_debug) 02363 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02364 } 02365 return res; 02366 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 165 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00166 { 00167 return pickup_ext; 00168 }
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 1023 of file res_features.c.
References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_verbose(), LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.
01024 { 01025 if (!feature) { 01026 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01027 return; 01028 } 01029 01030 AST_LIST_LOCK(&feature_list); 01031 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01032 AST_LIST_UNLOCK(&feature_list); 01033 01034 if (option_verbose >= 2) 01035 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 01036 }
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 1039 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.
01040 { 01041 if (!feature) 01042 return; 01043 01044 AST_LIST_LOCK(&feature_list); 01045 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 01046 AST_LIST_UNLOCK(&feature_list); 01047 free(feature); 01048 }