Sun Aug 6 15:15:24 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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.

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_bridge_call(), and 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 ast_bridge_call(), 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_bridge_call(), and ast_feature_interpret().

#define FEATURE_SENSE_PEER   (1 << 1)
 

Definition at line 444 of file res_features.c.

Referenced by ast_bridge_call(), builtin_atxfer(), and builtin_blindtransfer().

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

Definition at line 859 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 1261 of file res_features.c.

References ast_channel::appl, ast_answer(), ast_cdr_appenduserfield(), ast_cdr_setuserfield(), ast_channel_bridge(), ast_channel_setoption(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_OPTION, AST_CONTROL_RINGING, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree(), ast_indicate(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strlen_zero(), ast_channel::cdr, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_bridge_config::end_sound, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, monitor_ok, ast_channel::name, ast_option_header::option, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, set_config_flags(), ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::userfield, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

01262 {
01263    /* Copy voice back and forth between the two channels.  Give the peer
01264       the ability to transfer calls with '#<extension' syntax. */
01265    struct ast_frame *f;
01266    struct ast_channel *who;
01267    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01268    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01269    int res;
01270    int diff;
01271    int hasfeatures=0;
01272    int hadfeatures=0;
01273    struct ast_option_header *aoh;
01274    struct timeval start = { 0 , 0 };
01275    struct ast_bridge_config backup_config;
01276    char *monitor_exec;
01277 
01278    memset(&backup_config, 0, sizeof(backup_config));
01279 
01280    config->start_time = ast_tvnow();
01281 
01282    if (chan && peer) {
01283       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01284       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01285    } else if (chan)
01286       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01287 
01288    if (monitor_ok) {
01289       if (!monitor_app) { 
01290          if (!(monitor_app = pbx_findapp("Monitor")))
01291             monitor_ok=0;
01292       }
01293       if (monitor_app) {
01294          if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01295             pbx_exec(chan, monitor_app, monitor_exec, 1);
01296          else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01297             pbx_exec(peer, monitor_app, monitor_exec, 1);
01298       }
01299    }
01300    
01301    set_config_flags(chan, peer, config);
01302    config->firstpass = 1;
01303 
01304    /* Answer if need be */
01305    if (ast_answer(chan))
01306       return -1;
01307    peer->appl = "Bridged Call";
01308    peer->data = chan->name;
01309 
01310    /* copy the userfield from the B-leg to A-leg if applicable */
01311    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01312       char tmp[256];
01313       if (!ast_strlen_zero(chan->cdr->userfield)) {
01314          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01315          ast_cdr_appenduserfield(chan, tmp);
01316       } else
01317          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01318       /* free the peer's cdr without ast_cdr_free complaining */
01319       free(peer->cdr);
01320       peer->cdr = NULL;
01321    }
01322    for (;;) {
01323       if (config->feature_timer)
01324          start = ast_tvnow();
01325 
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(), start);
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             }
01368          } else {
01369             if (config->feature_timer <=0) {
01370                /* We ran out of time */
01371                config->feature_timer = 0;
01372                who = chan;
01373                if (f)
01374                   ast_frfree(f);
01375                f = NULL;
01376                res = 0;
01377             }
01378          }
01379       }
01380       if (res < 0) {
01381          ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01382          return -1;
01383       }
01384       
01385       if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
01386          (f->subclass == AST_CONTROL_CONGESTION)))) {
01387             res = -1;
01388             break;
01389       }
01390       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01391          if (who == chan)
01392             ast_indicate(peer, AST_CONTROL_RINGING);
01393          else
01394             ast_indicate(chan, AST_CONTROL_RINGING);
01395       }
01396       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01397          if (who == chan)
01398             ast_indicate(peer, -1);
01399          else
01400             ast_indicate(chan, -1);
01401       }
01402       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01403          if (who == chan)
01404             ast_indicate(peer, AST_CONTROL_FLASH);
01405          else
01406             ast_indicate(chan, AST_CONTROL_FLASH);
01407       }
01408       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01409          aoh = f->data;
01410          /* Forward option Requests */
01411          if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01412             if (who == chan)
01413                ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01414             else
01415                ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01416          }
01417       }
01418       /* check for '*', if we find it it's time to disconnect */
01419       if (f && (f->frametype == AST_FRAME_DTMF)) {
01420          char *featurecode;
01421          int sense;
01422          struct ast_channel *other;
01423 
01424          hadfeatures = hasfeatures;
01425          /* This cannot overrun because the longest feature is one shorter than our buffer */
01426          if (who == chan) {
01427             other = peer;
01428             sense = FEATURE_SENSE_CHAN;
01429             featurecode = chan_featurecode;
01430          } else  {
01431             other = chan;
01432             sense = FEATURE_SENSE_PEER;
01433             featurecode = peer_featurecode;
01434          }
01435          featurecode[strlen(featurecode)] = f->subclass;
01436          /* Get rid of the frame before we start doing "stuff" with the channels */
01437          ast_frfree(f);
01438          f = NULL;
01439          config->feature_timer = backup_config.feature_timer;
01440          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01441          switch(res) {
01442          case FEATURE_RETURN_PASSDIGITS:
01443             ast_dtmf_stream(other, who, featurecode, 0);
01444             /* Fall through */
01445          case FEATURE_RETURN_SUCCESS:
01446             memset(featurecode, 0, sizeof(chan_featurecode));
01447             break;
01448          }
01449          if (res >= FEATURE_RETURN_PASSDIGITS) {
01450             res = 0;
01451          } else 
01452             break;
01453          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01454          if (hadfeatures && !hasfeatures) {
01455             /* Restore backup */
01456             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01457             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01458          } else if (hasfeatures) {
01459             if (!hadfeatures) {
01460                /* Backup configuration */
01461                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01462                /* Setup temporary config options */
01463                config->play_warning = 0;
01464                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01465                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01466                config->warning_freq = 0;
01467                config->warning_sound = NULL;
01468                config->end_sound = NULL;
01469                config->start_sound = NULL;
01470                config->firstpass = 0;
01471             }
01472             config->feature_timer = featuredigittimeout;
01473             ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01474          }
01475       }
01476       if (f)
01477          ast_frfree(f);
01478    }
01479    return res;
01480 }

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 984 of file res_features.c.

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

Referenced by ast_bridge_call().

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

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 1088 of file res_features.c.

References 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(), 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().

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

static AST_LIST_HEAD_STATIC feature_list  ,
ast_call_feature 
[static]
 

int ast_masq_park_call struct ast_channel rchan,
struct ast_channel host,
int  timeout,
int *  extout
 

Park a call via a masqueraded channel.

Parameters:
rchan the real channel to be parked
host the channel to have the parking read to Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want

Definition at line 401 of file res_features.c.

References ast_channel_alloc(), ast_channel_masquerade(), ast_frfree(), ast_log(), ast_park_call(), ast_read(), ast_channel::context, ast_channel::exten, LOG_WARNING, ast_channel::name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

Referenced by mgcp_ss(), parkandannounce_exec(), rpt_exec(), skinny_ss(), and ss_thread().

00402 {
00403    struct ast_channel *chan;
00404    struct ast_frame *f;
00405 
00406    /* Make a new, fake channel that we'll use to masquerade in the real one */
00407    chan = ast_channel_alloc(0);
00408    if (chan) {
00409       /* Let us keep track of the channel name */
00410       snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
00411 
00412       /* Make formats okay */
00413       chan->readformat = rchan->readformat;
00414       chan->writeformat = rchan->writeformat;
00415       ast_channel_masquerade(chan, rchan);
00416 
00417       /* Setup the extensions and such */
00418       ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
00419       ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
00420       chan->priority = rchan->priority;
00421 
00422       /* Make the masq execute */
00423       f = ast_read(chan);
00424       if (f)
00425          ast_frfree(f);
00426       ast_park_call(chan, peer, timeout, extout);
00427    } else {
00428       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00429       return -1;
00430    }
00431    return 0;
00432 }

