Sat Nov 1 06:29:16 2008

Asterisk developer's documentation


res_features.c File Reference

Routines implementing call features as call pickup, parking and transfer. More...

#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_channelast_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_featurefind_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_cdrpick_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_appmonitor_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 parkeduserparkinglot
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]


Detailed Description

Routines implementing call features as call pickup, parking and transfer.

Author:
Mark Spencer <markster@digium.com>

Definition in file res_features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 72 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500

Definition at line 69 of file res_features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 70 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 67 of file res_features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 68 of file res_features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 539 of file res_features.c.

Referenced by builtin_disconnect().

#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

Definition at line 542 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_NO_HANGUP_PEER_PARKED   AST_PBX_NO_HANGUP_PEER_PARKED

Definition at line 543 of file res_features.c.

Referenced by feature_exec_app().

#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

Definition at line 541 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 545 of file res_features.c.

Referenced by ast_feature_interpret().

#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

Definition at line 540 of file res_features.c.

Referenced by feature_exec_app().

#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().


Enumeration Type Documentation

anonymous enum

Enumerator:
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 };


Function Documentation

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.

Todo:
XXX how do we guarantee the latter ?

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