This graph shows which files directly or indirectly include this file:
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 1376 of file res_features.c.
References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), AST_CDR_FLAG_LOCKED, ast_cdr_init(), ast_cdr_merge(), ast_cdr_setdestchan(), ast_cdr_setuserfield(), ast_cdr_start(), ast_channel_bridge(), ast_channel_setoption(), 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_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_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, ast_cdr::channel, config, ast_channel::data, ast_option_header::data, ast_cdr::dstchannel, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.
Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), park_exec(), and try_calling().
01377 { 01378 /* Copy voice back and forth between the two channels. Give the peer 01379 the ability to transfer calls with '#<extension' syntax. */ 01380 struct ast_frame *f; 01381 struct ast_channel *who; 01382 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01383 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01384 int res; 01385 int diff; 01386 int hasfeatures=0; 01387 int hadfeatures=0; 01388 struct ast_option_header *aoh; 01389 struct ast_bridge_config backup_config; 01390 struct ast_cdr *bridge_cdr; 01391 01392 memset(&backup_config, 0, sizeof(backup_config)); 01393 01394 config->start_time = ast_tvnow(); 01395 01396 if (chan && peer) { 01397 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01398 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01399 } else if (chan) 01400 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01401 01402 if (monitor_ok) { 01403 const char *monitor_exec; 01404 struct ast_channel *src = NULL; 01405 if (!monitor_app) { 01406 if (!(monitor_app = pbx_findapp("Monitor"))) 01407 monitor_ok=0; 01408 } 01409 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01410 src = chan; 01411 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01412 src = peer; 01413 if (monitor_app && src) { 01414 char *tmp = ast_strdupa(monitor_exec); 01415 pbx_exec(src, monitor_app, tmp); 01416 } 01417 } 01418 01419 set_config_flags(chan, peer, config); 01420 config->firstpass = 1; 01421 01422 /* Answer if need be */ 01423 if (ast_answer(chan)) 01424 return -1; 01425 peer->appl = "Bridged Call"; 01426 peer->data = chan->name; 01427 01428 /* copy the userfield from the B-leg to A-leg if applicable */ 01429 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01430 char tmp[256]; 01431 if (!ast_strlen_zero(chan->cdr->userfield)) { 01432 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01433 ast_cdr_appenduserfield(chan, tmp); 01434 } else 01435 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01436 /* free the peer's cdr without ast_cdr_free complaining */ 01437 free(peer->cdr); 01438 peer->cdr = NULL; 01439 } 01440 01441 for (;;) { 01442 struct ast_channel *other; /* used later */ 01443 01444 res = ast_channel_bridge(chan, peer, config, &f, &who); 01445 01446 if (config->feature_timer) { 01447 /* Update time limit for next pass */ 01448 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01449 config->feature_timer -= diff; 01450 if (hasfeatures) { 01451 /* Running on backup config, meaning a feature might be being 01452 activated, but that's no excuse to keep things going 01453 indefinitely! */ 01454 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01455 if (option_debug) 01456 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01457 config->feature_timer = 0; 01458 who = chan; 01459 if (f) 01460 ast_frfree(f); 01461 f = NULL; 01462 res = 0; 01463 } else if (config->feature_timer <= 0) { 01464 /* Not *really* out of time, just out of time for 01465 digits to come in for features. */ 01466 if (option_debug) 01467 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01468 if (!ast_strlen_zero(peer_featurecode)) { 01469 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01470 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01471 } 01472 if (!ast_strlen_zero(chan_featurecode)) { 01473 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01474 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01475 } 01476 if (f) 01477 ast_frfree(f); 01478 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01479 if (!hasfeatures) { 01480 /* Restore original (possibly time modified) bridge config */ 01481 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01482 memset(&backup_config, 0, sizeof(backup_config)); 01483 } 01484 hadfeatures = hasfeatures; 01485 /* Continue as we were */ 01486 continue; 01487 } else if (!f) { 01488 /* The bridge returned without a frame and there is a feature in progress. 01489 * However, we don't think the feature has quite yet timed out, so just 01490 * go back into the bridge. */ 01491 continue; 01492 } 01493 } else { 01494 if (config->feature_timer <=0) { 01495 /* We ran out of time */ 01496 config->feature_timer = 0; 01497 who = chan; 01498 if (f) 01499 ast_frfree(f); 01500 f = NULL; 01501 res = 0; 01502 } 01503 } 01504 } 01505 if (res < 0) { 01506 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01507 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01508 return -1; 01509 } 01510 01511 if (!f || (f->frametype == AST_FRAME_CONTROL && 01512 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01513 f->subclass == AST_CONTROL_CONGESTION))) { 01514 res = -1; 01515 break; 01516 } 01517 /* many things should be sent to the 'other' channel */ 01518 other = (who == chan) ? peer : chan; 01519 if (f->frametype == AST_FRAME_CONTROL) { 01520 switch (f->subclass) { 01521 case AST_CONTROL_RINGING: 01522 case AST_CONTROL_FLASH: 01523 case -1: 01524 ast_indicate(other, f->subclass); 01525 break; 01526 case AST_CONTROL_HOLD: 01527 case AST_CONTROL_UNHOLD: 01528 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01529 break; 01530 case AST_CONTROL_OPTION: 01531 aoh = f->data; 01532 /* Forward option Requests */ 01533 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01534 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01535 f->datalen - sizeof(struct ast_option_header), 0); 01536 } 01537 break; 01538 } 01539 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01540 /* eat it */ 01541 } else if (f->frametype == AST_FRAME_DTMF) { 01542 char *featurecode; 01543 int sense; 01544 01545 hadfeatures = hasfeatures; 01546 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01547 if (who == chan) { 01548 sense = FEATURE_SENSE_CHAN; 01549 featurecode = chan_featurecode; 01550 } else { 01551 sense = FEATURE_SENSE_PEER; 01552 featurecode = peer_featurecode; 01553 } 01554 /*! append the event to featurecode. we rely on the string being zero-filled, and 01555 * not overflowing it. 01556 * \todo XXX how do we guarantee the latter ? 01557 */ 01558 featurecode[strlen(featurecode)] = f->subclass; 01559 /* Get rid of the frame before we start doing "stuff" with the channels */ 01560 ast_frfree(f); 01561 f = NULL; 01562 config->feature_timer = backup_config.feature_timer; 01563 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01564 switch(res) { 01565 case FEATURE_RETURN_PASSDIGITS: 01566 ast_dtmf_stream(other, who, featurecode, 0); 01567 /* Fall through */ 01568 case FEATURE_RETURN_SUCCESS: 01569 memset(featurecode, 0, sizeof(chan_featurecode)); 01570 break; 01571 } 01572 if (res >= FEATURE_RETURN_PASSDIGITS) { 01573 res = 0; 01574 } else 01575 break; 01576 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01577 if (hadfeatures && !hasfeatures) { 01578 /* Restore backup */ 01579 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01580 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01581 } else if (hasfeatures) { 01582 if (!hadfeatures) { 01583 /* Backup configuration */ 01584 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01585 /* Setup temporary config options */ 01586 config->play_warning = 0; 01587 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01588 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01589 config->warning_freq = 0; 01590 config->warning_sound = NULL; 01591 config->end_sound = NULL; 01592 config->start_sound = NULL; 01593 config->firstpass = 0; 01594 } 01595 config->start_time = ast_tvnow(); 01596 config->feature_timer = featuredigittimeout; 01597 if (option_debug) 01598 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01599 } 01600 } 01601 if (f) 01602 ast_frfree(f); 01603 01604 } 01605 01606 /* arrange the cdrs */ 01607 bridge_cdr = ast_cdr_alloc(); 01608 if (bridge_cdr) { 01609 if (chan->cdr && peer->cdr) { /* both of them? merge */ 01610 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */ 01611 ast_cdr_start(bridge_cdr); /* now is the time to start */ 01612 01613 /* absorb the channel cdr */ 01614 ast_cdr_merge(bridge_cdr, chan->cdr); 01615 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01616 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01617 01618 /* absorb the peer cdr */ 01619 ast_cdr_merge(bridge_cdr, peer->cdr); 01620 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01621 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */ 01622 01623 peer->cdr = NULL; 01624 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01625 } else if (chan->cdr) { 01626 /* take the cdr from the channel - literally */ 01627 ast_cdr_init(bridge_cdr,chan); 01628 /* absorb this data */ 01629 ast_cdr_merge(bridge_cdr, chan->cdr); 01630 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01631 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01632 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01633 } else if (peer->cdr) { 01634 /* take the cdr from the peer - literally */ 01635 ast_cdr_init(bridge_cdr,peer); 01636 /* absorb this data */ 01637 ast_cdr_merge(bridge_cdr, peer->cdr); 01638 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01639 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01640 peer->cdr = NULL; 01641 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01642 } else { 01643 /* make up a new cdr */ 01644 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */ 01645 chan->cdr = bridge_cdr; /* */ 01646 } 01647 if (ast_strlen_zero(bridge_cdr->dstchannel)) { 01648 if (strcmp(bridge_cdr->channel, peer->name) != 0) 01649 ast_cdr_setdestchan(bridge_cdr, peer->name); 01650 else 01651 ast_cdr_setdestchan(bridge_cdr, chan->name); 01652 } 01653 } 01654 return res; 01655 }
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 477 of file res_features.c.
References ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, 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().
00478 { 00479 struct ast_channel *chan; 00480 struct ast_frame *f; 00481 char *orig_chan_name = NULL; 00482 00483 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00484 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00485 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00486 return -1; 00487 } 00488 00489 /* Make formats okay */ 00490 chan->readformat = rchan->readformat; 00491 chan->writeformat = rchan->writeformat; 00492 ast_channel_masquerade(chan, rchan); 00493 00494 /* Setup the extensions and such */ 00495 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00496 00497 /* Make the masq execute */ 00498 f = ast_read(chan); 00499 if (f) 00500 ast_frfree(f); 00501 00502 orig_chan_name = ast_strdupa(chan->name); 00503 00504 park_call_full(chan, peer, timeout, extout, orig_chan_name); 00505 00506 return 0; 00507 }
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 472 of file res_features.c.
References park_call_full().
Referenced by builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), and sip_park_thread().
00473 { 00474 return park_call_full(chan, peer, timeout, extout, NULL); 00475 }
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 159 of file res_features.c.
Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00160 { 00161 return parking_ext; 00162 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2324 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().
02325 { 02326 struct ast_channel *cur = NULL; 02327 int res = -1; 02328 02329 while ((cur = ast_channel_walk_locked(cur)) != NULL) { 02330 if (!cur->pbx && 02331 (cur != chan) && 02332 (chan->pickupgroup & cur->callgroup) && 02333 ((cur->_state == AST_STATE_RINGING) || 02334 (cur->_state == AST_STATE_RING))) { 02335 break; 02336 } 02337 ast_channel_unlock(cur); 02338 } 02339 if (cur) { 02340 if (option_debug) 02341 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02342 res = ast_answer(chan); 02343 if (res) 02344 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02345 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02346 if (res) 02347 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02348 res = ast_channel_masquerade(cur, chan); 02349 if (res) 02350 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02351 ast_channel_unlock(cur); 02352 } else { 02353 if (option_debug) 02354 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02355 } 02356 return res; 02357 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 164 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00165 { 00166 return pickup_ext; 00167 }
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 945 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.
00946 { 00947 if (!feature) { 00948 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00949 return; 00950 } 00951 00952 AST_LIST_LOCK(&feature_list); 00953 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00954 AST_LIST_UNLOCK(&feature_list); 00955 00956 if (option_verbose >= 2) 00957 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00958 }
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 961 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.
00962 { 00963 if (!feature) 00964 return; 00965 00966 AST_LIST_LOCK(&feature_list); 00967 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00968 AST_LIST_UNLOCK(&feature_list); 00969 free(feature); 00970 }