AST_MUTEX_DEFINE_STATIC parking_lock   ) 
 

int ast_park_call struct ast_channel chan,
struct ast_channel host,
int  timeout,
int *  extout
 

Park a call and read back parked location.

Parameters:
chan the channel to actually be parked
host the channel which will have the parked location read to Park the channel chan, and read back the parked location to the host. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context)
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want

Definition at line 278 of file res_features.c.

References adsi_announce_park(), adsi_available(), adsi_unload_session(), adsipark, ast_channel::appl, ast_add_extension2(), ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, exten, FREE, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, malloc, manager_event(), ast_channel::name, parkeduser::next, parkeduser::notquiteyet, option_verbose, parkedcall, parkfindnext, parking_con, parking_offset, parking_start, parking_stop, parking_thread, parkeduser::parkingnum, parkingtime, parkeduser::parkingtime, parkeduser::peername, ast_channel::priority, parkeduser::priority, registrar, parkeduser::start, strdup, and VERBOSE_PREFIX_2.

Referenced by ast_masq_park_call(), builtin_blindtransfer(), iax_park_thread(), park_call_exec(), and sip_park_thread().

00279 {
00280    struct parkeduser *pu, *cur;
00281    int i,x,parking_range;
00282    char exten[AST_MAX_EXTENSION];
00283    struct ast_context *con;
00284 
00285    pu = malloc(sizeof(struct parkeduser));
00286    if (!pu) {
00287       ast_log(LOG_WARNING, "Out of memory\n");
00288       return -1;
00289    }
00290    memset(pu, 0, sizeof(struct parkeduser));
00291    ast_mutex_lock(&parking_lock);
00292    parking_range = parking_stop - parking_start+1;
00293    for (i = 0; i < parking_range; i++) {
00294       x = (i + parking_offset) % parking_range + parking_start;
00295       cur = parkinglot;
00296       while(cur) {
00297          if (cur->parkingnum == x) 
00298             break;
00299          cur = cur->next;
00300       }
00301       if (!cur)
00302          break;
00303    }
00304 
00305    if (!(i < parking_range)) {
00306       ast_log(LOG_WARNING, "No more parking spaces\n");
00307       free(pu);
00308       ast_mutex_unlock(&parking_lock);
00309       return -1;
00310    }
00311    if (parkfindnext) 
00312       parking_offset = x - parking_start + 1;
00313    chan->appl = "Parked Call";
00314    chan->data = NULL; 
00315 
00316    pu->chan = chan;
00317    /* Start music on hold */
00318    if (chan != peer) {
00319       ast_indicate(pu->chan, AST_CONTROL_HOLD);
00320       ast_moh_start(pu->chan, NULL);
00321    }
00322    pu->start = ast_tvnow();
00323    pu->parkingnum = x;
00324    if (timeout > 0)
00325       pu->parkingtime = timeout;
00326    else
00327       pu->parkingtime = parkingtime;
00328    if (extout)
00329       *extout = x;
00330    if (peer) 
00331       ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00332 
00333    /* Remember what had been dialed, so that if the parking
00334       expires, we try to come back to the same place */
00335    if (!ast_strlen_zero(chan->macrocontext))
00336       ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
00337    else
00338       ast_copy_string(pu->context, chan->context, sizeof(pu->context));
00339    if (!ast_strlen_zero(chan->macroexten))
00340       ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
00341    else
00342       ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
00343    if (chan->macropriority)
00344       pu->priority = chan->macropriority;
00345    else
00346       pu->priority = chan->priority;
00347    pu->next = parkinglot;
00348    parkinglot = pu;
00349    /* If parking a channel directly, don't quiet yet get parking running on it */
00350    if (peer == chan) 
00351       pu->notquiteyet = 1;
00352    ast_mutex_unlock(&parking_lock);
00353    /* Wake up the (presumably select()ing) thread */
00354    pthread_kill(parking_thread, SIGURG);
00355    if (option_verbose > 1) 
00356       ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00357 
00358    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00359       "Exten: %d\r\n"
00360       "Channel: %s\r\n"
00361       "From: %s\r\n"
00362       "Timeout: %ld\r\n"
00363       "CallerID: %s\r\n"
00364       "CallerIDName: %s\r\n"
00365       ,pu->parkingnum, pu->chan->name, peer ? peer->name : ""
00366       ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
00367       ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
00368       ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
00369       );
00370 
00371    if (peer) {
00372       if (adsipark && adsi_available(peer)) {
00373          adsi_announce_park(peer, pu->parkingnum);
00374       }
00375       if (adsipark && adsi_available(peer)) {
00376          adsi_unload_session(peer);
00377       }
00378    }
00379    con = ast_context_find(parking_con);
00380    if (!con) {
00381       con = ast_context_create(NULL, parking_con, registrar);
00382       if (!con) {
00383          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00384       }
00385    }
00386    if (con) {
00387       snprintf(exten, sizeof(exten), "%d", x);
00388       ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
00389    }
00390    if (peer) 
00391       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00392    if (pu->notquiteyet) {
00393       /* Wake up parking thread if we're really done */
00394       ast_moh_start(pu->chan, NULL);
00395       pu->notquiteyet = 0;
00396       pthread_kill(parking_thread, SIGURG);
00397    }
00398    return 0;
00399 }

char* ast_parking_ext void   ) 
 

Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.

Definition at line 163 of file res_features.c.

References parking_ext.

Referenced by builtin_blindtransfer(), dp_lookup(), get_refer_info(), handle_request_refer(), load_config(), mgcp_ss(), skinny_ss(), socket_read(), and ss_thread().

00164 {
00165    return parking_ext;
00166 }

int ast_pickup_call struct ast_channel chan  ) 
 

Pickup a call.

Definition at line 1926 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_mutex_unlock(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.

Referenced by cb_events(), handle_request_invite(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread().

01927 {
01928    struct ast_channel *cur = NULL;
01929    int res = -1;
01930 
01931    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01932       if (!cur->pbx && 
01933          (cur != chan) &&
01934          (chan->pickupgroup & cur->callgroup) &&
01935          ((cur->_state == AST_STATE_RINGING) ||
01936           (cur->_state == AST_STATE_RING))) {
01937             break;
01938       }
01939       ast_mutex_unlock(&cur->lock);
01940    }
01941    if (cur) {
01942       if (option_debug)
01943          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01944       res = ast_answer(chan);
01945       if (res)
01946          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01947       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01948       if (res)
01949          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01950       res = ast_channel_masquerade(cur, chan);
01951       if (res)
01952          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
01953       ast_mutex_unlock(&cur->lock);
01954    } else   {
01955       if (option_debug)
01956          ast_log(LOG_DEBUG, "No call pickup possible...\n");
01957    }
01958    return res;
01959 }

char* ast_pickup_ext void   ) 
 

Determine system call pickup extension.

Definition at line 168 of file res_features.c.

References pickup_ext.

Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread().

00169 {
00170    return pickup_ext;
00171 }

void ast_register_feature struct ast_call_feature feature  ) 
 

register new feature into feature_set

Parameters:
feature an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call.

Definition at line 872 of file res_features.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_verbose(), LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.

Referenced by load_config().

00873 {
00874    if (!feature) {
00875       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00876          return;
00877    }
00878   
00879    AST_LIST_LOCK(&feature_list);
00880    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00881    AST_LIST_UNLOCK(&feature_list);
00882 
00883    if (option_verbose >= 2) 
00884       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00885 }

void ast_unregister_feature struct ast_call_feature feature  ) 
 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 888 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00889 {
00890    if (!feature) return;
00891 
00892    AST_LIST_LOCK(&feature_list);
00893    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00894    AST_LIST_UNLOCK(&feature_list);
00895    free(feature);
00896 }

static void ast_unregister_features void   )  [static]
 

Definition at line 898 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

Referenced by load_config().

00899 {
00900    struct ast_call_feature *feature;
00901 
00902    AST_LIST_LOCK(&feature_list);
00903    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00904       free(feature);
00905    AST_LIST_UNLOCK(&feature_list);
00906 }

