Sat Jul 26 06:44:57 2008

Asterisk developer's documentation


res_features.c File Reference

Routines implementing call parking. More...

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

Include dependency graph for res_features.c:

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  parkeduser

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500
#define DEFAULT_PARK_TIME   45000
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
#define FEATURE_RETURN_HANGUP   -1
#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
#define FEATURE_RETURN_PASSDIGITS   21
#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
#define FEATURE_RETURN_STOREDIGITS   22
#define FEATURE_RETURN_SUCCESS   23
#define FEATURE_RETURN_SUCCESSBREAK   0
#define FEATURE_SENSE_CHAN   (1 << 0)
#define FEATURE_SENSE_PEER   (1 << 1)
#define FEATURES_COUNT   (sizeof(builtin_features) / sizeof(builtin_features[0]))
#define FREE   free

Functions

static int adsi_announce_park (struct ast_channel *chan, int parkingnum)
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
static void * ast_bridge_call_thread (void *data)
static void ast_bridge_call_thread_launch (void *data)
static int ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static struct ast_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)
static AST_LIST_HEAD_STATIC (feature_list, ast_call_feature)
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
 AST_MUTEX_DEFINE_STATIC (parking_lock)
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call and read back parked location.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static void check_goto_on_transfer (struct ast_channel *chan)
char * description (void)
 Provides a description of the module.
static void * do_parking_thread (void *ignore)
static int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static struct ast_call_featurefind_feature (char *name)
static int handle_parkedcalls (int fd, int argc, char *argv[])
static int handle_showfeatures (int fd, int argc, char *argv[])
char * key ()
 Returns the ASTERISK_GPL_KEY.
static int load_config (void)
int load_module (void)
 Initialize the module.
static int manager_parking_status (struct mansession *s, struct message *m)
static int park_call_exec (struct ast_channel *chan, void *data)
static int park_exec (struct ast_channel *chan, void *data)
int reload (void)
 Reload stuff.
static int remap_feature (const char *name, const char *value)
static void set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
static void unmap_features (void)
int usecount (void)
 Provides a usecount.

Variables

static int adsipark
ast_call_feature builtin_features []
static char courtesytone [256]
static char * descrip
static char * descrip2
static int featuredigittimeout
 LOCAL_USER_DECL
static struct ast_appmonitor_app = NULL
static int monitor_ok = 1
static char * parkcall = "Park"
static char * parkedcall = "ParkedCall"
static int parkfindnext
static char parking_con [AST_MAX_EXTENSION]
static char parking_con_dial [AST_MAX_EXTENSION]
static char parking_ext [AST_MAX_EXTENSION]
static int parking_offset
static int parking_start
static int parking_stop
static pthread_t parking_thread
static struct parkeduserparkinglot
static int parkingtime = DEFAULT_PARK_TIME
static char pickup_ext [AST_MAX_EXTENSION]
static char * registrar = "res_features"
static struct ast_cli_entry showfeatures
static char showfeatures_help []
static struct ast_cli_entry showparked
static char showparked_help []
 STANDARD_LOCAL_USER
static char * synopsis = "Answer a parked call"
static char * synopsis2 = "Park yourself"
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Detailed Description

Routines implementing call parking.

Definition in file res_features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 73 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500

Definition at line 71 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 69 of file res_features.c.

Referenced by load_config().

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 70 of file res_features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 435 of file res_features.c.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 438 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 439 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 437 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 440 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_SUCCESS   23

Definition at line 441 of file res_features.c.

Referenced by builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app().

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 436 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 443 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 444 of file res_features.c.

Referenced by builtin_atxfer(), and builtin_blindtransfer().

#define FEATURES_COUNT   (sizeof(builtin_features) / sizeof(builtin_features[0]))

Definition at line 863 of file res_features.c.

Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), remap_feature(), set_config_flags(), and unmap_features().

#define FREE   free

Definition at line 66 of file res_features.c.


Function Documentation

static int adsi_announce_park ( struct ast_channel chan,
int  parkingnum 
) [static]

Definition at line 259 of file res_features.c.

References ADSI_JUST_CENT, adsi_load_session(), adsi_print(), and justify.

Referenced by ast_park_call().

