Sat Sep 16 07:28:20 2006

Asterisk developer's documentation


res_features.c File Reference

Routines implementing call parking. More...

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

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  features_parkwatch
struct  parkeduser

Defines

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

Functions

static int adsi_announce_park (struct ast_channel *chan, int parkingnum)
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
static void * ast_bridge_call_thread (void *data)
static void ast_bridge_call_thread_launch (void *data)
static int ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static struct ast_channelast_feature_request_and_dial (struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name)
static AST_LIST_HEAD_STATIC (feature_list, ast_call_feature)
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
 AST_MUTEX_DEFINE_STATIC (parking_lock)
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call and read back parked location.
int ast_park_metermaid_add (void(*maid)(char *exten, char *context), char *context)
 Add parking watcher (metermaid) to list. These will be notified when we create or remove parking extensions in the dial plan.
int ast_park_metermaid_remove (int id)
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 void notify_metermaids (char *exten, char *context)
static void park_add_hints (char *context, int start, int stop)
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
int metermaidid = 0
features_parkwatchmetermaids
static struct ast_appmonitor_app = NULL
static int monitor_ok = 1
static int parkaddhints = 0
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 532 of file res_features.c.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 535 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_PASSDIGITS   21

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

Referenced by feature_exec_app().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 537 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_SUCCESS   23

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

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 540 of file res_features.c.

Referenced by ast_bridge_call(), and ast_feature_interpret().

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 541 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 959 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 273 of file res_features.c.

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

Referenced by ast_park_call().

00274 {
00275    int res;
00276    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00277    char tmp[256];
00278    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00279 
00280    snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
00281    message[0] = tmp;
00282    res = adsi_load_session(chan, NULL, 0, 1);
00283    if (res == -1) {
00284       return res;
00285    }
00286    return adsi_print(chan, message, justify, 1);
00287 }

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 1361 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, config, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_channel::name, ast_option_header::option, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), ast_frame::subclass, and ast_cdr::userfield.

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

01362 {
01363    /* Copy voice back and forth between the two channels.  Give the peer
01364       the ability to transfer calls with '#<extension' syntax. */
01365    struct ast_frame *f;
01366    struct ast_channel *who;
01367    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01368    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01369    int res;
01370    int diff;
01371    int hasfeatures=0;
01372    int hadfeatures=0;
01373    struct ast_option_header *aoh;
01374    struct timeval start = { 0 , 0 };
01375    struct ast_bridge_config backup_config;
01376    char *monitor_exec;
01377 
01378    memset(&backup_config, 0, sizeof(backup_config));
01379 
01380    config->start_time = ast_tvnow();
01381 
01382    if (chan && peer) {
01383       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01384       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01385    } else if (chan)
01386       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01387 
01388    if (monitor_ok) {
01389       if (!monitor_app) { 
01390          if (!(monitor_app = pbx_findapp("Monitor")))
01391             monitor_ok=0;
01392       }
01393       if (monitor_app) {
01394          if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01395             pbx_exec(chan, monitor_app, monitor_exec, 1);
01396          else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01397             pbx_exec(peer, monitor_app, monitor_exec, 1);
01398       }
01399    }
01400    
01401    set_config_flags(chan, peer, config);
01402    config->firstpass = 1;
01403 
01404    /* Answer if need be */
01405    if (ast_answer(chan))
01406       return -1;
01407    peer->appl = "Bridged Call";
01408    peer->data = chan->name;
01409 
01410    /* copy the userfield from the B-leg to A-leg if applicable */
01411    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01412       char tmp[256];
01413       if (!ast_strlen_zero(chan->cdr->userfield)) {
01414          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01415          ast_cdr_appenduserfield(chan, tmp);
01416       } else
01417          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01418       /* free the peer's cdr without ast_cdr_free complaining */
01419       free(peer->cdr);
01420       peer->cdr = NULL;
01421    }
01422    for (;;) {
01423       if (config->feature_timer)
01424          start = ast_tvnow();
01425 
01426       res = ast_channel_bridge(chan, peer, config, &f, &who);
01427 
01428       if (config->feature_timer) {
01429          /* Update time limit for next pass */
01430          diff = ast_tvdiff_ms(ast_tvnow(), start);
01431          config->feature_timer -= diff;
01432          if (hasfeatures) {
01433             /* Running on backup config, meaning a feature might be being
01434                activated, but that's no excuse to keep things going 
01435                indefinitely! */
01436             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01437                ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01438                config->feature_timer = 0;
01439                who = chan;
01440                if (f)
01441                   ast_frfree(f);
01442                f = NULL;
01443                res = 0;
01444             } else if (config->feature_timer <= 0) {
01445                /* Not *really* out of time, just out of time for
01446                   digits to come in for features. */
01447                ast_log(LOG_DEBUG, "Timed out for feature!\n");
01448                if (!ast_strlen_zero(peer_featurecode)) {
01449                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01450                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01451                }
01452                if (!ast_strlen_zero(chan_featurecode)) {
01453                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01454                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01455                }
01456                if (f)
01457                   ast_frfree(f);
01458                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01459                if (!hasfeatures) {
01460                   /* Restore original (possibly time modified) bridge config */
01461                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01462                   memset(&backup_config, 0, sizeof(backup_config));
01463                }
01464                hadfeatures = hasfeatures;
01465                /* Continue as we were */
01466                continue;
01467             }
01468          } else {
01469             if (config->feature_timer <=0) {
01470                /* We ran out of time */
01471                config->feature_timer = 0;
01472                who = chan;
01473                if (f)
01474                   ast_frfree(f);
01475                f = NULL;
01476                res = 0;
01477             }
01478          }
01479       }
01480       if (res < 0) {
01481          ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01482          return -1;
01483       }
01484       
01485       if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
01486          (f->subclass == AST_CONTROL_CONGESTION)))) {
01487             res = -1;
01488             break;
01489       }
01490       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01491          if (who == chan)
01492             ast_indicate(peer, AST_CONTROL_RINGING);
01493          else
01494             ast_indicate(chan, AST_CONTROL_RINGING);
01495       }
01496       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01497          if (who == chan)
01498             ast_indicate(peer, -1);
01499          else
01500             ast_indicate(chan, -1);
01501       }
01502       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01503          if (who == chan)
01504             ast_indicate(peer, AST_CONTROL_FLASH);
01505          else
01506             ast_indicate(chan, AST_CONTROL_FLASH);
01507       }
01508       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01509          aoh = f->data;
01510          /* Forward option Requests */
01511          if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01512             if (who == chan)
01513                ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01514             else
01515                ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01516          }
01517       }
01518       /* check for '*', if we find it it's time to disconnect */
01519       if (f && (f->frametype == AST_FRAME_DTMF)) {
01520          char *featurecode;
01521          int sense;
01522          struct ast_channel *other;
01523 
01524          hadfeatures = hasfeatures;
01525          /* This cannot overrun because the longest feature is one shorter than our buffer */
01526          if (who == chan) {
01527             other = peer;
01528             sense = FEATURE_SENSE_CHAN;
01529             featurecode = chan_featurecode;
01530          } else  {
01531             other = chan;
01532             sense = FEATURE_SENSE_PEER;
01533             featurecode = peer_featurecode;
01534          }
01535          featurecode[strlen(featurecode)] = f->subclass;
01536          /* Get rid of the frame before we start doing "stuff" with the channels */
01537          ast_frfree(f);
01538          f = NULL;
01539          config->feature_timer = backup_config.feature_timer;
01540          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01541          switch(res) {
01542          case FEATURE_RETURN_PASSDIGITS:
01543             ast_dtmf_stream(other, who, featurecode, 0);
01544             /* Fall through */
01545          case FEATURE_RETURN_SUCCESS:
01546             memset(featurecode, 0, sizeof(chan_featurecode));
01547             break;
01548          }
01549          if (res >= FEATURE_RETURN_PASSDIGITS) {
01550             res = 0;
01551          } else 
01552             break;
01553          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01554          if (hadfeatures && !hasfeatures) {
01555             /* Restore backup */
01556             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01557             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01558          } else if (hasfeatures) {
01559             if (!hadfeatures) {
01560                /* Backup configuration */
01561                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01562                /* Setup temporary config options */
01563                config->play_warning = 0;
01564                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01565                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01566                config->warning_freq = 0;
01567                config->warning_sound = NULL;
01568                config->end_sound = NULL;
01569                config->start_sound = NULL;
01570                config->firstpass = 0;
01571             }
01572             config->start_time = ast_tvnow();
01573             config->feature_timer = featuredigittimeout;
01574             ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01575          }
01576       }
01577       if (f)
01578          ast_frfree(f);
01579    }
01580    return res;
01581 }

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

Definition at line 231 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().