static int builtin_atxfer struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense
[static]
 

Definition at line 666 of file res_features.c.

References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_channel_alloc(), ast_channel_make_compatible(), ast_channel_masquerade(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_read(), ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_waitfordigit(), ast_waitstream(), ast_channel::cid, ast_callerid::cid_name, cid_name, ast_callerid::cid_num, cid_num, ast_channel::context, ast_channel::exten, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_PEER, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, malloc, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::priority, ast_channel::readformat, transferdigittimeout, ast_channel::writeformat, xferfailsound, and xfersound.

00667 {
00668    struct ast_channel *transferer;
00669    struct ast_channel *transferee;
00670    struct ast_channel *newchan, *xferchan=NULL;
00671    int outstate=0;
00672    struct ast_bridge_config bconfig;
00673    char *transferer_real_context;
00674    char xferto[256],dialstr[265];
00675    char *cid_num;
00676    char *cid_name;
00677    int res;
00678    struct ast_frame *f = NULL;
00679    struct ast_bridge_thread_obj *tobj;
00680 
00681    ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
00682    if (sense == FEATURE_SENSE_PEER) {
00683       transferer = peer;
00684       transferee = chan;
00685    } else {
00686       transferer = chan;
00687       transferee = peer;
00688    }
00689    if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00690       !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00691       /* Use the non-macro context to transfer the call */
00692       if (!ast_strlen_zero(transferer->macrocontext))
00693          transferer_real_context = transferer->macrocontext;
00694       else
00695          transferer_real_context = transferer->context;
00696    }
00697    /* Start autoservice on chan while we talk
00698       to the originator */
00699    ast_indicate(transferee, AST_CONTROL_HOLD);
00700    ast_autoservice_start(transferee);
00701    ast_moh_start(transferee, NULL);
00702    memset(xferto, 0, sizeof(xferto));
00703    /* Transfer */
00704    if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00705       ast_moh_stop(transferee);
00706       ast_autoservice_stop(transferee);
00707       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00708       return res;
00709    }
00710    if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00711       ast_moh_stop(transferee);
00712       ast_autoservice_stop(transferee);
00713       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00714       return res;
00715    } else if(res > 0) {
00716       /* If they've typed a digit already, handle it */
00717       xferto[0] = (char) res;
00718    }
00719    if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
00720       cid_num = transferer->cid.cid_num;
00721       cid_name = transferer->cid.cid_name;
00722       if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
00723          snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
00724          newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
00725          ast_indicate(transferer, -1);
00726          if (newchan) {
00727             res = ast_channel_make_compatible(transferer, newchan);
00728             if (res < 0) {
00729                ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
00730                ast_hangup(newchan);
00731                return -1;
00732             }
00733             memset(&bconfig,0,sizeof(struct ast_bridge_config));
00734             ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00735             ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00736             res = ast_bridge_call(transferer,newchan,&bconfig);
00737             if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
00738                ast_hangup(newchan);
00739                if (f) {
00740                   ast_frfree(f);
00741                   f = NULL;
00742                }
00743                if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
00744                   if (ast_waitstream(transferer, "") < 0) {
00745                      ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00746                   }
00747                }
00748                ast_moh_stop(transferee);
00749                ast_autoservice_stop(transferee);
00750                ast_indicate(transferee, AST_CONTROL_UNHOLD);
00751                transferer->_softhangup = 0;
00752                return FEATURE_RETURN_SUCCESS;
00753             }
00754             
00755             res = ast_channel_make_compatible(transferee, newchan);
00756             if (res < 0) {
00757                ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
00758                ast_hangup(newchan);
00759                return -1;
00760             }
00761             
00762             
00763             ast_moh_stop(transferee);
00764             
00765             if ((ast_autoservice_stop(transferee) < 0)
00766                || (ast_waitfordigit(transferee, 100) < 0)
00767                || (ast_waitfordigit(newchan, 100) < 0) 
00768                || ast_check_hangup(transferee) 
00769                || ast_check_hangup(newchan)) {
00770                ast_hangup(newchan);
00771                res = -1;
00772                return -1;
00773             }
00774 
00775             if ((xferchan = ast_channel_alloc(0))) {
00776                snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name);
00777                /* Make formats okay */
00778                xferchan->readformat = transferee->readformat;
00779                xferchan->writeformat = transferee->writeformat;
00780                ast_channel_masquerade(xferchan, transferee);
00781                ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00782                xferchan->_state = AST_STATE_UP;
00783                ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00784                xferchan->_softhangup = 0;
00785 
00786                if ((f = ast_read(xferchan))) {
00787                   ast_frfree(f);
00788                   f = NULL;
00789                }
00790                
00791             } else {
00792                ast_hangup(newchan);
00793                return -1;
00794             }
00795 
00796             newchan->_state = AST_STATE_UP;
00797             ast_clear_flag(newchan, AST_FLAGS_ALL);   
00798             newchan->_softhangup = 0;
00799 
00800             tobj = malloc(sizeof(struct ast_bridge_thread_obj));
00801             if (tobj) {
00802                memset(tobj,0,sizeof(struct ast_bridge_thread_obj));
00803                tobj->chan = xferchan;
00804                tobj->peer = newchan;
00805                tobj->bconfig = *config;
00806    
00807                if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
00808                   if (ast_waitstream(newchan, "") < 0) {
00809                      ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00810                   }
00811                }
00812                ast_bridge_call_thread_launch(tobj);
00813             } else {
00814                ast_log(LOG_WARNING, "Out of memory!\n");
00815                ast_hangup(xferchan);
00816                ast_hangup(newchan);
00817             }
00818             return -1;
00819             
00820          } else {
00821             ast_moh_stop(transferee);
00822             ast_autoservice_stop(transferee);
00823             ast_indicate(transferee, AST_CONTROL_UNHOLD);
00824             /* any reason besides user requested cancel and busy triggers the failed sound */
00825             if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
00826                res = ast_streamfile(transferer, xferfailsound, transferer->language);
00827                if (!res && (ast_waitstream(transferer, "") < 0)) {
00828                   return -1;
00829                }
00830             }
00831             return FEATURE_RETURN_SUCCESS;
00832          }
00833       } else {
00834          ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00835          ast_moh_stop(transferee);
00836          ast_autoservice_stop(transferee);
00837          ast_indicate(transferee, AST_CONTROL_UNHOLD);
00838          res = ast_streamfile(transferer, "beeperr", transferer->language);
00839          if (!res && (ast_waitstream(transferer, "") < 0)) {
00840             return -1;
00841          }
00842       }
00843    }  else {
00844       ast_log(LOG_WARNING, "Did not read data.\n");
00845       res = ast_streamfile(transferer, "beeperr", transferer->language);
00846       if (ast_waitstream(transferer, "") < 0) {
00847          return -1;
00848       }
00849    }
00850    ast_moh_stop(transferee);
00851    ast_autoservice_stop(transferee);
00852    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00853 
00854    return FEATURE_RETURN_SUCCESS;
00855 }

static int builtin_automonitor struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense
[static]
 

Definition at line 447 of file res_features.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_monitor_stop(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), courtesytone, FEATURE_RETURN_SUCCESS, ast_channel::language, LOG_ERROR, LOG_NOTICE, LOG_WARNING, monitor_ok, option_verbose, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), and VERBOSE_PREFIX_3.