00260 {
00261    int res;
00262    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00263    char tmp[256];
00264    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00265 
00266    snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
00267    message[0] = tmp;
00268    res = adsi_load_session(chan, NULL, 0, 1);
00269    if (res == -1) {
00270       return res;
00271    }
00272    return adsi_print(chan, message, justify, 1);
00273 }

int ast_bridge_call ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config 
)

Bridge a call, optionally allowing redirection.

Definition at line 1265 of file res_features.c.

References ast_channel::appl, ast_answer(), ast_cdr_appenduserfield(), ast_cdr_setuserfield(), ast_channel_bridge(), ast_dtmf_stream(), ast_frfree(), ast_log(), ast_strlen_zero(), ast_channel::cdr, config, ast_channel::data, FEATURE_MAX_LEN, free, LOG_DEBUG, monitor_app, monitor_ok, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.

Referenced by ast_bridge_call_thread(), builtin_atxfer(), dial_exec_full(), park_exec(), and try_calling().

01266 {
01267    /* Copy voice back and forth between the two channels.  Give the peer
01268       the ability to transfer calls with '#<extension' syntax. */
01269    struct ast_frame *f;
01270    struct ast_channel *who;
01271    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01272    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01273    int res;
01274    int diff;
01275    int hasfeatures=0;
01276    int hadfeatures=0;
01277    struct ast_option_header *aoh;
01278    struct ast_bridge_config backup_config;
01279    char *monitor_exec;
01280 
01281    memset(&backup_config, 0, sizeof(backup_config));
01282 
01283    config->start_time = ast_tvnow();
01284 
01285    if (chan && peer) {
01286       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01287       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01288    } else if (chan)
01289       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01290 
01291    if (monitor_ok) {
01292       if (!monitor_app) { 
01293          if (!(monitor_app = pbx_findapp("Monitor")))
01294             monitor_ok=0;
01295       }
01296       if (monitor_app) {
01297          if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01298             pbx_exec(chan, monitor_app, monitor_exec, 1);
01299          else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01300             pbx_exec(peer, monitor_app, monitor_exec, 1);
01301       }
01302    }
01303    
01304    set_config_flags(chan, peer, config);
01305    config->firstpass = 1;
01306 
01307    /* Answer if need be */
01308    if (ast_answer(chan))
01309       return -1;
01310    peer->appl = "Bridged Call";
01311    peer->data = chan->name;
01312 
01313    /* copy the userfield from the B-leg to A-leg if applicable */
01314    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01315       char tmp[256];
01316       if (!ast_strlen_zero(chan->cdr->userfield)) {
01317          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01318          ast_cdr_appenduserfield(chan, tmp);
01319       } else
01320          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01321       /* free the peer's cdr without ast_cdr_free complaining */
01322       free(peer->cdr);
01323       peer->cdr = NULL;
01324    }
01325    for (;;) {
01326       res = ast_channel_bridge(chan, peer, config, &f, &who);
01327 
01328       if (config->feature_timer) {
01329          /* Update time limit for next pass */
01330          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01331          config->feature_timer -= diff;
01332          if (hasfeatures) {
01333             /* Running on backup config, meaning a feature might be being
01334                activated, but that's no excuse to keep things going 
01335                indefinitely! */
01336             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01337                ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01338                config->feature_timer = 0;
01339                who = chan;
01340                if (f)
01341                   ast_frfree(f);
01342                f = NULL;
01343                res = 0;
01344             } else if (config->feature_timer <= 0) {
01345                /* Not *really* out of time, just out of time for
01346                   digits to come in for features. */
01347                ast_log(LOG_DEBUG, "Timed out for feature!\n");
01348                if (!ast_strlen_zero(peer_featurecode)) {
01349                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01350                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01351                }
01352                if (!ast_strlen_zero(chan_featurecode)) {
01353                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01354                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01355                }
01356                if (f)
01357                   ast_frfree(f);
01358                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01359                if (!hasfeatures) {
01360                   /* Restore original (possibly time modified) bridge config */
01361                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01362                   memset(&backup_config, 0, sizeof(backup_config));
01363                }
01364                hadfeatures = hasfeatures;
01365                /* Continue as we were */
01366                continue;
01367             } else if (!f) {
01368                /* The bridge returned without a frame and there is a feature in progress.
01369                 * However, we don't think the feature has quite yet timed out, so just
01370                 * go back into the bridge. */
01371                continue;
01372             }
01373          } else {
01374             if (config->feature_timer <=0) {
01375                /* We ran out of time */
01376                config->feature_timer = 0;
01377                who = chan;
01378                if (f)
01379                   ast_frfree(f);
01380                f = NULL;
01381                res = 0;
01382             }
01383          }
01384       }
01385       if (res < 0) {
01386          ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01387          return -1;
01388       }
01389       
01390       if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
01391          (f->subclass == AST_CONTROL_CONGESTION)))) {
01392             res = -1;
01393             break;
01394       }
01395       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01396          if (who == chan)
01397             ast_indicate(peer, AST_CONTROL_RINGING);
01398          else
01399             ast_indicate(chan, AST_CONTROL_RINGING);
01400       }
01401       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01402          if (who == chan)
01403             ast_indicate(peer, -1);
01404          else
01405             ast_indicate(chan, -1);
01406       }
01407       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01408          if (who == chan)
01409             ast_indicate(peer, AST_CONTROL_FLASH);
01410          else
01411             ast_indicate(chan, AST_CONTROL_FLASH);
01412       }
01413       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01414          aoh = f->data;
01415          /* Forward option Requests */
01416          if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01417             if (who == chan)
01418                ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01419             else
01420                ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01421          }
01422       }
01423       /* check for '*', if we find it it's time to disconnect */
01424       if (f && (f->frametype == AST_FRAME_DTMF)) {
01425          char *featurecode;
01426          int sense;
01427          struct ast_channel *other;
01428 
01429          hadfeatures = hasfeatures;
01430          /* This cannot overrun because the longest feature is one shorter than our buffer */
01431          if (who == chan) {
01432             other = peer;
01433             sense = FEATURE_SENSE_CHAN;
01434             featurecode = chan_featurecode;
01435          } else  {
01436             other = chan;
01437             sense = FEATURE_SENSE_PEER;
01438             featurecode = peer_featurecode;
01439          }
01440          featurecode[strlen(featurecode)] = f->subclass;
01441          /* Get rid of the frame before we start doing "stuff" with the channels */
01442          ast_frfree(f);
01443          f = NULL;
01444          config->feature_timer = backup_config.feature_timer;
01445          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01446          switch(res) {
01447          case FEATURE_RETURN_PASSDIGITS:
01448             ast_dtmf_stream(other, who, featurecode, 0);
01449             /* Fall through */
01450          case FEATURE_RETURN_SUCCESS:
01451             memset(featurecode, 0, sizeof(chan_featurecode));
01452             break;
01453          }
01454          if (res >= FEATURE_RETURN_PASSDIGITS) {
01455             res = 0;
01456          } else 
01457             break;
01458          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01459          if (hadfeatures && !hasfeatures) {
01460             /* Restore backup */
01461             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01462             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01463          } else if (hasfeatures) {
01464             if (!hadfeatures) {
01465                /* Backup configuration */
01466                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01467                /* Setup temporary config options */
01468                config->play_warning = 0;
01469                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01470                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01471                config->warning_freq = 0;
01472                config->warning_sound = NULL;
01473                config->end_sound = NULL;
01474                config->start_sound = NULL;
01475                config->firstpass = 0;
01476             }
01477             config->start_time = ast_tvnow();
01478             config->feature_timer = featuredigittimeout;
01479             ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01480          }
01481       }
01482       if (f)
01483          ast_frfree(f);
01484    }
01485    return res;
01486 }

