#include "asterisk.h"
#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/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/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/global_datastores.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_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
| #define | DEFAULT_PARK_TIME 45000 |
| #define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
| #define | FEATURE_RETURN_HANGUP -1 |
| #define | FEATURE_RETURN_KEEPTRYING 24 |
| #define | FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
| #define | FEATURE_RETURN_NO_HANGUP_PEER_PARKED AST_PBX_NO_HANGUP_PEER_PARKED |
| #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])) |
Enumerations | |
| enum | { AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3), AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3) } |
Functions | |
| static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
| 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, const char *language) |
| 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_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Call Features Resource",.load=load_module,.unload=unload_module,.reload=reload,) | |
| 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 | |
| AST_RWLOCK_DEFINE_STATIC (features_lock) | |
| void | ast_unregister_feature (struct ast_call_feature *feature) |
| unregister feature from feature_set | |
| static void | ast_unregister_features (void) |
| Remove all features in the list. | |
| static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
| static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
| static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
| static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
| static int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
| support routing for one touch call parking | |
| static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
| static void | check_goto_on_transfer (struct ast_channel *chan) |
| static void * | do_parking_thread (void *ignore) |
| Take care of parked calls and unpark them if needed. | |
| static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
| exec an app by feature | |
| static struct ast_call_feature * | find_dynamic_feature (const char *name) |
| find a feature by name | |
| static int | finishup (struct ast_channel *chan) |
| static int | handle_parkedcalls (int fd, int argc, char *argv[]) |
| static int | handle_showfeatures (int fd, int argc, char *argv[]) |
| static int | load_config (void) |
| static int | load_module (void) |
| static int | manager_park (struct mansession *s, const struct message *m) |
| static int | manager_parking_status (struct mansession *s, const struct message *m) |
| Dump lot status. | |
| static int | masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement) |
| static int | masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
| static int | metermaidstate (const char *data) |
| metermaids callback from devicestate.c | |
| static void | notify_metermaids (char *exten, char *context) |
| Notify metermaids that we've changed an extension. | |
| static void | park_add_hints (char *context, int start, int stop) |
| Add parking hints for all defined parking lots. | |
| static int | park_call_exec (struct ast_channel *chan, void *data) |
| Park a call. | |
| static int | park_call_full (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name) |
| static int | park_exec (struct ast_channel *chan, void *data) |
| Pickup parked call. | |
| static struct ast_cdr * | pick_unlocked_cdr (struct ast_cdr *cdr) |
| static void | post_manager_event (const char *s, char *parkingexten, struct ast_channel *chan) |
| static const char * | real_ctx (struct ast_channel *transferer, struct ast_channel *transferee) |
| Find the context for the transfer. | |
| static int | reload (void) |
| static int | remap_feature (const char *name, const char *value) |
| static void | set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri) |
| store context, priority and extension | |
| static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
| static void | set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense) |
| set caller and callee according to the direction | |
| static int | unload_module (void) |
| static void | unmap_features (void) |
Variables | |
| static int | adsipark |
| static int | atxfernoanswertimeout |
| static struct ast_call_feature | builtin_features [] |
| static struct ast_cli_entry | cli_features [] |
| static struct ast_cli_entry | cli_show_features_deprecated |
| static char | courtesytone [256] |
| static char * | descrip |
| static char * | descrip2 |
| static int | featuredigittimeout |
| static char | mandescr_park [] |
| static struct ast_app * | monitor_app = NULL |
| static int | monitor_ok = 1 |
| static int | parkaddhints = 0 |
| static char * | parkcall = PARK_APP_NAME |
| static char * | parkedcall = "ParkedCall" |
| static int | parkedcalltransfers |
| static int | parkedplay = 0 |
| 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 | parkmohclass [MAX_MUSICCLASS] |
| static char | pickup_ext [AST_MAX_EXTENSION] |
| static char * | registrar = "res_features" |
| static char | showfeatures_help [] |
| static char | showparked_help [] |
| 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 72 of file res_features.c.
| #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
| #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
| #define DEFAULT_PARK_TIME 45000 |
Definition at line 67 of file res_features.c.
| #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
| #define FEATURE_RETURN_HANGUP -1 |
| #define FEATURE_RETURN_KEEPTRYING 24 |
Definition at line 547 of file res_features.c.
Referenced by ast_feature_interpret(), and feature_exec_app().
| #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
| #define FEATURE_RETURN_NO_HANGUP_PEER_PARKED AST_PBX_NO_HANGUP_PEER_PARKED |
| #define FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 544 of file res_features.c.
Referenced by ast_bridge_call(), and ast_feature_interpret().
| #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
| #define FEATURE_RETURN_STOREDIGITS 22 |
| #define FEATURE_RETURN_SUCCESS 23 |
Definition at line 546 of file res_features.c.
Referenced by ast_bridge_call(), builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app().
| #define FEATURE_RETURN_SUCCESSBREAK 0 |
| #define FEATURE_SENSE_CHAN (1 << 0) |
Definition at line 549 of file res_features.c.
Referenced by ast_bridge_call(), ast_feature_interpret(), builtin_parkcall(), and feature_exec_app().
| #define FEATURE_SENSE_PEER (1 << 1) |
Definition at line 550 of file res_features.c.
Referenced by ast_bridge_call(), builtin_parkcall(), feature_exec_app(), and set_peers().
| #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Definition at line 993 of file res_features.c.
Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().
| anonymous enum |
| AST_FEATURE_FLAG_NEEDSDTMF | |
| AST_FEATURE_FLAG_ONPEER | |
| AST_FEATURE_FLAG_ONSELF | |
| AST_FEATURE_FLAG_BYCALLEE | |
| AST_FEATURE_FLAG_BYCALLER | |
| AST_FEATURE_FLAG_BYBOTH |
Definition at line 74 of file res_features.c.
00074 { 00075 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00076 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00077 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00078 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00079 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00080 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00081 };
| static int adsi_announce_park | ( | struct ast_channel * | chan, | |
| char * | parkingexten | |||
| ) | [static] |
Definition at line 259 of file res_features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
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 %s", parkingexten); 00267 message[0] = tmp; 00268 res = ast_adsi_load_session(chan, NULL, 0, 1); 00269 if (res == -1) 00270 return res; 00271 return ast_adsi_print(chan, message, justify, 1); 00272 }
| 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 1437 of file res_features.c.
References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_answer(), ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), 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_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER_PARKED, ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_channel::cdr, ast_cdr::channel, config, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, ast_cdr::next, ast_option_header::option, option_debug, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), set_config_flags(), ast_cdr::start, ast_cdr::uniqueid, ast_cdr::userfield, and VERBOSE_PREFIX_2.
Referenced by app_exec(), ast_bridge_call_thread(), builtin_atxfer(), park_exec(), and try_calling().
01438 { 01439 /* Copy voice back and forth between the two channels. Give the peer 01440 the ability to transfer calls with '#<extension' syntax. */ 01441 struct ast_frame *f; 01442 struct ast_channel *who; 01443 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01444 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01445 char orig_channame[AST_MAX_EXTENSION]; 01446 char orig_peername[AST_MAX_EXTENSION]; 01447 01448 int res; 01449 int diff; 01450 int hasfeatures=0; 01451 int hadfeatures=0; 01452 int autoloopflag; 01453 struct ast_option_header *aoh; 01454 struct ast_bridge_config backup_config; 01455 struct ast_cdr *bridge_cdr = NULL; 01456 struct ast_cdr *orig_peer_cdr = NULL; 01457 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 01458 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 01459 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01460 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01461 01462 memset(&backup_config, 0, sizeof(backup_config)); 01463 01464 config->start_time = ast_tvnow(); 01465 01466 if (chan && peer) { 01467 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01468 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01469 } else if (chan) 01470 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01471 01472 if (monitor_ok) { 01473 const char *monitor_exec; 01474 struct ast_channel *src = NULL; 01475 if (!monitor_app) { 01476 if (!(monitor_app = pbx_findapp("Monitor"))) 01477 monitor_ok=0; 01478 } 01479 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01480 src = chan; 01481 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01482 src = peer; 01483 if (monitor_app && src) { 01484 char *tmp = ast_strdupa(monitor_exec); 01485 pbx_exec(src, monitor_app, tmp); 01486 } 01487 } 01488 01489 set_config_flags(chan, peer, config); 01490 config->firstpass = 1; 01491 01492 /* Answer if need be */ 01493 if (ast_answer(chan)) 01494 return -1; 01495 01496 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 01497 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 01498 orig_peer_cdr = peer_cdr; 01499 01500 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 01501 01502 if (chan_cdr) { 01503 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 01504 ast_cdr_update(chan); 01505 bridge_cdr = ast_cdr_dup(chan_cdr); 01506 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 01507 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 01508 } else { 01509 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 01510 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 01511 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 01512 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 01513 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 01514 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 01515 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 01516 ast_cdr_setcid(bridge_cdr, chan); 01517 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 01518 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 01519 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 01520 /* Destination information */ 01521 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 01522 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 01523 if (peer_cdr) { 01524 bridge_cdr->start = peer_cdr->start; 01525 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 01526 } else { 01527 ast_cdr_start(bridge_cdr); 01528 } 01529 } 01530 /* peer_cdr->answer will be set when a macro runs on the peer; 01531 in that case, the bridge answer will be delayed while the 01532 macro plays on the peer channel. The peer answered the call 01533 before the macro started playing. To the phone system, 01534 this is billable time for the call, even tho the caller 01535 hears nothing but ringing while the macro does its thing. */ 01536 if (peer_cdr && !ast_tvzero(peer_cdr->answer)) { 01537 bridge_cdr->answer = peer_cdr->answer; 01538 chan_cdr->answer = peer_cdr->answer; 01539 bridge_cdr->disposition = peer_cdr->disposition; 01540 chan_cdr->disposition = peer_cdr->disposition; 01541 } else { 01542 ast_cdr_answer(bridge_cdr); 01543 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 01544 } 01545 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 01546 if (peer_cdr) { 01547 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 01548 } 01549 } 01550 01551 for (;;) { 01552 struct ast_channel *other; /* used later */ 01553 01554 res = ast_channel_bridge(chan, peer, config, &f, &who); 01555 01556 if (config->feature_timer) { 01557 /* Update time limit for next pass */ 01558 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01559 config->feature_timer -= diff; 01560 if (hasfeatures) { 01561 /* Running on backup config, meaning a feature might be being 01562 activated, but that's no excuse to keep things going 01563 indefinitely! */ 01564 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01565 if (option_debug) 01566 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01567 config->feature_timer = 0; 01568 who = chan; 01569 if (f) 01570 ast_frfree(f); 01571 f = NULL; 01572 res = 0; 01573 } else if (config->feature_timer <= 0) { 01574 /* Not *really* out of time, just out of time for 01575 digits to come in for features. */ 01576 if (option_debug) 01577 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01578 if (!ast_strlen_zero(peer_featurecode)) { 01579 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01580 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01581 } 01582 if (!ast_strlen_zero(chan_featurecode)) { 01583 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01584 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01585 } 01586 if (f) 01587 ast_frfree(f); 01588 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01589 if (!hasfeatures) { 01590 /* Restore original (possibly time modified) bridge config */ 01591 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01592 memset(&backup_config, 0, sizeof(backup_config)); 01593 } 01594 hadfeatures = hasfeatures; 01595 /* Continue as we were */ 01596 continue; 01597 } else if (!f) { 01598 /* The bridge returned without a frame and there is a feature in progress. 01599 * However, we don't think the feature has quite yet timed out, so just 01600 * go back into the bridge. */ 01601 continue; 01602 } 01603 } else { 01604 if (config->feature_timer <=0) { 01605 /* We ran out of time */ 01606 config->feature_timer = 0; 01607 who = chan; 01608 if (f) 01609 ast_frfree(f); 01610 f = NULL; 01611 res = 0; 01612 } 01613 } 01614 } 01615 if (res < 0) { 01616 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01617 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01618 goto before_you_go; 01619 } 01620 01621 if (!f || (f->frametype == AST_FRAME_CONTROL && 01622 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01623 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01624 res = -1; 01625 break; 01626 } 01627 /* many things should be sent to the 'other' channel */ 01628 other = (who == chan) ? peer : chan; 01629 if (f->frametype == AST_FRAME_CONTROL) { 01630 switch (f->subclass) { 01631 case AST_CONTROL_RINGING: 01632 case AST_CONTROL_FLASH: 01633 case -1: 01634 ast_indicate(other, f->subclass); 01635 break; 01636 case AST_CONTROL_HOLD: 01637 case AST_CONTROL_UNHOLD: 01638 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01639 break; 01640 case AST_CONTROL_OPTION: 01641 aoh = f->data; 01642 /* Forward option Requests */ 01643 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01644 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01645 f->datalen - sizeof(struct ast_option_header), 0); 01646 } 01647 break; 01648 } 01649 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01650 /* eat it */ 01651 } else if (f->frametype == AST_FRAME_DTMF) { 01652 char *featurecode; 01653 int sense; 01654 01655 hadfeatures = hasfeatures; 01656 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01657 if (who == chan) { 01658 sense = FEATURE_SENSE_CHAN; 01659 featurecode = chan_featurecode; 01660 } else { 01661 sense = FEATURE_SENSE_PEER; 01662 featurecode = peer_featurecode; 01663 } 01664 /*! append the event to featurecode. we rely on the string being zero-filled, and 01665 * not overflowing it. 01666 * \todo XXX how do we guarantee the latter ? 01667 */ 01668 featurecode[strlen(featurecode)] = f->subclass; 01669 /* Get rid of the frame before we start doing "stuff" with the channels */ 01670 ast_frfree(f); 01671 f = NULL; 01672 config->feature_timer = backup_config.feature_timer; 01673 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01674 switch(res) { 01675 case FEATURE_RETURN_PASSDIGITS: 01676 ast_dtmf_stream(other, who, featurecode, 0); 01677 /* Fall through */ 01678 case FEATURE_RETURN_SUCCESS: 01679 memset(featurecode, 0, sizeof(chan_featurecode)); 01680 break; 01681 } 01682 if (res >= FEATURE_RETURN_PASSDIGITS) { 01683 res = 0; 01684 } else 01685 break; 01686 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01687 if (hadfeatures && !hasfeatures) { 01688 /* Restore backup */ 01689 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01690 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01691 } else if (hasfeatures) { 01692 if (!hadfeatures) { 01693 /* Backup configuration */ 01694 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01695 /* Setup temporary config options */ 01696 config->play_warning = 0; 01697 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01698 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01699 config->warning_freq = 0; 01700 config->warning_sound = NULL; 01701 config->end_sound = NULL; 01702 config->start_sound = NULL; 01703 config->firstpass = 0; 01704 } 01705 config->start_time = ast_tvnow(); 01706 config->feature_timer = featuredigittimeout; 01707 if (option_debug) 01708 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01709 } 01710 } 01711 if (f) 01712 ast_frfree(f); 01713 01714 } 01715 before_you_go: 01716 if (res != AST_PBX_KEEPALIVE && config->end_bridge_callback) { 01717 config->end_bridge_callback(); 01718 } 01719 01720 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 01721 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 01722 if (res != AST_PBX_KEEPALIVE && !ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 01723 struct ast_cdr *swapper; 01724 char savelastapp[AST_MAX_EXTENSION]; 01725 char savelastdata[AST_MAX_EXTENSION]; 01726 char save_exten[AST_MAX_EXTENSION]; 01727 int save_prio; 01728 01729 if (ast_opt_end_cdr_before_h_exten) { 01730 ast_cdr_end(bridge_cdr); 01731 } 01732 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 01733 dialplan code operate on it */ 01734 swapper = chan->cdr; 01735 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 01736 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 01737 ast_channel_lock(chan); 01738 chan->cdr = bridge_cdr; 01739 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 01740 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 01741 save_prio = chan->priority; 01742 chan->priority = 1; 01743 ast_channel_unlock(chan); 01744 while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) { 01745 if (ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) { 01746 /* Something bad happened, or a hangup has been requested. */ 01747 if (option_debug) 01748 ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 01749 if (option_verbose > 1) 01750 ast_verbose( VERBOSE_PREFIX_2 "Spawn h extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 01751 break; 01752 } 01753 chan->priority++; 01754 } 01755 /* swap it back */ 01756 ast_channel_lock(chan); 01757 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 01758 chan->priority = save_prio; 01759 chan->cdr = swapper; 01760 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 01761 ast_channel_unlock(chan); 01762 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 01763 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 01764 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 01765 } 01766 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 01767 01768 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 01769 if (res != AST_PBX_KEEPALIVE) { 01770 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 01771 if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 01772