00448 {
00449    char *touch_monitor = NULL, *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_format = NULL;
00450    int x = 0;
00451    size_t len;
00452    struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
00453 
00454 
00455    if(sense == 2) {
00456       caller_chan = peer;
00457       callee_chan = chan;
00458    } else {
00459       callee_chan = peer;
00460       caller_chan = chan;
00461    }
00462    
00463    if (!monitor_ok) {
00464       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00465       return -1;
00466    }
00467 
00468    if (!monitor_app) { 
00469       if (!(monitor_app = pbx_findapp("Monitor"))) {
00470          monitor_ok=0;
00471          ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00472          return -1;
00473       }
00474    }
00475    if (!ast_strlen_zero(courtesytone)) {
00476       if (ast_autoservice_start(callee_chan))
00477          return -1;
00478       if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
00479          if (ast_waitstream(caller_chan, "") < 0) {
00480             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00481             ast_autoservice_stop(callee_chan);
00482             return -1;
00483          }
00484       }
00485       if (ast_autoservice_stop(callee_chan))
00486          return -1;
00487    }
00488    
00489    if (callee_chan->monitor) {
00490       if (option_verbose > 3)
00491          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00492       ast_monitor_stop(callee_chan, 1);
00493       return FEATURE_RETURN_SUCCESS;
00494    }
00495 
00496    if (caller_chan && callee_chan) {
00497       touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00498       if (!touch_format)
00499          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00500 
00501       touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00502       if (!touch_monitor)
00503          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00504       
00505       if (touch_monitor) {
00506          len = strlen(touch_monitor) + 50;
00507          args = alloca(len);
00508          snprintf(args, len, "%s|auto-%ld-%s|m", (touch_format) ? touch_format : "wav", time(NULL), touch_monitor);
00509       } else {
00510          caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
00511          callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
00512          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00513          args = alloca(len);
00514          snprintf(args, len, "%s|auto-%ld-%s-%s|m", (touch_format) ? touch_format : "wav", time(NULL), caller_chan_id, callee_chan_id);
00515       }
00516 
00517       for( x = 0; x < strlen(args); x++)
00518          if (args[x] == '/')
00519             args[x] = '-';
00520       
00521       if (option_verbose > 3)
00522          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00523 
00524       pbx_exec(callee_chan, monitor_app, args, 1);
00525       
00526       return FEATURE_RETURN_SUCCESS;
00527    }
00528    
00529    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00530    return -1;
00531 }

static int builtin_blindtransfer struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense
[static]
 

Definition at line 540 of file res_features.c.

References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_autoservice_stop(), AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_park_call(), ast_parking_ext(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_PEER, ast_channel::language, LOG_WARNING, ast_channel::macrocontext, ast_channel::name, option_verbose, ast_channel::pbx, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, transferdigittimeout, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and xferfailsound.

00541 {
00542    struct ast_channel *transferer;
00543    struct ast_channel *transferee;
00544    char *transferer_real_context;
00545    char newext[256];
00546    int res;
00547 
00548    if (sense == FEATURE_SENSE_PEER) {
00549       transferer = peer;
00550       transferee = chan;
00551    } else {
00552       transferer = chan;
00553       transferee = peer;
00554    }
00555    if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00556       !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00557       /* Use the non-macro context to transfer the call */
00558       if (!ast_strlen_zero(transferer->macrocontext))
00559          transferer_real_context = transferer->macrocontext;
00560       else
00561          transferer_real_context = transferer->context;
00562    }
00563    /* Start autoservice on chan while we talk
00564       to the originator */
00565    ast_indicate(transferee, AST_CONTROL_HOLD);
00566    ast_autoservice_start(transferee);
00567    ast_moh_start(transferee, NULL);
00568 
00569    memset(newext, 0, sizeof(newext));
00570    
00571    /* Transfer */
00572    if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00573       ast_moh_stop(transferee);
00574       ast_autoservice_stop(transferee);
00575       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00576       return res;
00577    }
00578    if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00579       ast_moh_stop(transferee);
00580       ast_autoservice_stop(transferee);
00581       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00582       return res;
00583    } else if (res > 0) {
00584       /* If they've typed a digit already, handle it */
00585       newext[0] = (char) res;
00586    }
00587 
00588    ast_stopstream(transferer);
00589    res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
00590    if (res < 0) {
00591       ast_moh_stop(transferee);
00592       ast_autoservice_stop(transferee);
00593       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00594       return res;
00595    }
00596    if (!strcmp(newext, ast_parking_ext())) {
00597       ast_moh_stop(transferee);
00598 
00599       res = ast_autoservice_stop(transferee);
00600       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00601       if (res)
00602          res = -1;
00603       else if (!ast_park_call(transferee, transferer, 0, NULL)) {
00604          /* We return non-zero, but tell the PBX not to hang the channel when
00605             the thread dies -- We have to be careful now though.  We are responsible for 
00606             hanging up the channel, else it will never be hung up! */
00607 
00608          if (transferer == peer)
00609             res = AST_PBX_KEEPALIVE;
00610          else
00611             res = AST_PBX_NO_HANGUP_PEER;
00612          return res;
00613       } else {
00614          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00615       }
00616       /* XXX Maybe we should have another message here instead of invalid extension XXX */
00617    } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
00618       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
00619       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00620       ast_moh_stop(transferee);
00621       res=ast_autoservice_stop(transferee);
00622       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00623       if (!transferee->pbx) {
00624          /* Doh!  Use our handy async_goto functions */
00625          if (option_verbose > 2) 
00626             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00627                         ,transferee->name, newext, transferer_real_context);
00628          if (ast_async_goto(transferee, transferer_real_context, newext, 1))
00629             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00630          res = -1;
00631       } else {
00632          /* Set the channel's new extension, since it exists, using transferer context */
00633          ast_copy_string(transferee->exten, newext, sizeof(transferee->exten));
00634          ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context));
00635          transferee->priority = 0;
00636       }
00637       check_goto_on_transfer(transferer);
00638       return res;
00639    } else {
00640       if (option_verbose > 2) 
00641          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
00642    }
00643    if (!ast_strlen_zero(xferfailsound))
00644       res = ast_streamfile(transferer, xferfailsound, transferer->language);
00645    else
00646       res = 0;
00647    if (res) {
00648       ast_moh_stop(transferee);
00649       ast_autoservice_stop(transferee);
00650       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00651       return res;
00652    }
00653    res = ast_waitstream(transferer, AST_DIGIT_ANY);
00654    ast_stopstream(transferer);
00655    ast_moh_stop(transferee);
00656    res = ast_autoservice_stop(transferee);
00657    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00658    if (res) {
00659       if (option_verbose > 1)
00660          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00661       return res;
00662    }
00663    return FEATURE_RETURN_SUCCESS;
00664 }

static int builtin_disconnect struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense
[static]
 

Definition at line 533 of file res_features.c.

References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.

00534 {
00535    if (option_verbose > 3)
00536       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00537    return FEATURE_RETURN_HANGUP;
00538 }

static void check_goto_on_transfer struct ast_channel chan  )  [static]
 

Definition at line 180 of file res_features.c.

References ast_channel::_softhangup, ast_channel::_state, ast_channel_alloc(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_STATE_UP, ast_strlen_zero(), ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.

Referenced by builtin_blindtransfer().

00181 {
00182    struct ast_channel *xferchan;
00183    char *goto_on_transfer;
00184 
00185    goto_on_transfer = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00186 
00187    if (!ast_strlen_zero(goto_on_transfer) && (xferchan = ast_channel_alloc(0))) {
00188       char *x;
00189       struct ast_frame *f;
00190       
00191       for (x = goto_on_transfer; x && *x; x++)
00192          if (*x == '^')
00193             *x = '|';
00194 
00195       strcpy(xferchan->name, chan->name);
00196       /* Make formats okay */
00197       xferchan->readformat = chan->readformat;
00198       xferchan->writeformat = chan->writeformat;
00199       ast_channel_masquerade(xferchan, chan);
00200       ast_parseable_goto(xferchan, goto_on_transfer);
00201       xferchan->_state = AST_STATE_UP;
00202       ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00203       xferchan->_softhangup = 0;
00204       if ((f = ast_read(xferchan))) {
00205          ast_frfree(f);
00206          f = NULL;
00207          ast_pbx_start(xferchan);
00208       } else {
00209          ast_hangup(xferchan);
00210       }
00211    }
00212 }

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 2177 of file res_features.c.

02178 {
02179    return "Call Features Resource";
02180 }

static void* do_parking_thread void *  ignore  )  [static]
 