static void* ast_bridge_call_thread ( void *  data  )  [static]

Definition at line 217 of file res_features.c.

References ast_channel::appl, ast_bridge_call(), ast_cdr_reset(), ast_cdr_setdestchan(), ast_hangup(), ast_bridge_thread_obj::bconfig, ast_channel::cdr, ast_bridge_thread_obj::chan, ast_channel::data, free, ast_channel::name, and ast_bridge_thread_obj::peer.

Referenced by ast_bridge_call_thread_launch().

00218 {
00219    struct ast_bridge_thread_obj *tobj = data;
00220 
00221    tobj->chan->appl = "Transferred Call";
00222    tobj->chan->data = tobj->peer->name;
00223    tobj->peer->appl = "Transferred Call";
00224    tobj->peer->data = tobj->chan->name;
00225    if (tobj->chan->cdr) {
00226       ast_cdr_reset(tobj->chan->cdr, NULL);
00227       ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00228    }
00229    if (tobj->peer->cdr) {
00230       ast_cdr_reset(tobj->peer->cdr, NULL);
00231       ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00232    }
00233 
00234    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00235    ast_hangup(tobj->chan);
00236    ast_hangup(tobj->peer);
00237    tobj->chan = tobj->peer = NULL;
00238    free(tobj);
00239    tobj=NULL;
00240    return NULL;
00241 }

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 243 of file res_features.c.

