#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/monitor.h"
Include dependency graph for res_features.c:

Go to the source code of this file.
Data Structures | |
| struct | ast_bridge_thread_obj |
| struct | parkeduser |
Defines | |
| #define | AST_MAX_WATCHERS 256 |
| #define | DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
| #define | DEFAULT_PARK_TIME 45000 |
| #define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
| #define | FEATURE_RETURN_HANGUP -1 |
| #define | FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
| #define | FEATURE_RETURN_PASSDIGITS 21 |
| #define | FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
| #define | FEATURE_RETURN_STOREDIGITS 22 |
| #define | FEATURE_RETURN_SUCCESS 23 |
| #define | FEATURE_RETURN_SUCCESSBREAK 0 |
| #define | FEATURE_SENSE_CHAN (1 << 0) |
| #define | FEATURE_SENSE_PEER (1 << 1) |
| #define | FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
| #define | FREE free |
Functions | |
| static int | adsi_announce_park (struct ast_channel *chan, int parkingnum) |
| int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
| Bridge a call, optionally allowing redirection. | |
| static void * | ast_bridge_call_thread (void *data) |
| static void | ast_bridge_call_thread_launch (void *data) |
| static int | ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
| static struct ast_channel * | ast_feature_request_and_dial (struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name) |
| static | AST_LIST_HEAD_STATIC (feature_list, ast_call_feature) |
| int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
| Park a call via a masqueraded channel. | |
| AST_MUTEX_DEFINE_STATIC (parking_lock) | |
| int | ast_park_call (struct ast_channel *chan, struct ast_channel *peer, 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 | |
| static void | ast_unregister_features (void) |
| static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
| static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
| static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
| static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
| static void | check_goto_on_transfer (struct ast_channel *chan) |
| char * | description (void) |
| Provides a description of the module. | |
| static void * | do_parking_thread (void *ignore) |
| static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
| static struct ast_call_feature * | find_feature (char *name) |
| static int | handle_parkedcalls (int fd, int argc, char *argv[]) |
| static int | handle_showfeatures (int fd, int argc, char *argv[]) |
| char * | key () |
| Returns the ASTERISK_GPL_KEY. | |
| static int | load_config (void) |
| int | load_module (void) |
| Initialize the module. | |
| static int | manager_parking_status (struct mansession *s, struct message *m) |
| static int | park_call_exec (struct ast_channel *chan, void *data) |
| static int | park_exec (struct ast_channel *chan, void *data) |
| int | reload (void) |
| Reload stuff. | |
| static int | remap_feature (const char *name, const char *value) |
| static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
| int | unload_module (void) |
| Cleanup all module structures, sockets, etc. | |
| static void | unmap_features (void) |
| int | usecount (void) |
| Provides a usecount. | |
Variables | |
| static int | adsipark |
| ast_call_feature | builtin_features [] |
| static char | courtesytone [256] |
| static char * | descrip |
| static char * | descrip2 |
| static int | featuredigittimeout |
| LOCAL_USER_DECL | |
| static struct ast_app * | monitor_app = NULL |
| static int | monitor_ok = 1 |
| static char * | parkcall = "Park" |
| static char * | parkedcall = "ParkedCall" |
| static int | parkfindnext |
| static char | parking_con [AST_MAX_EXTENSION] |
| static char | parking_con_dial [AST_MAX_EXTENSION] |
| static char | parking_ext [AST_MAX_EXTENSION] |
| static int | parking_offset |
| static int | parking_start |
| static int | parking_stop |
| static pthread_t | parking_thread |
| static struct parkeduser * | parkinglot |
| static int | parkingtime = DEFAULT_PARK_TIME |
| static char | pickup_ext [AST_MAX_EXTENSION] |
| static char * | registrar = "res_features" |
| static struct ast_cli_entry | showfeatures |
| static char | showfeatures_help [] |
| static struct ast_cli_entry | showparked |
| static char | showparked_help [] |
| STANDARD_LOCAL_USER | |
| static char * | synopsis = "Answer a parked call" |
| static char * | synopsis2 = "Park yourself" |
| static int | transferdigittimeout |
| static char | xferfailsound [256] |
| static char | xfersound [256] |
Definition in file res_features.c.
| #define AST_MAX_WATCHERS 256 |
Definition at line 73 of file res_features.c.
| #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
| #define DEFAULT_PARK_TIME 45000 |
| #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
| #define FEATURE_RETURN_HANGUP -1 |
| #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
| #define FEATURE_RETURN_PASSDIGITS 21 |
| #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
| #define FEATURE_RETURN_STOREDIGITS 22 |
| #define FEATURE_RETURN_SUCCESS 23 |
Definition at line 441 of file res_features.c.
Referenced by builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app().
| #define FEATURE_RETURN_SUCCESSBREAK 0 |
| #define FEATURE_SENSE_CHAN (1 << 0) |
| #define FEATURE_SENSE_PEER (1 << 1) |
Definition at line 444 of file res_features.c.
Referenced by builtin_atxfer(), and builtin_blindtransfer().
| #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Definition at line 863 of file res_features.c.
Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), remap_feature(), set_config_flags(), and unmap_features().
| #define FREE free |
Definition at line 66 of file res_features.c.
| static int adsi_announce_park | ( | struct ast_channel * | chan, | |
| int | parkingnum | |||
| ) | [static] |
Definition at line 259 of file res_features.c.
References ADSI_JUST_CENT, adsi_load_session(), adsi_print(), and justify.
Referenced by ast_park_call().
00260 { 00261 int res; 00262 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00263 char tmp[256]; 00264 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00265 00266 snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum); 00267 message[0] = tmp; 00268 res = adsi_load_session(chan, NULL, 0, 1); 00269 if (res == -1) { 00270 return res; 00271 } 00272 return adsi_print(chan, message, justify, 1); 00273 }
| int ast_bridge_call | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config | |||
| ) |
Bridge a call, optionally allowing redirection.
Definition at line 1265 of file res_features.c.
References ast_channel::appl, ast_answer(), ast_cdr_appenduserfield(), ast_cdr_setuserfield(), ast_channel_bridge(), ast_dtmf_stream(), ast_frfree(), ast_log(), ast_strlen_zero(), ast_channel::cdr, config, ast_channel::data, FEATURE_MAX_LEN, free, LOG_DEBUG, monitor_app, monitor_ok, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.
Referenced by ast_bridge_call_thread(), builtin_atxfer(), dial_exec_full(), park_exec(), and try_calling().
01266 { 01267 /* Copy voice back and forth between the two channels. Give the peer 01268 the ability to transfer calls with '#<extension' syntax. */ 01269 struct ast_frame *f; 01270 struct ast_channel *who; 01271 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01272 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01273 int res; 01274 int diff; 01275 int hasfeatures=0; 01276 int hadfeatures=0; 01277 struct ast_option_header *aoh; 01278 struct ast_bridge_config backup_config; 01279 char *monitor_exec; 01280 01281 memset(&backup_config, 0, sizeof(backup_config)); 01282 01283 config->start_time = ast_tvnow(); 01284 01285 if (chan && peer) { 01286 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01287 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01288 } else if (chan) 01289 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01290 01291 if (monitor_ok) { 01292 if (!monitor_app) { 01293 if (!(monitor_app = pbx_findapp("Monitor"))) 01294 monitor_ok=0; 01295 } 01296 if (monitor_app) { 01297 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01298 pbx_exec(chan, monitor_app, monitor_exec, 1); 01299 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01300 pbx_exec(peer, monitor_app, monitor_exec, 1); 01301 } 01302 } 01303 01304 set_config_flags(chan, peer, config); 01305 config->firstpass = 1; 01306 01307 /* Answer if need be */ 01308 if (ast_answer(chan)) 01309 return -1; 01310 peer->appl = "Bridged Call"; 01311 peer->data = chan->name; 01312 01313 /* copy the userfield from the B-leg to A-leg if applicable */ 01314 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01315 char tmp[256]; 01316 if (!ast_strlen_zero(chan->cdr->userfield)) { 01317 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01318 ast_cdr_appenduserfield(chan, tmp); 01319 } else 01320 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01321 /* free the peer's cdr without ast_cdr_free complaining */ 01322 free(peer->cdr); 01323 peer->cdr = NULL; 01324 } 01325 for (;;) { 01326 res = ast_channel_bridge(chan, peer, config, &f, &who); 01327 01328 if (config->feature_timer) { 01329 /* Update time limit for next pass */ 01330 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01331 config->feature_timer -= diff; 01332 if (hasfeatures) { 01333 /* Running on backup config, meaning a feature might be being 01334 activated, but that's no excuse to keep things going 01335 indefinitely! */ 01336 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01337 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01338 config->feature_timer = 0; 01339 who = chan; 01340 if (f) 01341 ast_frfree(f); 01342 f = NULL; 01343 res = 0; 01344 } else if (config->feature_timer <= 0) { 01345 /* Not *really* out of time, just out of time for 01346 digits to come in for features. */ 01347 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01348 if (!ast_strlen_zero(peer_featurecode)) { 01349 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01350 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01351 } 01352 if (!ast_strlen_zero(chan_featurecode)) { 01353 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01354 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01355 } 01356 if (f) 01357 ast_frfree(f); 01358 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01359 if (!hasfeatures) { 01360 /* Restore original (possibly time modified) bridge config */ 01361 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01362 memset(&backup_config, 0, sizeof(backup_config)); 01363 } 01364 hadfeatures = hasfeatures; 01365 /* Continue as we were */ 01366 continue; 01367 } else if (!f) { 01368 /* The bridge returned without a frame and there is a feature in progress. 01369 * However, we don't think the feature has quite yet timed out, so just 01370 * go back into the bridge. */ 01371 continue; 01372 } 01373 } else { 01374 if (config->feature_timer <=0) { 01375 /* We ran out of time */ 01376 config->feature_timer = 0; 01377 who = chan; 01378 if (f) 01379 ast_frfree(f); 01380 f = NULL; 01381 res = 0; 01382 } 01383 } 01384 } 01385 if (res < 0) { 01386 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01387 return -1; 01388 } 01389 01390 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 01391 (f->subclass == AST_CONTROL_CONGESTION)))) { 01392 res = -1; 01393 break; 01394 } 01395 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) { 01396 if (who == chan) 01397 ast_indicate(peer, AST_CONTROL_RINGING); 01398 else 01399 ast_indicate(chan, AST_CONTROL_RINGING); 01400 } 01401 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) { 01402 if (who == chan) 01403 ast_indicate(peer, -1); 01404 else 01405 ast_indicate(chan, -1); 01406 } 01407 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) { 01408 if (who == chan) 01409 ast_indicate(peer, AST_CONTROL_FLASH); 01410 else 01411 ast_indicate(chan, AST_CONTROL_FLASH); 01412 } 01413 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) { 01414 aoh = f->data; 01415 /* Forward option Requests */ 01416 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) { 01417 if (who == chan) 01418 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01419 else 01420 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01421 } 01422 } 01423 /* check for '*', if we find it it's time to disconnect */ 01424 if (f && (f->frametype == AST_FRAME_DTMF)) { 01425 char *featurecode; 01426 int sense; 01427 struct ast_channel *other; 01428 01429 hadfeatures = hasfeatures; 01430 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01431 if (who == chan) { 01432 other = peer; 01433 sense = FEATURE_SENSE_CHAN; 01434 featurecode = chan_featurecode; 01435 } else { 01436 other = chan; 01437 sense = FEATURE_SENSE_PEER; 01438 featurecode = peer_featurecode; 01439 } 01440 featurecode[strlen(featurecode)] = f->subclass; 01441 /* Get rid of the frame before we start doing "stuff" with the channels */ 01442 ast_frfree(f); 01443 f = NULL; 01444 config->feature_timer = backup_config.feature_timer; 01445 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01446 switch(res) { 01447 case FEATURE_RETURN_PASSDIGITS: 01448 ast_dtmf_stream(other, who, featurecode, 0); 01449 /* Fall through */ 01450 case FEATURE_RETURN_SUCCESS: 01451 memset(featurecode, 0, sizeof(chan_featurecode)); 01452 break; 01453 } 01454 if (res >= FEATURE_RETURN_PASSDIGITS) { 01455 res = 0; 01456 } else 01457 break; 01458 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01459 if (hadfeatures && !hasfeatures) { 01460 /* Restore backup */ 01461 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01462 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01463 } else if (hasfeatures) { 01464 if (!hadfeatures) { 01465 /* Backup configuration */ 01466 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01467 /* Setup temporary config options */ 01468 config->play_warning = 0; 01469 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01470 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01471 config->warning_freq = 0; 01472 config->warning_sound = NULL; 01473 config->end_sound = NULL; 01474 config->start_sound = NULL; 01475 config->firstpass = 0; 01476 } 01477 config->start_time = ast_tvnow(); 01478 config->feature_timer = featuredigittimeout; 01479 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01480 } 01481 } 01482 if (f) 01483 ast_frfree(f); 01484 } 01485 return res; 01486 }
| static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
Definition at line 217 of file res_features.c.
References ast_channel::appl, ast_bridge_call(), ast_cdr_reset(), ast_cdr_setdestchan(), ast_hangup(), ast_bridge_thread_obj::bconfig, ast_channel::cdr, ast_bridge_thread_obj::chan, ast_channel::data, free, ast_channel::name, and ast_bridge_thread_obj::peer.
Referenced by ast_bridge_call_thread_launch().
00218 { 00219 struct ast_bridge_thread_obj *tobj = data; 00220 00221 tobj->chan->appl = "Transferred Call"; 00222 tobj->chan->data = tobj->peer->name; 00223 tobj->peer->appl = "Transferred Call"; 00224 tobj->peer->data = tobj->chan->name; 00225 if (tobj->chan->cdr) { 00226 ast_cdr_reset(tobj->chan->cdr, NULL); 00227 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name); 00228 } 00229 if (tobj->peer->cdr) { 00230 ast_cdr_reset(tobj->peer->cdr, NULL); 00231 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name); 00232 } 00233 00234 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00235 ast_hangup(tobj->chan); 00236 ast_hangup(tobj->peer); 00237 tobj->chan = tobj->peer = NULL; 00238 free(tobj); 00239 tobj=NULL; 00240 return NULL; 00241 }
| static void ast_bridge_call_thread_launch | ( | void * | data | ) | [static] |
Definition at line 243 of file res_features.c.
References ast_bridge_call_thread(), and ast_pthread_create.
Referenced by builtin_atxfer().
00244 { 00245 pthread_t thread; 00246 pthread_attr_t attr; 00247 struct sched_param sched; 00248 00249 pthread_attr_init(&attr); 00250 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00251 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00252 pthread_attr_destroy(&attr); 00253 memset(&sched, 0, sizeof(sched)); 00254 pthread_setschedparam(thread, SCHED_RR, &sched); 00255 }
| static int ast_feature_interpret | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| char * | code, | |||
| int | sense | |||
| ) | [static] |
Definition at line 988 of file res_features.c.
References ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), builtin_features, config, exten, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, features, FEATURES_COUNT, find_feature(), LOG_DEBUG, ast_channel::name, ast_call_feature::operation, option_verbose, pbx_builtin_getvar_helper(), strsep(), and VERBOSE_PREFIX_3.
00989 { 00990 int x; 00991 struct ast_flags features; 00992 int res = FEATURE_RETURN_PASSDIGITS; 00993 struct ast_call_feature *feature; 00994 char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES"); 00995 00996 if (sense == FEATURE_SENSE_CHAN) 00997 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 00998 else 00999 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01000 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags); 01001 01002 for (x=0; x < FEATURES_COUNT; x++) { 01003 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01004 !ast_strlen_zero(builtin_features[x].exten)) { 01005 /* Feature is up for consideration */ 01006 if (!strcmp(builtin_features[x].exten, code)) { 01007 res = builtin_features[x].operation(chan, peer, config, code, sense); 01008 break; 01009 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01010 if (res == FEATURE_RETURN_PASSDIGITS) 01011 res = FEATURE_RETURN_STOREDIGITS; 01012 } 01013 } 01014 } 01015 01016 01017 if (!ast_strlen_zero(dynamic_features)) { 01018 char *tmp = ast_strdupa(dynamic_features); 01019 char *tok; 01020 01021 if (!tmp) 01022 return res; 01023 01024 while ((tok = strsep(&tmp, "#")) != NULL) { 01025 feature = find_feature(tok); 01026 01027 if (feature) { 01028 /* Feature is up for consideration */ 01029 if (!strcmp(feature->exten, code)) { 01030 if (option_verbose > 2) 01031 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01032 if (sense == FEATURE_SENSE_CHAN) 01033 res = feature->operation(chan, peer, config, code, sense); 01034 else 01035 res = feature->operation(peer, chan, config, code, sense); 01036 break; 01037 } else if (!strncmp(feature->exten, code, strlen(code))) { 01038 res = FEATURE_RETURN_STOREDIGITS; 01039 } 01040 } 01041 } 01042 } 01043 01044 return res; 01045 }
| static struct ast_channel * ast_feature_request_and_dial | ( | struct ast_channel * | caller, | |
| const char * | type, | |||
| int | format, | |||
| void * | data, | |||
| int | timeout, | |||
| int * | outstate, | |||
| const char * | cid_num, | |||
| const char * | cid_name | |||
| ) | [static] |
Definition at line 1092 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), AST_STATE_UP, ast_verbose(), ast_waitfor_n(), builtin_features, ast_channel::cdr, ast_call_feature::exten, FEATURES_COUNT, ast_frame::frametype, ast_channel::hangupcause, LOG_NOTICE, LOG_WARNING, option_verbose, ast_frame::subclass, and VERBOSE_PREFIX_3.
Referenced by builtin_atxfer().
01093 { 01094 int state = 0; 01095 int cause = 0; 01096 int to; 01097 struct ast_channel *chan; 01098 struct ast_channel *monitor_chans[2]; 01099 struct ast_channel *active_channel; 01100 struct ast_frame *f = NULL; 01101 int res = 0, ready = 0; 01102 01103 if ((chan = ast_request(type, format, data, &cause))) { 01104 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01105 ast_channel_inherit_variables(caller, chan); 01106 if (!ast_call(chan, data, timeout)) { 01107 struct timeval started; 01108 int x, len = 0; 01109 char *disconnect_code = NULL, *dialed_code = NULL; 01110 01111 ast_indicate(caller, AST_CONTROL_RINGING); 01112 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01113 for (x=0; x < FEATURES_COUNT; x++) { 01114 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01115 continue; 01116 01117 disconnect_code = builtin_features[x].exten; 01118 len = strlen(disconnect_code) + 1; 01119 dialed_code = alloca(len); 01120 memset(dialed_code, 0, len); 01121 break; 01122 } 01123 x = 0; 01124 started = ast_tvnow(); 01125 to = timeout; 01126 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01127 monitor_chans[0] = caller; 01128 monitor_chans[1] = chan; 01129 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01130 01131 /* see if the timeout has been violated */ 01132 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01133 state = AST_CONTROL_UNHOLD; 01134 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01135 break; /*doh! timeout*/ 01136 } 01137 01138 if (!active_channel) { 01139 continue; 01140 } 01141 01142 if (chan && (chan == active_channel)){ 01143 f = ast_read(chan); 01144 if (f == NULL) { /*doh! where'd he go?*/ 01145 state = AST_CONTROL_HANGUP; 01146 res = 0; 01147 break; 01148 } 01149 01150 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01151 if (f->subclass == AST_CONTROL_RINGING) { 01152 state = f->subclass; 01153 if (option_verbose > 2) 01154 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01155 ast_indicate(caller, AST_CONTROL_RINGING); 01156 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01157 state = f->subclass; 01158 if (option_verbose > 2) 01159 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01160 ast_indicate(caller, AST_CONTROL_BUSY); 01161 ast_frfree(f); 01162 f = NULL; 01163 break; 01164 } else if (f->subclass == AST_CONTROL_ANSWER) { 01165 /* This is what we are hoping for */ 01166 state = f->subclass; 01167 ast_frfree(f); 01168 f = NULL; 01169 ready=1; 01170 break; 01171 } else { 01172 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01173 } 01174 /* else who cares */ 01175 } 01176 01177 } else if (caller && (active_channel == caller)) { 01178 f = ast_read(caller); 01179 if (f == NULL) { /*doh! where'd he go?*/ 01180 if (caller->_softhangup && !chan->_softhangup) { 01181 /* make this a blind transfer */ 01182 ready = 1; 01183 break; 01184 } 01185 state = AST_CONTROL_HANGUP; 01186 res = 0; 01187 break; 01188 } 01189 01190 if (f->frametype == AST_FRAME_DTMF) { 01191 dialed_code[x++] = f->subclass; 01192 dialed_code[x] = '\0'; 01193 if (strlen(dialed_code) == len) { 01194 x = 0; 01195 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01196 x = 0; 01197 dialed_code[x] = '\0'; 01198 } 01199 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01200 /* Caller Canceled the call */ 01201 state = AST_CONTROL_UNHOLD; 01202 ast_frfree(f); 01203 f = NULL; 01204 break; 01205 } 01206 } 01207 } 01208 if (f) { 01209 ast_frfree(f); 01210 } 01211 } 01212 } else 01213 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01214 } else { 01215 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01216 switch(cause) { 01217 case AST_CAUSE_BUSY: 01218 state = AST_CONTROL_BUSY; 01219 break; 01220 case AST_CAUSE_CONGESTION: 01221 state = AST_CONTROL_CONGESTION; 01222 break; 01223 } 01224 } 01225 01226 ast_indicate(caller, -1); 01227 if (chan && ready) { 01228 if (chan->_state == AST_STATE_UP) 01229 state = AST_CONTROL_ANSWER; 01230 res = 0; 01231 } else if(chan) { 01232 res = -1; 01233 ast_hangup(chan); 01234 chan = NULL; 01235 } else { 01236 res = -1; 01237 } 01238 01239 if (outstate) 01240 *outstate = state; 01241 01242 if (chan && res <= 0) { 01243 if (!chan->cdr) {