00232 {
00233    struct ast_bridge_thread_obj *tobj = data;
00234 
00235    tobj->chan->appl = "Transferred Call";
00236    tobj->chan->data = tobj->peer->name;
00237    tobj->peer->appl = "Transferred Call";
00238    tobj->peer->data = tobj->chan->name;
00239    if (tobj->chan->cdr) {
00240       ast_cdr_reset(tobj->chan->cdr, NULL);
00241       ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00242    }
00243    if (tobj->peer->cdr) {
00244       ast_cdr_reset(tobj->peer->cdr, NULL);
00245       ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00246    }
00247 
00248    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00249    ast_hangup(tobj->chan);
00250    ast_hangup(tobj->peer);
00251    tobj->chan = tobj->peer = NULL;
00252    free(tobj);
00253    tobj=NULL;
00254    return NULL;
00255 }

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 257 of file res_features.c.

References ast_bridge_call_thread(), and ast_pthread_create.

Referenced by builtin_atxfer().

00258 {
00259    pthread_t thread;
00260    pthread_attr_t attr;
00261    struct sched_param sched;
00262 
00263    pthread_attr_init(&attr);
00264    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00265    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00266    pthread_attr_destroy(&attr);
00267    memset(&sched, 0, sizeof(sched));
00268    pthread_setschedparam(thread, SCHED_RR, &sched);
00269 }

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

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

Referenced by ast_bridge_call().

01085 {
01086    int x;
01087    struct ast_flags features;
01088    int res = FEATURE_RETURN_PASSDIGITS;
01089    struct ast_call_feature *feature;
01090    char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
01091 
01092    if (sense == FEATURE_SENSE_CHAN)
01093       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
01094    else
01095       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01096    ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
01097 
01098    for (x=0; x < FEATURES_COUNT; x++) {
01099       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01100           !ast_strlen_zero(builtin_features[x].exten)) {
01101          /* Feature is up for consideration */
01102          if (!strcmp(builtin_features[x].exten, code)) {
01103             res = builtin_features[x].operation(chan, peer, config, code, sense);
01104             break;
01105          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01106             if (res == FEATURE_RETURN_PASSDIGITS)
01107                res = FEATURE_RETURN_STOREDIGITS;
01108          }
01109       }
01110    }
01111 
01112 
01113    if (!ast_strlen_zero(dynamic_features)) {
01114       char *tmp = ast_strdupa(dynamic_features);
01115       char *tok;
01116 
01117       if (!tmp)
01118          return res;
01119       
01120       while ((tok = strsep(&tmp, "#")) != NULL) {
01121          feature = find_feature(tok);
01122          
01123          if (feature) {
01124             /* Feature is up for consideration */
01125             if (!strcmp(feature->exten, code)) {
01126                if (option_verbose > 2)
01127                   ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01128                if (sense == FEATURE_SENSE_CHAN)
01129                   res = feature->operation(chan, peer, config, code, sense);
01130                else
01131                   res = feature->operation(peer, chan, config, code, sense);
01132                break;
01133             } else if (!strncmp(feature->exten, code, strlen(code))) {
01134                res = FEATURE_RETURN_STOREDIGITS;
01135             }
01136          }
01137       }
01138    }
01139    
01140    return res;
01141 }

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

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

Referenced by builtin_atxfer().

01189 {
01190    int state = 0;
01191    int cause = 0;
01192    int to;
01193    struct ast_channel *chan;
01194    struct ast_channel *monitor_chans[2];
01195    struct ast_channel *active_channel;
01196    struct ast_frame *f = NULL;
01197    int res = 0, ready = 0;
01198    
01199    if ((chan = ast_request(type, format, data, &cause))) {
01200       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01201       ast_channel_inherit_variables(caller, chan); 
01202       if (!ast_call(chan, data, timeout)) {
01203          struct timeval started;
01204          int x, len = 0;
01205          char *disconnect_code = NULL, *dialed_code = NULL;
01206 
01207          ast_indicate(caller, AST_CONTROL_RINGING);
01208          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01209          for (x=0; x < FEATURES_COUNT; x++) {
01210             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01211                continue;
01212 
01213             disconnect_code = builtin_features[x].exten;
01214             len = strlen(disconnect_code) + 1;
01215             dialed_code = alloca(len);
01216             memset(dialed_code, 0, len);
01217             break;
01218          }
01219          x = 0;
01220          started = ast_tvnow();
01221          to = timeout;
01222          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01223             monitor_chans[0] = caller;
01224             monitor_chans[1] = chan;
01225             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01226 
01227             /* see if the timeout has been violated */
01228             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01229                state = AST_CONTROL_UNHOLD;
01230                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01231                break; /*doh! timeout*/
01232             }
01233 
01234             if (!active_channel) {
01235                continue;
01236             }
01237 
01238             if (chan && (chan == active_channel)){
01239                f = ast_read(chan);
01240                if (f == NULL) { /*doh! where'd he go?*/
01241                   state = AST_CONTROL_HANGUP;
01242                   res = 0;
01243                   break;
01244                }
01245                
01246                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01247                   if (f->subclass == AST_CONTROL_RINGING) {
01248                      state = f->subclass;
01249                      if (option_verbose > 2)
01250                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01251                      ast_indicate(caller, AST_CONTROL_RINGING);
01252                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01253                      state = f->subclass;
01254                      if (option_verbose > 2)
01255                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01256                      ast_indicate(caller, AST_CONTROL_BUSY);
01257                      ast_frfree(f);
01258                      f = NULL;
01259                      break;
01260                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01261                      /* This is what we are hoping for */
01262                      state = f->subclass;
01263                      ast_frfree(f);
01264                      f = NULL;
01265                      ready=1;
01266                      break;
01267                   } else {
01268                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01269                   }
01270                   /* else who cares */
01271                }
01272 
01273             } else if (caller && (active_channel == caller)) {
01274                f = ast_read(caller);
01275                if (f == NULL) { /*doh! where'd he go?*/
01276                   if (caller->_softhangup && !chan->_softhangup) {
01277                      /* make this a blind transfer */
01278                      ready = 1;
01279                      break;
01280                   }
01281                   state = AST_CONTROL_HANGUP;
01282                   res = 0;
01283                   break;
01284                }
01285                
01286                if (f->frametype == AST_FRAME_DTMF) {
01287                   dialed_code[x++] = f->subclass;
01288                   dialed_code[x] = '\0';
01289                   if (strlen(dialed_code) == len) {
01290                      x = 0;
01291                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01292                      x = 0;
01293                      dialed_code[x] = '\0';
01294                   }
01295                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01296                      /* Caller Canceled the call */
01297                      state = AST_CONTROL_UNHOLD;
01298                      ast_frfree(f);
01299                      f = NULL;
01300                      break;
01301                   }
01302                }
01303             }
01304             if (f) {
01305                ast_frfree(f);
01306             }
01307          }
01308       } else
01309          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01310    } else {
01311       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01312       switch(cause) {
01313       case AST_CAUSE_BUSY:
01314          state = AST_CONTROL_BUSY;
01315          break;
01316       case AST_CAUSE_CONGESTION:
01317          state = AST_CONTROL_CONGESTION;
01318          break;
01319       }
01320    }
01321    
01322    ast_indicate(caller, -1);
01323    if (chan && ready) {
01324       if (chan->_state == AST_STATE_UP) 
01325          state = AST_CONTROL_ANSWER;
01326       res = 0;
01327    } else if(chan) {
01328       res = -1;
01329       ast_hangup(chan);
01330       chan = NULL;
01331    } else {
01332       res = -1;
01333    }
01334    
01335    if (outstate)
01336       *outstate = state;
01337 
01338    if (chan && res <= 0) {
01339       if (!chan->cdr) {
01340          chan->cdr = ast_cdr_alloc();
01341       }
01342       if (chan->cdr) {
01343          char tmp[256];
01344          ast_cdr_init(chan->cdr, chan);
01345          snprintf(tmp, 256, "%s/%s", type, (char *)data);
01346          ast_cdr_setapp(chan->cdr,"Dial",tmp);
01347          ast_cdr_update(chan);
01348          ast_cdr_start(chan->cdr);
01349          ast_cdr_end(chan->cdr);
01350          /* If the cause wasn't handled properly */
01351          if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01352             ast_cdr_failed(chan->cdr);
01353       } else {
01354          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01355       }
01356    }
01357    
01358    return chan;
01359 }

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

00499 {
00500    struct ast_channel *chan;
00501    struct ast_frame *f;
00502 
00503    /* Make a new, fake channel that we'll use to masquerade in the real one */
00504    chan = ast_channel_alloc(0);
00505    if (chan) {
00506       /* Let us keep track of the channel name */
00507       snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
00508 
00509       /* Make formats okay */
00510       chan->readformat = rchan->readformat;
00511       chan->writeformat = rchan->writeformat;
00512       ast_channel_masquerade(chan, rchan);
00513 
00514       /* Setup the extensions and such */
00515       ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
00516       ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
00517       chan->priority = rchan->priority;
00518 
00519       /* Make the masq execute */
00520       f = ast_read(chan);
00521       if (f)
00522          ast_frfree(f);
00523       ast_park_call(chan, peer, timeout, extout);
00524    } else {
00525       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00526       return -1;
00527    }
00528    return 0;
00529 }

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

