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_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.
|
|
Definition at line 29 of file features.h. Referenced by load_config(). |
|
|
Definition at line 28 of file features.h. Referenced by load_config(). |
|
|
Definition at line 31 of file features.h. Referenced by load_config(). |
|
|
Definition at line 27 of file features.h. Referenced by ast_bridge_call(). |
|
|
Definition at line 30 of file features.h. Referenced by load_config(). |
|
||||||||||||||||
|
Bridge a call, optionally allowing redirection.
Definition at line 1251 of file res_features.c. References ast_channel::appl, ast_answer(), ast_cdr_appenduserfield(), ast_cdr_setuserfield(), ast_channel_bridge(), ast_channel_setoption(), ast_clear_flag, AST_CONTROL_FLASH, AST_CONTROL_RINGING, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, ast_frfree(), ast_indicate(), ast_log(), ast_strlen_zero(), ast_channel::cdr, ast_channel::data, ast_frame::data, ast_option_header::data, ast_frame::datalen, ast_bridge_config::end_sound, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_option_header::option, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, set_config_flags(), ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::userfield, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound. Referenced by ast_bridge_call_thread(), builtin_atxfer(), dial_exec_full(), park_exec(), and try_calling(). 01252 {
01253 /* Copy voice back and forth between the two channels. Give the peer
01254 the ability to transfer calls with '#<extension' syntax. */
01255 struct ast_frame *f;
01256 struct ast_channel *who;
01257 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01258 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01259 int res;
01260 int diff;
01261 int hasfeatures=0;
01262 int hadfeatures=0;
01263 struct ast_option_header *aoh;
01264 struct timeval start = { 0 , 0 };
01265 struct ast_bridge_config backup_config;
01266 char *monitor_exec;
01267
01268 memset(&backup_config, 0, sizeof(backup_config));
01269
01270 config->start_time = ast_tvnow();
01271
01272 if (chan && peer) {
01273 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01274 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01275 } else if (chan)
01276 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01277
01278 if (monitor_ok) {
01279 if (!monitor_app) {
01280 if (!(monitor_app = pbx_findapp("Monitor")))
01281 monitor_ok=0;
01282 }
01283 if (monitor_app) {
01284 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
01285 pbx_exec(chan, monitor_app, monitor_exec, 1);
01286 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01287 pbx_exec(peer, monitor_app, monitor_exec, 1);
01288 }
01289 }
01290
01291 set_config_flags(chan, peer, config);
01292 config->firstpass = 1;
01293
01294 /* Answer if need be */
01295 if (ast_answer(chan))
01296 return -1;
01297 peer->appl = "Bridged Call";
01298 peer->data = chan->name;
01299
01300 /* copy the userfield from the B-leg to A-leg if applicable */
01301 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01302 char tmp[256];
01303 if (!ast_strlen_zero(chan->cdr->userfield)) {
01304 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01305 ast_cdr_appenduserfield(chan, tmp);
01306 } else
01307 ast_cdr_setuserfield(chan, peer->cdr->userfield);
01308 /* free the peer's cdr without ast_cdr_free complaining */
01309 free(peer->cdr);
01310 peer->cdr = NULL;
01311 }
01312 for (;;) {
01313 if (config->feature_timer)
01314 start = ast_tvnow();
01315
01316 res = ast_channel_bridge(chan, peer, config, &f, &who);
01317
01318 if (config->feature_timer) {
01319 /* Update time limit for next pass */
01320 diff = ast_tvdiff_ms(ast_tvnow(), start);
01321 config->feature_timer -= diff;
01322 if (hasfeatures) {
01323 /* Running on backup config, meaning a feature might be being
01324 activated, but that's no excuse to keep things going
01325 indefinitely! */
01326 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01327 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01328 config->feature_timer = 0;
01329 who = chan;
01330 if (f)
01331 ast_frfree(f);
01332 f = NULL;
01333 res = 0;
01334 } else if (config->feature_timer <= 0) {
01335 /* Not *really* out of time, just out of time for
01336 digits to come in for features. */
01337 ast_log(LOG_DEBUG, "Timed out for feature!\n");
01338 if (!ast_strlen_zero(peer_featurecode)) {
01339 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01340 memset(peer_featurecode, 0, sizeof(peer_featurecode));
01341 }
01342 if (!ast_strlen_zero(chan_featurecode)) {
01343 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01344 memset(chan_featurecode, 0, sizeof(chan_featurecode));
01345 }
01346 if (f)
01347 ast_frfree(f);
01348 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01349 if (!hasfeatures) {
01350 /* Restore original (possibly time modified) bridge config */
01351 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01352 memset(&backup_config, 0, sizeof(backup_config));
01353 }
01354 hadfeatures = hasfeatures;
01355 /* Continue as we were */
01356 continue;
01357 }
01358 } else {
01359 if (config->feature_timer <=0) {
01360 /* We ran out of time */
01361 config->feature_timer = 0;
01362 who = chan;
01363 if (f)
01364 ast_frfree(f);
01365 f = NULL;
01366 res = 0;
01367 }
01368 }
01369 }
01370 if (res < 0) {
01371 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01372 return -1;
01373 }
01374
01375 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) ||
01376 (f->subclass == AST_CONTROL_CONGESTION)))) {
01377 res = -1;
01378 break;
01379 }
01380 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01381 if (who == chan)
01382 ast_indicate(peer, AST_CONTROL_RINGING);
01383 else
01384 ast_indicate(chan, AST_CONTROL_RINGING);
01385 }
01386 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01387 if (who == chan)
01388 ast_indicate(peer, -1);
01389 else
01390 ast_indicate(chan, -1);
01391 }
01392 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01393 if (who == chan)
01394 ast_indicate(peer, AST_CONTROL_FLASH);
01395 else
01396 ast_indicate(chan, AST_CONTROL_FLASH);
01397 }
01398 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01399 aoh = f->data;
01400 /* Forward option Requests */
01401 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01402 if (who == chan)
01403 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01404 else
01405 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01406 }
01407 }
01408 /* check for '*', if we find it it's time to disconnect */
01409 if (f && (f->frametype == AST_FRAME_DTMF)) {
01410 char *featurecode;
01411 int sense;
01412 struct ast_channel *other;
01413
01414 hadfeatures = hasfeatures;
01415 /* This cannot overrun because the longest feature is one shorter than our buffer */
01416 if (who == chan) {
01417 other = peer;
01418 sense = FEATURE_SENSE_CHAN;
01419 featurecode = chan_featurecode;
01420 } else {
01421 other = chan;
01422 sense = FEATURE_SENSE_PEER;
01423 featurecode = peer_featurecode;
01424 }
01425 featurecode[strlen(featurecode)] = f->subclass;
01426 config->feature_timer = backup_config.feature_timer;
01427 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01428 switch(res) {
01429 case FEATURE_RETURN_PASSDIGITS:
01430 ast_dtmf_stream(other, who, featurecode, 0);
01431 /* Fall through */
01432 case FEATURE_RETURN_SUCCESS:
01433 memset(featurecode, 0, sizeof(chan_featurecode));
01434 break;
01435 }
01436 if (res >= FEATURE_RETURN_PASSDIGITS) {
01437 res = 0;
01438 } else {
01439 ast_frfree(f);
01440 break;
01441 }
01442 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01443 if (hadfeatures && !hasfeatures) {
01444 /* Restore backup */
01445 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01446 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01447 } else if (hasfeatures) {
01448 if (!hadfeatures) {
01449 /* Backup configuration */
01450 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01451 /* Setup temporary config options */
01452 config->play_warning = 0;
01453 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01454 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01455 config->warning_freq = 0;
01456 config->warning_sound = NULL;
01457 config->end_sound = NULL;
01458 config->start_sound = NULL;
01459 config->firstpass = 0;
01460 }
01461 config->feature_timer = featuredigittimeout;
01462 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01463 }
01464 }
01465 if (f)
01466 ast_frfree(f);
01467 }
01468 return res;
01469 }
|
|
||||||||||||||||||||
|
Park a call via a masqueraded channel.
Definition at line 401 of file res_features.c. References ast_channel_alloc(), ast_channel_masquerade(), ast_frfree(), ast_log(), ast_park_call(), ast_read(), ast_channel::context, ast_channel::exten, LOG_WARNING, ast_channel::name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat. Referenced by mgcp_ss(), parkandannounce_exec(), rpt_exec(), skinny_ss(), and ss_thread(). 00402 {
00403 struct ast_channel *chan;
00404 struct ast_frame *f;
00405
00406 /* Make a new, fake channel that we'll use to masquerade in the real one */
00407 chan = ast_channel_alloc(0);
00408 if (chan) {
00409 /* Let us keep track of the channel name */
00410 snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
00411
00412 /* Make formats okay */
00413 chan->readformat = rchan->readformat;
00414 chan->writeformat = rchan->writeformat;
00415 ast_channel_masquerade(chan, rchan);
00416
00417 /* Setup the extensions and such */
00418 ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
00419 ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
00420 chan->priority = rchan->priority;
00421
00422 /* Make the masq execute */
00423 f = ast_read(chan);
00424 if (f)
00425 ast_frfree(f);
00426 ast_park_call(chan, peer, timeout, extout);
00427 } else {
00428 ast_log(LOG_WARNING, "Unable to create parked channel\n");
00429 return -1;
00430 }
00431 return 0;
00432 }
|
|
||||||||||||||||||||
|
Park a call and read back parked location.
Definition at line 278 of file res_features.c. References adsi_announce_park(), adsi_available(), adsi_unload_session(), adsipark, ast_channel::appl, ast_add_extension2(), ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_indicate(), ast_log(), ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::context, ast_channel::context, ast_channel::data, EVENT_FLAG_CALL, parkeduser::exten, ast_channel::exten, free, FREE, ast_channel::language, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, malloc, manager_event(), ast_channel::name, parkeduser::next, parkeduser::notquiteyet, option_verbose, parkedcall, parking_con, parking_offset, parking_start, parking_stop, parking_thread, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, parkeduser::priority, ast_channel::priority, registrar, parkeduser::start, strdup, and VERBOSE_PREFIX_2. Referenced by ast_masq_park_call(), builtin_blindtransfer(), iax_park_thread(), park_call_exec(), and sip_park_thread(). 00279 {
00280 struct parkeduser *pu, *cur;
00281 int i,x,parking_range;
00282 char exten[AST_MAX_EXTENSION];
00283 struct ast_context *con;
00284
00285 pu = malloc(sizeof(struct parkeduser));
00286 if (!pu) {
00287 ast_log(LOG_WARNING, "Out of memory\n");
00288 return -1;
00289 }
00290 memset(pu, 0, sizeof(struct parkeduser));
00291 ast_mutex_lock(&parking_lock);
00292 parking_range = parking_stop - parking_start+1;
00293 for (i = 0; i < parking_range; i++) {
00294 x = (i + parking_offset) % parking_range + parking_start;
00295 cur = parkinglot;
00296 while(cur) {
00297 if (cur->parkingnum == x)
00298 break;
00299 cur = cur->next;
00300 }
00301 if (!cur)
00302 break;
00303 }
00304
00305 if (!(i < parking_range)) {
00306 ast_log(LOG_WARNING, "No more parking spaces\n");
00307 free(pu);
00308 ast_mutex_unlock(&parking_lock);
00309 return -1;
00310 }
00311 if (parkfindnext)
00312 parking_offset = x - parking_start + 1;
00313 chan->appl = "Parked Call";
00314 chan->data = NULL;
00315
00316 pu->chan = chan;
00317 /* Start music on hold */
00318 if (chan != peer) {
00319 ast_indicate(pu->chan, AST_CONTROL_HOLD);
00320 ast_moh_start(pu->chan, NULL);
00321 }
00322 pu->start = ast_tvnow();
00323 pu->parkingnum = x;
00324 if (timeout > 0)
00325 pu->parkingtime = timeout;
00326 else
00327 pu->parkingtime = parkingtime;
00328 if (extout)
00329 *extout = x;
00330 if (peer)
00331 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00332
00333 /* Remember what had been dialed, so that if the parking
00334 expires, we try to come back to the same place */
00335 if (!ast_strlen_zero(chan->macrocontext))
00336 ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
00337 else
00338 ast_copy_string(pu->context, chan->context, sizeof(pu->context));
00339 if (!ast_strlen_zero(chan->macroexten))
00340 ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
00341 else
00342 ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
00343 if (chan->macropriority)
00344 pu->priority = chan->macropriority;
00345 else
00346 pu->priority = chan->priority;
00347 pu->next = parkinglot;
00348 parkinglot = pu;
00349 /* If parking a channel directly, don't quiet yet get parking running on it */
00350 if (peer == chan)
00351 pu->notquiteyet = 1;
00352 ast_mutex_unlock(&parking_lock);
00353 /* Wake up the (presumably select()ing) thread */
00354 pthread_kill(parking_thread, SIGURG);
00355 if (option_verbose > 1)
00356 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00357
00358 manager_event(EVENT_FLAG_CALL, "ParkedCall",
00359 "Exten: %d\r\n"
00360 "Channel: %s\r\n"
00361 "From: %s\r\n"
00362 "Timeout: %ld\r\n"
00363 "CallerID: %s\r\n"
00364 "CallerIDName: %s\r\n"
00365 ,pu->parkingnum, pu->chan->name, peer->name
00366 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
00367 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
00368 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
00369 );
00370
00371 if (peer) {
00372 if (adsipark && adsi_available(peer)) {
00373 adsi_announce_park(peer, pu->parkingnum);
00374 }
00375 if (adsipark && adsi_available(peer)) {
00376 adsi_unload_session(peer);
00377 }
00378 }
00379 con = ast_context_find(parking_con);
00380 if (!con) {
00381 con = ast_context_create(NULL, parking_con, registrar);
00382 if (!con) {
00383 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00384 }
00385 }
00386 if (con) {
00387 snprintf(exten, sizeof(exten), "%d", x);
00388 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
00389 }
00390 if (peer)
00391 ast_say_digits(peer, pu->parkingnum, "", peer->language);
00392 if (pu->notquiteyet) {
00393 /* Wake up parking thread if we're really done */
00394 ast_moh_start(pu->chan, NULL);
00395 pu->notquiteyet = 0;
00396 pthread_kill(parking_thread, SIGURG);
00397 }
00398 return 0;
00399 }
|
|
|
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
Definition at line 163 of file res_features.c. Referenced by builtin_blindtransfer(), dp_lookup(), get_refer_info(), handle_request_refer(), load_config(), mgcp_ss(), skinny_ss(), socket_read(), and ss_thread(). 00164 {
00165 return parking_ext;
00166 }
|
|
|
Pickup a call.
Definition at line 1915 of file res_features.c. References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_mutex_unlock(), ast_queue_control(), ast_channel::callgroup, ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup. Referenced by cb_events(), handle_request_invite(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread(). 01916 {
01917 struct ast_channel *cur = NULL;
01918 int res = -1;
01919
01920 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01921 if (!cur->pbx &&
01922 (cur != chan) &&
01923 (chan->pickupgroup & cur->callgroup) &&
01924 ((cur->_state == AST_STATE_RINGING) ||
01925 (cur->_state == AST_STATE_RING))) {
01926 break;
01927 }
01928 ast_mutex_unlock(&cur->lock);
01929 }
01930 if (cur) {
01931 if (option_debug)
01932 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01933 res = ast_answer(chan);
01934 if (res)
01935 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01936 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01937 if (res)
01938 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01939 res = ast_channel_masquerade(cur, chan);
01940 if (res)
01941 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
01942 ast_mutex_unlock(&cur->lock);
01943 } else {
01944 if (option_debug)
01945 ast_log(LOG_DEBUG, "No call pickup possible...\n");
01946 }
01947 return res;
01948 }
|
|
|
Determine system call pickup extension.
Definition at line 168 of file res_features.c. Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread(). 00169 {
00170 return pickup_ext;
00171 }
|
|
|
register new feature into feature_set
Referenced by load_config(). |
|
|
unregister feature from feature_set
Definition at line 888 of file res_features.c. References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free. 00889 {
00890 if (!feature) return;
00891
00892 AST_LIST_LOCK(&feature_list);
00893 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00894 AST_LIST_UNLOCK(&feature_list);
00895 free(feature);
00896 }
|
1.3.9.1