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 |
#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 |
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 1326 of file res_features.c.
Referenced by app_exec(), ast_bridge_call_thread(), builtin_atxfer(), park_exec(), and try_calling().
01327 { 01328 /* Copy voice back and forth between the two channels. Give the peer 01329 the ability to transfer calls with '#<extension' syntax. */ 01330 struct ast_frame *f; 01331 struct ast_channel *who; 01332 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01333 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01334 int res; 01335 int diff; 01336 int hasfeatures=0; 01337 int hadfeatures=0; 01338 struct ast_option_header *aoh; 01339 struct ast_bridge_config backup_config; 01340 struct ast_cdr *bridge_cdr; 01341 01342 memset(&backup_config, 0, sizeof(backup_config)); 01343 01344 config->start_time = ast_tvnow(); 01345 01346 if (chan && peer) { 01347 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01348 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01349 } else if (chan) 01350 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01351 01352 if (monitor_ok) { 01353 const char *monitor_exec; 01354 struct ast_channel *src = NULL; 01355 if (!monitor_app) { 01356 if (!(monitor_app = pbx_findapp("Monitor"))) 01357 monitor_ok=0; 01358 } 01359 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01360 src = chan; 01361 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01362 src = peer; 01363 if (monitor_app && src) { 01364 char *tmp = ast_strdupa(monitor_exec); 01365 pbx_exec(src, monitor_app, tmp); 01366 } 01367 } 01368 01369 set_config_flags(chan, peer, config); 01370 config->firstpass = 1; 01371 01372 /* Answer if need be */ 01373 if (ast_answer(chan)) 01374 return -1; 01375 peer->appl = "Bridged Call"; 01376 peer->data = chan->name; 01377 01378 /* copy the userfield from the B-leg to A-leg if applicable */ 01379 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01380 char tmp[256]; 01381 if (!ast_strlen_zero(chan->cdr->userfield)) { 01382 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01383 ast_cdr_appenduserfield(chan, tmp); 01384 } else 01385 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01386 /* free the peer's cdr without ast_cdr_free complaining */ 01387 free(peer->cdr); 01388 peer->cdr = NULL; 01389 } 01390 01391 for (;;) { 01392 struct ast_channel *other; /* used later */ 01393 01394 res = ast_channel_bridge(chan, peer, config, &f, &who); 01395 01396 if (config->feature_timer) { 01397 /* Update time limit for next pass */ 01398 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01399 config->feature_timer -= diff; 01400 if (hasfeatures) { 01401 /* Running on backup config, meaning a feature might be being 01402 activated, but that's no excuse to keep things going 01403 indefinitely! */ 01404 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01405 if (option_debug) 01406 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01407 config->feature_timer = 0; 01408 who = chan; 01409 if (f) 01410 ast_frfree(f); 01411 f = NULL; 01412 res = 0; 01413 } else if (config->feature_timer <= 0) { 01414 /* Not *really* out of time, just out of time for 01415 digits to come in for features. */ 01416 if (option_debug) 01417 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01418 if (!ast_strlen_zero(peer_featurecode)) { 01419 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01420 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01421 } 01422 if (!ast_strlen_zero(chan_featurecode)) { 01423 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01424 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01425 } 01426 if (f) 01427 ast_frfree(f); 01428 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01429 if (!hasfeatures) { 01430 /* Restore original (possibly time modified) bridge config */ 01431 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01432 memset(&backup_config, 0, sizeof(backup_config)); 01433 } 01434 hadfeatures = hasfeatures; 01435 /* Continue as we were */ 01436 continue; 01437 } else if (!f) { 01438 /* The bridge returned without a frame and there is a feature in progress. 01439 * However, we don't think the feature has quite yet timed out, so just 01440 * go back into the bridge. */ 01441 continue; 01442 } 01443 } else { 01444 if (config->feature_timer <=0) { 01445 /* We ran out of time */ 01446 config->feature_timer = 0; 01447 who = chan; 01448 if (f) 01449 ast_frfree(f); 01450 f = NULL; 01451 res = 0; 01452 } 01453 } 01454 } 01455 if (res < 0) { 01456 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01457 return -1; 01458 } 01459 01460 if (!f || (f->frametype == AST_FRAME_CONTROL && 01461 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01462 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01463 res = -1; 01464 break; 01465 } 01466 /* many things should be sent to the 'other' channel */ 01467 other = (who == chan) ? peer : chan; 01468 if (f->frametype == AST_FRAME_CONTROL) { 01469 switch (f->subclass) { 01470 case AST_CONTROL_RINGING: 01471 case AST_CONTROL_FLASH: 01472 case -1: 01473 ast_indicate(other, f->subclass); 01474 break; 01475 case AST_CONTROL_HOLD: 01476 case AST_CONTROL_UNHOLD: 01477 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01478 break; 01479 case AST_CONTROL_OPTION: 01480 aoh = f->data; 01481 /* Forward option Requests */ 01482 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01483 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01484 f->datalen - sizeof(struct ast_option_header), 0); 01485 } 01486 break; 01487 } 01488 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01489 /* eat it */ 01490 } else if (f->frametype == AST_FRAME_DTMF) { 01491 char *featurecode; 01492 int sense; 01493 01494 hadfeatures = hasfeatures; 01495 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01496 if (who == chan) { 01497 sense = FEATURE_SENSE_CHAN; 01498 featurecode = chan_featurecode; 01499 } else { 01500 sense = FEATURE_SENSE_PEER; 01501 featurecode = peer_featurecode; 01502 } 01503 /*! append the event to featurecode. we rely on the string being zero-filled, and 01504 * not overflowing it. 01505 * \todo XXX how do we guarantee the latter ? 01506 */ 01507 featurecode[strlen(featurecode)] = f->subclass; 01508 /* Get rid of the frame before we start doing "stuff" with the channels */ 01509 ast_frfree(f); 01510 f = NULL; 01511 config->feature_timer = backup_config.feature_timer; 01512 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01513 switch(res) { 01514 case FEATURE_RETURN_PASSDIGITS: 01515 ast_dtmf_stream(other, who, featurecode, 0); 01516 /* Fall through */ 01517 case FEATURE_RETURN_SUCCESS: 01518 memset(featurecode, 0, sizeof(chan_featurecode)); 01519 break; 01520 } 01521 if (res >= FEATURE_RETURN_PASSDIGITS) { 01522 res = 0; 01523 } else 01524 break; 01525 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01526 if (hadfeatures && !hasfeatures) { 01527 /* Restore backup */ 01528 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01529 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01530 } else if (hasfeatures) { 01531 if (!hadfeatures) { 01532 /* Backup configuration */ 01533 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01534 /* Setup temporary config options */ 01535 config->play_warning = 0; 01536 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01537 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01538 config->warning_freq = 0; 01539 config->warning_sound = NULL; 01540 config->end_sound = NULL; 01541 config->start_sound = NULL; 01542 config->firstpass = 0; 01543 } 01544 config->start_time = ast_tvnow(); 01545 config->feature_timer = featuredigittimeout; 01546 if (option_debug) 01547 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01548 } 01549 } 01550 if (f) 01551 ast_frfree(f); 01552 01553 } 01554 01555 /* arrange the cdrs */ 01556 bridge_cdr = ast_cdr_alloc(); 01557 if (bridge_cdr) { 01558 if (chan->cdr && peer->cdr) { /* both of them? merge */ 01559 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */ 01560 ast_cdr_start(bridge_cdr); /* now is the time to start */ 01561 01562 /* absorb the channel cdr */ 01563 ast_cdr_merge(bridge_cdr, chan->cdr); 01564 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01565 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01566 01567 /* absorb the peer cdr */ 01568 ast_cdr_merge(bridge_cdr, peer->cdr); 01569 if (ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01570 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */ 01571 01572 peer->cdr = NULL; 01573 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01574 } else if (chan->cdr) { 01575 /* take the cdr from the channel - literally */ 01576 ast_cdr_init(bridge_cdr,chan); 01577 /* absorb this data */ 01578 ast_cdr_merge(bridge_cdr, chan->cdr); 01579 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01580 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01581 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01582 } else if (peer->cdr) { 01583 /* take the cdr from the peer - literally */ 01584 ast_cdr_init(bridge_cdr,peer); 01585 /* absorb this data */ 01586 ast_cdr_merge(bridge_cdr, peer->cdr); 01587 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01588 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01589 peer->cdr = NULL; 01590 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01591 } else { 01592 /* make up a new cdr */ 01593 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */ 01594 chan->cdr = bridge_cdr; /* */ 01595 } 01596 if (ast_strlen_zero(bridge_cdr->dstchannel)) { 01597 if (strcmp(bridge_cdr->channel, peer->name) != 0) 01598 ast_cdr_setdestchan(bridge_cdr, peer->name); 01599 else 01600 ast_cdr_setdestchan(bridge_cdr, chan->name); 01601 } 01602 } 01603 return res; 01604 }
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 442 of file res_features.c.
Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().
00443 { 00444 struct ast_channel *chan; 00445 struct ast_frame *f; 00446 00447 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00448 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00449 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00450 return -1; 00451 } 00452 00453 /* Make formats okay */ 00454 chan->readformat = rchan->readformat; 00455 chan->writeformat = rchan->writeformat; 00456 ast_channel_masquerade(chan, rchan); 00457 00458 /* Setup the extensions and such */ 00459 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00460 00461 /* Make the masq execute */ 00462 f = ast_read(chan); 00463 if (f) 00464 ast_frfree(f); 00465 00466 ast_park_call(chan, peer, timeout, extout); 00467 return 0; 00468 }
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 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) | |
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 311 of file res_features.c.
Referenced by ast_masq_park_call(), builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), park_call_exec(), and sip_park_thread().
00312 { 00313 struct parkeduser *pu, *cur; 00314 int i, x = -1, parking_range; 00315 struct ast_context *con; 00316 const char *parkingexten; 00317 00318 /* Allocate memory for parking data */ 00319 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00320 return -1; 00321 00322 /* Lock parking lot */ 00323 ast_mutex_lock(&parking_lock); 00324 /* Check for channel variable PARKINGEXTEN */ 00325 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00326 if (!ast_strlen_zero(parkingexten)) { 00327 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) { 00328 ast_mutex_unlock(&parking_lock); 00329 free(pu); 00330 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00331 return -1; /* We failed to park this call, plain and simple so we need to error out */ 00332 } 00333 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten)); 00334 x = atoi(parkingexten); 00335 } else { 00336 /* Select parking space within range */ 00337 parking_range = parking_stop - parking_start+1; 00338 for (i = 0; i < parking_range; i++) { 00339 x = (i + parking_offset) % parking_range + parking_start; 00340 cur = parkinglot; 00341 while(cur) { 00342 if (cur->parkingnum == x) 00343 break; 00344 cur = cur->next; 00345 } 00346 if (!cur) 00347 break; 00348 } 00349 00350 if (!(i < parking_range)) { 00351 ast_log(LOG_WARNING, "No more parking spaces\n"); 00352 free(pu); 00353 ast_mutex_unlock(&parking_lock); 00354 return -1; 00355 } 00356 /* Set pointer for next parking */ 00357 if (parkfindnext) 00358 parking_offset = x - parking_start + 1; 00359 } 00360 00361 chan->appl = "Parked Call"; 00362 chan->data = NULL; 00363 00364 pu->chan = chan; 00365 00366 /* Put the parked channel on hold if we have two different channels */ 00367 if (chan != peer) { 00368 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00369 S_OR(parkmohclass, NULL), 00370 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00371 } 00372 00373 pu->start = ast_tvnow(); 00374 pu->parkingnum = x; 00375 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00376 if (extout) 00377 *extout = x; 00378 00379 if (peer) 00380 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername)); 00381 00382 /* Remember what had been dialed, so that if the parking 00383 expires, we try to come back to the same place */ 00384 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00385 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00386 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00387 pu->next = parkinglot; 00388 parkinglot = pu; 00389 00390 /* If parking a channel directly, don't quiet yet get parking running on it */ 00391 if (peer == chan) 00392 pu->notquiteyet = 1; 00393 ast_mutex_unlock(&parking_lock); 00394 /* Wake up the (presumably select()ing) thread */ 00395 pthread_kill(parking_thread, SIGURG); 00396 if (option_verbose > 1) 00397 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); 00398 00399 if (pu->parkingnum != -1) 00400 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); 00401 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00402 "Exten: %s\r\n" 00403 "Channel: %s\r\n" 00404 "From: %s\r\n" 00405 "Timeout: %ld\r\n" 00406 "CallerID: %s\r\n" 00407 "CallerIDName: %s\r\n", 00408 pu->parkingexten, pu->chan->name, peer ? peer->name : "", 00409 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00410 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00411 S_OR(pu->chan->cid.cid_name, "<unknown>") 00412 ); 00413 00414 if (peer && adsipark && ast_adsi_available(peer)) { 00415 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00416 ast_adsi_unload_session(peer); 00417 } 00418 00419 con = ast_context_find(parking_con); 00420 if (!con) 00421 con = ast_context_create(NULL, parking_con, registrar); 00422 if (!con) /* Still no context? Bad */ 00423 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00424 /* Tell the peer channel the number of the parking space */ 00425 if (peer && pu->parkingnum != -1) /* Only say number if it's a number */ 00426 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00427 if (con) { 00428 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) 00429 notify_metermaids(pu->parkingexten, parking_con); 00430 } 00431 if (pu->notquiteyet) { 00432 /* Wake up parking thread if we're really done */ 00433 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00434 S_OR(parkmohclass, NULL), 00435 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00436 pu->notquiteyet = 0; 00437 pthread_kill(parking_thread, SIGURG); 00438 } 00439 return 0; 00440 }
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 155 of file res_features.c.
Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), load_config(), mgcp_ss(), socket_process(), and ss_thread().
00156 { 00157 return parking_ext; 00158 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2134 of file res_features.c.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), and ss_thread().
02135 { 02136 struct ast_channel *cur = NULL; 02137 int res = -1; 02138 02139 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02140 if (!cur->pbx && 02141 (cur != chan) && 02142 (chan->pickupgroup & cur->callgroup) && 02143 ((cur->_state == AST_STATE_RINGING) || 02144 (cur->_state == AST_STATE_RING))) { 02145 break; 02146 } 02147 ast_channel_unlock(cur); 02148 } 02149 if (cur) { 02150 if (option_debug) 02151 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02152 res = ast_answer(chan); 02153 if (res) 02154 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02155 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02156 if (res) 02157 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02158 res = ast_channel_masquerade(cur, chan); 02159 if (res) 02160 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02161 ast_channel_unlock(cur); 02162 } else { 02163 if (option_debug) 02164 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02165 } 02166 return res; 02167 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 160 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00161 { 00162 return pickup_ext; 00163 }
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 895 of file res_features.c.
Referenced by load_config().
00896 { 00897 if (!feature) { 00898 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00899 return; 00900 } 00901 00902 AST_LIST_LOCK(&feature_list); 00903 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00904 AST_LIST_UNLOCK(&feature_list); 00905 00906 if (option_verbose >= 2) 00907 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00908 }
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 911 of file res_features.c.
00912 { 00913 if (!feature) 00914 return; 00915 00916 AST_LIST_LOCK(&feature_list); 00917 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00918 AST_LIST_UNLOCK(&feature_list); 00919 free(feature); 00920 }