References adsi_announce_park(), adsi_available(), adsi_unload_session(), 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, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, ast_channel::priority, parkeduser::priority, 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().

00374 {
00375    struct parkeduser *pu, *cur;
00376    int i,x,parking_range;
00377    char exten[AST_MAX_EXTENSION];
00378    struct ast_context *con;
00379 
00380    pu = malloc(sizeof(struct parkeduser));
00381    if (!pu) {
00382       ast_log(LOG_WARNING, "Out of memory\n");
00383       return -1;
00384    }
00385    memset(pu, 0, sizeof(struct parkeduser));
00386    ast_mutex_lock(&parking_lock);
00387    parking_range = parking_stop - parking_start+1;
00388    for (i = 0; i < parking_range; i++) {
00389       x = (i + parking_offset) % parking_range + parking_start;
00390       cur = parkinglot;
00391       while(cur) {
00392          if (cur->parkingnum == x) 
00393             break;
00394          cur = cur->next;
00395       }
00396       if (!cur)
00397          break;
00398    }
00399 
00400    if (!(i < parking_range)) {
00401       ast_log(LOG_WARNING, "No more parking spaces\n");
00402       free(pu);
00403       ast_mutex_unlock(&parking_lock);
00404       return -1;
00405    }
00406    if (parkfindnext) 
00407       parking_offset = x - parking_start + 1;
00408    chan->appl = "Parked Call";
00409    chan->data = NULL; 
00410 
00411    pu->chan = chan;
00412    /* Start music on hold */
00413    if (chan != peer) {
00414       ast_indicate(pu->chan, AST_CONTROL_HOLD);
00415       ast_moh_start(pu->chan, NULL);
00416    }
00417    pu->start = ast_tvnow();
00418    pu->parkingnum = x;
00419    if (timeout > 0)
00420       pu->parkingtime = timeout;
00421    else
00422       pu->parkingtime = parkingtime;
00423    if (extout)
00424       *extout = x;
00425    if (peer) 
00426       ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00427 
00428    /* Remember what had been dialed, so that if the parking
00429       expires, we try to come back to the same place */
00430    if (!ast_strlen_zero(chan->macrocontext))
00431       ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
00432    else
00433       ast_copy_string(pu->context, chan->context, sizeof(pu->context));
00434    if (!ast_strlen_zero(chan->macroexten))
00435       ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
00436    else
00437       ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
00438    if (chan->macropriority)
00439       pu->priority = chan->macropriority;
00440    else
00441       pu->priority = chan->priority;
00442    pu->next = parkinglot;
00443    parkinglot = pu;
00444    /* If parking a channel directly, don't quiet yet get parking running on it */
00445    if (peer == chan) 
00446       pu->notquiteyet = 1;
00447    ast_mutex_unlock(&parking_lock);
00448    /* Wake up the (presumably select()ing) thread */
00449    pthread_kill(parking_thread, SIGURG);
00450    if (option_verbose > 1) 
00451       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));
00452 
00453    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00454       "Exten: %d\r\n"
00455       "Channel: %s\r\n"
00456       "From: %s\r\n"
00457       "Timeout: %ld\r\n"
00458       "CallerID: %s\r\n"
00459       "CallerIDName: %s\r\n"
00460       ,pu->parkingnum, pu->chan->name, peer ? peer->name : ""
00461       ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
00462       ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
00463       ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
00464       );
00465 
00466    if (peer) {
00467       if (adsipark && adsi_available(peer)) {
00468          adsi_announce_park(peer, pu->parkingnum);
00469       }
00470       if (adsipark && adsi_available(peer)) {
00471          adsi_unload_session(peer);
00472       }
00473    }
00474    con = ast_context_find(parking_con);
00475    if (!con) {
00476       con = ast_context_create(NULL, parking_con, registrar);
00477       if (!con) {
00478          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00479       }
00480    }
00481    if (con) {
00482       snprintf(exten, sizeof(exten), "%d", x);
00483    
00484       if (ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar) == 0)
00485          notify_metermaids(exten, parking_con); /* Notify watchers */
00486    }
00487    if (peer) 
00488       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00489    if (pu->notquiteyet) {
00490       /* Wake up parking thread if we're really done */
00491       ast_moh_start(pu->chan, NULL);
00492       pu->notquiteyet = 0;
00493       pthread_kill(parking_thread, SIGURG);
00494    }
00495    return 0;
00496 }