Definition at line 1482 of file res_features.c.

References ast_add_extension2(), ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_read(), ast_select(), ast_set_flag, ast_strdupa, ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::context, ast_channel::context, EVENT_FLAG_CALL, parkeduser::exten, ast_channel::exten, exten, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, FREE, ast_channel::generatordata, LOG_DEBUG, LOG_ERROR, LOG_WARNING, manager_event(), parkeduser::moh_trys, ast_channel::name, parkeduser::next, parkeduser::notquiteyet, option_verbose, parking_con, parking_con_dial, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, parkeduser::priority, ast_channel::priority, registrar, parkeduser::start, strdup, ast_frame::subclass, and VERBOSE_PREFIX_2.

Referenced by load_module().

01483 {
01484    int ms, tms, max;
01485    struct parkeduser *pu, *pl, *pt = NULL;
01486    struct timeval tv;
01487    struct ast_frame *f;
01488    char exten[AST_MAX_EXTENSION];
01489    char *peername,*cp;
01490    char returnexten[AST_MAX_EXTENSION];
01491    struct ast_context *con;
01492    int x;
01493    fd_set rfds, efds;
01494    fd_set nrfds, nefds;
01495    FD_ZERO(&rfds);
01496    FD_ZERO(&efds);
01497 
01498    for (;;) {
01499       ms = -1;
01500       max = -1;
01501       ast_mutex_lock(&parking_lock);
01502       pl = NULL;
01503       pu = parkinglot;
01504       FD_ZERO(&nrfds);
01505       FD_ZERO(&nefds);
01506       while(pu) {
01507          if (pu->notquiteyet) {
01508             /* Pretend this one isn't here yet */
01509             pl = pu;
01510             pu = pu->next;
01511             continue;
01512          }
01513          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01514          if (tms > pu->parkingtime) {
01515             /* Stop music on hold */
01516             ast_moh_stop(pu->chan);
01517             ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
01518             /* Get chan, exten from derived kludge */
01519             if (pu->peername[0]) {
01520                peername = ast_strdupa(pu->peername);
01521                cp = strrchr(peername, '-');
01522                if (cp) 
01523                   *cp = 0;
01524                con = ast_context_find(parking_con_dial);
01525                if (!con) {
01526                   con = ast_context_create(NULL, parking_con_dial, registrar);
01527                   if (!con) {
01528                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01529                   }
01530                }
01531                if (con) {
01532                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01533                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
01534                }
01535                ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
01536                ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
01537                pu->chan->priority = 1;
01538 
01539             } else {
01540                /* They've been waiting too long, send them back to where they came.  Theoretically they
01541                   should have their original extensions and such, but we copy to be on the safe side */
01542                ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
01543                ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
01544                pu->chan->priority = pu->priority;
01545             }
01546 
01547             manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
01548                "Exten: %d\r\n"
01549                "Channel: %s\r\n"
01550                "CallerID: %s\r\n"
01551                "CallerIDName: %s\r\n"
01552                ,pu->parkingnum, pu->chan->name
01553                ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01554                ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01555                );
01556 
01557             if (option_verbose > 1) 
01558                ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
01559             /* Start up the PBX, or hang them up */
01560             if (ast_pbx_start(pu->chan))  {
01561                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
01562                ast_hangup(pu->chan);
01563             }
01564             /* And take them out of the parking lot */
01565             if (pl) 
01566                pl->next = pu->next;
01567             else
01568                parkinglot = pu->next;
01569             pt = pu;
01570             pu = pu->next;
01571             con = ast_context_find(parking_con);
01572             if (con) {
01573                snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01574                if (ast_context_remove_extension2(con, exten, 1, NULL))
01575                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01576             } else
01577                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01578             free(pt);
01579          } else {
01580             for (x = 0; x < AST_MAX_FDS; x++) {
01581                if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
01582                   if (FD_ISSET(pu->chan->fds[x], &efds))
01583                      ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
01584                   else
01585                      ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
01586                   pu->chan->fdno = x;
01587                   /* See if they need servicing */
01588                   f = ast_read(pu->chan);
01589                   if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
01590                      if (f)
01591                         ast_frfree(f);
01592                      manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
01593                         "Exten: %d\r\n"
01594                         "Channel: %s\r\n"
01595                         "CallerID: %s\r\n"
01596                         "CallerIDName: %s\r\n"
01597                         ,pu->parkingnum, pu->chan->name
01598                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01599                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01600                         );
01601 
01602                      /* There's a problem, hang them up*/
01603                      if (option_verbose > 1) 
01604                         ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
01605                      ast_hangup(pu->chan);
01606                      /* And take them out of the parking lot */
01607                      if (pl) 
01608                         pl->next = pu->next;
01609                      else
01610                         parkinglot = pu->next;
01611                      pt = pu;
01612                      pu = pu->next;
01613                      con = ast_context_find(parking_con);
01614                      if (con) {
01615                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01616                         if (ast_context_remove_extension2(con, exten, 1, NULL))
01617                            ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01618                      } else
01619                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01620                      free(pt);
01621                      break;
01622                   } else {
01623                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01624                      ast_frfree(f);
01625                      if (pu->moh_trys < 3 && !pu->chan->generatordata) {
01626                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01627                         ast_moh_start(pu->chan, NULL);
01628                         pu->moh_trys++;
01629                      }
01630                      goto std;   /* XXX Ick: jumping into an else statement??? XXX */
01631                   }
01632                }
01633             }
01634             if (x >= AST_MAX_FDS) {
01635 std:              for (x=0; x<AST_MAX_FDS; x++) {
01636                   /* Keep this one for next one */
01637                   if (pu->chan->fds[x] > -1) {
01638                      FD_SET(pu->chan->fds[x], &nrfds);
01639                      FD_SET(pu->chan->fds[x], &nefds);
01640                      if (pu->chan->fds[x] > max)
01641                         max = pu->chan->fds[x];
01642                   }
01643                }
01644                /* Keep track of our longest wait */
01645                if ((tms < ms) || (ms < 0))
01646                   ms = tms;
01647                pl = pu;
01648                pu = pu->next;
01649             }
01650          }
01651       }
01652       ast_mutex_unlock(&parking_lock);
01653       rfds = nrfds;
01654       efds = nefds;
01655       tv = ast_samp2tv(ms, 1000);
01656       /* Wait for something to happen */
01657       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01658       pthread_testcancel();
01659    }
01660    return NULL;   /* Never reached */
01661 }

static int feature_exec_app struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense
[static]
 

Definition at line 924 of file res_features.c.

References ast_call_feature::app, app, AST_FEATURE_FLAG_CALLEE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_test_flag, ast_call_feature::exten, FEATURE_RETURN_NO_HANGUP_PEER, FEATURE_RETURN_PBX_KEEPALIVE, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, LOG_NOTICE, LOG_WARNING, pbx_exec(), and pbx_findapp().

Referenced by load_config().

00925 {
00926    struct ast_app *app;
00927    struct ast_call_feature *feature;
00928    int res;
00929 
00930    AST_LIST_LOCK(&feature_list);
00931    AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
00932       if (!strcasecmp(feature->exten,code)) break;
00933    }
00934    AST_LIST_UNLOCK(&feature_list);
00935 
00936    if (!feature) { /* shouldn't ever happen! */
00937       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
00938       return -1; 
00939    }
00940    
00941    app = pbx_findapp(feature->app);
00942    if (app) {
00943       struct ast_channel *work = chan;
00944       if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
00945          work = peer;
00946       res = pbx_exec(work, app, feature->app_args, 1);
00947       if (res == AST_PBX_KEEPALIVE)
00948          return FEATURE_RETURN_PBX_KEEPALIVE;
00949       else if (res == AST_PBX_NO_HANGUP_PEER)
00950          return FEATURE_RETURN_NO_HANGUP_PEER;
00951       else if (res)
00952          return FEATURE_RETURN_SUCCESSBREAK;
00953    } else {
00954       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
00955       return -2;
00956    }
00957    
00958    return FEATURE_RETURN_SUCCESS;
00959 }

