
Go to the source code of this file.
Data Structures | |
| struct | ast_call_feature |
| main call feature structure More... | |
Defines | |
| #define | AST_FEATURE_RETURN_HANGUP -1 |
| #define | AST_FEATURE_RETURN_KEEPTRYING 24 |
| #define | AST_FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
| #define | AST_FEATURE_RETURN_PARKFAILED 25 |
| #define | AST_FEATURE_RETURN_PASSDIGITS 21 |
| #define | AST_FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
| #define | AST_FEATURE_RETURN_STOREDIGITS 22 |
| #define | AST_FEATURE_RETURN_SUCCESS 23 |
| #define | AST_FEATURE_RETURN_SUCCESSBREAK 0 |
| #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_SENSE_CHAN (1 << 0) |
| #define | FEATURE_SENSE_PEER (1 << 1) |
| #define | FEATURE_SNAME_LEN 32 |
Typedefs | |
| typedef int(* | ast_feature_operation )(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
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_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature) |
| detect a feature before bridging | |
| int | ast_features_reload (void) |
| Reload call features from features.conf. | |
| struct ast_call_feature * | ast_find_call_feature (const char *name) |
| look for a call feature entry by its sname | |
| 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. | |
| const char * | ast_parking_ext (void) |
| Determine system parking extension. | |
| int | ast_pickup_call (struct ast_channel *chan) |
| Pickup a call. | |
| const char * | ast_pickup_ext (void) |
| Determine system call pickup extension. | |
| void | ast_rdlock_call_features (void) |
| void | ast_register_feature (struct ast_call_feature *feature) |
| register new feature into feature_set | |
| void | ast_unlock_call_features (void) |
| void | ast_unregister_feature (struct ast_call_feature *feature) |
| unregister feature from feature_set | |
Definition in file features.h.
| #define AST_FEATURE_RETURN_HANGUP -1 |
Definition at line 34 of file features.h.
| #define AST_FEATURE_RETURN_KEEPTRYING 24 |
| #define AST_FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
Definition at line 37 of file features.h.
| #define AST_FEATURE_RETURN_PARKFAILED 25 |
Definition at line 42 of file features.h.
| #define AST_FEATURE_RETURN_PASSDIGITS 21 |
| #define AST_FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
Definition at line 36 of file features.h.
| #define AST_FEATURE_RETURN_STOREDIGITS 22 |
Definition at line 39 of file features.h.
Referenced by detect_disconnect(), and feature_interpret_helper().
| #define AST_FEATURE_RETURN_SUCCESS 23 |
Definition at line 40 of file features.h.
| #define AST_FEATURE_RETURN_SUCCESSBREAK 0 |
Definition at line 35 of 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_SENSE_CHAN (1 << 0) |
Definition at line 44 of file features.h.
Referenced by ast_bridge_call(), ast_feature_interpret(), and feature_exec_app().
| #define FEATURE_SENSE_PEER (1 << 1) |
| #define FEATURE_SNAME_LEN 32 |
| typedef int(* ast_feature_operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Definition at line 47 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.
Bridge a call, optionally allowing redirection.
| chan,peer,config | Set start time, check for two channels,check if monitor on check for feature activation, create new CDR |
| res | on success. | |
| -1 | on failure to bridge. |
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 2187 of file features.c.
References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, 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_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_bridge_config::end_sound, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_frame::frametype, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_bridge_config::play_warning, ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, ast_channel::visible_indication, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), park_exec(), and try_calling().
02188 { 02189 /* Copy voice back and forth between the two channels. Give the peer 02190 the ability to transfer calls with '#<extension' syntax. */ 02191 struct ast_frame *f; 02192 struct ast_channel *who; 02193 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02194 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02195 char orig_channame[AST_MAX_EXTENSION]; 02196 char orig_peername[AST_MAX_EXTENSION]; 02197 int res; 02198 int diff; 02199 int hasfeatures=0; 02200 int hadfeatures=0; 02201 int autoloopflag; 02202 struct ast_option_header *aoh; 02203 struct ast_bridge_config backup_config; 02204 struct ast_cdr *bridge_cdr = NULL; 02205 struct ast_cdr *orig_peer_cdr = NULL; 02206 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02207 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02208 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02209 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02210 02211 memset(&backup_config, 0, sizeof(backup_config)); 02212 02213 config->start_time = ast_tvnow(); 02214 02215 if (chan && peer) { 02216 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02217 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02218 } else if (chan) { 02219 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02220 } 02221 02222 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02223 add_features_datastores(chan, peer, config); 02224 02225 /* This is an interesting case. One example is if a ringing channel gets redirected to 02226 * an extension that picks up a parked call. This will make sure that the call taken 02227 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02228 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02229 ast_indicate(peer, AST_CONTROL_RINGING); 02230 } 02231 02232 if (monitor_ok) { 02233 const char *monitor_exec; 02234 struct ast_channel *src = NULL; 02235 if (!monitor_app) { 02236 if (!(monitor_app = pbx_findapp("Monitor"))) 02237 monitor_ok=0; 02238 } 02239 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02240 src = chan; 02241 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02242 src = peer; 02243 if (monitor_app && src) { 02244 char *tmp = ast_strdupa(monitor_exec); 02245 pbx_exec(src, monitor_app, tmp); 02246 } 02247 } 02248 02249 set_config_flags(chan, peer, config); 02250 config->firstpass = 1; 02251 02252 /* Answer if need be */ 02253 if (chan->_state != AST_STATE_UP) { 02254 if (ast_raw_answer(chan, 1)) { 02255 return -1; 02256 } 02257 } 02258 02259 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02260 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02261 orig_peer_cdr = peer_cdr; 02262 02263 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02264 02265 if (chan_cdr) { 02266 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02267 ast_cdr_update(chan); 02268 bridge_cdr = ast_cdr_dup(chan_cdr); 02269 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02270 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02271 } else { 02272 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02273 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02274 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02275 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02276 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02277 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02278 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02279 ast_cdr_setcid(bridge_cdr, chan); 02280 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02281 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02282 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02283 /* Destination information */ 02284 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02285 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02286 if (peer_cdr) { 02287 bridge_cdr->start = peer_cdr->start; 02288 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02289 } else { 02290 ast_cdr_start(bridge_cdr); 02291 } 02292 } 02293 ast_debug(4,"bridge answer set, chan answer set\n"); 02294 /* peer_cdr->answer will be set when a macro runs on the peer; 02295 in that case, the bridge answer will be delayed while the 02296 macro plays on the peer channel. The peer answered the call 02297 before the macro started playing. To the phone system, 02298 this is billable time for the call, even tho the caller 02299 hears nothing but ringing while the macro does its thing. */ 02300 02301 /* Another case where the peer cdr's time will be set, is when 02302 A self-parks by pickup up phone and dialing 700, then B 02303 picks up A by dialing its parking slot; there may be more 02304 practical paths that get the same result, tho... in which 02305 case you get the previous answer time from the Park... which 02306 is before the bridge's start time, so I added in the 02307 tvcmp check to the if below */ 02308 02309 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 02310 bridge_cdr->answer = peer_cdr->answer; 02311 bridge_cdr->disposition = peer_cdr->disposition; 02312 if (chan_cdr) { 02313 chan_cdr->answer = peer_cdr->answer; 02314 chan_cdr->disposition = peer_cdr->disposition; 02315 } 02316 } else { 02317 ast_cdr_answer(bridge_cdr); 02318 if (chan_cdr) { 02319 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02320 } 02321 } 02322 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 02323 if (chan_cdr) { 02324 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02325 } 02326 if (peer_cdr) { 02327 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02328 } 02329 } 02330 } 02331 for (;;) { 02332 struct ast_channel *other; /* used later */ 02333 02334 res = ast_channel_bridge(chan, peer, config, &f, &who); 02335 02336 /* When frame is not set, we are probably involved in a situation 02337 where we've timed out. 02338 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02339 and also for DTMF_END. If we flow into the following 'if' for both, then 02340 our wait times are cut in half, as both will subtract from the 02341 feature_timer. Not good! 02342 */ 02343 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02344 /* Update time limit for next pass */ 02345 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02346 if (res == AST_BRIDGE_RETRY) { 02347 /* The feature fully timed out but has not been updated. Skip 02348 * the potential round error from the diff calculation and 02349 * explicitly set to expired. */ 02350 config->feature_timer = -1; 02351 } else { 02352 config->feature_timer -= diff; 02353 } 02354 02355 if (hasfeatures) { 02356 /* Running on backup config, meaning a feature might be being 02357 activated, but that's no excuse to keep things going 02358 indefinitely! */ 02359 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02360 ast_debug(1, "Timed out, realtime this time!\n"); 02361 config->feature_timer = 0; 02362 who = chan; 02363 if (f) 02364 ast_frfree(f); 02365 f = NULL; 02366 res = 0; 02367 } else if (config->feature_timer <= 0) { 02368 /* Not *really* out of time, just out of time for 02369 digits to come in for features. */ 02370 ast_debug(1, "Timed out for feature!\n"); 02371 if (!ast_strlen_zero(peer_featurecode)) { 02372 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02373 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02374 } 02375 if (!ast_strlen_zero(chan_featurecode)) { 02376 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02377 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02378 } 02379 if (f) 02380 ast_frfree(f); 02381 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02382 if (!hasfeatures) { 02383 /* Restore original (possibly time modified) bridge config */ 02384 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02385 memset(&backup_config, 0, sizeof(backup_config)); 02386 } 02387 hadfeatures = hasfeatures; 02388 /* Continue as we were */ 02389 continue; 02390 } else if (!f) { 02391 /* The bridge returned without a frame and there is a feature in progress. 02392 * However, we don't think the feature has quite yet timed out, so just 02393 * go back into the bridge. */ 02394 continue; 02395 } 02396 } else { 02397 if (config->feature_timer <=0) { 02398 /* We ran out of time */ 02399 config->feature_timer = 0; 02400 who = chan; 02401 if (f) 02402 ast_frfree(f); 02403 f = NULL; 02404 res = 0; 02405 } 02406 } 02407 } 02408 if (res < 0) { 02409 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02410 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02411 goto before_you_go; 02412 } 02413 02414 if (!f || (f->frametype == AST_FRAME_CONTROL && 02415 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02416 f->subclass == AST_CONTROL_CONGESTION))) { 02417 res = -1; 02418 break; 02419 } 02420 /* many things should be sent to the 'other' channel */ 02421 other = (who == chan) ? peer : chan; 02422 if (f->frametype == AST_FRAME_CONTROL) { 02423 switch (f->subclass) { 02424 case AST_CONTROL_RINGING: 02425 case AST_CONTROL_FLASH: 02426 case -1: 02427 ast_indicate(other, f->subclass); 02428 break; 02429 case AST_CONTROL_HOLD: 02430 case AST_CONTROL_UNHOLD: 02431 ast_indicate_data(other, f->subclass, f->data, f->datalen); 02432 break; 02433 case AST_CONTROL_OPTION: 02434 aoh = f->data; 02435 /* Forward option Requests */ 02436 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02437 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02438 f->datalen - sizeof(struct ast_option_header), 0); 02439 } 02440 break; 02441 } 02442 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02443 /* eat it */ 02444 } else if (f->frametype == AST_FRAME_DTMF) { 02445 char *featurecode; 02446 int sense; 02447 02448 hadfeatures = hasfeatures; 02449 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02450 if (who == chan) { 02451 sense = FEATURE_SENSE_CHAN; 02452 featurecode = chan_featurecode; 02453 } else { 02454 sense = FEATURE_SENSE_PEER; 02455 featurecode = peer_featurecode; 02456 } 02457 /*! append the event to featurecode. we rely on the string being zero-filled, and 02458 * not overflowing it. 02459 * \todo XXX how do we guarantee the latter ? 02460 */ 02461 featurecode[strlen(featurecode)] = f->subclass; 02462 /* Get rid of the frame before we start doing "stuff" with the channels */ 02463 ast_frfree(f); 02464 f = NULL; 02465 config->feature_timer = backup_config.feature_timer; 02466 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 02467 switch(res) { 02468 case FEATURE_RETURN_PASSDIGITS: 02469 ast_dtmf_stream(other, who, featurecode, 0, 0); 02470 /* Fall through */ 02471 case FEATURE_RETURN_SUCCESS: 02472 memset(featurecode, 0, sizeof(chan_featurecode)); 02473 break; 02474 } 02475 if (res >= FEATURE_RETURN_PASSDIGITS) { 02476 res = 0; 02477 } else 02478 break; 02479 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02480 if (hadfeatures && !hasfeatures) { 02481 /* Restore backup */ 02482 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02483 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02484 } else if (hasfeatures) { 02485 if (!hadfeatures) { 02486 /* Backup configuration */ 02487 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02488 /* Setup temporary config options */ 02489 config->play_warning = 0; 02490 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02491 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02492 config->warning_freq = 0; 02493 config->warning_sound = NULL; 02494 config->end_sound = NULL; 02495 config->start_sound = NULL; 02496 config->firstpass = 0; 02497 } 02498 config->start_time = ast_tvnow(); 02499 config->feature_timer = featuredigittimeout; 02500 ast_debug(1, "Set time limit to %ld\n", config->feature_timer); 02501 } 02502 } 02503 if (f) 02504 ast_frfree(f); 02505 02506 } 02507 before_you_go: 02508 02509 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02510 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02511 if (bridge_cdr) { 02512 ast_cdr_discard(bridge_cdr); 02513 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02514 } 02515 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02516 } 02517 02518 if (config->end_bridge_callback) { 02519 config->end_bridge_callback(config->end_bridge_callback_data); 02520 } 02521 02522 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02523 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02524 struct ast_cdr *swapper = NULL; 02525 char savelastapp[AST_MAX_EXTENSION]; 02526 char savelastdata[AST_MAX_EXTENSION]; 02527 char save_exten[AST_MAX_EXTENSION]; 02528 int save_prio; 02529 int found = 0; /* set if we find at least one match */ 02530 int spawn_error = 0; 02531 02532 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02533 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02534 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02535 ast_cdr_end(bridge_cdr); 02536 } 02537 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02538 dialplan code operate on it */ 02539 ast_channel_lock(chan); 02540 if (bridge_cdr) { 02541 swapper = chan->cdr; 02542 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02543 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02544 chan->cdr = bridge_cdr; 02545 } 02546 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02547 save_prio = chan->priority; 02548 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02549 chan->priority = 1; 02550 ast_channel_unlock(chan); 02551 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 02552 chan->priority++; 02553 } 02554 if (found && spawn_error) { 02555 /* Something bad happened, or a hangup has been requested. */ 02556 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02557 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02558 } 02559 /* swap it back */ 02560 ast_channel_lock(chan); 02561 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02562 chan->priority = save_prio; 02563 if (bridge_cdr) { 02564 if (chan->cdr == bridge_cdr) { 02565 chan->cdr = swapper; 02566 } else { 02567 bridge_cdr = NULL; 02568 } 02569 } 02570 if (chan->priority != 1 || !spawn_error) { 02571 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02572 } 02573 ast_channel_unlock(chan); 02574 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02575 if (bridge_cdr) { 02576 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02577 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02578 } 02579 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02580 } 02581 02582 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02583 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02584 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 02585 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02586 02587 /* we can post the bridge CDR at this point */ 02588 if (bridge_cdr) { 02589 ast_cdr_end(bridge_cdr); 02590 ast_cdr_detach(bridge_cdr); 02591 } 02592 02593 /* do a specialized reset on the beginning channel 02594 CDR's, if they still exist, so as not to mess up 02595 issues in future bridges; 02596 02597 Here are the rules of the game: 02598 1. The chan and peer channel pointers will not change 02599 during the life of the bridge. 02600 2. But, in transfers, the channel names will change. 02601 between the time the bridge is started, and the 02602 time the channel ends. 02603 Usually, when a channel changes names, it will 02604 also change CDR pointers. 02605 3. Usually, only one of the two channels (chan or peer) 02606 will change names. 02607 4. Usually, if a channel changes names during a bridge, 02608 it is because of a transfer. Usually, in these situations, 02609 it is normal to see 2 bridges running simultaneously, and 02610 it is not unusual to see the two channels that change 02611 swapped between bridges. 02612 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02613 to attend to; if the chan or peer changed names, 02614 we have the before and after attached CDR's. 02615 */ 02616 02617 if (new_chan_cdr) { 02618 struct ast_channel *chan_ptr = NULL; 02619 02620 if (strcasecmp(orig_channame, chan->name) != 0) { 02621 /* old channel */ 02622 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02623 if (chan_ptr) { 02624 if (!ast_bridged_channel(chan_ptr)) { 02625 struct ast_cdr *cur; 02626 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02627 if (cur == chan_cdr) { 02628 break; 02629 } 02630 } 02631 if (cur) 02632 ast_cdr_specialized_reset(chan_cdr,0); 02633 } 02634 ast_channel_unlock(chan_ptr); 02635 } 02636 /* new channel */ 02637 ast_cdr_specialized_reset(new_chan_cdr,0); 02638 } else { 02639 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02640 } 02641 } 02642 02643 { 02644 struct ast_channel *chan_ptr = NULL; 02645 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02646 if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED)) 02647 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02648 if (strcasecmp(orig_peername, peer->name) != 0) { 02649 /* old channel */ 02650 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02651 if (chan_ptr) { 02652 if (!ast_bridged_channel(chan_ptr)) { 02653 struct ast_cdr *cur; 02654 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02655 if (cur == peer_cdr) { 02656 break; 02657 } 02658 } 02659 if (cur) 02660 ast_cdr_specialized_reset(peer_cdr,0); 02661 } 02662 ast_channel_unlock(chan_ptr); 02663 } 02664 /* new channel */ 02665 ast_cdr_specialized_reset(new_peer_cdr,0); 02666 } else { 02667 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02668 } 02669 } 02670 02671 return res; 02672 }
| int ast_feature_detect | ( | struct ast_channel * | chan, | |
| struct ast_flags * | features, | |||
| char * | code, | |||
| struct ast_call_feature * | feature | |||
| ) |
detect a feature before bridging
| chan | ||
| ast_flags | ptr | |
| char | ptr of input code |
| ast_call_feature | ptr to be set if found |
Definition at line 1842 of file features.c.
References feature_interpret_helper().
Referenced by detect_disconnect().
01842 { 01843 01844 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 01845 }
| int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 3496 of file features.c.
References load_config(), and RESULT_SUCCESS.
03497 { 03498 load_config(); 03499 03500 return RESULT_SUCCESS; 03501 }
| struct ast_call_feature* ast_find_call_feature | ( | const char * | name | ) | [read] |
look for a call feature entry by its sname
| name | a string ptr, should match "automon", "blindxfer", "atxfer", etc. |
Definition at line 1597 of file features.c.
References FEATURES_COUNT, and ast_call_feature::sname.
Referenced by handle_request_info(), and load_config().
01598 { 01599 int x; 01600 for (x = 0; x < FEATURES_COUNT; x++) { 01601 if (!strcasecmp(name, builtin_features[x].sname)) 01602 return &builtin_features[x]; 01603 } 01604 return NULL; 01605 }
| 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. | |
| timeout | is a timeout in milliseconds | |
| extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
| 0 | on success. | |
| -1 | on failure. |
Definition at line 665 of file features.c.
References masq_park_call().
Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().
00666 { 00667 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00668 }
| 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. | |
| timeout | is a timeout in milliseconds | |
| extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
| 0 | on success. | |
| -1 | on failure. |
Definition at line 611 of file features.c.
References park_call_full().
Referenced by iax_park_thread(), and sip_park_thread().
00612 { 00613 return park_call_full(chan, peer, timeout, extout, NULL, NULL); 00614 }
| const char* ast_parking_ext | ( | void | ) |
Determine system parking extension.
Definition at line 226 of file features.c.
References parking_ext.
Referenced by builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), load_config(), mgcp_ss(), socket_process(), and ss_thread().
00227 { 00228 return parking_ext; 00229 }
| int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
| chan | channel that initiated pickup. |
Definition at line 3864 of file features.c.
References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), pickup_exec(), and ss_thread().
03865 { 03866 struct ast_channel *cur = NULL; 03867 int res = -1; 03868 03869 while ((cur = ast_channel_walk_locked(cur)) != NULL) { 03870 if (!cur->pbx && 03871 (cur != chan) && 03872 (chan->pickupgroup & cur->callgroup) && 03873 ((cur->_state == AST_STATE_RINGING) || 03874 (cur->_state == AST_STATE_RING))) { 03875 break; 03876 } 03877 ast_channel_unlock(cur); 03878 } 03879 if (cur) { 03880 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 03881 res = ast_answer(chan); 03882 if (res) 03883 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 03884 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 03885 if (res) 03886 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 03887 res = ast_channel_masquerade(cur, chan); 03888 if (res) 03889 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 03890 ast_channel_unlock(cur); 03891 } else { 03892 ast_debug(1, "No call pickup possible...\n"); 03893 } 03894 return res; 03895 }
| const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 231 of file features.c.
References pickup_ext.
Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().
00232 { 00233 return pickup_ext; 00234 }
| void ast_rdlock_call_features | ( | void | ) |
Definition at line 1587 of file features.c.
References ast_rwlock_rdlock(), and features_lock.
Referenced by handle_request_info().
01588 { 01589 ast_rwlock_rdlock(&features_lock); 01590 }
| 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 1424 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, LOG_NOTICE, and ast_call_feature::sname.
Referenced by load_config().
01425 { 01426 if (!feature) { 01427 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01428 return; 01429 } 01430 01431 AST_RWLIST_WRLOCK(&feature_list); 01432 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01433 AST_RWLIST_UNLOCK(&feature_list); 01434 01435 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 01436 }
| void ast_unlock_call_features | ( | void | ) |
Definition at line 1592 of file features.c.
References ast_rwlock_unlock(), and features_lock.
Referenced by handle_request_info().
01593 { 01594 ast_rwlock_unlock(&features_lock); 01595 }
| 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 1512 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
01513 { 01514 if (!feature) { 01515 return; 01516 } 01517 01518 AST_RWLIST_WRLOCK(&feature_list); 01519 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01520 AST_RWLIST_UNLOCK(&feature_list); 01521 01522 ast_free(feature); 01523 }
1.5.6