int ast_park_metermaid_add ( void(*)(char *exten, char *context maid,
char *  context 
)

Add parking watcher (metermaid) to list. These will be notified when we create or remove parking extensions in the dial plan.

Add parking watcher (metermaid) to list. These will be notified when we create or remove parking extensions in the dial plan

Definition at line 292 of file res_features.c.

References ast_log(), features_parkwatch::callback, features_parkwatch::context, features_parkwatch::id, LOG_DEBUG, LOG_ERROR, malloc, metermaids, features_parkwatch::next, option_debug, and strdup.

Referenced by load_module().

00293 {
00294    struct features_parkwatch *newmaid;
00295    struct features_parkwatch *maids = metermaids;
00296 
00297    newmaid = malloc(sizeof(struct features_parkwatch));
00298    if (!newmaid) {
00299       ast_log(LOG_ERROR, "Can't allocate parking watcher, out of memory.\n");
00300       return -1;
00301    }
00302    memset(newmaid, 0, sizeof(struct features_parkwatch));
00303 
00304    /* Spool till end of list */
00305    while(maids && maids->next) {
00306       maids = maids->next;
00307    }
00308 
00309    newmaid->callback = maid;
00310    if (context)
00311       newmaid->context = strdup(context);
00312    newmaid->id = metermaidid;
00313 
00314    /* Generate new ID */
00315    metermaidid++;
00316 
00317    /* Link the new object to the list */
00318    if (maids)
00319       maids->next = newmaid;
00320    else
00321       metermaids = newmaid;
00322    if (option_debug > 1)
00323       ast_log(LOG_DEBUG, "Added metermaid # %d\n", metermaidid);
00324    return metermaidid;
00325 }

int ast_park_metermaid_remove ( int  id  ) 

Remove parking watcher

Definition at line 328 of file res_features.c.

References features_parkwatch::context, free, features_parkwatch::id, metermaids, and features_parkwatch::next.

Referenced by unload_module().

00329 {
00330    struct features_parkwatch *maids = metermaids;
00331    struct features_parkwatch *prev = NULL;
00332    struct features_parkwatch *kill = NULL;
00333 
00334    while (maids && !kill) {
00335       if (maids->id == id) {
00336          if (prev) {
00337             prev->next = maids->next;
00338          } else {
00339             metermaids = maids->next;
00340          }
00341          kill = maids;
00342       }
00343       prev = maids;
00344       maids = maids->next;
00345    }
00346    if (!kill)
00347       return -1;     /* Did not find id */
00348    if (kill->context)
00349       free(kill->context);
00350    free(kill);
00351    return 0;
00352 }

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

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

00178 {
00179    return parking_ext;
00180 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2033 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().

02034 {
02035    struct ast_channel *cur = NULL;
02036    int res = -1;
02037 
02038    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02039       if (!cur->pbx && 
02040          (cur != chan) &&
02041          (chan->pickupgroup & cur->callgroup) &&
02042          ((cur->_state == AST_STATE_RINGING) ||
02043           (cur->_state == AST_STATE_RING))) {
02044             break;
02045       }
02046       ast_mutex_unlock(&cur->lock);
02047    }
02048    if (cur) {
02049       if (option_debug)
02050          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02051       res = ast_answer(chan);
02052       if (res)
02053          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02054       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02055       if (res)
02056          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02057       res = ast_channel_masquerade(cur, chan);
02058       if (res)
02059          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02060       ast_mutex_unlock(&cur->lock);
02061    } else   {
02062       if (option_debug)
02063          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02064    }
02065    return res;
02066 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 182 of file res_features.c.

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

00183 {
00184    return pickup_ext;
00185 }

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

00973 {
00974    if (!feature) {
00975       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00976          return;
00977    }
00978   
00979    AST_LIST_LOCK(&feature_list);
00980    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00981    AST_LIST_UNLOCK(&feature_list);
00982 
00983    if (option_verbose >= 2) 
00984       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00985 }

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00989 {
00990    if (!feature) return;
00991 
00992    AST_LIST_LOCK(&feature_list);
00993    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00994    AST_LIST_UNLOCK(&feature_list);
00995    free(feature);
00996 }

static void ast_unregister_features ( void   )  [static]

Definition at line 998 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

Referenced by load_config().

00999 {
01000    struct ast_call_feature *feature;
01001 
01002    AST_LIST_LOCK(&feature_list);
01003    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
01004       free(feature);
01005    AST_LIST_UNLOCK(&feature_list);
01006 }

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 763 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_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, cid_name, cid_num, config, 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_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

00764 {
00765    struct ast_channel *transferer;
00766    struct ast_channel *transferee;
00767    struct ast_channel *newchan, *xferchan=NULL;
00768    int outstate=0;
00769    struct ast_bridge_config bconfig;
00770    char *transferer_real_context;
00771    char xferto[256],dialstr[265];
00772    char *cid_num;
00773    char *cid_name;
00774    int res;
00775    struct ast_frame *f = NULL;
00776    struct ast_bridge_thread_obj *tobj;
00777 
00778    ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
00779    if (sense == FEATURE_SENSE_PEER) {
00780       transferer = peer;
00781       transferee = chan;
00782    } else {
00783       transferer = chan;
00784       transferee = peer;
00785    }
00786    if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00787       !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00788       /* Use the non-macro context to transfer the call */
00789       if (!ast_strlen_zero(transferer->macrocontext))
00790          transferer_real_context = transferer->macrocontext;
00791       else
00792          transferer_real_context = transferer->context;
00793    }
00794    /* Start autoservice on chan while we talk
00795       to the originator */
00796    ast_indicate(transferee, AST_CONTROL_HOLD);
00797    ast_autoservice_start(transferee);
00798    ast_moh_start(transferee, NULL);
00799    memset(xferto, 0, sizeof(xferto));
00800    /* Transfer */
00801    if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00802       ast_moh_stop(transferee);
00803       ast_autoservice_stop(transferee);
00804       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00805       return res;
00806    }
00807    if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00808       ast_moh_stop(transferee);
00809       ast_autoservice_stop(transferee);
00810       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00811       return res;
00812    } else if(res > 0) {
00813       /* If they've typed a digit already, handle it */
00814       xferto[0] = (char) res;
00815    }
00816    if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
00817       cid_num = transferer->cid.cid_num;
00818       cid_name = transferer->cid.cid_name;
00819       if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
00820          snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
00821          newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
00822          ast_indicate(transferer, -1);
00823          if (newchan) {
00824             res = ast_channel_make_compatible(transferer, newchan);
00825             if (res < 0) {
00826                ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
00827                ast_hangup(newchan);
00828                return -1;
00829             }
00830             memset(&bconfig,0,sizeof(struct ast_bridge_config));
00831             ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00832             ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00833             res = ast_bridge_call(transferer,newchan,&bconfig);
00834             if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
00835                ast_hangup(newchan);
00836                if (f) {
00837                   ast_frfree(f);
00838                   f = NULL;
00839                }
00840                if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
00841                   if (ast_waitstream(transferer, "") < 0) {
00842                      ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00843                   }
00844                }
00845                ast_moh_stop(transferee);
00846                ast_autoservice_stop(transferee);
00847                ast_indicate(transferee, AST_CONTROL_UNHOLD);
00848                transferer->_softhangup = 0;
00849                return FEATURE_RETURN_SUCCESS;
00850             }
00851             
00852             res = ast_channel_make_compatible(transferee, newchan);
00853             if (res < 0) {
00854                ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
00855                ast_hangup(newchan);
00856                return -1;
00857             }
00858             
00859             
00860             ast_moh_stop(transferee);
00861             
00862             if ((ast_autoservice_stop(transferee) < 0)
00863                || (ast_waitfordigit(transferee, 100) < 0)
00864                || (ast_waitfordigit(newchan, 100) < 0) 
00865                || ast_check_hangup(transferee) 
00866                || ast_check_hangup(newchan)) {
00867                ast_hangup(newchan);
00868                res = -1;
00869                return -1;
00870             }
00871 
00872             if ((xferchan = ast_channel_alloc(0))) {
00873                snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name);
00874                /* Make formats okay */
00875                xferchan->readformat = transferee->readformat;
00876                xferchan->writeformat = transferee->writeformat;
00877                ast_channel_masquerade(xferchan, transferee);
00878                ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00879                xferchan->_state = AST_STATE_UP;
00880                ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00881                xferchan->_softhangup = 0;
00882 
00883                if ((f = ast_read(xferchan))) {
00884                   ast_frfree(f);
00885                   f = NULL;
00886                }
00887                
00888             } else {
00889                ast_hangup(newchan);
00890                return -1;
00891             }
00892 
00893             newchan->_state = AST_STATE_UP;
00894             ast_clear_flag(newchan, AST_FLAGS_ALL);   
00895             newchan->_softhangup = 0;
00896 
00897             tobj = malloc(sizeof(struct ast_bridge_thread_obj));
00898             if (tobj) {
00899                memset(tobj,0,sizeof(struct ast_bridge_thread_obj));
00900                tobj->chan = xferchan;
00901                tobj->peer = newchan;
00902                tobj->bconfig = *config;
00903    
00904                if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
00905                   if (ast_waitstream(newchan, "") < 0) {
00906                      ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00907                   }
00908                }
00909                ast_bridge_call_thread_launch(tobj);
00910             } else {
00911                ast_log(LOG_WARNING, "Out of memory!\n");
00912                ast_hangup(xferchan);
00913                ast_hangup(newchan);
00914             }
00915             return -1;
00916             
00917          } else {
00918             ast_moh_stop(transferee);
00919             ast_autoservice_stop(transferee);
00920             ast_indicate(transferee, AST_CONTROL_UNHOLD);
00921             /* any reason besides user requested cancel and busy triggers the failed sound */
00922             if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
00923                res = ast_streamfile(transferer, xferfailsound, transferer->language);
00924                if (!res && (ast_waitstream(transferer, "") < 0)) {
00925                   return -1;
00926                }
00927             }
00928             return FEATURE_RETURN_SUCCESS;
00929          }
00930       } else {
00931          ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00932          ast_moh_stop(transferee);
00933          ast_autoservice_stop(transferee);
00934          ast_indicate(transferee, AST_CONTROL_UNHOLD);
00935          res = ast_streamfile(transferer, "beeperr", transferer->language);
00936          if (!res && (ast_waitstream(transferer, "") < 0)) {
00937             return -1;
00938          }
00939       }
00940    }  else {
00941       ast_log(LOG_WARNING, "Did not read data.\n");
00942       ast_moh_stop(transferee);
00943       ast_autoservice_stop(transferee);
00944       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00945       res = ast_streamfile(transferer, "beeperr", transferer->language);
00946       if (ast_waitstream(transferer, "") < 0) {
00947          return -1;
00948       }
00949    }
00950    ast_moh_stop(transferee);
00951    ast_autoservice_stop(transferee);
00952    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00953 
00954    return FEATURE_RETURN_SUCCESS;
00955 }

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 544 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(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, ast_channel::language, LOG_ERROR, LOG_NOTICE, LOG_WARNING, monitor_app, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), and VERBOSE_PREFIX_3.

00545 {
00546    char *touch_monitor = NULL, *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_format = NULL;
00547    int x = 0;
00548    size_t len;
00549    struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
00550 
00551 
00552    if(sense == 2) {
00553       caller_chan = peer;
00554       callee_chan = chan;
00555    } else {
00556       callee_chan = peer;
00557       caller_chan = chan;
00558    }
00559    
00560    if (!monitor_ok) {
00561       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00562       return -1;
00563    }
00564 
00565    if (!monitor_app) { 
00566       if (!(monitor_app = pbx_findapp("Monitor"))) {
00567          monitor_ok=0;
00568          ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00569          return -1;
00570       }
00571    }
00572    if (!ast_strlen_zero(courtesytone)) {
00573       if (ast_autoservice_start(callee_chan))
00574          return -1;
00575       if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
00576          if (ast_waitstream(caller_chan, "") < 0) {
00577             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00578             ast_autoservice_stop(callee_chan);
00579             return -1;
00580          }
00581       }
00582       if (ast_autoservice_stop(callee_chan))
00583          return -1;
00584    }
00585    
00586    if (callee_chan->monitor) {
00587       if (option_verbose > 3)
00588          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00589       ast_monitor_stop(callee_chan, 1);
00590       return FEATURE_RETURN_SUCCESS;
00591    }
00592 
00593    if (caller_chan && callee_chan) {
00594       touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00595       if (!touch_format)
00596          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00597 
00598       touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00599       if (!touch_monitor)
00600          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00601       
00602       if (touch_monitor) {
00603          len = strlen(touch_monitor) + 50;
00604          args = alloca(len);
00605          snprintf(args, len, "%s|auto-%ld-%s|m", (touch_format) ? touch_format : "wav", time(NULL), touch_monitor);
00606       } else {
00607          caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
00608          callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
00609          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00610          args = alloca(len);
00611          snprintf(args, len, "%s|auto-%ld-%s-%s|m", (touch_format) ? touch_format : "wav", time(NULL), caller_chan_id, callee_chan_id);
00612       }
00613 
00614       for( x = 0; x < strlen(args); x++)
00615          if (args[x] == '/')
00616             args[x] = '-';
00617       
00618       if (option_verbose > 3)
00619          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00620 
00621       pbx_exec(callee_chan, monitor_app, args, 1);
00622       
00623       return FEATURE_RETURN_SUCCESS;
00624    }
00625    
00626    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00627    return -1;
00628 }

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 637 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, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.