static struct ast_call_feature* find_feature char *  name  )  [static]
 

Definition at line 909 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and ast_call_feature::sname.

Referenced by ast_feature_interpret(), load_config(), and set_config_flags().

00910 {
00911    struct ast_call_feature *tmp;
00912 
00913    AST_LIST_LOCK(&feature_list);
00914    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00915       if (!strcasecmp(tmp->sname, name))
00916          break;
00917    }
00918    AST_LIST_UNLOCK(&feature_list);
00919 
00920    return tmp;
00921 }

static int handle_parkedcalls int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 1849 of file res_features.c.

References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, ast_channel::name, parkeduser::next, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.

01850 {
01851    struct parkeduser *cur;
01852    int numparked = 0;
01853 
01854    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01855       , "Context", "Extension", "Pri", "Timeout");
01856 
01857    ast_mutex_lock(&parking_lock);
01858 
01859    cur = parkinglot;
01860    while(cur) {
01861       ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
01862          ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
01863          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01864 
01865       cur = cur->next;
01866       numparked++;
01867    }
01868    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01869 
01870    ast_mutex_unlock(&parking_lock);
01871 
01872    return RESULT_SUCCESS;
01873 }

static int handle_showfeatures int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 1801 of file res_features.c.

References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_pickup_ext(), ast_call_feature::default_exten, ast_call_feature::exten, exten, ast_call_feature::fname, format, parking_con, parking_ext, parking_start, parking_stop, RESULT_SUCCESS, and ast_call_feature::sname.

01802 {
01803    int i;
01804    int fcount;
01805    struct ast_call_feature *feature;
01806    char format[] = "%-25s %-7s %-7s\n";
01807 
01808    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01809    ast_cli(fd, format, "---------------", "-------", "-------");
01810 
01811    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01812 
01813    fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01814 
01815    for (i = 0; i < fcount; i++)
01816    {
01817       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01818    }
01819    ast_cli(fd, "\n");
01820    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01821    ast_cli(fd, format, "---------------", "-------", "-------");
01822    if (AST_LIST_EMPTY(&feature_list)) {
01823       ast_cli(fd, "(none)\n");
01824    }
01825    else {
01826       AST_LIST_LOCK(&feature_list);
01827       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01828          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01829       }
01830       AST_LIST_UNLOCK(&feature_list);
01831    }
01832    ast_cli(fd, "\nCall parking\n");
01833    ast_cli(fd, "------------\n");
01834    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01835    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01836    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01837    ast_cli(fd,"\n");
01838    
01839    return RESULT_SUCCESS;
01840 }

char* key void   ) 
 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 2195 of file res_features.c.

References ASTERISK_GPL_KEY.

02196 {
02197    return ASTERISK_GPL_KEY;
02198 }

static int load_config void   )  [static]
 

Definition at line 1961 of file res_features.c.

References adsipark, ast_call_feature::app, app, ast_call_feature::app_args, ast_add_extension2(), ast_config_destroy(), ast_config_load(), ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_FEATURE_FLAG_CALLEE, AST_FEATURE_FLAG_CALLER, AST_FEATURE_FLAG_NEEDSDTMF, ast_log(), AST_MAX_EXTENSION, ast_parking_ext(), ast_register_feature(), ast_set_flag, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_variable_browse(), ast_verbose(), cfg, courtesytone, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_PARK_TIME, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_SNAME_LEN, featuredigittimeout, find_feature(), FREE, free, ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, ast_variable::name, ast_variable::next, ast_call_feature::operation, option_verbose, parkcall, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkingtime, pickup_ext, registrar, remap_feature(), ast_call_feature::sname, strdup, strsep(), transferdigittimeout, unmap_features(), ast_variable::value, var, VERBOSE_PREFIX_2, xferfailsound, and xfersound.

01962 {
01963    int start = 0, end = 0;
01964    struct ast_context *con = NULL;
01965    struct ast_config *cfg = NULL;
01966    struct ast_variable *var = NULL;
01967    char old_parking_ext[AST_MAX_EXTENSION];
01968    char old_parking_con[AST_MAX_EXTENSION] = "";
01969 
01970    if (!ast_strlen_zero(parking_con)) {
01971       strcpy(old_parking_ext, parking_ext);
01972       strcpy(old_parking_con, parking_con);
01973    } 
01974 
01975    /* Reset to defaults */
01976    strcpy(parking_con, "parkedcalls");
01977    strcpy(parking_con_dial, "park-dial");
01978    strcpy(parking_ext, "700");
01979    strcpy(pickup_ext, "*8");
01980    courtesytone[0] = '\0';
01981    strcpy(xfersound, "beep");
01982    strcpy(xferfailsound, "pbx-invalid");
01983    parking_start = 701;
01984    parking_stop = 750;
01985    parkfindnext = 0;
01986    adsipark = 0;
01987 
01988    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
01989    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
01990 
01991    cfg = ast_config_load("features.conf");
01992    if (!cfg) {
01993       cfg = ast_config_load("parking.conf");
01994       if (cfg)
01995          ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
01996    }
01997    if (cfg) {
01998       var = ast_variable_browse(cfg, "general");
01999       while(var) {
02000          if (!strcasecmp(var->name, "parkext")) {
02001             ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02002          } else if (!strcasecmp(var->name, "context")) {
02003             ast_copy_string(parking_con, var->value, sizeof(parking_con));
02004          } else if (!strcasecmp(var->name, "parkingtime")) {
02005             if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02006                ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02007                parkingtime = DEFAULT_PARK_TIME;
02008             } else
02009                parkingtime = parkingtime * 1000;
02010          } else if (!strcasecmp(var->name, "parkpos")) {
02011             if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02012                ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno);
02013             } else {
02014                parking_start = start;
02015                parking_stop = end;
02016             }
02017          } else if (!strcasecmp(var->name, "findslot")) {
02018             parkfindnext = (!strcasecmp(var->value, "next"));
02019          } else if (!strcasecmp(var->name, "adsipark")) {
02020             adsipark = ast_true(var->value);
02021          } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02022             if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02023                ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02024                transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02025             } else
02026                transferdigittimeout = transferdigittimeout * 1000;
02027          } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02028             if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02029                ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02030                featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02031             }
02032          } else if (!strcasecmp(var->name, "courtesytone")) {
02033             ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02034          } else if (!strcasecmp(var->name, "xfersound")) {
02035             ast_copy_string(xfersound, var->value, sizeof(xfersound));
02036          } else if (!strcasecmp(var->name, "xferfailsound")) {
02037             ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02038          } else if (!strcasecmp(var->name, "pickupexten")) {
02039             ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02040          }
02041          var = var->next;
02042       }
02043 
02044       unmap_features();
02045       var = ast_variable_browse(cfg, "featuremap");
02046       while(var) {
02047          if (remap_feature(var->name, var->value))
02048             ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02049          var = var->next;
02050       }
02051 
02052       /* Map a key combination to an application*/
02053       ast_unregister_features();
02054       var = ast_variable_browse(cfg, "applicationmap");
02055       while(var) {
02056          char *tmp_val=strdup(var->value);
02057          char *exten, *party=NULL, *app=NULL, *app_args=NULL; 
02058 
02059          if (!tmp_val) { 
02060             ast_log(LOG_ERROR, "res_features: strdup failed");
02061             continue;
02062          }
02063          
02064 
02065          exten=strsep(&tmp_val,",");
02066          if (exten) party=strsep(&tmp_val,",");
02067          if (party) app=strsep(&tmp_val,",");
02068 
02069          if (app) app_args=strsep(&tmp_val,",");
02070 
02071          if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
02072             ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",app,exten,party,var->name);
02073             free(tmp_val);
02074             var = var->next;
02075             continue;
02076          }
02077 
02078          {
02079             struct ast_call_feature *feature=find_feature(var->name);
02080             int mallocd=0;
02081             
02082             if (!feature) {
02083                feature=malloc(sizeof(struct ast_call_feature));
02084                mallocd=1;
02085             }
02086             if (!feature) {
02087                ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n");
02088                free(tmp_val);
02089                var = var->next;
02090                continue;
02091             }
02092 
02093             memset(feature,0,sizeof(struct ast_call_feature));
02094             ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
02095             ast_copy_string(feature->app,app,FEATURE_APP_LEN);
02096             ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
02097             free(tmp_val);
02098             
02099             if (app_args) 
02100                ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
02101             
02102             ast_copy_string(feature->exten, exten,sizeof(feature->exten));
02103             feature->operation=feature_exec_app;
02104             ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
02105             
02106             if (!strcasecmp(party,"caller"))
02107                ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
02108             else if (!strcasecmp(party, "callee"))
02109                ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
02110             else {
02111                ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
02112                var = var->next;
02113                continue;
02114             }
02115 
02116             ast_register_feature(feature);
02117             
02118             if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);  
02119          }
02120          var = var->next;
02121       }   
02122    }
02123    ast_config_destroy(cfg);
02124 
02125    /* Remove the old parking extension */
02126    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02127       ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
02128       ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02129    }
02130    
02131    if (!(con = ast_context_find(parking_con))) {
02132       if (!(con = ast_context_create(NULL, parking_con, registrar))) {
02133          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02134          return -1;
02135       }
02136    }
02137    return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
02138 }