References ast_bridge_call_thread(), and ast_pthread_create.

Referenced by builtin_atxfer().

00244 {
00245    pthread_t thread;
00246    pthread_attr_t attr;
00247    struct sched_param sched;
00248 
00249    pthread_attr_init(&attr);
00250    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00251    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00252    pthread_attr_destroy(&attr);
00253    memset(&sched, 0, sizeof(sched));
00254    pthread_setschedparam(thread, SCHED_RR, &sched);
00255 }

static int ast_feature_interpret ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense 
) [static]

Definition at line 988 of file res_features.c.

References ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), builtin_features, config, exten, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, features, FEATURES_COUNT, find_feature(), LOG_DEBUG, ast_channel::name, ast_call_feature::operation, option_verbose, pbx_builtin_getvar_helper(), strsep(), and VERBOSE_PREFIX_3.

00989 {
00990    int x;
00991    struct ast_flags features;
00992    int res = FEATURE_RETURN_PASSDIGITS;
00993    struct ast_call_feature *feature;
00994    char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
00995 
00996    if (sense == FEATURE_SENSE_CHAN)
00997       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
00998    else
00999       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01000    ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
01001 
01002    for (x=0; x < FEATURES_COUNT; x++) {
01003       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01004           !ast_strlen_zero(builtin_features[x].exten)) {
01005          /* Feature is up for consideration */
01006          if (!strcmp(builtin_features[x].exten, code)) {
01007             res = builtin_features[x].operation(chan, peer, config, code, sense);
01008             break;
01009          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01010             if (res == FEATURE_RETURN_PASSDIGITS)
01011                res = FEATURE_RETURN_STOREDIGITS;
01012          }
01013       }
01014    }
01015 
01016 
01017    if (!ast_strlen_zero(dynamic_features)) {
01018       char *tmp = ast_strdupa(dynamic_features);
01019       char *tok;
01020 
01021       if (!tmp)
01022          return res;
01023       
01024       while ((tok = strsep(&tmp, "#")) != NULL) {
01025          feature = find_feature(tok);
01026          
01027          if (feature) {
01028             /* Feature is up for consideration */
01029             if (!strcmp(feature->exten, code)) {
01030                if (option_verbose > 2)
01031                   ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01032                if (sense == FEATURE_SENSE_CHAN)
01033                   res = feature->operation(chan, peer, config, code, sense);
01034                else
01035                   res = feature->operation(peer, chan, config, code, sense);
01036                break;
01037             } else if (!strncmp(feature->exten, code, strlen(code))) {
01038                res = FEATURE_RETURN_STOREDIGITS;
01039             }
01040          }
01041       }
01042    }
01043    
01044    return res;
01045 }

static struct ast_channel * ast_feature_request_and_dial ( struct ast_channel caller,
const char *  type,
int  format,
void *  data,
int  timeout,
int *  outstate,
const char *  cid_num,
const char *  cid_name 
) [static]

Definition at line 1092 of file res_features.c.

References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), AST_STATE_UP, ast_verbose(), ast_waitfor_n(), builtin_features, ast_channel::cdr, ast_call_feature::exten, FEATURES_COUNT, ast_frame::frametype, ast_channel::hangupcause, LOG_NOTICE, LOG_WARNING, option_verbose, ast_frame::subclass, and VERBOSE_PREFIX_3.

Referenced by builtin_atxfer().