00638 {
00639    struct ast_channel *transferer;
00640    struct ast_channel *transferee;
00641    char *transferer_real_context;
00642    char newext[256];
00643    int res;
00644 
00645    if (sense == FEATURE_SENSE_PEER) {
00646       transferer = peer;
00647       transferee = chan;
00648    } else {
00649       transferer = chan;
00650       transferee = peer;
00651    }
00652    if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00653       !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00654       /* Use the non-macro context to transfer the call */
00655       if (!ast_strlen_zero(transferer->macrocontext))
00656          transferer_real_context = transferer->macrocontext;
00657       else
00658          transferer_real_context = transferer->context;
00659    }
00660    /* Start autoservice on chan while we talk
00661       to the originator */
00662    ast_indicate(transferee, AST_CONTROL_HOLD);
00663    ast_autoservice_start(transferee);
00664    ast_moh_start(transferee, NULL);
00665 
00666    memset(newext, 0, sizeof(newext));
00667    
00668    /* Transfer */
00669    if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00670       ast_moh_stop(transferee);
00671       ast_autoservice_stop(transferee);
00672       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00673       return res;
00674    }
00675    if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00676       ast_moh_stop(transferee);
00677       ast_autoservice_stop(transferee);
00678       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00679       return res;
00680    } else if (res > 0) {
00681       /* If they've typed a digit already, handle it */
00682       newext[0] = (char) res;
00683    }
00684 
00685    ast_stopstream(transferer);
00686    res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
00687    if (res < 0) {
00688       ast_moh_stop(transferee);
00689       ast_autoservice_stop(transferee);
00690       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00691       return res;
00692    }
00693    if (!strcmp(newext, ast_parking_ext())) {
00694       ast_moh_stop(transferee);
00695 
00696       res = ast_autoservice_stop(transferee);
00697       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00698       if (res)
00699          res = -1;
00700       else if (!ast_park_call(transferee, transferer, 0, NULL)) {
00701          /* We return non-zero, but tell the PBX not to hang the channel when
00702             the thread dies -- We have to be careful now though.  We are responsible for 
00703             hanging up the channel, else it will never be hung up! */
00704 
00705          if (transferer == peer)
00706             res = AST_PBX_KEEPALIVE;
00707          else
00708             res = AST_PBX_NO_HANGUP_PEER;
00709          return res;
00710       } else {
00711          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00712       }
00713       /* XXX Maybe we should have another message here instead of invalid extension XXX */
00714    } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
00715       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
00716       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00717       ast_moh_stop(transferee);
00718       res=ast_autoservice_stop(transferee);
00719       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00720       if (!transferee->pbx) {
00721          /* Doh!  Use our handy async_goto functions */
00722          if (option_verbose > 2) 
00723             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00724                         ,transferee->name, newext, transferer_real_context);
00725          if (ast_async_goto(transferee, transferer_real_context, newext, 1))
00726             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00727          res = -1;
00728       } else {
00729          /* Set the channel's new extension, since it exists, using transferer context */
00730          ast_copy_string(transferee->exten, newext, sizeof(transferee->exten));
00731          ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context));
00732          transferee->priority = 0;
00733       }
00734       check_goto_on_transfer(transferer);
00735       return res;
00736    } else {
00737       if (option_verbose > 2) 
00738          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
00739    }
00740    if (!ast_strlen_zero(xferfailsound))
00741       res = ast_streamfile(transferer, xferfailsound, transferer->language);
00742    else
00743       res = 0;
00744    if (res) {
00745       ast_moh_stop(transferee);
00746       ast_autoservice_stop(transferee);
00747       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00748       return res;
00749    }
00750    res = ast_waitstream(transferer, AST_DIGIT_ANY);
00751    ast_stopstream(transferer);
00752    ast_moh_stop(transferee);
00753    res = ast_autoservice_stop(transferee);
00754    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00755    if (res) {
00756       if (option_verbose > 1)
00757          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00758       return res;
00759    }
00760    return FEATURE_RETURN_SUCCESS;
00761 }

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

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

00631 {
00632    if (option_verbose > 3)
00633       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00634    return FEATURE_RETURN_HANGUP;
00635 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Definition at line 194 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().

00195 {
00196    struct ast_channel *xferchan;
00197    char *goto_on_transfer;
00198 
00199    goto_on_transfer = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00200 
00201    if (!ast_strlen_zero(goto_on_transfer) && (xferchan = ast_channel_alloc(0))) {
00202       char *x;
00203       struct ast_frame *f;
00204       
00205       for (x = goto_on_transfer; x && *x; x++)
00206          if (*x == '^')
00207             *x = '|';
00208 
00209       strcpy(xferchan->name, chan->name);
00210       /* Make formats okay */
00211       xferchan->readformat = chan->readformat;
00212       xferchan->writeformat = chan->writeformat;
00213       ast_channel_masquerade(xferchan, chan);
00214       ast_parseable_goto(xferchan, goto_on_transfer);
00215       xferchan->_state = AST_STATE_UP;
00216       ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00217       xferchan->_softhangup = 0;
00218       if ((f = ast_read(xferchan))) {
00219          ast_frfree(f);
00220          f = NULL;
00221          ast_pbx_start(xferchan);
00222       } else {
00223          ast_hangup(xferchan);
00224       }
00225    }
00226 }

char* description ( void   ) 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 2306 of file res_features.c.

02307 {
02308    return "Call Features Resource";
02309 }

static void* do_parking_thread ( void *  ignore  )  [static]

Definition at line 1583 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_pbx_start(), ast_read(), 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, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, parkeduser::priority, ast_channel::priority, parkeduser::start, strdup, ast_frame::subclass, and VERBOSE_PREFIX_2.

Referenced by load_module().

01584 {
01585    int ms, tms, max;
01586    struct parkeduser *pu, *pl, *pt = NULL;
01587    struct timeval tv;
01588    struct ast_frame *f;
01589    char exten[AST_MAX_EXTENSION];
01590    char *peername,*cp;
01591    char returnexten[AST_MAX_EXTENSION];
01592    struct ast_context *con;
01593    int x;
01594    fd_set rfds, efds;
01595    fd_set nrfds, nefds;
01596    FD_ZERO(&rfds);
01597    FD_ZERO(&efds);
01598 
01599    for (;;) {
01600       ms = -1;
01601       max = -1;
01602       ast_mutex_lock(&parking_lock);
01603       pl = NULL;
01604       pu = parkinglot;
01605       FD_ZERO(&nrfds);
01606       FD_ZERO(&nefds);
01607       while(pu) {
01608          if (pu->notquiteyet) {
01609             /* Pretend this one isn't here yet */
01610             pl = pu;
01611             pu = pu->next;
01612             continue;
01613          }
01614          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01615          if (tms > pu->parkingtime) {
01616             /* Stop music on hold */
01617             ast_moh_stop(pu->chan);
01618             ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
01619             /* Get chan, exten from derived kludge */
01620             if (pu->peername[0]) {
01621                peername = ast_strdupa(pu->peername);
01622                cp = strrchr(peername, '-');
01623                if (cp) 
01624                   *cp = 0;
01625                con = ast_context_find(parking_con_dial);
01626                if (!con) {
01627                   con = ast_context_create(NULL, parking_con_dial, registrar);
01628                   if (!con) {
01629                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01630                   }
01631                }
01632                if (con) {
01633                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01634                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
01635                }
01636                ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
01637                ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
01638                pu->chan->priority = 1;
01639 
01640             } else {
01641                /* They've been waiting too long, send them back to where they came.  Theoretically they
01642                   should have their original extensions and such, but we copy to be on the safe side */
01643                ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
01644                ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
01645                pu->chan->priority = pu->priority;
01646             }
01647 
01648             manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
01649                "Exten: %d\r\n"
01650                "Channel: %s\r\n"
01651                "CallerID: %s\r\n"
01652                "CallerIDName: %s\r\n"
01653                ,pu->parkingnum, pu->chan->name
01654                ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01655                ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01656                );
01657 
01658             if (option_verbose > 1) 
01659                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);
01660             /* Start up the PBX, or hang them up */
01661             if (ast_pbx_start(pu->chan))  {
01662                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
01663                ast_hangup(pu->chan);
01664             }
01665             /* And take them out of the parking lot */
01666             if (pl) 
01667                pl->next = pu->next;
01668             else
01669                parkinglot = pu->next;
01670             pt = pu;
01671             pu = pu->next;
01672             con = ast_context_find(parking_con);
01673             if (con) {
01674                snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01675                if (ast_context_remove_extension2(con, exten, 1, NULL))
01676                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01677                else
01678                   notify_metermaids(exten, parking_con); /* Notify watchers */
01679             } else
01680                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01681             free(pt);
01682          } else {
01683             for (x = 0; x < AST_MAX_FDS; x++) {
01684                if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
01685                   if (FD_ISSET(pu->chan->fds[x], &efds))
01686                      ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
01687                   else
01688                      ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
01689                   pu->chan->fdno = x;
01690                   /* See if they need servicing */
01691                   f = ast_read(pu->chan);
01692                   if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
01693                      if (f)
01694                         ast_frfree(f);
01695                      manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
01696                         "Exten: %d\r\n"
01697                         "Channel: %s\r\n"
01698                         "CallerID: %s\r\n"
01699                         "CallerIDName: %s\r\n"
01700                         ,pu->parkingnum, pu->chan->name
01701                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01702                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01703                         );
01704 
01705                      /* There's a problem, hang them up*/
01706                      if (option_verbose > 1) 
01707                         ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
01708                      ast_hangup(pu->chan);
01709                      /* And take them out of the parking lot */
01710                      if (pl) 
01711                         pl->next = pu->next;
01712                      else
01713                         parkinglot = pu->next;
01714                      pt = pu;
01715                      pu = pu->next;
01716                      con = ast_context_find(parking_con);
01717                      if (con) {
01718                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01719                         if (ast_context_remove_extension2(con, exten, 1, NULL))
01720                            ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01721                         else
01722                            notify_metermaids(exten, parking_con);
01723                      } else
01724                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01725                      free(pt);
01726                      break;
01727                   } else {
01728                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01729                      ast_frfree(f);
01730                      if (pu->moh_trys < 3 && !pu->chan->generatordata) {
01731                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01732                         ast_moh_start(pu->chan, NULL);
01733                         pu->moh_trys++;
01734                      }
01735                      goto std;   /* XXX Ick: jumping into an else statement??? XXX */
01736                   }
01737                }
01738             }
01739             if (x >= AST_MAX_FDS) {
01740 std:              for (x=0; x<AST_MAX_FDS; x++) {
01741                   /* Keep this one for next one */
01742                   if (pu->chan->fds[x] > -1) {
01743                      FD_SET(pu->chan->fds[x], &nrfds);
01744                      FD_SET(pu->chan->fds[x], &nefds);
01745                      if (pu->chan->fds[x] > max)
01746                         max = pu->chan->fds[x];
01747                   }
01748                }
01749                /* Keep track of our longest wait */
01750                if ((tms < ms) || (ms < 0))
01751                   ms = tms;
01752                pl = pu;
01753                pu = pu->next;
01754             }
01755          }
01756       }
01757       ast_mutex_unlock(&parking_lock);
01758       rfds = nrfds;
01759       efds = nefds;
01760       tv = ast_samp2tv(ms, 1000);
01761       /* Wait for something to happen */
01762       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01763       pthread_testcancel();
01764    }
01765    return NULL;   /* Never reached */
01766 }

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