int load_module void   ) 
 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 2144 of file res_features.c.

References ast_cli_register(), ast_manager_register, ast_pthread_create, ast_register_application(), descrip, descrip2, do_parking_thread(), load_config(), manager_parking_status(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, synopsis, and synopsis2.

02145 {
02146    int res;
02147    
02148    memset(parking_ext, 0, sizeof(parking_ext));
02149    memset(parking_con, 0, sizeof(parking_con));
02150 
02151    if ((res = load_config()))
02152       return res;
02153    ast_cli_register(&showparked);
02154    ast_cli_register(&showfeatures);
02155    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02156    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02157    if (!res)
02158       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02159    if (!res) {
02160       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02161    }
02162    return res;
02163 }

static int manager_parking_status struct mansession s,
struct message m
[static]
 

Definition at line 1883 of file res_features.c.

References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, mansession::fd, ast_channel::name, parkeduser::next, parkeduser::parkingnum, parkeduser::parkingtime, RESULT_SUCCESS, and parkeduser::start.

Referenced by load_module().

01884 {
01885    struct parkeduser *cur;
01886    char *id = astman_get_header(m,"ActionID");
01887    char idText[256] = "";
01888 
01889    if (!ast_strlen_zero(id))
01890       snprintf(idText,256,"ActionID: %s\r\n",id);
01891 
01892    astman_send_ack(s, m, "Parked calls will follow");
01893 
01894         ast_mutex_lock(&parking_lock);
01895 
01896         cur=parkinglot;
01897         while(cur) {
01898          ast_cli(s->fd, "Event: ParkedCall\r\n"
01899          "Exten: %d\r\n"
01900          "Channel: %s\r\n"
01901          "Timeout: %ld\r\n"
01902          "CallerID: %s\r\n"
01903          "CallerIDName: %s\r\n"
01904          "%s"
01905          "\r\n"
01906                         ,cur->parkingnum, cur->chan->name
01907                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
01908          ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
01909          ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
01910          ,idText);
01911 
01912             cur = cur->next;
01913         }
01914 
01915    ast_cli(s->fd,
01916    "Event: ParkedCallsComplete\r\n"
01917    "%s"
01918    "\r\n",idText);
01919 
01920         ast_mutex_unlock(&parking_lock);
01921 
01922         return RESULT_SUCCESS;
01923 }

static int park_call_exec struct ast_channel chan,
void *  data
[static]
 

Definition at line 1663 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_park_call(), AST_PBX_KEEPALIVE, ast_safe_sleep(), AST_STATE_UP, ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, and ast_channel::priority.

Referenced by load_module().

01664 {
01665    /* Data is unused at the moment but could contain a parking
01666       lot context eventually */
01667    int res=0;
01668    struct localuser *u;
01669    LOCAL_USER_ADD(u);
01670    /* Setup the exten/priority to be s/1 since we don't know
01671       where this call should return */
01672    strcpy(chan->exten, "s");
01673    chan->priority = 1;
01674    if (chan->_state != AST_STATE_UP)
01675       res = ast_answer(chan);
01676    if (!res)
01677       res = ast_safe_sleep(chan, 1000);
01678    if (!res)
01679       res = ast_park_call(chan, chan, 0, NULL);
01680    LOCAL_USER_REMOVE(u);
01681    if (!res)
01682       res = AST_PBX_KEEPALIVE;
01683    return res;
01684 }

static int park_exec struct ast_channel chan,
void *  data
[static]
 

Definition at line 1686 of file res_features.c.

References ast_answer(), ast_bridge_call(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, courtesytone, EVENT_FLAG_CALL, exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, option_verbose, parking_con, parkeduser::parkingnum, ast_bridge_config::play_warning, ast_bridge_config::timelimit, VERBOSE_PREFIX_3, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by load_module().

01687 {
01688    int res=0;
01689    struct localuser *u;
01690    struct ast_channel *peer=NULL;
01691    struct parkeduser *pu, *pl=NULL;
01692    char exten[AST_MAX_EXTENSION];
01693    struct ast_context *con;
01694    int park;
01695    int dres;
01696    struct ast_bridge_config config;
01697 
01698    if (!data) {
01699       ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
01700       return -1;
01701    }
01702    LOCAL_USER_ADD(u);
01703    park = atoi((char *)data);
01704    ast_mutex_lock(&parking_lock);
01705    pu = parkinglot;
01706    while(pu) {
01707       if (pu->parkingnum == park) {
01708          if (pl)
01709             pl->next = pu->next;
01710          else
01711             parkinglot = pu->next;
01712          break;
01713       }
01714       pl = pu;
01715       pu = pu->next;
01716    }
01717    ast_mutex_unlock(&parking_lock);
01718    if (pu) {
01719       peer = pu->chan;
01720       con = ast_context_find(parking_con);
01721       if (con) {
01722          snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
01723          if (ast_context_remove_extension2(con, exten, 1, NULL))
01724             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01725       } else
01726          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01727 
01728       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01729          "Exten: %d\r\n"
01730          "Channel: %s\r\n"
01731          "From: %s\r\n"
01732          "CallerID: %s\r\n"
01733          "CallerIDName: %s\r\n"
01734          ,pu->parkingnum, pu->chan->name, chan->name
01735          ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01736          ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01737          );
01738 
01739       free(pu);
01740    }
01741    /* JK02: it helps to answer the channel if not already up */
01742    if (chan->_state != AST_STATE_UP) {
01743       ast_answer(chan);
01744    }
01745 
01746    if (peer) {
01747       /* Play a courtesy beep in the calling channel to prefix the bridge connecting */   
01748       if (!ast_strlen_zero(courtesytone)) {
01749          if (!ast_streamfile(chan, courtesytone, chan->language)) {
01750             if (ast_waitstream(chan, "") < 0) {
01751                ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01752                ast_hangup(peer);
01753                return -1;
01754             }
01755          }
01756       }
01757  
01758       ast_moh_stop(peer);
01759       ast_indicate(peer, AST_CONTROL_UNHOLD);
01760       res = ast_channel_make_compatible(chan, peer);
01761       if (res < 0) {
01762          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01763          ast_hangup(peer);
01764          return -1;
01765       }
01766       /* This runs sorta backwards, since we give the incoming channel control, as if it
01767          were the person called. */
01768       if (option_verbose > 2) 
01769          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01770 
01771       memset(&config, 0, sizeof(struct ast_bridge_config));
01772       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01773       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01774       config.timelimit = 0;
01775       config.play_warning = 0;
01776       config.warning_freq = 0;
01777       config.warning_sound=NULL;
01778       res = ast_bridge_call(chan, peer, &config);
01779 
01780       /* Simulate the PBX hanging up */
01781       if (res != AST_PBX_NO_HANGUP_PEER)
01782          ast_hangup(peer);
01783       return res;
01784    } else {
01785       /* XXX Play a message XXX */
01786       dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
01787       if (!dres)
01788             dres = ast_waitstream(chan, "");
01789       else {
01790          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01791          dres = 0;
01792       }
01793       if (option_verbose > 2) 
01794          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01795       res = -1;
01796    }
01797    LOCAL_USER_REMOVE(u);
01798    return res;
01799 }

int reload void   ) 
 