01093 {
01094    int state = 0;
01095    int cause = 0;
01096    int to;
01097    struct ast_channel *chan;
01098    struct ast_channel *monitor_chans[2];
01099    struct ast_channel *active_channel;
01100    struct ast_frame *f = NULL;
01101    int res = 0, ready = 0;
01102    
01103    if ((chan = ast_request(type, format, data, &cause))) {
01104       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01105       ast_channel_inherit_variables(caller, chan); 
01106       if (!ast_call(chan, data, timeout)) {
01107          struct timeval started;
01108          int x, len = 0;
01109          char *disconnect_code = NULL, *dialed_code = NULL;
01110 
01111          ast_indicate(caller, AST_CONTROL_RINGING);
01112          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01113          for (x=0; x < FEATURES_COUNT; x++) {
01114             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01115                continue;
01116 
01117             disconnect_code = builtin_features[x].exten;
01118             len = strlen(disconnect_code) + 1;
01119             dialed_code = alloca(len);
01120             memset(dialed_code, 0, len);
01121             break;
01122          }
01123          x = 0;
01124          started = ast_tvnow();
01125          to = timeout;
01126          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01127             monitor_chans[0] = caller;
01128             monitor_chans[1] = chan;
01129             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01130 
01131             /* see if the timeout has been violated */
01132             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01133                state = AST_CONTROL_UNHOLD;
01134                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01135                break; /*doh! timeout*/
01136             }
01137 
01138             if (!active_channel) {
01139                continue;
01140             }
01141 
01142             if (chan && (chan == active_channel)){
01143                f = ast_read(chan);
01144                if (f == NULL) { /*doh! where'd he go?*/
01145                   state = AST_CONTROL_HANGUP;
01146                   res = 0;
01147                   break;
01148                }
01149                
01150                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01151                   if (f->subclass == AST_CONTROL_RINGING) {
01152                      state = f->subclass;
01153                      if (option_verbose > 2)
01154                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01155                      ast_indicate(caller, AST_CONTROL_RINGING);
01156                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01157                      state = f->subclass;
01158                      if (option_verbose > 2)
01159                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01160                      ast_indicate(caller, AST_CONTROL_BUSY);
01161                      ast_frfree(f);
01162                      f = NULL;
01163                      break;
01164                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01165                      /* This is what we are hoping for */
01166                      state = f->subclass;
01167                      ast_frfree(f);
01168                      f = NULL;
01169                      ready=1;
01170                      break;
01171                   } else {
01172                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01173                   }
01174                   /* else who cares */
01175                }
01176 
01177             } else if (caller && (active_channel == caller)) {
01178                f = ast_read(caller);
01179                if (f == NULL) { /*doh! where'd he go?*/
01180                   if (caller->_softhangup && !chan->_softhangup) {
01181                      /* make this a blind transfer */
01182                      ready = 1;
01183                      break;
01184                   }
01185                   state = AST_CONTROL_HANGUP;
01186                   res = 0;
01187                   break;
01188                }
01189                
01190                if (f->frametype == AST_FRAME_DTMF) {
01191                   dialed_code[x++] = f->subclass;
01192                   dialed_code[x] = '\0';
01193                   if (strlen(dialed_code) == len) {
01194                      x = 0;
01195                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01196                      x = 0;
01197                      dialed_code[x] = '\0';
01198                   }
01199                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01200                      /* Caller Canceled the call */
01201                      state = AST_CONTROL_UNHOLD;
01202                      ast_frfree(f);
01203                      f = NULL;
01204                      break;
01205                   }
01206                }
01207             }
01208             if (f) {
01209                ast_frfree(f);
01210             }
01211          }
01212       } else
01213          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01214    } else {
01215       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01216       switch(cause) {
01217       case AST_CAUSE_BUSY:
01218          state = AST_CONTROL_BUSY;
01219          break;
01220       case AST_CAUSE_CONGESTION:
01221          state = AST_CONTROL_CONGESTION;
01222          break;
01223       }
01224    }
01225    
01226    ast_indicate(caller, -1);
01227    if (chan && ready) {
01228       if (chan->_state == AST_STATE_UP) 
01229          state = AST_CONTROL_ANSWER;
01230       res = 0;
01231    } else if(chan) {
01232       res = -1;
01233       ast_hangup(chan);
01234       chan = NULL;
01235    } else {
01236       res = -1;
01237    }
01238    
01239    if (outstate)
01240       *outstate = state;
01241 
01242    if (chan && res <= 0) {
01243       if (!chan->cdr) {