References ast_call_feature::app, app, ast_call_feature::app_args, 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().

01025 {
01026    struct ast_app *app;
01027    struct ast_call_feature *feature;
01028    int res;
01029 
01030    AST_LIST_LOCK(&feature_list);
01031    AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
01032       if (!strcasecmp(feature->exten,code)) break;
01033    }
01034    AST_LIST_UNLOCK(&feature_list);
01035 
01036    if (!feature) { /* shouldn't ever happen! */
01037       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01038       return -1; 
01039    }
01040    
01041    app = pbx_findapp(feature->app);
01042    if (app) {
01043       struct ast_channel *work = chan;
01044       if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
01045          work = peer;
01046       res = pbx_exec(work, app, feature->app_args, 1);
01047       if (res == AST_PBX_KEEPALIVE)
01048          return FEATURE_RETURN_PBX_KEEPALIVE;
01049       else if (res == AST_PBX_NO_HANGUP_PEER)
01050          return FEATURE_RETURN_NO_HANGUP_PEER;
01051       else if (res)
01052          return FEATURE_RETURN_SUCCESSBREAK;
01053    } else {
01054       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01055       return -2;
01056    }
01057    
01058    return FEATURE_RETURN_SUCCESS;
01059 }

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

Definition at line 1009 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().

01010 {
01011    struct ast_call_feature *tmp;
01012 
01013    AST_LIST_LOCK(&feature_list);
01014    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01015       if (!strcasecmp(tmp->sname, name))
01016          break;
01017    }
01018    AST_LIST_UNLOCK(&feature_list);
01019 
01020    return tmp;
01021 }

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

Definition at line 1956 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, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.

01957 {
01958    struct parkeduser *cur;
01959    int numparked = 0;
01960 
01961    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01962       , "Context", "Extension", "Pri", "Timeout");
01963 
01964    ast_mutex_lock(&parking_lock);
01965 
01966    cur = parkinglot;
01967    while(cur) {
01968       ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
01969          ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
01970          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01971 
01972       cur = cur->next;
01973       numparked++;
01974    }
01975    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01976 
01977    ast_mutex_unlock(&parking_lock);
01978 
01979    return RESULT_SUCCESS;
01980 }

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

Definition at line 1908 of file res_features.c.

References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_pickup_ext(), builtin_features, 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.

01909 {
01910    int i;
01911    int fcount;
01912    struct ast_call_feature *feature;
01913    char format[] = "%-25s %-7s %-7s\n";
01914 
01915    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01916    ast_cli(fd, format, "---------------", "-------", "-------");
01917 
01918    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01919 
01920    fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01921 
01922    for (i = 0; i < fcount; i++)
01923    {
01924       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01925    }
01926    ast_cli(fd, "\n");
01927    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01928    ast_cli(fd, format, "---------------", "-------", "-------");
01929    if (AST_LIST_EMPTY(&feature_list)) {
01930       ast_cli(fd, "(none)\n");
01931    }
01932    else {
01933       AST_LIST_LOCK(&feature_list);
01934       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01935          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01936       }
01937       AST_LIST_UNLOCK(&feature_list);
01938    }
01939    ast_cli(fd, "\nCall parking\n");
01940    ast_cli(fd, "------------\n");
01941    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01942    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01943    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01944    ast_cli(fd,"\n");
01945    
01946    return RESULT_SUCCESS;
01947 }

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

References ASTERISK_GPL_KEY.

02325 {
02326    return ASTERISK_GPL_KEY;
02327 }

static int load_config ( void   )  [static]

Definition at line 2080 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, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, notify_metermaids(), ast_call_feature::operation, option_verbose, park_add_hints(), parkaddhints, 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(), var, VERBOSE_PREFIX_2, xferfailsound, and xfersound.