Reload stuff.

This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.

Returns:
The return value is not used.

Definition at line 2140 of file res_features.c.

References load_config().

02140                  {
02141    return load_config();
02142 }

static int remap_feature const char *  name,
const char *  value
[static]
 

Definition at line 968 of file res_features.c.

References ast_log(), ast_verbose(), exten, FEATURES_COUNT, LOG_WARNING, option_verbose, and VERBOSE_PREFIX_2.

Referenced by load_config().

00969 {
00970    int x;
00971    int res = -1;
00972    for (x = 0; x < FEATURES_COUNT; x++) {
00973       if (!strcasecmp(name, builtin_features[x].sname)) {
00974          ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
00975          if (option_verbose > 1)
00976             ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
00977          res = 0;
00978       } else if (!strcmp(value, builtin_features[x].exten)) 
00979          ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name);
00980    }
00981    return res;
00982 }

static void set_config_flags struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config
[static]
 

Definition at line 1043 of file res_features.c.

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_CALLEE, AST_FEATURE_FLAG_CALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, ast_set_flag, ast_strdupa, ast_test_flag, ast_call_feature::feature_mask, ast_bridge_config::features_caller, FEATURES_COUNT, find_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

01044 {
01045    int x;
01046    
01047    ast_clear_flag(config, AST_FLAGS_ALL); 
01048    for (x = 0; x < FEATURES_COUNT; x++) {
01049       if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
01050          if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01051             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01052 
01053          if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01054             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01055       }
01056    }
01057    
01058    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01059       char *dynamic_features;
01060 
01061       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01062 
01063       if (dynamic_features) {
01064          char *tmp = ast_strdupa(dynamic_features);
01065          char *tok;
01066          struct ast_call_feature *feature;
01067 
01068          if (!tmp) {
01069             return;
01070          }
01071 
01072          /* while we have a feature */
01073          while (NULL != (tok = strsep(&tmp, "#"))) {
01074             if ((feature = find_feature(tok))) {
01075                if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01076                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
01077                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01078                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
01079                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01080                }
01081             }
01082          }
01083       }
01084    }
01085 }

int unload_module void   ) 
 

Cleanup all module structures, sockets, etc.

Standard module functions ...

Definition at line 2166 of file res_features.c.

References ast_cli_unregister(), ast_manager_unregister(), ast_unregister_application(), parkcall, parkedcall, and STANDARD_HANGUP_LOCALUSERS.

static void unmap_features void   )  [static]
 

Definition at line 961 of file res_features.c.

References exten, and FEATURES_COUNT.

Referenced by load_config().

00962 {
00963    int x;
00964    for (x = 0; x < FEATURES_COUNT; x++)
00965       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
00966 }

int usecount void   ) 
 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 2182 of file res_features.c.

References STANDARD_USECOUNT.

02183 {
02184    /* Never allow parking to be unloaded because it will
02185       unresolve needed symbols in the dialer */
02186 #if 0
02187    int res;
02188    STANDARD_USECOUNT(res);
02189    return res;
02190 #else
02191    return 1;
02192 #endif
02193 }


Variable Documentation

int adsipark [static]
 

Definition at line 106 of file res_features.c.

Referenced by ast_park_call(), and load_config().

struct ast_call_feature builtin_features[]
 

Definition at line 860 of file res_features.c.

char courtesytone[256] [static]
 

Definition at line 92 of file res_features.c.

Referenced by builtin_automonitor(), load_config(), and park_exec().

char* descrip [static]
 

Initial value:

 "ParkedCall(exten):"
"Used to connect to a parked call.  This application is always\n"
"registered internally and does not need to be explicitly added\n"
"into the dialplan, although you should include the 'parkedcalls'\n"
"context.\n"

Definition at line 118 of file res_features.c.

char* descrip2 [static]
 

Definition at line 128 of file res_features.c.

int featuredigittimeout [static]
 

Definition at line 109 of file res_features.c.

Referenced by ast_bridge_call(), and load_config().

LOCAL_USER_DECL
 

Definition at line 161 of file res_features.c.

struct ast_app* monitor_app = NULL [static]
 

Definition at line 135 of file res_features.c.

int monitor_ok = 1 [static]
 

Definition at line 136 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

char* parkcall = "Park" [static]
 

Definition at line 124 of file res_features.c.

Referenced by load_config(), load_module(), and unload_module().

char* parkedcall = "ParkedCall" [static]
 

Definition at line 75 of file res_features.c.

Referenced by ast_park_call(), load_module(), and unload_module().

int parkfindnext [static]
 

Definition at line 104 of file res_features.c.

Referenced by ast_park_call(), and load_config().

char parking_con[AST_MAX_EXTENSION] [static]
 

Definition at line 81 of file res_features.c.

Referenced by ast_park_call(), do_parking_thread(), handle_showfeatures(), load_config(), load_module(), and park_exec().

char parking_con_dial[AST_MAX_EXTENSION] [static]
 

Definition at line 84 of file res_features.c.

Referenced by do_parking_thread(), and load_config().

char parking_ext[AST_MAX_EXTENSION] [static]
 

Definition at line 87 of file res_features.c.

Referenced by ast_parking_ext(), handle_showfeatures(), load_config(), and load_module().

int parking_offset [static]
 

Definition at line 102 of file res_features.c.

Referenced by ast_park_call().

int parking_start [static]
 

Definition at line 97 of file res_features.c.

Referenced by ast_park_call(), handle_showfeatures(), and load_config().

int parking_stop [static]
 

Definition at line 100 of file res_features.c.

Referenced by ast_park_call(), handle_showfeatures(), and load_config().

pthread_t parking_thread [static]
 

Definition at line 157 of file res_features.c.

Referenced by ast_park_call(), and load_module().

struct parkeduser* parkinglot [static]
 

Definition at line 153 of file res_features.c.

int parkingtime = DEFAULT_PARK_TIME [static]
 

Definition at line 78 of file res_features.c.

Referenced by ast_park_call(), and load_config().

char pickup_ext[AST_MAX_EXTENSION] [static]
 

Definition at line 89 of file res_features.c.

Referenced by ast_pickup_ext(), and load_config().

char* registrar = "res_features" [static]
 

Definition at line 114 of file res_features.c.

struct ast_cli_entry showfeatures [static]
 

Initial value:

{ { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help }

Definition at line 1846 of file res_features.c.

char showfeatures_help[] [static]
 

Initial value:

"Usage: show features\n"
"       Lists currently configured features.\n"

Definition at line 1842 of file res_features.c.

struct ast_cli_entry showparked [static]
 

Initial value:

{ { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help }

Definition at line 1879 of file res_features.c.

char showparked_help[] [static]
 

Initial value:

"Usage: show parkedcalls\n"
"       Lists currently parked calls.\n"

Definition at line 1875 of file res_features.c.

STANDARD_LOCAL_USER
 

Definition at line 159 of file res_features.c.

char* synopsis = "Answer a parked call" [static]
 

Definition at line 116 of file res_features.c.

char* synopsis2 = "Park yourself" [static]
 

Definition at line 126 of file res_features.c.

int transferdigittimeout [static]
 

Definition at line 108 of file res_features.c.

Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().

char xferfailsound[256] [static]
 

Definition at line 94 of file res_features.c.

Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().

char xfersound[256] [static]
 

Definition at line 93 of file res_features.c.

Referenced by builtin_atxfer(), and load_config().


Generated on Sun Aug 6 15:15:26 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2