02081 {
02082    int start = 0, end = 0;
02083    int res;
02084    struct ast_context *con = NULL;
02085    struct ast_config *cfg = NULL;
02086    struct ast_variable *var = NULL;
02087    char old_parking_ext[AST_MAX_EXTENSION];
02088    char old_parking_con[AST_MAX_EXTENSION] = "";
02089 
02090    if (!ast_strlen_zero(parking_con)) {
02091       strcpy(old_parking_ext, parking_ext);
02092       strcpy(old_parking_con, parking_con);
02093    } 
02094 
02095    /* Reset to defaults */
02096    strcpy(parking_con, "parkedcalls");
02097    strcpy(parking_con_dial, "park-dial");
02098    strcpy(parking_ext, "700");
02099    strcpy(pickup_ext, "*8");
02100    courtesytone[0] = '\0';
02101    strcpy(xfersound, "beep");
02102    strcpy(xferfailsound, "pbx-invalid");
02103    parking_start = 701;
02104    parking_stop = 750;
02105    parkfindnext = 0;
02106    parkaddhints = 0;
02107    adsipark = 0;
02108 
02109    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02110    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02111 
02112    cfg = ast_config_load("features.conf");
02113    if (!cfg) {
02114       cfg = ast_config_load("parking.conf");
02115       if (cfg)
02116          ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
02117    }
02118    if (cfg) {
02119       var = ast_variable_browse(cfg, "general");
02120       while(var) {
02121          if (!strcasecmp(var->name, "parkext")) {
02122             ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02123          } else if (!strcasecmp(var->name, "context")) {
02124             ast_copy_string(parking_con, var->value, sizeof(parking_con));
02125          } else if (!strcasecmp(var->name, "parkingtime")) {
02126             if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02127                ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02128                parkingtime = DEFAULT_PARK_TIME;
02129             } else
02130                parkingtime = parkingtime * 1000;
02131          } else if (!strcasecmp(var->name, "parkpos")) {
02132             if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02133                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);
02134             } else {
02135                parking_start = start;
02136                parking_stop = end;
02137             }
02138          } else if (!strcasecmp(var->name, "findslot")) {
02139             parkfindnext = (!strcasecmp(var->value, "next"));
02140          } else if (!strcasecmp(var->name, "parkhints")) {
02141             parkaddhints = ast_true(var->value);
02142          } else if (!strcasecmp(var->name, "adsipark")) {
02143             adsipark = ast_true(var->value);
02144          } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02145             if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02146                ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02147                transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02148             } else
02149                transferdigittimeout = transferdigittimeout * 1000;
02150          } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02151             if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02152                ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02153                featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02154             }
02155          } else if (!strcasecmp(var->name, "courtesytone")) {
02156             ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02157          } else if (!strcasecmp(var->name, "xfersound")) {
02158             ast_copy_string(xfersound, var->value, sizeof(xfersound));
02159          } else if (!strcasecmp(var->name, "xferfailsound")) {
02160             ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02161          } else if (!strcasecmp(var->name, "pickupexten")) {
02162             ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02163          }
02164          var = var->next;
02165       }
02166 
02167       unmap_features();
02168       var = ast_variable_browse(cfg, "featuremap");
02169       while(var) {
02170          if (remap_feature(var->name, var->value))
02171             ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02172          var = var->next;
02173       }
02174 
02175       /* Map a key combination to an application*/
02176       ast_unregister_features();
02177       var = ast_variable_browse(cfg, "applicationmap");
02178       while(var) {
02179          char *tmp_val=strdup(var->value);
02180          char *exten, *party=NULL, *app=NULL, *app_args=NULL; 
02181 
02182          if (!tmp_val) { 
02183             ast_log(LOG_ERROR, "res_features: strdup failed");
02184             continue;
02185          }
02186          
02187 
02188          exten=strsep(&tmp_val,",");
02189          if (exten) party=strsep(&tmp_val,",");
02190          if (party) app=strsep(&tmp_val,",");
02191 
02192          if (app) app_args=strsep(&tmp_val,",");
02193 
02194          if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
02195             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);
02196             free(tmp_val);
02197             var = var->next;
02198             continue;
02199          }
02200 
02201          {
02202             struct ast_call_feature *feature=find_feature(var->name);
02203             int mallocd=0;
02204             
02205             if (!feature) {
02206                feature=malloc(sizeof(struct ast_call_feature));
02207                mallocd=1;
02208             }
02209             if (!feature) {
02210                ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n");
02211                free(tmp_val);
02212                var = var->next;
02213                continue;
02214             }
02215 
02216             memset(feature,0,sizeof(struct ast_call_feature));
02217             ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
02218             ast_copy_string(feature->app,app,FEATURE_APP_LEN);
02219             ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
02220             free(tmp_val);
02221             
02222             if (app_args) 
02223                ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
02224             
02225             ast_copy_string(feature->exten, exten,sizeof(feature->exten));
02226             feature->operation=feature_exec_app;
02227             ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
02228             
02229             if (!strcasecmp(party,"caller"))
02230                ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
02231             else if (!strcasecmp(party, "callee"))
02232                ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
02233             else {
02234                ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
02235                var = var->next;
02236                continue;
02237             }
02238 
02239             ast_register_feature(feature);
02240             
02241             if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);  
02242          }
02243          var = var->next;
02244       }   
02245    }
02246    ast_config_destroy(cfg);
02247 
02248    /* Remove the old parking extension */
02249    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02250       if(!ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
02251          notify_metermaids(old_parking_ext, old_parking_con);
02252       ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02253    }
02254    
02255    if (!(con = ast_context_find(parking_con))) {
02256       if (!(con = ast_context_create(NULL, parking_con, registrar))) {
02257          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02258          return -1;
02259       }
02260    }
02261    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
02262    if (parkaddhints)
02263       park_add_hints(parking_con, parking_start, parking_stop);
02264    if (!res)
02265       notify_metermaids(ast_parking_ext(), parking_con);
02266    return res;
02267 }

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 2273 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, showfeatures, showparked, synopsis, and synopsis2.

02274 {
02275    int res;
02276    
02277    memset(parking_ext, 0, sizeof(parking_ext));
02278    memset(parking_con, 0, sizeof(parking_con));
02279 
02280    if ((res = load_config()))
02281       return res;
02282    ast_cli_register(&showparked);
02283    ast_cli_register(&showfeatures);
02284    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02285    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02286    if (!res)
02287       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02288    if (!res) {
02289       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02290    }
02291    return res;
02292 }

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

Definition at line 1990 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, ast_channel::name, parkeduser::next, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, RESULT_SUCCESS, s, and parkeduser::start.

Referenced by load_module().

01991 {
01992    struct parkeduser *cur;
01993    char *id = astman_get_header(m,"ActionID");
01994    char idText[256] = "";
01995 
01996    if (!ast_strlen_zero(id))
01997       snprintf(idText,256,"ActionID: %s\r\n",id);
01998 
01999    astman_send_ack(s, m, "Parked calls will follow");
02000 
02001         ast_mutex_lock(&parking_lock);
02002 
02003         cur=parkinglot;
02004         while(cur) {
02005          ast_cli(s->fd, "Event: ParkedCall\r\n"
02006          "Exten: %d\r\n"
02007          "Channel: %s\r\n"
02008          "Timeout: %ld\r\n"
02009          "CallerID: %s\r\n"
02010          "CallerIDName: %s\r\n"
02011          "%s"
02012          "\r\n"
02013                         ,cur->parkingnum, cur->chan->name
02014                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
02015          ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
02016          ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
02017          ,idText);
02018 
02019             cur = cur->next;
02020         }
02021 
02022    ast_cli(s->fd,
02023    "Event: ParkedCallsComplete\r\n"
02024    "%s"
02025    "\r\n",idText);
02026 
02027         ast_mutex_unlock(&parking_lock);
02028 
02029         return RESULT_SUCCESS;
02030 }

static void notify_metermaids ( char *  exten,
char *  context 
) [static]

Notify metermaids that we've changed an extension

Definition at line 355 of file res_features.c.

References ast_log(), features_parkwatch::callback, features_parkwatch::context, LOG_DEBUG, metermaids, features_parkwatch::next, and option_debug.

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

00356 {
00357    struct features_parkwatch *maid = metermaids;
00358    if (!maid)
00359       return;
00360    while (maid) {
00361       if (!maid->context || !strcmp(context, maid->context))
00362          maid->callback(exten, context);
00363       maid = maid->next;
00364    }
00365    if (option_debug > 3)
00366       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00367    return;
00368 }

static void park_add_hints ( char *  context,
int  start,
int  stop 
) [static]

Definition at line 2068 of file res_features.c.

References ast_add_extension(), AST_MAX_EXTENSION, exten, PRIORITY_HINT, and registrar.

Referenced by load_config().

02069 {
02070    int numext;
02071    char device[AST_MAX_EXTENSION];
02072    char exten[10];
02073    for (numext = start; numext <= stop; numext++) {
02074       snprintf(exten, sizeof(exten), "%d", numext);
02075       snprintf(device, sizeof(device), "Local/%s@%s", exten, context);
02076       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02077    }
02078 }

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

Definition at line 1768 of file res_features.c.

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

Referenced by load_module().

01769 {
01770    /* Data is unused at the moment but could contain a parking
01771       lot context eventually */
01772    int res=0;
01773    struct localuser *u;
01774    LOCAL_USER_ADD(u);
01775    /* Setup the exten/priority to be s/1 since we don't know
01776       where this call should return */
01777    strcpy(chan->exten, "s");
01778    chan->priority = 1;
01779    if (chan->_state != AST_STATE_UP)
01780       res = ast_answer(chan);
01781    if (!res)
01782       res = ast_safe_sleep(chan, 1000);
01783    if (!res)
01784       res = ast_park_call(chan, chan, 0, NULL);
01785    LOCAL_USER_REMOVE(u);
01786    if (!res)
01787       res = AST_PBX_KEEPALIVE;
01788    return res;
01789 }

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

Definition at line 1791 of file res_features.c.

References ast_channel::_state, 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, config, courtesytone, EVENT_FLAG_CALL, exten, free, ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), option_verbose, parking_con, parkinglot, parkeduser::parkingnum, and VERBOSE_PREFIX_3.

Referenced by load_module().

01792 {
01793    int res=0;
01794    struct localuser *u;
01795    struct ast_channel *peer=NULL;
01796    struct parkeduser *pu, *pl=NULL;
01797    char exten[AST_MAX_EXTENSION];
01798    struct ast_context *con;
01799    int park;
01800    int dres;
01801    struct ast_bridge_config config;
01802 
01803    if (!data) {
01804       ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
01805       return -1;
01806    }
01807    LOCAL_USER_ADD(u);
01808    park = atoi((char *)data);
01809    ast_mutex_lock(&parking_lock);
01810    pu = parkinglot;
01811    while(pu) {
01812       if (pu->parkingnum == park) {
01813          if (pl)
01814             pl->next = pu->next;
01815          else
01816             parkinglot = pu->next;
01817          break;
01818       }
01819       pl = pu;
01820       pu = pu->next;
01821    }
01822    ast_mutex_unlock(&parking_lock);
01823    if (pu) {
01824       peer = pu->chan;
01825       con = ast_context_find(parking_con);
01826       if (con) {
01827          snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
01828          if (ast_context_remove_extension2(con, exten, 1, NULL))
01829             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01830          else
01831             notify_metermaids(exten, parking_con);
01832       } else
01833          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01834 
01835       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01836          "Exten: %d\r\n"
01837          "Channel: %s\r\n"
01838          "From: %s\r\n"
01839          "CallerID: %s\r\n"
01840          "CallerIDName: %s\r\n"
01841          ,pu->parkingnum, pu->chan->name, chan->name
01842          ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01843          ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01844          );
01845 
01846       free(pu);
01847    }
01848    /* JK02: it helps to answer the channel if not already up */
01849    if (chan->_state != AST_STATE_UP) {
01850       ast_answer(chan);
01851    }
01852 
01853    if (peer) {
01854       /* Play a courtesy beep in the calling channel to prefix the bridge connecting */   
01855       if (!ast_strlen_zero(courtesytone)) {
01856          if (!ast_streamfile(chan, courtesytone, chan->language)) {
01857             if (ast_waitstream(chan, "") < 0) {
01858                ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01859                ast_hangup(peer);
01860                return -1;
01861             }
01862          }
01863       }
01864  
01865       ast_moh_stop(peer);
01866       ast_indicate(peer, AST_CONTROL_UNHOLD);
01867       res = ast_channel_make_compatible(chan, peer);
01868       if (res < 0) {
01869          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01870          ast_hangup(peer);
01871          return -1;
01872       }
01873       /* This runs sorta backwards, since we give the incoming channel control, as if it
01874          were the person called. */
01875       if (option_verbose > 2) 
01876          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01877 
01878       memset(&config, 0, sizeof(struct ast_bridge_config));
01879       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01880       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01881       config.timelimit = 0;
01882       config.play_warning = 0;
01883       config.warning_freq = 0;
01884       config.warning_sound=NULL;
01885       res = ast_bridge_call(chan, peer, &config);
01886 
01887       /* Simulate the PBX hanging up */
01888       if (res != AST_PBX_NO_HANGUP_PEER)
01889          ast_hangup(peer);
01890       return res;
01891    } else {
01892       /* XXX Play a message XXX */
01893       dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
01894       if (!dres)
01895             dres = ast_waitstream(chan, "");
01896       else {
01897          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01898          dres = 0;
01899       }
01900       if (option_verbose > 2) 
01901          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01902       res = -1;
01903    }
01904    LOCAL_USER_REMOVE(u);
01905    return res;
01906 }

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

References load_config().

02269                  {
02270    return load_config();
02271 }

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

Definition at line 1068 of file res_features.c.

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

Referenced by load_config().

01069 {
01070    int x;
01071    int res = -1;
01072    for (x = 0; x < FEATURES_COUNT; x++) {
01073       if (!strcasecmp(name, builtin_features[x].sname)) {
01074          ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01075          if (option_verbose > 1)
01076             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);
01077          res = 0;
01078       } else if (!strcmp(value, builtin_features[x].exten)) 
01079          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);
01080    }
01081    return res;
01082 }

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

Definition at line 1143 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, builtin_features, config, ast_call_feature::feature_mask, FEATURES_COUNT, find_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

01144 {
01145    int x;
01146    
01147    ast_clear_flag(config, AST_FLAGS_ALL); 
01148    for (x = 0; x < FEATURES_COUNT; x++) {
01149       if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
01150          if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01151             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01152 
01153          if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01154             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01155       }
01156    }
01157    
01158    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01159       char *dynamic_features;
01160 
01161       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01162 
01163       if (dynamic_features) {
01164          char *tmp = ast_strdupa(dynamic_features);
01165          char *tok;
01166          struct ast_call_feature *feature;
01167 
01168          if (!tmp) {
01169             return;
01170          }
01171 
01172          /* while we have a feature */
01173          while (NULL != (tok = strsep(&tmp, "#"))) {
01174             if ((feature = find_feature(tok))) {
01175                if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01176                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
01177                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01178                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
01179                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01180                }
01181             }
01182          }
01183       }
01184    }
01185 }

int unload_module ( void   ) 

Cleanup all module structures, sockets, etc.

Standard module functions ...

Definition at line 2295 of file res_features.c.

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

static void unmap_features ( void   )  [static]

Definition at line 1061 of file res_features.c.

References builtin_features, exten, and FEATURES_COUNT.

Referenced by load_config().

01062 {
01063    int x;
01064    for (x = 0; x < FEATURES_COUNT; x++)
01065       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01066 }

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

References STANDARD_USECOUNT.

02312 {
02313    /* Never allow parking to be unloaded because it will
02314       unresolve needed symbols in the dialer */
02315 #if 0
02316    int res;
02317    STANDARD_USECOUNT(res);
02318    return res;
02319 #else
02320    return 1;
02321 #endif
02322 }


Variable Documentation

int adsipark [static]

Definition at line 120 of file res_features.c.

Referenced by load_config().

struct ast_call_feature builtin_features[]

Definition at line 960 of file res_features.c.

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

char courtesytone[256] [static]

Definition at line 106 of file res_features.c.

Referenced by 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 132 of file res_features.c.

char* descrip2 [static]

Definition at line 142 of file res_features.c.

int featuredigittimeout [static]

Definition at line 123 of file res_features.c.

Referenced by load_config().

LOCAL_USER_DECL

Definition at line 175 of file res_features.c.

int metermaidid = 0

Definition at line 85 of file res_features.c.

struct features_parkwatch* metermaids

Metermaid ID

Definition at line 84 of file res_features.c.

Referenced by ast_park_metermaid_add(), ast_park_metermaid_remove(), and notify_metermaids().

struct ast_app* monitor_app = NULL [static]

Definition at line 149 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 150 of file res_features.c.

int parkaddhints = 0 [static]

Definition at line 103 of file res_features.c.

Referenced by load_config().

char* parkcall = "Park" [static]

Definition at line 138 of file res_features.c.

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

char* parkedcall = "ParkedCall" [static]

Definition at line 87 of file res_features.c.

Referenced by load_module(), and unload_module().

int parkfindnext [static]

Definition at line 118 of file res_features.c.

Referenced by load_config().

char parking_con[AST_MAX_EXTENSION] [static]

Definition at line 93 of file res_features.c.

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

char parking_con_dial[AST_MAX_EXTENSION] [static]

Definition at line 96 of file res_features.c.

Referenced by load_config().

char parking_ext[AST_MAX_EXTENSION] [static]

Definition at line 99 of file res_features.c.

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

int parking_offset [static]

Definition at line 116 of file res_features.c.

int parking_start [static]

Definition at line 111 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

int parking_stop [static]

Definition at line 114 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

pthread_t parking_thread [static]

Definition at line 171 of file res_features.c.

Referenced by load_module().

struct parkeduser* parkinglot [static]

Definition at line 167 of file res_features.c.

Referenced by ast_park_call(), do_parking_thread(), handle_parkedcalls(), manager_parking_status(), and park_exec().

int parkingtime = DEFAULT_PARK_TIME [static]

Definition at line 90 of file res_features.c.

Referenced by load_config().

char pickup_ext[AST_MAX_EXTENSION] [static]

Definition at line 101 of file res_features.c.

Referenced by load_config().

char* registrar = "res_features" [static]

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

Referenced by load_module(), and unload_module().

char showfeatures_help[] [static]

Initial value:

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

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

Referenced by load_module(), and unload_module().

char showparked_help[] [static]

Initial value:

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

Definition at line 1982 of file res_features.c.

STANDARD_LOCAL_USER

Definition at line 173 of file res_features.c.

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

Definition at line 130 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 140 of file res_features.c.

int transferdigittimeout [static]

Definition at line 122 of file res_features.c.

Referenced by load_config().

char xferfailsound[256] [static]

Definition at line 108 of file res_features.c.

Referenced by load_config().

char xfersound[256] [static]

Definition at line 107 of file res_features.c.

Referenced by load_config().


Generated on Sat Sep 16 07:28:20 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7