Thu Jul 9 13:41:17 2009

Asterisk developer's documentation


features.c File Reference

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

#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  ast_dial_features
struct  feature_group
struct  feature_group_exten
struct  feature_groups
struct  feature_list
struct  parkeduser
struct  parkinglot

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_ATXFER_CALLBACK_RETRIES   2
#define DEFAULT_ATXFER_DROP_CALL   0
#define DEFAULT_ATXFER_LOOP_DELAY   10000
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000
#define DEFAULT_PARK_TIME   45000
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
#define FEATURE_RETURN_HANGUP   -1
#define FEATURE_RETURN_KEEPTRYING   24
#define FEATURE_RETURN_PARKFAILED   25
#define FEATURE_RETURN_PASSDIGITS   21
#define FEATURE_RETURN_STOREDIGITS   22
#define FEATURE_RETURN_SUCCESS   23
#define FEATURE_RETURN_SUCCESSBREAK   0
#define FEATURES_COUNT   ARRAY_LEN(builtin_features)
#define HFS_FORMAT   "%-25s %-7s %-7s\n"
#define MAX_DIAL_FEATURE_OPTIONS   30

Enumerations

enum  {
  AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
  AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3)
}
enum  { BRIDGE_OPT_PLAYTONE = (1 << 0) }

Functions

static int action_bridge (struct mansession *s, const struct message *m)
 Bridge channels together.
static void add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
 Announce call parking by ADSI.
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)
 bridge the call
static void ast_bridge_call_thread_launch (void *data)
 create thread for the parked call
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature)
 detect a feature before bridging
static int ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
 Check the dynamic features.
static struct ast_channelast_feature_request_and_dial (struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language)
 Get feature and dial.
int ast_features_init (void)
int ast_features_reload (void)
 Reload call features from features.conf.
ast_call_featureast_find_call_feature (const char *name)
 look for a call feature entry by its sname
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call and read back parked location.
const char * ast_parking_ext (void)
 Determine system parking extension.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
const char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_rdlock_call_features (void)
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unlock_call_features (void)
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
 Remove all features in the list.
static void ast_unregister_groups (void)
 Remove all feature groups in the list.
static int bridge_exec (struct ast_channel *chan, void *data)
 Bridge channels.
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 Attended transfer.
static int builtin_automixmonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 Monitor a channel by DTMF.
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 Blind transfer user to another extension.
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 support routing for one touch call parking
static char * callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
static int check_compat (struct ast_channel *c, struct ast_channel *newchan)
 make channels compatible
static void check_goto_on_transfer (struct ast_channel *chan)
 Check goto on transfer.
static void dial_features_destroy (void *data)
static void * dial_features_duplicate (void *data)
static void do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan)
 Actual bridge.
static void * do_parking_thread (void *ignore)
 Take care of parked calls and unpark them if needed.
static int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 exec an app by feature
static int feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, int operation, struct ast_call_feature *feature)
 Helper function for feature_interpret and ast_feature_detect.
static struct ast_call_featurefind_dynamic_feature (const char *name)
 find a call feature by name
static struct feature_groupfind_group (const char *name)
 Find a group by name.
static int finishup (struct ast_channel *chan)
static char * handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list configured features.
static char * handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list parked calls.
static char * handle_parkedcalls_deprecated (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int load_config (void)
static int manager_park (struct mansession *s, const struct message *m)
 Create manager event for parked calls.
static int manager_parking_status (struct mansession *s, const struct message *m)
 Dump parking lot status.
static int masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, const char *orig_chan_name)
static int masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name)
static enum ast_device_state metermaidstate (const char *data)
 metermaids callback from devicestate.c
static void notify_metermaids (const char *exten, char *context, enum ast_device_state state)
 Notify metermaids that we've changed an extension.
static void park_add_hints (char *context, int start, int stop)
 Add parking hints for all defined parking lots.
static int park_call_exec (struct ast_channel *chan, void *data)
 Park a call.
static int park_call_full (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name, struct parkeduser *pu)
static int park_exec (struct ast_channel *chan, void *data)
 Pickup parked call.
static struct parkeduserpark_space_reserve (struct ast_channel *chan)
static struct ast_cdrpick_unlocked_cdr (struct ast_cdr *cdr)
 return the first unlocked cdr in a possible chain
static void post_manager_event (const char *s, struct parkeduser *pu)
 Output parking event to manager.
static const char * real_ctx (struct ast_channel *transferer, struct ast_channel *transferee)
 Find the context for the transfer.
static struct feature_groupregister_group (const char *fgname)
 Add new feature group.
static void register_group_feature (struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
 Add feature to group.
static int remap_feature (const char *name, const char *value)
static void set_bridge_features_on_config (struct ast_bridge_config *config, const char *features)
static void set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri)
 store context, extension and priority
static void set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
static void set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense)
 set caller and callee according to the direction
static void unmap_features (void)

Variables

static int adsipark
static char * app_bridge = "Bridge"
static unsigned int atxfercallbackretries
static unsigned int atxferdropcall
static unsigned int atxferloopdelay
static int atxfernoanswertimeout
static char * bridge_descrip
static struct ast_app_option bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE } }
static char * bridge_synopsis = "Bridge two channels"
static struct ast_call_feature builtin_features []
static struct ast_cli_entry cli_features []
static struct ast_cli_entry cli_show_parkedcalls_deprecated = { .handler = handle_parkedcalls_deprecated , .summary = "List currently parked calls." ,__VA_ARGS__ }
static int comebacktoorigin = 1
static char courtesytone [256]
static char * descrip
static char * descrip2
ast_datastore_info dial_features_info
static int featuredigittimeout
static ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER
static char mandescr_bridge []
static char mandescr_park []
static struct ast_appmixmonitor_app = NULL
static int mixmonitor_ok = 1
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 parkedcallhangup = 0
static int parkedcallrecording = 0
static int parkedcallreparking = 0
static int parkedcalltransfers = 0
static int parkedplay = 0
static int parkfindnext
static char parking_con [AST_MAX_EXTENSION]
static char parking_con_dial [AST_MAX_EXTENSION]
static char parking_ext [AST_MAX_EXTENSION]
static int parking_offset
static int parking_start
static int parking_stop
static pthread_t parking_thread
static int parkingtime = DEFAULT_PARK_TIME
static char parkmohclass [MAX_MUSICCLASS]
static char pickup_ext [AST_MAX_EXTENSION]
static char * registrar = "features"
static struct ast_appstopmixmonitor_app = NULL
static int stopmixmonitor_ok = 1
static char * synopsis = "Answer a parked call"
static char * synopsis2 = "Park yourself"
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 66 of file features.c.

#define DEFAULT_ATXFER_CALLBACK_RETRIES   2

Definition at line 64 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_DROP_CALL   0

Definition at line 62 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_LOOP_DELAY   10000

Definition at line 63 of file features.c.

Referenced by load_config().

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

Definition at line 60 of file features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 61 of file features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 58 of file features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 59 of file features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 69 of file features.c.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 74 of file features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_PARKFAILED   25

Definition at line 75 of file features.c.

Referenced by builtin_blindtransfer(), and masq_park_call().

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 71 of file features.c.

Referenced by ast_bridge_call().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 72 of file features.c.

#define FEATURE_RETURN_SUCCESS   23

Definition at line 73 of file features.c.

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

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 70 of file features.c.

Referenced by feature_exec_app().

#define FEATURES_COUNT   ARRAY_LEN(builtin_features)

Definition at line 1406 of file features.c.

Referenced by ast_feature_request_and_dial(), ast_find_call_feature(), feature_interpret_helper(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().

#define HFS_FORMAT   "%-25s %-7s %-7s\n"

Referenced by handle_feature_show().

#define MAX_DIAL_FEATURE_OPTIONS   30

Definition at line 67 of file features.c.

Referenced by do_parking_thread().


Enumeration Type Documentation

anonymous enum

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 77 of file features.c.

00077      {
00078    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00079    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00080    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00081    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00082    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00083    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00084 };

anonymous enum

Enumerator:
BRIDGE_OPT_PLAYTONE 

Definition at line 3896 of file features.c.

03896      {
03897    BRIDGE_OPT_PLAYTONE = (1 << 0),
03898 };


Function Documentation

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

Bridge channels together.

Parameters:
s 
m Make sure valid channels were specified, send errors if any of the channels could not be found/locked, answer channels if needed, create the placeholder channels and grab the other channels make the channels compatible, send error if we fail doing so setup the bridge thread object and start the bridge.
Return values:
0 on success or on incorrect use.
1 on failure to bridge channels.

Definition at line 3553 of file features.c.

References ast_channel::_state, ast_answer(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc, ast_channel_make_compatible(), ast_channel_unlock, ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), buf, do_bridge_masquerade(), errno, LOG_WARNING, ast_channel::name, playtone(), s, and xfersound.

Referenced by ast_features_init().

03554 {
03555    const char *channela = astman_get_header(m, "Channel1");
03556    const char *channelb = astman_get_header(m, "Channel2");
03557    const char *playtone = astman_get_header(m, "Tone");
03558    struct ast_channel *chana = NULL, *chanb = NULL;
03559    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
03560    struct ast_bridge_thread_obj *tobj = NULL;
03561 
03562    /* make sure valid channels were specified */
03563    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
03564       astman_send_error(s, m, "Missing channel parameter in request");
03565       return 0;
03566    }
03567 
03568    /* The same code must be executed for chana and chanb.  To avoid a
03569     * theoretical deadlock, this code is separated so both chana and chanb will
03570     * not hold locks at the same time. */
03571 
03572    /* Start with chana */
03573    chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
03574 
03575    /* send errors if any of the channels could not be found/locked */
03576    if (!chana) {
03577       char buf[256];
03578       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
03579       astman_send_error(s, m, buf);
03580       return 0;
03581    }
03582 
03583    /* Answer the channels if needed */
03584    if (chana->_state != AST_STATE_UP)
03585       ast_answer(chana);
03586 
03587    /* create the placeholder channels and grab the other channels */
03588    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
03589       NULL, NULL, 0, "Bridge/%s", chana->name))) {
03590       astman_send_error(s, m, "Unable to create temporary channel!");
03591       ast_channel_unlock(chana);
03592       return 1;
03593    }
03594 
03595    do_bridge_masquerade(chana, tmpchana);
03596    ast_channel_unlock(chana);
03597    chana = NULL;
03598 
03599    /* now do chanb */
03600    chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
03601    /* send errors if any of the channels could not be found/locked */
03602    if (!chanb) {
03603       char buf[256];
03604       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
03605       ast_hangup(tmpchana);
03606       astman_send_error(s, m, buf);
03607       return 0;
03608    }
03609 
03610    /* Answer the channels if needed */
03611    if (chanb->_state != AST_STATE_UP)
03612       ast_answer(chanb);
03613 
03614    /* create the placeholder channels and grab the other channels */
03615    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
03616       NULL, NULL, 0, "Bridge/%s", chanb->name))) {
03617       astman_send_error(s, m, "Unable to create temporary channels!");
03618       ast_hangup(tmpchana);
03619       ast_channel_unlock(chanb);
03620       return 1;
03621    }
03622    do_bridge_masquerade(chanb, tmpchanb);
03623    ast_channel_unlock(chanb);
03624    chanb = NULL;
03625 
03626    /* make the channels compatible, send error if we fail doing so */
03627    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
03628       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
03629       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
03630       ast_hangup(tmpchana);
03631       ast_hangup(tmpchanb);
03632       return 1;
03633    }
03634 
03635    /* setup the bridge thread object and start the bridge */
03636    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
03637       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
03638       astman_send_error(s, m, "Unable to spawn a new bridge thread");
03639       ast_hangup(tmpchana);
03640       ast_hangup(tmpchanb);
03641       return 1;
03642    }
03643 
03644    tobj->chan = tmpchana;
03645    tobj->peer = tmpchanb;
03646    tobj->return_to_pbx = 1;
03647 
03648    if (ast_true(playtone)) {
03649       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
03650          if (ast_waitstream(tmpchanb, "") < 0)
03651             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
03652       }
03653    }
03654 
03655    ast_bridge_call_thread_launch(tobj);
03656 
03657    astman_send_ack(s, m, "Launched bridge thread with success");
03658 
03659    return 0;
03660 }

static void add_features_datastores ( struct ast_channel caller,
struct ast_channel callee,
struct ast_bridge_config config 
) [static]

Definition at line 2116 of file features.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, AST_FLAGS_ALL, ast_log(), config, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, and LOG_WARNING.

Referenced by ast_bridge_call().

02117 {
02118    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
02119    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
02120 
02121    ast_channel_lock(caller);
02122    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
02123    ast_channel_unlock(caller);
02124    if (!ds_caller_features) {
02125       if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
02126          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
02127          return;
02128       }
02129       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
02130          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02131          ast_channel_datastore_free(ds_caller_features);
02132          return;
02133       }
02134       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
02135       caller_features->is_caller = 1;
02136       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
02137       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
02138       ds_caller_features->data = caller_features;
02139       ast_channel_lock(caller);
02140       ast_channel_datastore_add(caller, ds_caller_features);
02141       ast_channel_unlock(caller);
02142    } else {
02143       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
02144        * flags over from the atxfer to the caller */
02145       return;
02146    }
02147 
02148    ast_channel_lock(callee);
02149    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
02150    ast_channel_unlock(callee);
02151    if (!ds_callee_features) {
02152       if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
02153          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
02154          return;
02155       }
02156       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
02157          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02158          ast_channel_datastore_free(ds_callee_features);
02159          return;
02160       }
02161       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
02162       callee_features->is_caller = 0;
02163       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
02164       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
02165       ds_callee_features->data = callee_features;
02166       ast_channel_lock(callee);
02167       ast_channel_datastore_add(callee, ds_callee_features);
02168       ast_channel_unlock(callee);
02169    }
02170 
02171    return;
02172 }

static int adsi_announce_park ( struct ast_channel chan,
char *  parkingexten 
) [static]

Announce call parking by ADSI.

Parameters:
chan .
parkingexten . Create message to show for ADSI, display message.
Return values:
0 on success.
-1 on failure.

Definition at line 376 of file features.c.

References ADSI_JUST_CENT, ast_adsi_load_session, ast_adsi_print, chan, and justify.

Referenced by park_call_full().

00377 {
00378    int res;
00379    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00380    char tmp[256];
00381    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00382 
00383    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00384    message[0] = tmp;
00385    res = ast_adsi_load_session(chan, NULL, 0, 1);
00386    if (res == -1)
00387       return res;
00388    return ast_adsi_print(chan, message, justify, 1);
00389 }

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

Bridge a call, optionally allowing redirection.

Parameters:
chan,peer,config Set start time, check for two channels,check if monitor on check for feature activation, create new CDR
Return values:
res on success.
-1 on failure to bridge.

append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.

Todo:
XXX how do we guarantee the latter ?

Definition at line 2183 of file features.c.

References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_channel::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, config, ast_channel::context, ast_channel::data, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_cdr::uniqueid, ast_channel::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.

Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), and park_exec().

02184 {
02185    /* Copy voice back and forth between the two channels.  Give the peer
02186       the ability to transfer calls with '#<extension' syntax. */
02187    struct ast_frame *f;
02188    struct ast_channel *who;
02189    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
02190    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
02191    char orig_channame[AST_MAX_EXTENSION];
02192    char orig_peername[AST_MAX_EXTENSION];
02193    int res;
02194    int diff;
02195    int hasfeatures=0;
02196    int hadfeatures=0;
02197    int autoloopflag;
02198    struct ast_option_header *aoh;
02199    struct ast_bridge_config backup_config;
02200    struct ast_cdr *bridge_cdr = NULL;
02201    struct ast_cdr *orig_peer_cdr = NULL;
02202    struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02203    struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02204    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02205    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02206 
02207    memset(&backup_config, 0, sizeof(backup_config));
02208 
02209    config->start_time = ast_tvnow();
02210 
02211    if (chan && peer) {
02212       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
02213       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
02214    } else if (chan) {
02215       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
02216    }
02217 
02218    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
02219    add_features_datastores(chan, peer, config);
02220 
02221    /* This is an interesting case.  One example is if a ringing channel gets redirected to
02222     * an extension that picks up a parked call.  This will make sure that the call taken
02223     * out of parking gets told that the channel it just got bridged to is still ringing. */
02224    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
02225       ast_indicate(peer, AST_CONTROL_RINGING);
02226    }
02227 
02228    if (monitor_ok) {
02229       const char *monitor_exec;
02230       struct ast_channel *src = NULL;
02231       if (!monitor_app) { 
02232          if (!(monitor_app = pbx_findapp("Monitor")))
02233             monitor_ok=0;
02234       }
02235       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
02236          src = chan;
02237       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
02238          src = peer;
02239       if (monitor_app && src) {
02240          char *tmp = ast_strdupa(monitor_exec);
02241          pbx_exec(src, monitor_app, tmp);
02242       }
02243    }
02244 
02245    set_config_flags(chan, peer, config);
02246    config->firstpass = 1;
02247 
02248    /* Answer if need be */
02249    if (chan->_state != AST_STATE_UP) {
02250       if (ast_raw_answer(chan, 1)) {
02251          return -1;
02252       }
02253    }
02254 
02255    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
02256    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
02257    orig_peer_cdr = peer_cdr;
02258    
02259    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
02260       
02261       if (chan_cdr) {
02262          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
02263          ast_cdr_update(chan);
02264          bridge_cdr = ast_cdr_dup(chan_cdr);
02265          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02266          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02267       } else {
02268          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
02269          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
02270          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
02271          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
02272          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
02273          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02274          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02275          ast_cdr_setcid(bridge_cdr, chan);
02276          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
02277          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
02278          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
02279          /* Destination information */
02280          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
02281          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
02282          if (peer_cdr) {
02283             bridge_cdr->start = peer_cdr->start;
02284             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02285          } else {
02286             ast_cdr_start(bridge_cdr);
02287          }
02288       }
02289       ast_debug(4,"bridge answer set, chan answer set\n");
02290       /* peer_cdr->answer will be set when a macro runs on the peer;
02291          in that case, the bridge answer will be delayed while the
02292          macro plays on the peer channel. The peer answered the call
02293          before the macro started playing. To the phone system,
02294          this is billable time for the call, even tho the caller
02295          hears nothing but ringing while the macro does its thing. */
02296       if (peer_cdr && !ast_tvzero(peer_cdr->answer)) {
02297          bridge_cdr->answer = peer_cdr->answer;
02298          bridge_cdr->disposition = peer_cdr->disposition;
02299          if (chan_cdr) {
02300             chan_cdr->answer = peer_cdr->answer;
02301             chan_cdr->disposition = peer_cdr->disposition;
02302          }
02303       } else {
02304          ast_cdr_answer(bridge_cdr);
02305          if (chan_cdr) {
02306             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
02307          }
02308       }
02309       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
02310          if (chan_cdr) {
02311             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
02312          }
02313          if (peer_cdr) {
02314             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
02315          }
02316       }
02317    }
02318    for (;;) {
02319       struct ast_channel *other; /* used later */
02320    
02321       res = ast_channel_bridge(chan, peer, config, &f, &who);
02322       
02323       /* When frame is not set, we are probably involved in a situation
02324          where we've timed out.
02325          When frame is set, we'll come this code twice; once for DTMF_BEGIN
02326          and also for DTMF_END. If we flow into the following 'if' for both, then 
02327          our wait times are cut in half, as both will subtract from the
02328          feature_timer. Not good!
02329       */
02330       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
02331          /* Update time limit for next pass */
02332          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
02333          if (res == AST_BRIDGE_RETRY) {
02334             /* The feature fully timed out but has not been updated. Skip
02335              * the potential round error from the diff calculation and
02336              * explicitly set to expired. */
02337             config->feature_timer = -1;
02338          } else {
02339             config->feature_timer -= diff;
02340          }
02341 
02342          if (hasfeatures) {
02343             /* Running on backup config, meaning a feature might be being
02344                activated, but that's no excuse to keep things going 
02345                indefinitely! */
02346             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
02347                ast_debug(1, "Timed out, realtime this time!\n");
02348                config->feature_timer = 0;
02349                who = chan;
02350                if (f)
02351                   ast_frfree(f);
02352                f = NULL;
02353                res = 0;
02354             } else if (config->feature_timer <= 0) {
02355                /* Not *really* out of time, just out of time for
02356                   digits to come in for features. */
02357                ast_debug(1, "Timed out for feature!\n");
02358                if (!ast_strlen_zero(peer_featurecode)) {
02359                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
02360                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
02361                }
02362                if (!ast_strlen_zero(chan_featurecode)) {
02363                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
02364                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
02365                }
02366                if (f)
02367                   ast_frfree(f);
02368                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02369                if (!hasfeatures) {
02370                   /* Restore original (possibly time modified) bridge config */
02371                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02372                   memset(&backup_config, 0, sizeof(backup_config));
02373                }
02374                hadfeatures = hasfeatures;
02375                /* Continue as we were */
02376                continue;
02377             } else if (!f) {
02378                /* The bridge returned without a frame and there is a feature in progress.
02379                 * However, we don't think the feature has quite yet timed out, so just
02380                 * go back into the bridge. */
02381                continue;
02382             }
02383          } else {
02384             if (config->feature_timer <=0) {
02385                /* We ran out of time */
02386                config->feature_timer = 0;
02387                who = chan;
02388                if (f)
02389                   ast_frfree(f);
02390                f = NULL;
02391                res = 0;
02392             }
02393          }
02394       }
02395       if (res < 0) {
02396          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
02397             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
02398          goto before_you_go;
02399       }
02400       
02401       if (!f || (f->frametype == AST_FRAME_CONTROL &&
02402             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
02403                f->subclass == AST_CONTROL_CONGESTION))) {
02404          res = -1;
02405          break;
02406       }
02407       /* many things should be sent to the 'other' channel */
02408       other = (who == chan) ? peer : chan;
02409       if (f->frametype == AST_FRAME_CONTROL) {
02410          switch (f->subclass) {
02411          case AST_CONTROL_RINGING:
02412          case AST_CONTROL_FLASH:
02413          case -1:
02414             ast_indicate(other, f->subclass);
02415             break;
02416          case AST_CONTROL_HOLD:
02417          case AST_CONTROL_UNHOLD:
02418             ast_indicate_data(other, f->subclass, f->data, f->datalen);
02419             break;
02420          case AST_CONTROL_OPTION:
02421             aoh = f->data;
02422             /* Forward option Requests */
02423             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02424                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
02425                   f->datalen - sizeof(struct ast_option_header), 0);
02426             }
02427             break;
02428          }
02429       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02430          /* eat it */
02431       } else if (f->frametype == AST_FRAME_DTMF) {
02432          char *featurecode;
02433          int sense;
02434 
02435          hadfeatures = hasfeatures;
02436          /* This cannot overrun because the longest feature is one shorter than our buffer */
02437          if (who == chan) {
02438             sense = FEATURE_SENSE_CHAN;
02439             featurecode = chan_featurecode;
02440          } else  {
02441             sense = FEATURE_SENSE_PEER;
02442             featurecode = peer_featurecode;
02443          }
02444          /*! append the event to featurecode. we rely on the string being zero-filled, and
02445           * not overflowing it. 
02446           * \todo XXX how do we guarantee the latter ?
02447           */
02448          featurecode[strlen(featurecode)] = f->subclass;
02449          /* Get rid of the frame before we start doing "stuff" with the channels */
02450          ast_frfree(f);
02451          f = NULL;
02452          config->feature_timer = backup_config.feature_timer;
02453          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
02454          switch(res) {
02455          case FEATURE_RETURN_PASSDIGITS:
02456             ast_dtmf_stream(other, who, featurecode, 0, 0);
02457             /* Fall through */
02458          case FEATURE_RETURN_SUCCESS:
02459             memset(featurecode, 0, sizeof(chan_featurecode));
02460             break;
02461          }
02462          if (res >= FEATURE_RETURN_PASSDIGITS) {
02463             res = 0;
02464          } else 
02465             break;
02466          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02467          if (hadfeatures && !hasfeatures) {
02468             /* Restore backup */
02469             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02470             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02471          } else if (hasfeatures) {
02472             if (!hadfeatures) {
02473                /* Backup configuration */
02474                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02475                /* Setup temporary config options */
02476                config->play_warning = 0;
02477                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02478                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02479                config->warning_freq = 0;
02480                config->warning_sound = NULL;
02481                config->end_sound = NULL;
02482                config->start_sound = NULL;
02483                config->firstpass = 0;
02484             }
02485             config->start_time = ast_tvnow();
02486             config->feature_timer = featuredigittimeout;
02487             ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
02488          }
02489       }
02490       if (f)
02491          ast_frfree(f);
02492 
02493    }
02494    before_you_go:
02495 
02496    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02497       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
02498       if (bridge_cdr) {
02499          ast_cdr_discard(bridge_cdr);
02500          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
02501       }
02502       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
02503    }
02504 
02505    if (config->end_bridge_callback) {
02506       config->end_bridge_callback(config->end_bridge_callback_data);
02507    }
02508 
02509    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) &&
02510       ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02511       struct ast_cdr *swapper = NULL;
02512       char savelastapp[AST_MAX_EXTENSION];
02513       char savelastdata[AST_MAX_EXTENSION];
02514       char save_exten[AST_MAX_EXTENSION];
02515       int  save_prio;
02516       int  found = 0;   /* set if we find at least one match */
02517       int  spawn_error = 0;
02518       
02519       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02520       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02521       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02522          ast_cdr_end(bridge_cdr);
02523       }
02524       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
02525          dialplan code operate on it */
02526       ast_channel_lock(chan);
02527       if (bridge_cdr) {
02528          swapper = chan->cdr;
02529          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02530          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02531          chan->cdr = bridge_cdr;
02532       }
02533       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02534       save_prio = chan->priority;
02535       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02536       chan->priority = 1;
02537       ast_channel_unlock(chan);
02538       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) {
02539          chan->priority++;
02540       }
02541       if (found && spawn_error) {
02542          /* Something bad happened, or a hangup has been requested. */
02543          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02544          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02545       }
02546       /* swap it back */
02547       ast_channel_lock(chan);
02548       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02549       chan->priority = save_prio;
02550       if (bridge_cdr) {
02551          if (chan->cdr == bridge_cdr) {
02552             chan->cdr = swapper;
02553          } else {
02554             bridge_cdr = NULL;
02555          }
02556       }
02557       if (chan->priority != 1 || !spawn_error) {
02558          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02559       }
02560       ast_channel_unlock(chan);
02561       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
02562       if (bridge_cdr) {
02563          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02564          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02565       }
02566       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02567    }
02568    
02569    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
02570    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02571    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
02572       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02573 
02574    /* we can post the bridge CDR at this point */
02575    if (bridge_cdr) {
02576       ast_cdr_end(bridge_cdr);
02577       ast_cdr_detach(bridge_cdr);
02578    }
02579    
02580    /* do a specialized reset on the beginning channel
02581       CDR's, if they still exist, so as not to mess up
02582       issues in future bridges;
02583       
02584       Here are the rules of the game:
02585       1. The chan and peer channel pointers will not change
02586          during the life of the bridge.
02587       2. But, in transfers, the channel names will change.
02588          between the time the bridge is started, and the
02589          time the channel ends. 
02590          Usually, when a channel changes names, it will
02591          also change CDR pointers.
02592       3. Usually, only one of the two channels (chan or peer)
02593          will change names.
02594       4. Usually, if a channel changes names during a bridge,
02595          it is because of a transfer. Usually, in these situations,
02596          it is normal to see 2 bridges running simultaneously, and
02597          it is not unusual to see the two channels that change
02598          swapped between bridges.
02599       5. After a bridge occurs, we have 2 or 3 channels' CDRs
02600          to attend to; if the chan or peer changed names,
02601          we have the before and after attached CDR's.
02602    */
02603    
02604    if (new_chan_cdr) {
02605       struct ast_channel *chan_ptr = NULL;
02606  
02607       if (strcasecmp(orig_channame, chan->name) != 0) { 
02608          /* old channel */
02609          chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02610          if (chan_ptr) {
02611             if (!ast_bridged_channel(chan_ptr)) {
02612                struct ast_cdr *cur;
02613                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02614                   if (cur == chan_cdr) {
02615                      break;
02616                   }
02617                }
02618                if (cur)
02619                   ast_cdr_specialized_reset(chan_cdr,0);
02620             }
02621             ast_channel_unlock(chan_ptr);
02622          }
02623          /* new channel */
02624          ast_cdr_specialized_reset(new_chan_cdr,0);
02625       } else {
02626          ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr  */
02627       }
02628    }
02629    
02630    {
02631       struct ast_channel *chan_ptr = NULL;
02632       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02633       if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED))
02634          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
02635       if (strcasecmp(orig_peername, peer->name) != 0) { 
02636          /* old channel */
02637          chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02638          if (chan_ptr) {
02639             if (!ast_bridged_channel(chan_ptr)) {
02640                struct ast_cdr *cur;
02641                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02642                   if (cur == peer_cdr) {
02643                      break;
02644                   }
02645                }
02646                if (cur)
02647                   ast_cdr_specialized_reset(peer_cdr,0);
02648             }
02649             ast_channel_unlock(chan_ptr);
02650          }
02651          /* new channel */
02652          ast_cdr_specialized_reset(new_peer_cdr,0);
02653       } else {
02654          ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr  */
02655       }
02656    }
02657    
02658    return res;
02659 }

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

bridge the call

Parameters:
data thread bridge.
Set Last Data for respective channels, reset cdr for channels bridge call, check if we're going back to dialplan if not hangup both legs of the call

Definition at line 311 of file features.c.

References ast_channel::appl, ast_bridge_call(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, LOG_VERBOSE, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.

Referenced by ast_bridge_call_thread_launch().

00312 {
00313    struct ast_bridge_thread_obj *tobj = data;
00314    int res;
00315 
00316    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00317    tobj->chan->data = tobj->peer->name;
00318    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00319    tobj->peer->data = tobj->chan->name;
00320 
00321    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00322 
00323    if (tobj->return_to_pbx) {
00324       if (!ast_check_hangup(tobj->peer)) {
00325          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00326          res = ast_pbx_start(tobj->peer);
00327          if (res != AST_PBX_SUCCESS)
00328             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00329       } else
00330          ast_hangup(tobj->peer);
00331       if (!ast_check_hangup(tobj->chan)) {
00332          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00333          res = ast_pbx_start(tobj->chan);
00334          if (res != AST_PBX_SUCCESS)
00335             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00336       } else
00337          ast_hangup(tobj->chan);
00338    } else {
00339       ast_hangup(tobj->chan);
00340       ast_hangup(tobj->peer);
00341    }
00342 
00343    ast_free(tobj);
00344 
00345    return NULL;
00346 }

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

create thread for the parked call

Parameters:
data Create thread and attributes, call ast_bridge_call_thread

Definition at line 354 of file features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by action_bridge(), and builtin_atxfer().

00355 {
00356    pthread_t thread;
00357    pthread_attr_t attr;
00358    struct sched_param sched;
00359 
00360    pthread_attr_init(&attr);
00361    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00362    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00363    pthread_attr_destroy(&attr);
00364    memset(&sched, 0, sizeof(sched));
00365    pthread_setschedparam(thread, SCHED_RR, &sched);
00366 }

int ast_feature_detect ( struct ast_channel chan,
struct ast_flags features,
char *  code,
struct ast_call_feature feature 
)

detect a feature before bridging

Parameters:
chan 
ast_flags ptr
char ptr of input code
Return values:
ast_call_feature ptr to be set if found
Returns:
result, was feature found or not

Definition at line 1842 of file features.c.

References chan, feature_group_exten::feature, and feature_interpret_helper().

Referenced by detect_disconnect().

01842                                                                                                                            {
01843 
01844    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01845 }

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

Check the dynamic features.

Parameters:
chan,peer,config,code,sense 
Return values:
res on success.
-1 on failure.

Definition at line 1813 of file features.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, chan, config, feature_group_exten::feature, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

01813                                                                                                                                               {
01814 
01815    char dynamic_features_buf[128];
01816    const char *peer_dynamic_features, *chan_dynamic_features;
01817    struct ast_flags features;
01818    struct ast_call_feature feature;
01819    if (sense == FEATURE_SENSE_CHAN) {
01820       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01821    }
01822    else {
01823       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01824    }
01825 
01826    ast_channel_lock(peer);
01827    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
01828    ast_channel_unlock(peer);
01829 
01830    ast_channel_lock(chan);
01831    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
01832    ast_channel_unlock(chan);
01833 
01834    snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,""));
01835 
01836    ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf);
01837 
01838    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
01839 }

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

Get feature and dial.

Parameters:
caller,transferee,type,format,data,timeout,outstate,cid_num,cid_name,igncallerstate Request channel, set channel variables, initiate call,check if they want to disconnect go into loop, check if timeout has elapsed, check if person to be transfered hung up, check for answer break loop, set cdr return channel.
Todo:
XXX Check - this is very similar to the code in channel.c
Returns:
always a channel

Definition at line 1900 of file features.c.

References ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, 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_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), builtin_features, chan, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, len(), LOG_NOTICE, ast_channel::name, and pbx_builtin_setvar_helper().

Referenced by builtin_atxfer().

01901 {
01902    int state = 0;
01903    int cause = 0;
01904    int to;
01905    struct ast_channel *chan;
01906    struct ast_channel *monitor_chans[2];
01907    struct ast_channel *active_channel;
01908    int res = 0, ready = 0;
01909 
01910    if ((chan = ast_request(type, format, data, &cause))) {
01911       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01912       ast_string_field_set(chan, language, language);
01913       ast_channel_inherit_variables(caller, chan); 
01914       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01915          
01916       if (!ast_call(chan, data, timeout)) {
01917          struct timeval started;
01918          int x, len = 0;
01919          char *disconnect_code = NULL, *dialed_code = NULL;
01920 
01921          ast_indicate(caller, AST_CONTROL_RINGING);
01922          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01923          ast_rwlock_rdlock(&features_lock);
01924          for (x = 0; x < FEATURES_COUNT; x++) {
01925             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01926                continue;
01927 
01928             disconnect_code = builtin_features[x].exten;
01929             len = strlen(disconnect_code) + 1;
01930             dialed_code = alloca(len);
01931             memset(dialed_code, 0, len);
01932             break;
01933          }
01934          ast_rwlock_unlock(&features_lock);
01935          x = 0;
01936          started = ast_tvnow();
01937          to = timeout;
01938 
01939          ast_poll_channel_add(caller, chan);
01940 
01941          while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
01942             struct ast_frame *f = NULL;
01943 
01944             monitor_chans[0] = caller;
01945             monitor_chans[1] = chan;
01946             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01947 
01948             /* see if the timeout has been violated */
01949             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01950                state = AST_CONTROL_UNHOLD;
01951                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01952                break; /*doh! timeout*/
01953             }
01954 
01955             if (!active_channel)
01956                continue;
01957 
01958             if (chan && (chan == active_channel)) {
01959                if (!ast_strlen_zero(chan->call_forward)) {
01960                   if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) {
01961                      return NULL;
01962                   }
01963                   continue;
01964                }
01965                f = ast_read(chan);
01966                if (f == NULL) { /*doh! where'd he go?*/
01967                   state = AST_CONTROL_HANGUP;
01968                   res = 0;
01969                   break;
01970                }
01971                
01972                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01973                   if (f->subclass == AST_CONTROL_RINGING) {
01974                      state = f->subclass;
01975                      ast_verb(3, "%s is ringing\n", chan->name);
01976                      ast_indicate(caller, AST_CONTROL_RINGING);
01977                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01978                      state = f->subclass;
01979                      ast_verb(3, "%s is busy\n", chan->name);
01980                      ast_indicate(caller, AST_CONTROL_BUSY);
01981                      ast_frfree(f);
01982                      f = NULL;
01983                      break;
01984                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01985                      /* This is what we are hoping for */
01986                      state = f->subclass;
01987                      ast_frfree(f);
01988                      f = NULL;
01989                      ready=1;
01990                      break;
01991                   } else if (f->subclass != -1) {
01992                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01993                   }
01994                   /* else who cares */
01995                }
01996 
01997             } else if (caller && (active_channel == caller)) {
01998                f = ast_read(caller);
01999                if (f == NULL) { /*doh! where'd he go?*/
02000                   if (!igncallerstate) {
02001                      if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
02002                         /* make this a blind transfer */
02003                         ready = 1;
02004                         break;
02005                      }
02006                      state = AST_CONTROL_HANGUP;
02007                      res = 0;
02008                      break;
02009                   }
02010                } else {
02011                
02012                   if (f->frametype == AST_FRAME_DTMF) {
02013                      dialed_code[x++] = f->subclass;
02014                      dialed_code[x] = '\0';
02015                      if (strlen(dialed_code) == len) {
02016                         x = 0;
02017                      } else if (x && strncmp(dialed_code, disconnect_code, x)) {
02018                         x = 0;
02019                         dialed_code[x] = '\0';
02020                      }
02021                      if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
02022                         /* Caller Canceled the call */
02023                         state = AST_CONTROL_UNHOLD;
02024                         ast_frfree(f);
02025                         f = NULL;
02026                         break;
02027                      }
02028                   }
02029                }
02030             }
02031             if (f)
02032                ast_frfree(f);
02033          } /* end while */
02034 
02035          ast_poll_channel_del(caller, chan);
02036 
02037       } else
02038          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
02039    } else {
02040       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
02041       switch(cause) {
02042       case AST_CAUSE_BUSY:
02043          state = AST_CONTROL_BUSY;
02044          break;
02045       case AST_CAUSE_CONGESTION:
02046          state = AST_CONTROL_CONGESTION;
02047          break;
02048       }
02049    }
02050    
02051    ast_indicate(caller, -1);
02052    if (chan && ready) {
02053       if (chan->_state == AST_STATE_UP) 
02054          state = AST_CONTROL_ANSWER;
02055       res = 0;
02056    } else if(chan) {
02057       res = -1;
02058       ast_hangup(chan);
02059       chan = NULL;
02060    } else {
02061       res = -1;
02062    }
02063    
02064    if (outstate)
02065       *outstate = state;
02066 
02067    return chan;
02068 }

int ast_features_init ( void   ) 

Provided by features.c

Definition at line 4033 of file features.c.

References action_bridge(), ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application2(), bridge_exec(), cli_features, descrip, descrip2, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, synopsis, and synopsis2.

Referenced by main().

04034 {
04035    int res;
04036 
04037    ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
04038 
04039    memset(parking_ext, 0, sizeof(parking_ext));
04040    memset(parking_con, 0, sizeof(parking_con));
04041 
04042    if ((res = load_config()))
04043       return res;
04044    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
04045    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
04046    res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
04047    if (!res)
04048       res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
04049    if (!res) {
04050       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
04051       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
04052          "Park a channel", mandescr_park); 
04053       ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
04054    }
04055 
04056    res |= ast_devstate_prov_add("Park", metermaidstate);
04057 
04058    return res;
04059 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 3483 of file features.c.

References load_config(), and RESULT_SUCCESS.

03484 {
03485    load_config();
03486 
03487    return RESULT_SUCCESS;
03488 }

struct ast_call_feature* ast_find_call_feature ( const char *  name  ) 

look for a call feature entry by its sname

Parameters:
name a string ptr, should match "automon", "blindxfer", "atxfer", etc.

Definition at line 1597 of file features.c.

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by handle_request_info().

01598 {
01599    int x;
01600    for (x = 0; x < FEATURES_COUNT; x++) {
01601       if (!strcasecmp(name, builtin_features[x].sname))
01602          return &builtin_features[x];
01603    }
01604    return NULL;
01605 }

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.
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.
Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
Return values:
0 on success.
-1 on failure.

Definition at line 665 of file features.c.

References masq_park_call().

Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().

00666 {
00667    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00668 }

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.
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.
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)
Return values:
0 on success.
-1 on failure.

Definition at line 611 of file features.c.

References chan, and park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00612 {
00613    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00614 }

const 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 226 of file features.c.

References parking_ext.

Referenced by builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().

00227 {
00228    return parking_ext;
00229 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Parameters:
chan channel that initiated pickup.
Walk list of channels, checking it is not itself, channel is pbx one, check that the callgroup for both channels are the same and the channel is ringing. Answer calling channel, flag channel as answered on queue, masq channels together.

Definition at line 3851 of file features.c.

References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, chan, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup.

Referenced by cb_events(), handle_request_invite(), mgcp_ss(), pickup_exec(), and ss_thread().

03852 {
03853    struct ast_channel *cur = NULL;
03854    int res = -1;
03855 
03856    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
03857       if (!cur->pbx && 
03858          (cur != chan) &&
03859          (chan->pickupgroup & cur->callgroup) &&
03860          ((cur->_state == AST_STATE_RINGING) ||
03861           (cur->_state == AST_STATE_RING))) {
03862             break;
03863       }
03864       ast_channel_unlock(cur);
03865    }
03866    if (cur) {
03867       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
03868       res = ast_answer(chan);
03869       if (res)
03870          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
03871       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
03872       if (res)
03873          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
03874       res = ast_channel_masquerade(cur, chan);
03875       if (res)
03876          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
03877       ast_channel_unlock(cur);
03878    } else   {
03879       ast_debug(1, "No call pickup possible...\n");
03880    }
03881    return res;
03882 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 231 of file features.c.

References pickup_ext.

Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().

00232 {
00233    return pickup_ext;
00234 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1587 of file features.c.

References ast_rwlock_rdlock(), and features_lock.

Referenced by handle_request_info().

01588 {
01589    ast_rwlock_rdlock(&features_lock);
01590 }

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 1424 of file features.c.

References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, feature_group_exten::feature, LOG_NOTICE, and ast_call_feature::sname.

01425 {
01426    if (!feature) {
01427       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01428       return;
01429    }
01430   
01431    AST_RWLIST_WRLOCK(&feature_list);
01432    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01433    AST_RWLIST_UNLOCK(&feature_list);
01434 
01435    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01436 }

void ast_unlock_call_features ( void   ) 

Definition at line 1592 of file features.c.

References ast_rwlock_unlock(), and features_lock.

Referenced by handle_request_info().

01593 {
01594    ast_rwlock_unlock(&features_lock);
01595 }

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 1512 of file features.c.

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.

01513 {
01514    if (!feature) {
01515       return;
01516    }
01517 
01518    AST_RWLIST_WRLOCK(&feature_list);
01519    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01520    AST_RWLIST_UNLOCK(&feature_list);
01521 
01522    ast_free(feature);
01523 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1526 of file features.c.

References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.

01527 {
01528    struct ast_call_feature *feature;
01529 
01530    AST_RWLIST_WRLOCK(&feature_list);
01531    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01532       ast_free(feature);
01533    }
01534    AST_RWLIST_UNLOCK(&feature_list);
01535 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

Definition at line 1552 of file features.c.

References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, feature_group_exten::entry, and feature_group::features.

01553 {
01554    struct feature_group *fg;
01555    struct feature_group_exten *fge;
01556 
01557    AST_RWLIST_WRLOCK(&feature_groups);
01558    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
01559       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
01560          ast_string_field_free_memory(fge);
01561          ast_free(fge);
01562       }
01563 
01564       ast_string_field_free_memory(fg);
01565       ast_free(fg);
01566    }
01567    AST_RWLIST_UNLOCK(&feature_groups);
01568 }

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

Bridge channels.

Parameters:
chan 
data channel to bridge with.
Split data, check we aren't bridging with ourself, check valid channel, answer call if not already, check compatible channels, setup bridge config now bridge call, if transfered party hangs up return to PBX extension.

Definition at line 3913 of file features.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_channel_alloc, ast_channel_make_compatible(), ast_channel_unlock, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, chan, ast_channel::context, do_bridge_masquerade(), EVENT_FLAG_CALL, ast_channel::exten, ast_channel::language, LOG_WARNING, manager_event, ast_channel::name, pbx_builtin_setvar_helper(), ast_channel::priority, and xfersound.

Referenced by ast_features_init().

03914 {
03915    struct ast_channel *current_dest_chan, *final_dest_chan;
03916    char *tmp_data  = NULL;
03917    struct ast_flags opts = { 0, };
03918    struct ast_bridge_config bconfig = { { 0, }, };
03919 
03920    AST_DECLARE_APP_ARGS(args,
03921       AST_APP_ARG(dest_chan);
03922       AST_APP_ARG(options);
03923    );
03924    
03925    if (ast_strlen_zero(data)) {
03926       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
03927       return -1;
03928    }
03929 
03930    tmp_data = ast_strdupa(data);
03931    AST_STANDARD_APP_ARGS(args, tmp_data);
03932    if (!ast_strlen_zero(args.options))
03933       ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options);
03934 
03935    /* avoid bridge with ourselves */
03936    if (!strncmp(chan->name, args.dest_chan, 
03937       strlen(chan->name) < strlen(args.dest_chan) ? 
03938       strlen(chan->name) : strlen(args.dest_chan))) {
03939       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
03940       manager_event(EVENT_FLAG_CALL, "BridgeExec",
03941                "Response: Failed\r\n"
03942                "Reason: Unable to bridge channel to itself\r\n"
03943                "Channel1: %s\r\n"
03944                "Channel2: %s\r\n",
03945                chan->name, args.dest_chan);
03946       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
03947       return 0;
03948    }
03949 
03950    /* make sure we have a valid end point */
03951    if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 
03952       strlen(args.dest_chan)))) {
03953       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
03954          "cannot get its lock\n", args.dest_chan);
03955       manager_event(EVENT_FLAG_CALL, "BridgeExec",
03956                "Response: Failed\r\n"
03957                "Reason: Cannot grab end point\r\n"
03958                "Channel1: %s\r\n"
03959                "Channel2: %s\r\n", chan->name, args.dest_chan);
03960       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
03961       return 0;
03962    }
03963 
03964    /* answer the channel if needed */
03965    if (current_dest_chan->_state != AST_STATE_UP)
03966       ast_answer(current_dest_chan);
03967 
03968    /* try to allocate a place holder where current_dest_chan will be placed */
03969    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
03970       NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) {
03971       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
03972       manager_event(EVENT_FLAG_CALL, "BridgeExec",
03973                "Response: Failed\r\n"
03974                "Reason: cannot create placeholder\r\n"
03975                "Channel1: %s\r\n"
03976                "Channel2: %s\r\n", chan->name, args.dest_chan);
03977    }
03978    do_bridge_masquerade(current_dest_chan, final_dest_chan);
03979 
03980    ast_channel_unlock(current_dest_chan);
03981 
03982    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
03983    /* try to make compatible, send error if we fail */
03984    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
03985       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
03986       manager_event(EVENT_FLAG_CALL, "BridgeExec",
03987                "Response: Failed\r\n"
03988                "Reason: Could not make channels compatible for bridge\r\n"
03989                "Channel1: %s\r\n"
03990                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
03991       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
03992       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
03993       return 0;
03994    }
03995 
03996    /* Report that the bridge will be successfull */
03997    manager_event(EVENT_FLAG_CALL, "BridgeExec",
03998             "Response: Success\r\n"
03999             "Channel1: %s\r\n"
04000             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04001 
04002    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
04003    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
04004       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
04005          if (ast_waitstream(final_dest_chan, "") < 0)
04006             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
04007       }
04008    }
04009    
04010    /* do the bridge */
04011    ast_bridge_call(chan, final_dest_chan, &bconfig);
04012 
04013    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
04014    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
04015    if (!ast_check_hangup(final_dest_chan)) {
04016       ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 
04017          final_dest_chan->context, final_dest_chan->exten, 
04018          final_dest_chan->priority, final_dest_chan->name);
04019 
04020       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
04021          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
04022          ast_hangup(final_dest_chan);
04023       } else
04024          ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
04025    } else {
04026       ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name);
04027       ast_hangup(final_dest_chan);
04028    }
04029 
04030    return 0;
04031 }

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

Attended transfer.

Parameters:
chan transfered user
peer person transfering call
config 
code 
sense feature options
data Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel.
Returns:
-1 on failure

Definition at line 1124 of file 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_calloc, ast_channel_alloc, ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, 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_parking_ext(), ast_read(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), builtin_parkcall(), chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), strsep(), ast_channel::visible_indication, and ast_channel::writeformat.

01125 {
01126    struct ast_channel *transferer;
01127    struct ast_channel *transferee;
01128    const char *transferer_real_context;
01129    char xferto[256] = "";
01130    int res;
01131    int outstate=0;
01132    struct ast_channel *newchan;
01133    struct ast_channel *xferchan;
01134    struct ast_bridge_thread_obj *tobj;
01135    struct ast_bridge_config bconfig;
01136    struct ast_frame *f;
01137    int l;
01138    struct ast_datastore *features_datastore;
01139    struct ast_dial_features *dialfeatures = NULL;
01140 
01141    ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
01142    set_peers(&transferer, &transferee, peer, chan, sense);
01143    transferer_real_context = real_ctx(transferer, transferee);
01144    /* Start autoservice on chan while we talk to the originator */
01145    ast_autoservice_start(transferee);
01146    ast_indicate(transferee, AST_CONTROL_HOLD);
01147    
01148    /* Transfer */
01149    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01150    if (res < 0) {
01151       finishup(transferee);
01152       return res;
01153    }
01154    if (res > 0) /* If they've typed a digit already, handle it */
01155       xferto[0] = (char) res;
01156 
01157    /* this is specific of atxfer */
01158    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01159    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
01160       finishup(transferee);
01161       return res;
01162    }
01163    if (res == 0) {
01164       ast_log(LOG_WARNING, "Did not read data.\n");
01165       finishup(transferee);
01166       if (ast_stream_and_wait(transferer, "beeperr", ""))
01167          return -1;
01168       return FEATURE_RETURN_SUCCESS;
01169    }
01170 
01171    /* valid extension, res == 1 */
01172    if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01173       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
01174       finishup(transferee);
01175       if (ast_stream_and_wait(transferer, "beeperr", ""))
01176          return -1;
01177       return FEATURE_RETURN_SUCCESS;
01178    }
01179 
01180    /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of
01181     * the different variables for handling this properly with a builtin_atxfer */
01182    if (!strcmp(xferto, ast_parking_ext())) {
01183       finishup(transferee);
01184       return builtin_parkcall(chan, peer, config, code, sense, data);
01185    }
01186 
01187    l = strlen(xferto);
01188    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);   /* append context */
01189    newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01190       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01191 
01192    if (!ast_check_hangup(transferer)) {
01193       /* Transferer is up - old behaviour */
01194       ast_indicate(transferer, -1);
01195       if (!newchan) {
01196          finishup(transferee);
01197          /* any reason besides user requested cancel and busy triggers the failed sound */
01198          if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
01199             ast_stream_and_wait(transferer, xferfailsound, ""))
01200             return -1;
01201          if (ast_stream_and_wait(transferer, xfersound, ""))
01202             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01203          return FEATURE_RETURN_SUCCESS;
01204       }
01205 
01206       if (check_compat(transferer, newchan)) {
01207          /* we do mean transferee here, NOT transferer */
01208          finishup(transferee);
01209          return -1;
01210       }
01211       memset(&bconfig,0,sizeof(struct ast_bridge_config));
01212       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
01213       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
01214       res = ast_bridge_call(transferer, newchan, &bconfig);
01215       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
01216          ast_hangup(newchan);
01217          if (ast_stream_and_wait(transferer, xfersound, ""))
01218             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01219          finishup(transferee);
01220          transferer->_softhangup = 0;
01221          return FEATURE_RETURN_SUCCESS;
01222       }
01223       if (check_compat(transferee, newchan)) {
01224          finishup(transferee);
01225          return -1;
01226       }
01227       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01228 
01229       if ((ast_autoservice_stop(transferee) < 0)
01230        || (ast_waitfordigit(transferee, 100) < 0)
01231        || (ast_waitfordigit(newchan, 100) < 0)
01232        || ast_check_hangup(transferee)
01233        || ast_check_hangup(newchan)) {
01234          ast_hangup(newchan);
01235          return -1;
01236       }
01237       xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01238       if (!xferchan) {
01239          ast_hangup(newchan);
01240          return -1;
01241       }
01242       /* Make formats okay */
01243       xferchan->visible_indication = transferer->visible_indication;
01244       xferchan->readformat = transferee->readformat;
01245       xferchan->writeformat = transferee->writeformat;
01246       ast_channel_masquerade(xferchan, transferee);
01247       ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01248       xferchan->_state = AST_STATE_UP;
01249       ast_clear_flag(xferchan, AST_FLAGS_ALL);
01250       xferchan->_softhangup = 0;
01251       if ((f = ast_read(xferchan)))
01252          ast_frfree(f);
01253       newchan->_state = AST_STATE_UP;
01254       ast_clear_flag(newchan, AST_FLAGS_ALL);
01255       newchan->_softhangup = 0;
01256       if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01257          ast_hangup(xferchan);
01258          ast_hangup(newchan);
01259          return -1;
01260       }
01261 
01262       ast_channel_lock(newchan);
01263       if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
01264             dialfeatures = features_datastore->data;
01265       }
01266       ast_channel_unlock(newchan);
01267 
01268       if (dialfeatures) {
01269          /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
01270             I don't currently understand, the abilities of newchan seem to be stored on the caller side */
01271          ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01272          dialfeatures = NULL;
01273       }
01274 
01275       ast_channel_lock(xferchan);
01276       if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
01277          dialfeatures = features_datastore->data;
01278       }
01279       ast_channel_unlock(xferchan);
01280     
01281       if (dialfeatures) {
01282          ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01283       }
01284     
01285       tobj->chan = newchan;
01286       tobj->peer = xferchan;
01287       tobj->bconfig = *config;
01288 
01289       if (tobj->bconfig.end_bridge_callback_data_fixup) {
01290          tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01291       }
01292 
01293       if (ast_stream_and_wait(newchan, xfersound, ""))
01294          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01295       ast_bridge_call_thread_launch(tobj);
01296       return -1;      /* XXX meaning the channel is bridged ? */
01297    } else if (!ast_check_hangup(transferee)) {
01298       /* act as blind transfer */
01299       if (ast_autoservice_stop(transferee) < 0) {
01300          ast_hangup(newchan);
01301          return -1;
01302       }
01303 
01304       if (!newchan) {
01305          unsigned int tries = 0;
01306          char *transferer_tech, *transferer_name = ast_strdupa(transferer->name);
01307 
01308          transferer_tech = strsep(&transferer_name, "/");
01309          transferer_name = strsep(&transferer_name, "-");
01310 
01311          if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
01312             ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name);
01313             if (ast_stream_and_wait(transferee, "beeperr", ""))
01314                return -1;
01315             return FEATURE_RETURN_SUCCESS;
01316          }
01317 
01318          ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name);
01319          newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01320             transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01321          while (!newchan && !atxferdropcall && tries < atxfercallbackretries) {
01322             /* Trying to transfer again */
01323             ast_autoservice_start(transferee);
01324             ast_indicate(transferee, AST_CONTROL_HOLD);
01325 
01326             newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01327                xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01328             if (ast_autoservice_stop(transferee) < 0) {
01329                if (newchan)
01330                   ast_hangup(newchan);
01331                return -1;
01332             }
01333             if (!newchan) {
01334                /* Transfer failed, sleeping */
01335                ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay);
01336                ast_safe_sleep(transferee, atxferloopdelay);
01337                ast_debug(1, "Trying to callback...\n");
01338                newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01339                   transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01340             }
01341             tries++;
01342          }
01343       }
01344       if (!newchan)
01345          return -1;
01346 
01347       /* newchan is up, we should prepare transferee and bridge them */
01348       if (check_compat(transferee, newchan)) {
01349          finishup(transferee);
01350          return -1;
01351       }
01352       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01353 
01354       if ((ast_waitfordigit(transferee, 100) < 0)
01355          || (ast_waitfordigit(newchan, 100) < 0)
01356          || ast_check_hangup(transferee)
01357          || ast_check_hangup(newchan)) {
01358          ast_hangup(newchan);
01359          return -1;
01360       }
01361 
01362       xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01363       if (!xferchan) {
01364          ast_hangup(newchan);
01365          return -1;
01366       }
01367       /* Make formats okay */
01368       xferchan->visible_indication = transferer->visible_indication;
01369       xferchan->readformat = transferee->readformat;
01370       xferchan->writeformat = transferee->writeformat;
01371       ast_channel_masquerade(xferchan, transferee);
01372       ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01373       xferchan->_state = AST_STATE_UP;
01374       ast_clear_flag(xferchan, AST_FLAGS_ALL);
01375       xferchan->_softhangup = 0;
01376       if ((f = ast_read(xferchan)))
01377          ast_frfree(f);
01378       newchan->_state = AST_STATE_UP;
01379       ast_clear_flag(newchan, AST_FLAGS_ALL);
01380       newchan->_softhangup = 0;
01381       if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01382          ast_hangup(xferchan);
01383          ast_hangup(newchan);
01384          return -1;
01385       }
01386       tobj->chan = newchan;
01387       tobj->peer = xferchan;
01388       tobj->bconfig = *config;
01389 
01390       if (tobj->bconfig.end_bridge_callback_data_fixup) {
01391          tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01392       }
01393 
01394       if (ast_stream_and_wait(newchan, xfersound, ""))
01395          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01396       ast_bridge_call_thread_launch(tobj);
01397       return -1;      /* XXX meaning the channel is bridged ? */
01398    } else {
01399       /* Transferee hung up */
01400       finishup(transferee);
01401       return -1;
01402    }
01403 }

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

Definition at line 832 of file features.c.

References AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_unlock, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mixmonitor_app, mixmonitor_spy_type, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and stopmixmonitor_app.

00833 {
00834    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00835    int x = 0;
00836    size_t len;
00837    struct ast_channel *caller_chan, *callee_chan;
00838    const char *mixmonitor_spy_type = "MixMonitor";
00839    int count = 0;
00840 
00841    if (!mixmonitor_ok) {
00842       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
00843       return -1;
00844    }
00845 
00846    if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
00847       mixmonitor_ok = 0;
00848       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
00849       return -1;
00850    }
00851 
00852    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00853 
00854    if (!ast_strlen_zero(courtesytone)) {
00855       if (ast_autoservice_start(callee_chan))
00856          return -1;
00857       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
00858          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00859          ast_autoservice_stop(callee_chan);
00860          return -1;
00861       }
00862       if (ast_autoservice_stop(callee_chan))
00863          return -1;
00864    }
00865 
00866    ast_channel_lock(callee_chan);
00867    count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
00868    ast_channel_unlock(callee_chan);
00869 
00870    // This means a mixmonitor is attached to the channel, running or not is unknown.
00871    if (count > 0) {
00872       
00873       ast_verb(3, "User hit '%s' to stop recording call.\n", code);
00874 
00875       //Make sure they are running
00876       ast_channel_lock(callee_chan);
00877       count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
00878       ast_channel_unlock(callee_chan);
00879       if (count > 0) {
00880          if (!stopmixmonitor_ok) {
00881             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
00882             return -1;
00883          }
00884          if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
00885             stopmixmonitor_ok = 0;
00886             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
00887             return -1;
00888          } else {
00889             pbx_exec(callee_chan, stopmixmonitor_app, "");
00890             return FEATURE_RETURN_SUCCESS;
00891          }
00892       }
00893       
00894       ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 
00895    }        
00896 
00897    if (caller_chan && callee_chan) {
00898       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
00899       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
00900 
00901       if (!touch_format)
00902          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
00903 
00904       if (!touch_monitor)
00905          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
00906 
00907       if (touch_monitor) {
00908          len = strlen(touch_monitor) + 50;
00909          args = alloca(len);
00910          touch_filename = alloca(len);
00911          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00912          snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
00913       } else {
00914          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00915          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00916          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00917          args = alloca(len);
00918          touch_filename = alloca(len);
00919          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00920          snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
00921       }
00922 
00923       for( x = 0; x < strlen(args); x++) {
00924          if (args[x] == '/')
00925             args[x] = '-';
00926       }
00927 
00928       ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
00929 
00930       pbx_exec(callee_chan, mixmonitor_app, args);
00931       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
00932       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
00933       return FEATURE_RETURN_SUCCESS;
00934    
00935    }
00936 
00937    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
00938    return -1;
00939 
00940 }

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

Monitor a channel by DTMF.

Parameters:
chan channel requesting monitor
peer channel to be monitored
config 
code 
sense feature options
data Check monitor app enabled, setup channels, both caller/callee chans not null get TOUCH_MONITOR variable for filename if exists, exec monitor app.
Return values:
FEATURE_RETURN_SUCCESS on success.
-1 on error.

Definition at line 746 of file features.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::monitor, monitor_app, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and ast_channel_monitor::stop.

00747 {
00748    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00749    int x = 0;
00750    size_t len;
00751    struct ast_channel *caller_chan, *callee_chan;
00752 
00753    if (!monitor_ok) {
00754       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00755       return -1;
00756    }
00757 
00758    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00759       monitor_ok = 0;
00760       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00761       return -1;
00762    }
00763 
00764    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00765 
00766    if (!ast_strlen_zero(courtesytone)) {
00767       if (ast_autoservice_start(callee_chan))
00768          return -1;
00769       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
00770          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00771          ast_autoservice_stop(callee_chan);
00772          return -1;
00773       }
00774       if (ast_autoservice_stop(callee_chan))
00775          return -1;
00776    }
00777    
00778    if (callee_chan->monitor) {
00779       ast_verb(4, "User hit '%s' to stop recording call.\n", code);
00780       callee_chan->monitor->stop(callee_chan, 1);
00781       return FEATURE_RETURN_SUCCESS;
00782    }
00783 
00784    if (caller_chan && callee_chan) {
00785       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00786       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00787       const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
00788 
00789       if (!touch_format)
00790          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00791 
00792       if (!touch_monitor)
00793          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00794    
00795       if (!touch_monitor_prefix)
00796          touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
00797    
00798       if (touch_monitor) {
00799          len = strlen(touch_monitor) + 50;
00800          args = alloca(len);
00801          touch_filename = alloca(len);
00802          snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
00803          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
00804       } else {
00805          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00806          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00807          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00808          args = alloca(len);
00809          touch_filename = alloca(len);
00810          snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
00811          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
00812       }
00813 
00814       for(x = 0; x < strlen(args); x++) {
00815          if (args[x] == '/')
00816             args[x] = '-';
00817       }
00818       
00819       ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
00820 
00821       pbx_exec(callee_chan, monitor_app, args);
00822       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00823       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00824    
00825       return FEATURE_RETURN_SUCCESS;
00826    }
00827    
00828    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00829    return -1;
00830 }

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

Blind transfer user to another extension.

Parameters:
chan channel to be transfered
peer channel initiated blind transfer
config 
code 
data 
sense feature options
Place chan on hold, check if transferred to parkinglot extension, otherwise check extension exists and transfer caller.
Return values:
FEATURE_RETURN_SUCCESS. 
-1 on failure.

Todo:
XXX Maybe we should have another message here instead of invalid extension XXX

Definition at line 992 of file features.c.

References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), AST_FLAG_BRIDGE_HANGUP_DONT, ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, ast_stopstream(), ast_stream_and_wait(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_cdr::dstchannel, FEATURE_RETURN_PARKFAILED, FEATURE_RETURN_SUCCESS, finishup(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, masq_park_call_announce(), ast_channel::name, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), and set_peers().

00993 {
00994    struct ast_channel *transferer;
00995    struct ast_channel *transferee;
00996    const char *transferer_real_context;
00997    char xferto[256];
00998    int res;
00999    int parkstatus = 0;
01000 
01001    set_peers(&transferer, &transferee, peer, chan, sense);
01002    transferer_real_context = real_ctx(transferer, transferee);
01003    /* Start autoservice on chan while we talk to the originator */
01004    ast_autoservice_start(transferee);
01005    ast_indicate(transferee, AST_CONTROL_HOLD);
01006 
01007    memset(xferto, 0, sizeof(xferto));
01008 
01009    /* Transfer */
01010    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01011    if (res < 0) {
01012       finishup(transferee);
01013       return -1; /* error ? */
01014    }
01015    if (res > 0)   /* If they've typed a digit already, handle it */
01016       xferto[0] = (char) res;
01017 
01018    ast_stopstream(transferer);
01019    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01020    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
01021       finishup(transferee);
01022       return res;
01023    }
01024    if (!strcmp(xferto, ast_parking_ext())) {
01025       res = finishup(transferee);
01026       if (res)
01027          res = -1;
01028       else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, NULL))) {   /* success */
01029          /* We return non-zero, but tell the PBX not to hang the channel when
01030             the thread dies -- We have to be careful now though.  We are responsible for 
01031             hanging up the channel, else it will never be hung up! */
01032 
01033          return 0;
01034       } else {
01035          ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01036       }
01037       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
01038    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01039       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01040       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01041       res=finishup(transferee);
01042       if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
01043          transferer->cdr=ast_cdr_alloc();
01044          if (transferer->cdr) {
01045             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
01046             ast_cdr_start(transferer->cdr);
01047          }
01048       }
01049       if (transferer->cdr) {
01050          struct ast_cdr *swap = transferer->cdr;
01051          ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01052                transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 
01053                transferer->cdr->channel, transferer->cdr->dstchannel);
01054          ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01055                transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01056          ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01057          /* swap cdrs-- it will save us some time & work */
01058          transferer->cdr = transferee->cdr;
01059          transferee->cdr = swap;
01060       }
01061       if (!transferee->pbx) {
01062          /* Doh!  Use our handy async_goto functions */
01063          ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01064                         ,transferee->name, xferto, transferer_real_context);
01065          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01066             ast_log(LOG_WARNING, "Async goto failed :-(\n");
01067       } else {
01068          /* Set the channel's new extension, since it exists, using transferer context */
01069          ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
01070          ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01071          set_c_e_p(transferee, transferer_real_context, xferto, 0);
01072       }
01073       check_goto_on_transfer(transferer);
01074       return res;
01075    } else {
01076       ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
01077    }
01078    if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
01079       finishup(transferee);
01080       return -1;
01081    }
01082    ast_stopstream(transferer);
01083    res = finishup(transferee);
01084    if (res) {
01085       ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01086       return res;
01087    }
01088    return FEATURE_RETURN_SUCCESS;
01089 }

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

Definition at line 942 of file features.c.

References ast_verb, and FEATURE_RETURN_HANGUP.

00943 {
00944    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
00945    return FEATURE_RETURN_HANGUP;
00946 }

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

support routing for one touch call parking

Parameters:
chan channel parking call
peer channel to be parked
config unsed
code unused
sense feature options
data Setup channel, set return exten,priority to 's,1' answer chan, sleep chan, park call

Definition at line 705 of file features.c.

References ast_channel::_state, ast_answer(), ast_safe_sleep(), AST_STATE_UP, chan, masq_park_call_announce(), and set_peers().

Referenced by builtin_atxfer().

00706 {
00707    struct ast_channel *parker;
00708    struct ast_channel *parkee;
00709    int res = 0;
00710 
00711    set_peers(&parker, &parkee, peer, chan, sense);
00712    /* we used to set chan's exten and priority to "s" and 1
00713       here, but this generates (in some cases) an invalid
00714       extension, and if "s" exists, could errantly
00715       cause execution of extensions you don't expect. It
00716       makes more sense to let nature take its course
00717       when chan finishes, and let the pbx do its thing
00718       and hang up when the park is over.
00719    */
00720    if (chan->_state != AST_STATE_UP)
00721       res = ast_answer(chan);
00722    if (!res)
00723       res = ast_safe_sleep(chan, 1000);
00724 
00725    if (!res) { /* one direction used to call park_call.... */
00726       res = masq_park_call_announce(parkee, parker, 0, NULL, NULL);
00727       /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
00728    }
00729    return res;
00730 }

static char* callback_dialoptions ( struct ast_flags features_callee,
struct ast_flags features_caller,
char *  options,
size_t  len 
) [static]

Definition at line 2676 of file features.c.

References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, and ast_test_flag.

Referenced by do_parking_thread().

02677 {
02678    int i = 0;
02679    enum {
02680       OPT_CALLEE_REDIRECT   = 't',
02681       OPT_CALLER_REDIRECT   = 'T',
02682       OPT_CALLEE_AUTOMON    = 'w',
02683       OPT_CALLER_AUTOMON    = 'W',
02684       OPT_CALLEE_DISCONNECT = 'h',
02685       OPT_CALLER_DISCONNECT = 'H',
02686       OPT_CALLEE_PARKCALL   = 'k',
02687       OPT_CALLER_PARKCALL   = 'K',
02688    };
02689 
02690    memset(options, 0, len);
02691    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02692       options[i++] = OPT_CALLER_REDIRECT;
02693    }
02694    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02695       options[i++] = OPT_CALLER_AUTOMON;
02696    }
02697    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02698       options[i++] = OPT_CALLER_DISCONNECT;
02699    }
02700    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02701       options[i++] = OPT_CALLER_PARKCALL;
02702    }
02703 
02704    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02705       options[i++] = OPT_CALLEE_REDIRECT;
02706    }
02707    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02708       options[i++] = OPT_CALLEE_AUTOMON;
02709    }
02710    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02711       options[i++] = OPT_CALLEE_DISCONNECT;
02712    }
02713    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02714       options[i++] = OPT_CALLEE_PARKCALL;
02715    }
02716 
02717    return options;
02718 }

static int check_compat ( struct ast_channel c,
struct ast_channel newchan 
) [static]

make channels compatible

Parameters:
c 
newchan 
Return values:
0 on success.
-1 on failure.

Definition at line 1098 of file features.c.

References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.

Referenced by builtin_atxfer().

01099 {
01100    if (ast_channel_make_compatible(c, newchan) < 0) {
01101       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01102          c->name, newchan->name);
01103       ast_hangup(newchan);
01104       return -1;
01105    }
01106    return 0;
01107 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Check goto on transfer.

Parameters:
chan Check if channel has 'GOTO_ON_BLINDXFR' set, if not exit. When found make sure the types are compatible. Check if channel is valid if so start the new channel else hangup the call.

Definition at line 265 of file 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_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), chan, f, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.

Referenced by builtin_blindtransfer().

00266 {
00267    struct ast_channel *xferchan;
00268    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00269    char *x, *goto_on_transfer;
00270    struct ast_frame *f;
00271 
00272    if (ast_strlen_zero(val))
00273       return;
00274 
00275    goto_on_transfer = ast_strdupa(val);
00276 
00277    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name)))
00278       return;
00279 
00280    for (x = goto_on_transfer; x && *x; x++) {
00281       if (*x == '^')
00282          *x = '|';
00283    }
00284    /* Make formats okay */
00285    xferchan->readformat = chan->readformat;
00286    xferchan->writeformat = chan->writeformat;
00287    ast_channel_masquerade(xferchan, chan);
00288    ast_parseable_goto(xferchan, goto_on_transfer);
00289    xferchan->_state = AST_STATE_UP;
00290    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00291    xferchan->_softhangup = 0;
00292    if ((f = ast_read(xferchan))) {
00293       ast_frfree(f);
00294       f = NULL;
00295       ast_pbx_start(xferchan);
00296    } else {
00297       ast_hangup(xferchan);
00298    }
00299 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 210 of file features.c.

References ast_free.

00211  {
00212    struct ast_dial_features *df = data;
00213    if (df) {
00214       ast_free(df);
00215    }
00216  }

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

Definition at line 197 of file features.c.

References ast_calloc.

00198 {
00199    struct ast_dial_features *df = data, *df_copy;
00200  
00201    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00202       return NULL;
00203    }
00204  
00205    memcpy(df_copy, df, sizeof(*df));
00206  
00207    return df_copy;
00208  }

static void do_bridge_masquerade ( struct ast_channel chan,
struct ast_channel tmpchan 
) [static]

Actual bridge.

Parameters:
chan 
tmpchan Stop hold music, lock both channels, masq channels, after bridge return channel to next priority.

Definition at line 3523 of file features.c.

References ast_channel::_state, ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_explicit_goto(), ast_moh_stop(), ast_setstate(), chan, ast_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

Referenced by action_bridge(), and bridge_exec().

03524 {
03525    ast_moh_stop(chan);
03526    ast_channel_lock(chan);
03527    ast_setstate(tmpchan, chan->_state);
03528    tmpchan->readformat = chan->readformat;
03529    tmpchan->writeformat = chan->writeformat;
03530    ast_channel_masquerade(tmpchan, chan);
03531    ast_channel_lock(tmpchan);
03532    ast_do_masquerade(tmpchan);
03533    /* when returning from bridge, the channel will continue at the next priority */
03534    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
03535    ast_channel_unlock(tmpchan);
03536    ast_channel_unlock(chan);
03537 }

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

Take care of parked calls and unpark them if needed.

Parameters:
ignore unused var.
Start inf loop, lock parking lot, check if any parked channels have gone above timeout if so, remove channel from parking lot and return it to the extension that parked it. Check if parked channel decided to hangup, wait until next FD via select().

Todo:
XXX Maybe we could do something with packets, like dial "0" for operator or something XXX

Todo:
XXX Ick: jumping into an else statement??? XXX

Definition at line 2728 of file features.c.

References ast_add_extension2(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), AST_MAX_FDS, ast_pbx_start(), ast_read(), ast_samp2tv(), ast_select(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, buf, callback_dialoptions(), chan, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, f, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, ast_channel::name, notify_metermaids(), parking_con, parking_con_dial, parkmohclass, pbx_builtin_setvar_helper(), post_manager_event(), ast_channel::priority, registrar, S_OR, and set_c_e_p().

Referenced by ast_features_init().

02729 {
02730    char parkingslot[AST_MAX_EXTENSION];
02731    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
02732 
02733    FD_ZERO(&rfds);
02734    FD_ZERO(&efds);
02735 
02736    for (;;) {
02737       struct parkeduser *pu;
02738       int ms = -1;   /* select timeout, uninitialized */
02739       int max = -1;  /* max fd, none there yet */
02740       fd_set nrfds, nefds; /* args for the next select */
02741       FD_ZERO(&nrfds);
02742       FD_ZERO(&nefds);
02743 
02744       AST_LIST_LOCK(&parkinglot);
02745       AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) {
02746          struct ast_channel *chan = pu->chan;   /* shorthand */
02747          int tms;        /* timeout for this item */
02748          int x;          /* fd index in channel */
02749          struct ast_context *con;
02750 
02751          if (pu->notquiteyet) /* Pretend this one isn't here yet */
02752             continue;
02753          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
02754          if (tms > pu->parkingtime) {
02755             ast_indicate(chan, AST_CONTROL_UNHOLD);
02756             /* Get chan, exten from derived kludge */
02757             if (pu->peername[0]) {
02758                char *peername = ast_strdupa(pu->peername);
02759                char *cp = strrchr(peername, '-');
02760                char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */
02761                int i;
02762 
02763                if (cp) 
02764                   *cp = 0;
02765                ast_copy_string(peername_flat,peername,sizeof(peername_flat));
02766                for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
02767                   if (peername_flat[i] == '/') 
02768                      peername_flat[i]= '0';
02769                }
02770                con = ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar);
02771                if (!con)
02772                   ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
02773                if (con) {
02774                   char returnexten[AST_MAX_EXTENSION];
02775                   struct ast_datastore *features_datastore;
02776                   struct ast_dial_features *dialfeatures = NULL;
02777 
02778                   ast_channel_lock(chan);
02779 
02780                   if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
02781                      dialfeatures = features_datastore->data;
02782 
02783                   ast_channel_unlock(chan);
02784 
02785                   if (!strncmp(peername, "Parked/", 7)) {
02786                      peername += 7;
02787                   }
02788 
02789                   if (dialfeatures) {
02790                      char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
02791                      snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
02792                   } else { /* Existing default */
02793                      snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
02794                   }
02795                   ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
02796                }
02797                if (comebacktoorigin) {
02798                   set_c_e_p(chan, parking_con_dial, peername_flat, 1);
02799                } else {
02800                   ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
02801                   snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
02802                   pbx_builtin_setvar_helper(pu->chan, "PARKINGSLOT", parkingslot);
02803                   set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
02804                }
02805             } else {
02806                /* They've been waiting too long, send them back to where they came.  Theoretically they
02807                   should have their original extensions and such, but we copy to be on the safe side */
02808                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
02809             }
02810 
02811             post_manager_event("ParkedCallTimeOut", pu);
02812 
02813             ast_verb(2, "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority);
02814             /* Start up the PBX, or hang them up */
02815             if (ast_pbx_start(chan))  {
02816                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
02817                ast_hangup(chan);
02818             }
02819             /* And take them out of the parking lot */
02820             AST_LIST_REMOVE_CURRENT(list);
02821             con = ast_context_find(parking_con);
02822             if (con) {
02823                if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
02824                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02825                else
02826                   notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
02827             } else
02828                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02829             ast_free(pu);
02830          } else { /* still within parking time, process descriptors */
02831             for (x = 0; x < AST_MAX_FDS; x++) {
02832                struct ast_frame *f;
02833 
02834                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
02835                   continue;   /* nothing on this descriptor */
02836 
02837                if (FD_ISSET(chan->fds[x], &efds))
02838                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
02839                else
02840                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
02841                chan->fdno = x;
02842 
02843                /* See if they need servicing */
02844                f = ast_read(chan);
02845                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
02846                   if (f)
02847                      ast_frfree(f);
02848                   post_manager_event("ParkedCallGiveUp", pu);
02849 
02850                   /* There's a problem, hang them up*/
02851                   ast_verb(2, "%s got tired of being parked\n", chan->name);
02852                   ast_hangup(chan);
02853                   /* And take them out of the parking lot */
02854                   AST_LIST_REMOVE_CURRENT(list);
02855                   con = ast_context_find(parking_con);
02856                   if (con) {
02857                      if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
02858                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02859                      else
02860                         notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
02861                   } else
02862                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02863                   ast_free(pu);
02864                   break;
02865                } else {
02866                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02867                   ast_frfree(f);
02868                   if (pu->moh_trys < 3 && !chan->generatordata) {
02869                      ast_debug(1, "MOH on parked call stopped by outside source.  Restarting.\n");
02870                      ast_indicate_data(chan, AST_CONTROL_HOLD, 
02871                         S_OR(parkmohclass, NULL),
02872                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
02873                      pu->moh_trys++;
02874                   }
02875                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
02876                }
02877 
02878             } /* end for */
02879             if (x >= AST_MAX_FDS) {
02880 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
02881                   if (chan->fds[x] > -1) {
02882                      FD_SET(chan->fds[x], &nrfds);
02883                      FD_SET(chan->fds[x], &nefds);
02884                      if (chan->fds[x] > max)
02885                         max = chan->fds[x];
02886                   }
02887                }
02888                /* Keep track of our shortest wait */
02889                if (tms < ms || ms < 0)
02890                   ms = tms;
02891             }
02892          }
02893       } /* end while */
02894       AST_LIST_TRAVERSE_SAFE_END
02895       AST_LIST_UNLOCK(&parkinglot);
02896       rfds = nrfds;
02897       efds = nefds;
02898       {
02899          struct timeval tv = ast_samp2tv(ms, 1000);
02900          /* Wait for something to happen */
02901          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02902       }
02903       pthread_testcancel();
02904    }
02905    return NULL;   /* Never reached */
02906 }

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

exec an app by feature

Parameters:
chan,peer,config,code,sense,data Find a feature, determine which channel activated
Return values:
-1 error.
-2 when an application cannot be found.

Todo:
XXX should probably return res

Definition at line 1615 of file features.c.

References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, chan, feature_group_exten::feature, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().

01616 {
01617    struct ast_app *app;
01618    struct ast_call_feature *feature = data;
01619    struct ast_channel *work, *idle;
01620    int res;
01621 
01622    if (!feature) { /* shouldn't ever happen! */
01623       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01624       return -1; 
01625    }
01626 
01627    if (sense == FEATURE_SENSE_CHAN) {
01628       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01629          return FEATURE_RETURN_KEEPTRYING;
01630       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01631          work = chan;
01632          idle = peer;
01633       } else {
01634          work = peer;
01635          idle = chan;
01636       }
01637    } else {
01638       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01639          return FEATURE_RETURN_KEEPTRYING;
01640       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01641          work = peer;
01642          idle = chan;
01643       } else {
01644          work = chan;
01645          idle = peer;
01646       }
01647    }
01648 
01649    if (!(app = pbx_findapp(feature->app))) {
01650       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01651       return -2;
01652    }
01653 
01654    ast_autoservice_start(idle);
01655    
01656    if (!ast_strlen_zero(feature->moh_class))
01657       ast_moh_start(idle, feature->moh_class, NULL);
01658 
01659    res = pbx_exec(work, app, feature->app_args);
01660 
01661    if (!ast_strlen_zero(feature->moh_class))
01662       ast_moh_stop(idle);
01663 
01664    ast_autoservice_stop(idle);
01665 
01666    if (res) {
01667       return FEATURE_RETURN_SUCCESSBREAK;
01668    }
01669    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01670 }

static int feature_interpret_helper ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense,
char *  dynamic_features_buf,
struct ast_flags features,
int  operation,
struct ast_call_feature feature 
) [static]

Helper function for feature_interpret and ast_feature_detect.

Parameters:
chan,peer,config,code,sense,dynamic_features char buf,feature flags,operation,feature
Lock features list, browse for code, unlock list If a feature is found and the operation variable is set, that feature's operation is executed. The first feature found is copied to the feature parameter.
Return values:
res on success.
-1 on failure.

Definition at line 1710 of file features.c.

References ast_debug, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_STOREDIGITS, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strlen_zero(), ast_test_flag, ast_verb, builtin_features, chan, config, feature_group_exten::entry, ast_call_feature::exten, feature_group_exten::exten, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), find_group(), ast_call_feature::fname, ast_call_feature::operation, ast_call_feature::sname, and strsep().

Referenced by ast_feature_detect(), and ast_feature_interpret().

01713 {
01714    int x;
01715    struct feature_group *fg = NULL;
01716    struct feature_group_exten *fge;
01717    struct ast_call_feature *tmpfeature;
01718    char *tmp, *tok;
01719    int res = AST_FEATURE_RETURN_PASSDIGITS;
01720    int feature_detected = 0;
01721 
01722    if (!(peer && chan && config) && operation) {
01723       return -1; /* can not run feature operation */
01724    }
01725 
01726    ast_rwlock_rdlock(&features_lock);
01727    for (x = 0; x < FEATURES_COUNT; x++) {
01728       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
01729           !ast_strlen_zero(builtin_features[x].exten)) {
01730          /* Feature is up for consideration */
01731          if (!strcmp(builtin_features[x].exten, code)) {
01732             ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
01733             if (operation) {
01734                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01735             }
01736             memcpy(feature, &builtin_features[x], sizeof(feature));
01737             feature_detected = 1;
01738             break;
01739          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01740             if (res == AST_FEATURE_RETURN_PASSDIGITS)
01741                res = AST_FEATURE_RETURN_STOREDIGITS;
01742          }
01743       }
01744    }
01745    ast_rwlock_unlock(&features_lock);
01746 
01747    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
01748       return res;
01749    }
01750 
01751    tmp = dynamic_features_buf;
01752 
01753    while ((tok = strsep(&tmp, "#"))) {
01754       AST_RWLIST_RDLOCK(&feature_groups);
01755 
01756       fg = find_group(tok);
01757 
01758       if (fg) {
01759          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
01760             if (strcasecmp(fge->exten, code))
01761                continue;
01762             if (operation) {
01763                res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
01764             }
01765             memcpy(feature, fge->feature, sizeof(feature));
01766             if (res != AST_FEATURE_RETURN_KEEPTRYING) {
01767                AST_RWLIST_UNLOCK(&feature_groups);
01768                break;
01769             }
01770             res = AST_FEATURE_RETURN_PASSDIGITS;
01771          }
01772          if (fge)
01773             break;
01774       }
01775 
01776       AST_RWLIST_UNLOCK(&feature_groups);
01777 
01778       AST_RWLIST_RDLOCK(&feature_list);
01779 
01780       if (!(tmpfeature = find_dynamic_feature(tok))) {
01781          AST_RWLIST_UNLOCK(&feature_list);
01782          continue;
01783       }
01784 
01785       /* Feature is up for consideration */
01786       if (!strcmp(tmpfeature->exten, code)) {
01787          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
01788          if (operation) {
01789             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
01790          }
01791          memcpy(feature, tmpfeature, sizeof(feature));
01792          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
01793             AST_RWLIST_UNLOCK(&feature_list);
01794             break;
01795          }
01796          res = AST_FEATURE_RETURN_PASSDIGITS;
01797       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
01798          res = AST_FEATURE_RETURN_STOREDIGITS;
01799 
01800       AST_RWLIST_UNLOCK(&feature_list);
01801    }
01802 
01803    return res;
01804 }

static struct ast_call_feature* find_dynamic_feature ( const char *  name  )  [static]

find a call feature by name

Definition at line 1538 of file features.c.

References AST_RWLIST_TRAVERSE, and ast_call_feature::sname.

Referenced by feature_interpret_helper(), and set_config_flags().

01539 {
01540    struct ast_call_feature *tmp;
01541 
01542    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01543       if (!strcasecmp(tmp->sname, name)) {
01544          break;
01545       }
01546    }
01547 
01548    return tmp;
01549 }

static struct feature_group* find_group ( const char *  name  )  [static]

Find a group by name.

Parameters:
name feature name
Return values:
feature group on success.
NULL on failure.

Definition at line 1576 of file features.c.

References AST_LIST_TRAVERSE, feature_group_exten::entry, and feature_group::gname.

Referenced by feature_interpret_helper().

01576                                                           {
01577    struct feature_group *fg = NULL;
01578 
01579    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
01580       if (!strcasecmp(fg->gname, name))
01581          break;
01582    }
01583 
01584    return fg;
01585 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 948 of file features.c.

References ast_autoservice_stop(), AST_CONTROL_UNHOLD, ast_indicate(), and chan.

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00949 {
00950    ast_indicate(chan, AST_CONTROL_UNHOLD);
00951 
00952    return ast_autoservice_stop(chan);
00953 }

static char* handle_feature_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command to list configured features.

Parameters:
e 
cmd 
a 
Return values:
CLI_SUCCESS on success.
NULL when tab completion is used.

Definition at line 3433 of file features.c.

References ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), builtin_features, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, ast_call_feature::exten, ast_cli_args::fd, FEATURES_COUNT, features_lock, ast_call_feature::fname, HFS_FORMAT, parking_con, parking_ext, parking_start, parking_stop, ast_call_feature::sname, and ast_cli_entry::usage.

03434 {
03435    int i;
03436    struct ast_call_feature *feature;
03437 #define HFS_FORMAT "%-25s %-7s %-7s\n"
03438 
03439    switch (cmd) {
03440    
03441    case CLI_INIT:
03442       e->command = "features show";
03443       e->usage =
03444          "Usage: features show\n"
03445          "       Lists configured features\n";
03446       return NULL;
03447    case CLI_GENERATE:
03448       return NULL;
03449    }
03450 
03451    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
03452    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03453 
03454    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
03455 
03456    ast_rwlock_rdlock(&features_lock);
03457    for (i = 0; i < FEATURES_COUNT; i++)
03458       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
03459    ast_rwlock_unlock(&features_lock);
03460 
03461    ast_cli(a->fd, "\n");
03462    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
03463    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03464    if (AST_RWLIST_EMPTY(&feature_list)) {
03465       ast_cli(a->fd, "(none)\n");
03466    } else {
03467       AST_RWLIST_RDLOCK(&feature_list);
03468       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
03469          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
03470       }
03471       AST_RWLIST_UNLOCK(&feature_list);
03472    }
03473    ast_cli(a->fd, "\nCall parking\n");
03474    ast_cli(a->fd, "------------\n");
03475    ast_cli(a->fd,"%-20s:      %s\n", "Parking extension", parking_ext);
03476    ast_cli(a->fd,"%-20s:      %s\n", "Parking context", parking_con);
03477    ast_cli(a->fd,"%-20s:      %d-%d\n", "Parked call extensions", parking_start, parking_stop);
03478    ast_cli(a->fd,"\n");
03479 
03480    return CLI_SUCCESS;
03481 }

static char* handle_features_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3490 of file features.c.

References CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, load_config(), and ast_cli_entry::usage.

03491 {
03492    switch (cmd) { 
03493    case CLI_INIT:
03494       e->command = "features reload";
03495       e->usage =
03496          "Usage: features reload\n"
03497          "       Reloads configured call features from features.conf\n";
03498       return NULL;
03499    case CLI_GENERATE:
03500       return NULL;
03501    }
03502    load_config();
03503 
03504    return CLI_SUCCESS;
03505 }

static char* handle_parkedcalls ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command to list parked calls.

Parameters:
e 
cmd 
a Check right usage, lock parking lot, display parked calls, unlock parking lot list.
Return values:
CLI_SUCCESS on success.
CLI_SHOWUSAGE on incorrect number of arguments.
NULL when tab completion is used.

Definition at line 3673 of file features.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, parkeduser::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, parkeduser::context, ESS, parkeduser::exten, ast_cli_args::fd, parkeduser::list, ast_channel::name, parkeduser::parkingexten, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.

Referenced by handle_parkedcalls_deprecated().

03674 {
03675    struct parkeduser *cur;
03676    int numparked = 0;
03677 
03678    switch (cmd) {
03679    case CLI_INIT:
03680       e->command = "parkedcalls show";
03681       e->usage =
03682          "Usage: parkedcalls show\n"
03683          "       List currently parked calls\n";
03684       return NULL;
03685    case CLI_GENERATE:
03686       return NULL;
03687    }
03688 
03689    if (a->argc > e->args)
03690       return CLI_SHOWUSAGE;
03691 
03692    ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
03693       , "Context", "Extension", "Pri", "Timeout");
03694 
03695    AST_LIST_LOCK(&parkinglot);
03696    AST_LIST_TRAVERSE(&parkinglot, cur, list) {
03697       ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
03698          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
03699          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
03700 
03701       numparked++;
03702    }
03703    AST_LIST_UNLOCK(&parkinglot);
03704    ast_cli(a->fd, "%d parked call%s.\n", numparked, ESS(numparked));
03705 
03706 
03707    return CLI_SUCCESS;
03708 }

static char* handle_parkedcalls_deprecated ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3710 of file features.c.

References CLI_INIT, ast_cli_entry::command, and handle_parkedcalls().

03711 {
03712    char *res = handle_parkedcalls(e, cmd, a);
03713    if (cmd == CLI_INIT)
03714       e->command = "show parkedcalls";
03715    return res;
03716 }

static int load_config ( void   )  [static]

Definition at line 3118 of file features.c.

References adsipark, ast_config_load, ast_copy_string(), ast_log(), AST_MAX_EXTENSION, ast_strlen_zero(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, comebacktoorigin, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_WARNING, parkaddhints, parkedcallhangup, parkedcallrecording, parkedcallreparking, parkedcalltransfers, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkmohclass, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.

Referenced by ast_features_init(), ast_features_reload(), handle_features_reload(), handle_voicemail_reload(), load_module(), and reload().

03119 {
03120    int start = 0, end = 0;
03121    int res;
03122    int i;
03123    struct ast_context *con = NULL;
03124    struct ast_config *cfg = NULL;
03125    struct ast_variable *var = NULL;
03126    struct feature_group *fg = NULL;
03127    struct ast_flags config_flags = { 0 };
03128    char old_parking_ext[AST_MAX_EXTENSION];
03129    char old_parking_con[AST_MAX_EXTENSION] = "";
03130    char *ctg; 
03131    static const char *categories[] = { 
03132       /* Categories in features.conf that are not
03133        * to be parsed as group categories
03134        */
03135       "general",
03136       "featuremap",
03137       "applicationmap"
03138    };
03139 
03140    if (!ast_strlen_zero(parking_con)) {
03141       strcpy(old_parking_ext, parking_ext);
03142       strcpy(old_parking_con, parking_con);
03143    } 
03144 
03145    /* Reset to defaults */
03146    strcpy(parking_con, "parkedcalls");
03147    strcpy(parking_con_dial, "park-dial");
03148    strcpy(parking_ext, "700");
03149    strcpy(pickup_ext, "*8");
03150    strcpy(parkmohclass, "default");
03151    courtesytone[0] = '\0';
03152    strcpy(xfersound, "beep");
03153    strcpy(xferfailsound, "pbx-invalid");
03154    parking_start = 701;
03155    parking_stop = 750;
03156    parkfindnext = 0;
03157    adsipark = 0;
03158    comebacktoorigin = 1;
03159    parkaddhints = 0;
03160    parkedcalltransfers = 0;
03161    parkedcallreparking = 0;
03162    parkedcallrecording = 0;
03163    parkedcallhangup = 0;
03164 
03165    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03166    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03167    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03168    atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03169    atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
03170    atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03171 
03172    cfg = ast_config_load("features.conf", config_flags);
03173    if (!cfg) {
03174       ast_log(LOG_WARNING,"Could not load features.conf\n");
03175       return 0;
03176    }
03177    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03178       if (!strcasecmp(var->name, "parkext")) {
03179          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
03180       } else if (!strcasecmp(var->name, "context")) {
03181          ast_copy_string(parking_con, var->value, sizeof(parking_con));
03182       } else if (!strcasecmp(var->name, "parkingtime")) {
03183          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
03184             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
03185             parkingtime = DEFAULT_PARK_TIME;
03186          } else
03187             parkingtime = parkingtime * 1000;
03188       } else if (!strcasecmp(var->name, "parkpos")) {
03189          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
03190             ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno);
03191          } else {
03192             parking_start = start;
03193             parking_stop = end;
03194          }
03195       } else if (!strcasecmp(var->name, "findslot")) {
03196          parkfindnext = (!strcasecmp(var->value, "next"));
03197       } else if (!strcasecmp(var->name, "parkinghints")) {
03198          parkaddhints = ast_true(var->value);
03199       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
03200          if (!strcasecmp(var->value, "both"))
03201             parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
03202          else if (!strcasecmp(var->value, "caller"))
03203             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
03204          else if (!strcasecmp(var->value, "callee"))
03205             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
03206       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
03207          if (!strcasecmp(var->value, "both"))
03208             parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
03209          else if (!strcasecmp(var->value, "caller"))
03210             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
03211          else if (!strcasecmp(var->value, "callee"))
03212             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
03213       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
03214          if (!strcasecmp(var->value, "both"))
03215             parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
03216          else if (!strcasecmp(var->value, "caller"))
03217             parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
03218          else if (!strcasecmp(var->value, "callee"))
03219             parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
03220       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
03221          if (!strcasecmp(var->value, "both"))
03222             parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
03223          else if (!strcasecmp(var->value, "caller"))
03224             parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
03225          else if (!strcasecmp(var->value, "callee"))
03226             parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
03227       } else if (!strcasecmp(var->name, "adsipark")) {
03228          adsipark = ast_true(var->value);
03229       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03230          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03231             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03232             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03233          } else
03234             transferdigittimeout = transferdigittimeout * 1000;
03235       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03236          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03237             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03238             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03239          }
03240       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03241          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03242             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03243             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03244          } else
03245             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03246       } else if (!strcasecmp(var->name, "atxferloopdelay")) {
03247          if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
03248             ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
03249             atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03250          } else 
03251             atxferloopdelay *= 1000;
03252       } else if (!strcasecmp(var->name, "atxferdropcall")) {
03253          atxferdropcall = ast_true(var->value);
03254       } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
03255          if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
03256             ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
03257             atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03258          }
03259       } else if (!strcasecmp(var->name, "courtesytone")) {
03260          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03261       }  else if (!strcasecmp(var->name, "parkedplay")) {
03262          if (!strcasecmp(var->value, "both"))
03263             parkedplay = 2;
03264          else if (!strcasecmp(var->value, "parked"))
03265             parkedplay = 1;
03266          else
03267             parkedplay = 0;
03268       } else if (!strcasecmp(var->name, "xfersound")) {
03269          ast_copy_string(xfersound, var->value, sizeof(xfersound));
03270       } else if (!strcasecmp(var->name, "xferfailsound")) {
03271          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03272       } else if (!strcasecmp(var->name, "pickupexten")) {
03273          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03274       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
03275          comebacktoorigin = ast_true(var->value);
03276       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03277          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
03278       }
03279    }
03280 
03281    unmap_features();
03282    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03283       if (remap_feature(var->name, var->value))
03284          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03285    }
03286 
03287    /* Map a key combination to an application*/
03288    ast_unregister_features();
03289    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03290       char *tmp_val = ast_strdupa(var->value);
03291       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
03292       struct ast_call_feature *feature;
03293 
03294       /* strsep() sets the argument to NULL if match not found, and it
03295        * is safe to use it with a NULL argument, so we don't check
03296        * between calls.
03297        */
03298       exten = strsep(&tmp_val,",");
03299       activatedby = strsep(&tmp_val,",");
03300       app = strsep(&tmp_val,",");
03301       app_args = strsep(&tmp_val,",");
03302       moh_class = strsep(&tmp_val,",");
03303 
03304       activateon = strsep(&activatedby, "/");   
03305 
03306       /*! \todo XXX var_name or app_args ? */
03307       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03308          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03309             app, exten, activateon, var->name);
03310          continue;
03311       }
03312 
03313       AST_RWLIST_RDLOCK(&feature_list);
03314       if ((feature = find_dynamic_feature(var->name))) {
03315          AST_RWLIST_UNLOCK(&feature_list);
03316          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03317          continue;
03318       }
03319       AST_RWLIST_UNLOCK(&feature_list);
03320             
03321       if (!(feature = ast_calloc(1, sizeof(*feature))))
03322          continue;               
03323 
03324       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03325       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03326       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03327       
03328       if (app_args) 
03329          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03330 
03331       if (moh_class)
03332          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03333          
03334       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03335       feature->operation = feature_exec_app;
03336       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03337 
03338       /* Allow caller and calle to be specified for backwards compatability */
03339       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03340          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03341       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03342          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03343       else {
03344          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03345             " must be 'self', or 'peer'\n", var->name);
03346          continue;
03347       }
03348 
03349       if (ast_strlen_zero(activatedby))
03350          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03351       else if (!strcasecmp(activatedby, "caller"))
03352          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03353       else if (!strcasecmp(activatedby, "callee"))
03354          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03355       else if (!strcasecmp(activatedby, "both"))
03356          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03357       else {
03358          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03359             " must be 'caller', or 'callee', or 'both'\n", var->name);
03360          continue;
03361       }
03362 
03363       ast_register_feature(feature);
03364          
03365       ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
03366    }
03367 
03368    ast_unregister_groups();
03369    AST_RWLIST_WRLOCK(&feature_groups);
03370 
03371    ctg = NULL;
03372    while ((ctg = ast_category_browse(cfg, ctg))) {
03373       for (i = 0; i < ARRAY_LEN(categories); i++) {
03374          if (!strcasecmp(categories[i], ctg))
03375             break;
03376       }
03377 
03378       if (i < ARRAY_LEN(categories)) 
03379          continue;
03380 
03381       if (!(fg = register_group(ctg)))
03382          continue;
03383 
03384       for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
03385          struct ast_call_feature *feature;
03386 
03387          AST_RWLIST_RDLOCK(&feature_list);
03388          if (!(feature = find_dynamic_feature(var->name)) && 
03389              !(feature = ast_find_call_feature(var->name))) {
03390             AST_RWLIST_UNLOCK(&feature_list);
03391             ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
03392             continue;
03393          }
03394          AST_RWLIST_UNLOCK(&feature_list);
03395 
03396          register_group_feature(fg, var->value, feature);
03397       }
03398    }
03399 
03400    AST_RWLIST_UNLOCK(&feature_groups);
03401 
03402    ast_config_destroy(cfg);
03403 
03404    /* Remove the old parking extension */
03405    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03406       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0))
03407             notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE);
03408       ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03409    }
03410    
03411    if (!(con = ast_context_find_or_create(NULL, NULL, parking_con, registrar))) {
03412       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
03413       return -1;
03414    }
03415    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03416    if (parkaddhints)
03417       park_add_hints(parking_con, parking_start, parking_stop);
03418    if (!res)
03419       notify_metermaids(ast_parking_ext(), parking_con, AST_DEVICE_INUSE);
03420    return res;
03421 
03422 }

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

Create manager event for parked calls.

Parameters:
s 
m Get channels involved in park, create event.
Returns:
Always 0

Definition at line 3789 of file features.c.

References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), buf, and s.

Referenced by ast_features_init().

03790 {
03791    const char *channel = astman_get_header(m, "Channel");
03792    const char *channel2 = astman_get_header(m, "Channel2");
03793    const char *timeout = astman_get_header(m, "Timeout");
03794    char buf[BUFSIZ];
03795    int to = 0;
03796    int res = 0;
03797    int parkExt = 0;
03798    struct ast_channel *ch1, *ch2;
03799 
03800    if (ast_strlen_zero(channel)) {
03801       astman_send_error(s, m, "Channel not specified");
03802       return 0;
03803    }
03804 
03805    if (ast_strlen_zero(channel2)) {
03806       astman_send_error(s, m, "Channel2 not specified");
03807       return 0;
03808    }
03809 
03810    ch1 = ast_get_channel_by_name_locked(channel);
03811    if (!ch1) {
03812       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
03813       astman_send_error(s, m, buf);
03814       return 0;
03815    }
03816 
03817    ch2 = ast_get_channel_by_name_locked(channel2);
03818    if (!ch2) {
03819       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
03820       astman_send_error(s, m, buf);
03821       ast_channel_unlock(ch1);
03822       return 0;
03823    }
03824 
03825    if (!ast_strlen_zero(timeout)) {
03826       sscanf(timeout, "%d", &to);
03827    }
03828 
03829    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
03830    if (!res) {
03831       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
03832       astman_send_ack(s, m, "Park successful");
03833    } else {
03834       astman_send_error(s, m, "Park failure");
03835    }
03836 
03837    ast_channel_unlock(ch1);
03838    ast_channel_unlock(ch2);
03839 
03840    return 0;
03841 }

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

Dump parking lot status.

Parameters:
s 
m Lock parking lot, iterate list and append parked calls status, unlock parking lot.
Returns:
Always RESULT_SUCCESS

Definition at line 3734 of file features.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::list, ast_channel::name, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.

Referenced by ast_features_init().

03735 {
03736    struct parkeduser *cur;
03737    const char *id = astman_get_header(m, "ActionID");
03738    char idText[256] = "";
03739 
03740    if (!ast_strlen_zero(id))
03741       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
03742 
03743    astman_send_ack(s, m, "Parked calls will follow");
03744 
03745    AST_LIST_LOCK(&parkinglot);
03746 
03747    AST_LIST_TRAVERSE(&parkinglot, cur, list) {
03748       astman_append(s, "Event: ParkedCall\r\n"
03749          "Exten: %d\r\n"
03750          "Channel: %s\r\n"
03751          "From: %s\r\n"
03752          "Timeout: %ld\r\n"
03753          "CallerIDNum: %s\r\n"
03754          "CallerIDName: %s\r\n"
03755          "%s"
03756          "\r\n",
03757          cur->parkingnum, cur->chan->name, cur->peername,
03758          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
03759          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
03760          S_OR(cur->chan->cid.cid_name, ""),
03761          idText);
03762    }
03763 
03764    astman_append(s,
03765       "Event: ParkedCallsComplete\r\n"
03766       "%s"
03767       "\r\n",idText);
03768 
03769    AST_LIST_UNLOCK(&parkinglot);
03770 
03771    return RESULT_SUCCESS;
03772 }

static int masq_park_call ( struct ast_channel rchan,
struct ast_channel peer,
int  timeout,
int *  extout,
int  play_announcement,
const char *  orig_chan_name 
) [static]

Definition at line 616 of file features.c.

References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc, ast_channel_masquerade(), ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), chan, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_PARKFAILED, LOG_WARNING, ast_channel::name, park_call_full(), park_space_reserve(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

Referenced by ast_masq_park_call(), and masq_park_call_announce().

00617 {
00618    struct ast_channel *chan;
00619    struct ast_frame *f;
00620    struct parkeduser *pu;
00621    int park_status;
00622 
00623    if ((pu = park_space_reserve(rchan)) == NULL) {
00624       if (peer)
00625          ast_stream_and_wait(peer, "beeperr", "");
00626       return FEATURE_RETURN_PARKFAILED;
00627    }
00628 
00629    /* Make a new, fake channel that we'll use to masquerade in the real one */
00630    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00631       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00632       return -1;
00633    }
00634 
00635    /* Make formats okay */
00636    chan->readformat = rchan->readformat;
00637    chan->writeformat = rchan->writeformat;
00638    ast_channel_masquerade(chan, rchan);
00639 
00640    /* Setup the extensions and such */
00641    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00642 
00643    /* Make the masq execute */
00644    if ((f = ast_read(chan)))
00645       ast_frfree(f);
00646 
00647    if (peer == rchan) {
00648       peer = chan;
00649    }
00650 
00651    if (!play_announcement && !orig_chan_name) {
00652       orig_chan_name = ast_strdupa(chan->name);
00653    }
00654 
00655    park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu);
00656    if (park_status == 1) {
00657    /* would be nice to play "invalid parking extension" */
00658       ast_hangup(chan);
00659       return -1;
00660    }
00661    return 0;
00662 }

static int masq_park_call_announce ( struct ast_channel rchan,
struct ast_channel peer,
int  timeout,
int *  extout,
const char *  orig_chan_name 
) [static]

Definition at line 670 of file features.c.

References masq_park_call().

Referenced by builtin_blindtransfer(), builtin_parkcall(), and park_call_exec().

00671 {
00672    return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
00673 }

static enum ast_device_state metermaidstate ( const char *  data  )  [static]

metermaids callback from devicestate.c

Definition at line 401 of file features.c.

References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_strdupa, and strsep().

Referenced by ast_features_init().

00402 {
00403    char *context;
00404    char *exten;
00405 
00406    context = ast_strdupa(data);
00407 
00408    exten = strsep(&context, "@");
00409    if (!context)
00410       return AST_DEVICE_INVALID;
00411    
00412    ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
00413 
00414    if (!ast_exists_extension(NULL, context, exten, 1, NULL))
00415       return AST_DEVICE_NOT_INUSE;
00416 
00417    return AST_DEVICE_INUSE;
00418 }

static void notify_metermaids ( const char *  exten,
char *  context,
enum ast_device_state  state 
) [static]

Notify metermaids that we've changed an extension.

Definition at line 392 of file features.c.

References ast_debug, ast_devstate_changed(), and devstate2str().

Referenced by do_parking_thread(), park_call_full(), and park_exec().

00393 {
00394    ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
00395       exten, context, devstate2str(state));
00396 
00397    ast_devstate_changed(state, "park:%s@%s", exten, context);
00398 }

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

Add parking hints for all defined parking lots.

Parameters:
context 
start starting parkinglot number
stop ending parkinglot number

Definition at line 3105 of file features.c.

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

03106 {
03107    int numext;
03108    char device[AST_MAX_EXTENSION];
03109    char exten[10];
03110 
03111    for (numext = start; numext <= stop; numext++) {
03112       snprintf(exten, sizeof(exten), "%d", numext);
03113       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03114       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03115    }
03116 }

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

Park a call.

Definition at line 2909 of file features.c.

References ast_channel::_state, ast_answer(), ast_copy_string(), AST_MAX_EXTENSION, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, chan, ast_channel::exten, masq_park_call_announce(), ast_channel::name, orig_exten(), and ast_channel::priority.

Referenced by ast_features_init().

02910 {
02911    char *orig_chan_name = ast_strdupa(chan->name);
02912    char orig_exten[AST_MAX_EXTENSION];
02913    int orig_priority = chan->priority;
02914 
02915    /* Data is unused at the moment but could contain a parking
02916       lot context eventually */
02917    int res = 0;
02918 
02919    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
02920 
02921    /* Setup the exten/priority to be s/1 since we don't know
02922       where this call should return */
02923    strcpy(chan->exten, "s");
02924    chan->priority = 1;
02925    /* Answer if call is not up */
02926    if (chan->_state != AST_STATE_UP)
02927       res = ast_answer(chan);
02928    /* Sleep to allow VoIP streams to settle down */
02929    if (!res)
02930       res = ast_safe_sleep(chan, 1000);
02931    /* Park the call */
02932    if (!res) {
02933       res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name);
02934       /* Continue on in the dialplan */
02935       if (res == 1) {
02936          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
02937          chan->priority = orig_priority;
02938          res = 0;
02939       } else if (!res) {
02940          res = 1;
02941       }
02942    }
02943 
02944    return res;
02945 }

static int park_call_full ( struct ast_channel chan,
struct ast_channel peer,
int  timeout,
int *  extout,
const char *  orig_chan_name,
struct parkeduser pu 
) [static]

Definition at line 489 of file features.c.

References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available, ast_adsi_unload_session, ast_bridged_channel(), AST_CHANNEL_NAME, ast_channel_unlock, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HOLD, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_get_channel_by_name_locked(), ast_indicate_data(), ast_log(), ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_tvnow(), ast_verb, parkeduser::chan, 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, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, park_space_reserve(), parkedcall, parking_con, parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, parkmohclass, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, registrar, S_OR, parkeduser::start, ast_channel::tech, ast_channel_tech::type, and ast_channel::uniqueid.

Referenced by ast_park_call(), and masq_park_call().

00490 {  
00491    struct ast_context *con;
00492    const char *event_from;
00493 
00494    /* Get a valid space if not already done */
00495    if (pu == NULL)
00496       pu = park_space_reserve(chan);
00497    if (pu == NULL)
00498       return 1; /* Continue execution if possible */
00499 
00500    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
00501 
00502    chan->appl = "Parked Call";
00503    chan->data = NULL; 
00504 
00505    pu->chan = chan;
00506    
00507    /* Put the parked channel on hold if we have two different channels */
00508    if (chan != peer) {
00509       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00510          S_OR(parkmohclass, NULL),
00511          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00512    }
00513    
00514    pu->start = ast_tvnow();
00515    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00516    if (extout)
00517       *extout = pu->parkingnum;
00518 
00519    if (peer) { 
00520       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
00521          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
00522          and we need the callback name to be that of transferer.  Since local,1/2 have the same
00523          name we can be tricky and just grab the bridged channel from the other side of the local
00524       */
00525       if (!strcasecmp(peer->tech->type, "Local")) {
00526          struct ast_channel *tmpchan, *base_peer;
00527          char other_side[AST_CHANNEL_NAME];
00528          char *c;
00529          ast_copy_string(other_side, S_OR(orig_chan_name, peer->name), sizeof(other_side));
00530          if ((c = strrchr(other_side, ';'))) {
00531             *++c = '1';
00532          }
00533          if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00534             if ((base_peer = ast_bridged_channel(tmpchan))) {
00535                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00536             }
00537             ast_channel_unlock(tmpchan);
00538          }
00539       } else {
00540          ast_copy_string(pu->peername, S_OR(orig_chan_name, peer->name), sizeof(pu->peername));
00541       }
00542    }
00543 
00544    /* Remember what had been dialed, so that if the parking
00545       expires, we try to come back to the same place */
00546    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00547    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00548    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00549 
00550    /* If parking a channel directly, don't quiet yet get parking running on it.
00551     * All parking lot entries are put into the parking lot with notquiteyet on. */
00552    if (peer != chan) 
00553       pu->notquiteyet = 0;
00554 
00555    /* Wake up the (presumably select()ing) thread */
00556    pthread_kill(parking_thread, SIGURG);
00557    ast_verb(2, "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00558 
00559    if (peer) {
00560       event_from = peer->name;
00561    } else {
00562       event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
00563    }
00564 
00565    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00566       "Exten: %s\r\n"
00567       "Channel: %s\r\n"
00568       "From: %s\r\n"
00569       "Timeout: %ld\r\n"
00570       "CallerIDNum: %s\r\n"
00571       "CallerIDName: %s\r\n"
00572       "Uniqueid: %s\r\n",
00573       pu->parkingexten, pu->chan->name, event_from ? event_from : "",
00574       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00575       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00576       S_OR(pu->chan->cid.cid_name, "<unknown>"),
00577       pu->chan->uniqueid
00578       );
00579 
00580    if (peer && adsipark && ast_adsi_available(peer)) {
00581       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00582       ast_adsi_unload_session(peer);
00583    }
00584 
00585    con = ast_context_find_or_create(NULL, NULL, parking_con, registrar);
00586    if (!con)   /* Still no context? Bad */
00587       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00588    if (con) {
00589       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
00590          notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_INUSE);
00591    }
00592    /* Tell the peer channel the number of the parking space */
00593    if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) { /* Only say number if it's a number and the channel hasn't been masqueraded away */
00594       /* If a channel is masqueraded into peer while playing back the parking slot number do not continue playing it back. This is the case if an attended transfer occurs. */
00595       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00596       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00597       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00598    }
00599    if (pu->notquiteyet) {
00600       /* Wake up parking thread if we're really done */
00601       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00602          S_OR(parkmohclass, NULL),
00603          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00604       pu->notquiteyet = 0;
00605       pthread_kill(parking_thread, SIGURG);
00606    }
00607    return 0;
00608 }

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

Pickup parked call.

Todo:
XXX we would like to wait on both!

Todo:
XXX Play a message XXX

Definition at line 2948 of file features.c.

References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, ast_copy_flags, AST_DEVICE_NOT_INUSE, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_free, ast_hangup(), ast_indicate(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), chan, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, ast_datastore::data, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_callee, ast_dial_features::features_caller, ast_dial_features::is_caller, LOG_WARNING, manager_event, ast_channel::name, notify_metermaids(), parkedcallhangup, parkedcallrecording, parkedcallreparking, parkedcalltransfers, parkedplay, parking_con, parkeduser::parkingexten, parkeduser::parkingnum, pbx_builtin_setvar_helper(), and S_OR.

Referenced by ast_features_init().

02949 {
02950    int res = 0;
02951    struct ast_channel *peer=NULL;
02952    struct parkeduser *pu;
02953    struct ast_context *con;
02954    int park = 0;
02955    struct ast_bridge_config config;
02956 
02957    if (data)
02958       park = atoi((char *)data);
02959 
02960    AST_LIST_LOCK(&parkinglot);
02961    AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) {
02962       if (!data || pu->parkingnum == park) {
02963          AST_LIST_REMOVE_CURRENT(list);
02964          break;
02965       }
02966    }
02967    AST_LIST_TRAVERSE_SAFE_END
02968    AST_LIST_UNLOCK(&parkinglot);
02969 
02970    if (pu) {
02971       peer = pu->chan;
02972       con = ast_context_find(parking_con);
02973       if (con) {
02974          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
02975             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02976          else
02977             notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
02978       } else
02979          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02980 
02981       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
02982          "Exten: %s\r\n"
02983          "Channel: %s\r\n"
02984          "From: %s\r\n"
02985          "CallerIDNum: %s\r\n"
02986          "CallerIDName: %s\r\n",
02987          pu->parkingexten, pu->chan->name, chan->name,
02988          S_OR(pu->chan->cid.cid_num, "<unknown>"),
02989          S_OR(pu->chan->cid.cid_name, "<unknown>")
02990          );
02991 
02992       ast_free(pu);
02993    }
02994    /* JK02: it helps to answer the channel if not already up */
02995    if (chan->_state != AST_STATE_UP)
02996       ast_answer(chan);
02997 
02998    if (peer) {
02999       struct ast_datastore *features_datastore;
03000       struct ast_dial_features *dialfeatures = NULL;
03001 
03002       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
03003 
03004       if (!ast_strlen_zero(courtesytone)) {
03005          int error = 0;
03006          ast_indicate(peer, AST_CONTROL_UNHOLD);
03007          if (parkedplay == 0) {
03008             error = ast_stream_and_wait(chan, courtesytone, "");
03009          } else if (parkedplay == 1) {
03010             error = ast_stream_and_wait(peer, courtesytone, "");
03011          } else if (parkedplay == 2) {
03012             if (!ast_streamfile(chan, courtesytone, chan->language) &&
03013                   !ast_streamfile(peer, courtesytone, chan->language)) {
03014                /*! \todo XXX we would like to wait on both! */
03015                res = ast_waitstream(chan, "");
03016                if (res >= 0)
03017                   res = ast_waitstream(peer, "");
03018                if (res < 0)
03019                   error = 1;
03020             }
03021          }
03022          if (error) {
03023             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
03024             ast_hangup(peer);
03025             return -1;
03026          }
03027       } else
03028          ast_indicate(peer, AST_CONTROL_UNHOLD);
03029 
03030       res = ast_channel_make_compatible(chan, peer);
03031       if (res < 0) {
03032          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
03033          ast_hangup(peer);
03034          return -1;
03035       }
03036       /* This runs sorta backwards, since we give the incoming channel control, as if it
03037          were the person called. */
03038       ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
03039 
03040       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03041       ast_cdr_setdestchan(chan->cdr, peer->name);
03042       memset(&config, 0, sizeof(struct ast_bridge_config));
03043 
03044       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
03045       ast_channel_lock(peer);
03046       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
03047          dialfeatures = features_datastore->data;
03048       }
03049       ast_channel_unlock(peer);
03050 
03051       if (dialfeatures) {
03052          ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL);
03053       }
03054 
03055       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03056          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
03057       }
03058       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03059          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
03060       }
03061       if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03062          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
03063       }
03064       if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03065          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
03066       }
03067       if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03068          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
03069       }
03070       if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03071          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
03072       }
03073       if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03074          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
03075       }
03076       if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03077          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
03078       }
03079 
03080       res = ast_bridge_call(chan, peer, &config);
03081 
03082       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03083       ast_cdr_setdestchan(chan->cdr, peer->name);
03084 
03085       /* Simulate the PBX hanging up */
03086       ast_hangup(peer);
03087       return -1;
03088    } else {
03089       /*! \todo XXX Play a message XXX */
03090       if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
03091          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
03092       ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
03093       res = -1;
03094    }
03095 
03096    return -1;
03097 }

static struct parkeduser* park_space_reserve ( struct ast_channel chan  )  [static]

Definition at line 420 of file features.c.

References ast_calloc, ast_exists_extension(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), chan, parkeduser::list, LOG_WARNING, parking_con, parkeduser::parkingnum, and pbx_builtin_getvar_helper().

Referenced by masq_park_call(), and park_call_full().

00421 {
00422    struct parkeduser *pu, *cur;
00423    int i, parking_space = -1, parking_range;
00424    const char *parkingexten;
00425    
00426    /* Allocate memory for parking data */
00427    if (!(pu = ast_calloc(1, sizeof(*pu)))) 
00428       return NULL;
00429 
00430    /* Lock parking lot */
00431    AST_LIST_LOCK(&parkinglot);
00432    /* Check for channel variable PARKINGEXTEN */
00433    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00434    if (!ast_strlen_zero(parkingexten)) {
00435       /*!\note The API forces us to specify a numeric parking slot, even
00436        * though the architecture would tend to support non-numeric extensions
00437        * (as are possible with SIP, for example).  Hence, we enforce that
00438        * limitation here.  If extout was not numeric, we could permit
00439        * arbitrary non-numeric extensions.
00440        */
00441         if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) {
00442          AST_LIST_UNLOCK(&parkinglot);
00443             ast_free(pu);
00444             ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00445             return NULL;
00446         }
00447         snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00448 
00449       if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
00450          AST_LIST_UNLOCK(&parkinglot);
00451          ast_free(pu);
00452          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00453          return NULL;
00454       }
00455    } else {
00456       /* Select parking space within range */
00457       parking_range = parking_stop - parking_start+1;
00458       for (i = 0; i < parking_range; i++) {
00459          parking_space = (i + parking_offset) % parking_range + parking_start;
00460          AST_LIST_TRAVERSE(&parkinglot, cur, list) {
00461             if (cur->parkingnum == parking_space)
00462                break;
00463          }
00464          if (!cur)
00465             break;
00466       }
00467 
00468       if (!(i < parking_range)) {
00469          ast_log(LOG_WARNING, "No more parking spaces\n");
00470          ast_free(pu);
00471          AST_LIST_UNLOCK(&parkinglot);
00472          return NULL;
00473       }
00474       /* Set pointer for next parking */
00475       if (parkfindnext) 
00476          parking_offset = parking_space - parking_start + 1;
00477       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00478    }
00479 
00480    pu->notquiteyet = 1;
00481    pu->parkingnum = parking_space;
00482    AST_LIST_INSERT_TAIL(&parkinglot, pu, list); 
00483    AST_LIST_UNLOCK(&parkinglot);
00484 
00485    return pu;
00486 }

static struct ast_cdr* pick_unlocked_cdr ( struct ast_cdr cdr  )  [static]

return the first unlocked cdr in a possible chain

Definition at line 2073 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

02074 {
02075    struct ast_cdr *cdr_orig = cdr;
02076    while (cdr) {
02077       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02078          return cdr;
02079       cdr = cdr->next;
02080    }
02081    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
02082 }

static void post_manager_event ( const char *  s,
struct parkeduser pu 
) [static]

Output parking event to manager.

Definition at line 2662 of file features.c.

References parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event, ast_channel::name, parkeduser::parkingexten, and S_OR.

Referenced by do_parking_thread().

02663 {
02664    manager_event(EVENT_FLAG_CALL, s,
02665       "Exten: %s\r\n"
02666       "Channel: %s\r\n"
02667       "CallerIDNum: %s\r\n"
02668       "CallerIDName: %s\r\n\r\n",
02669       pu->parkingexten, 
02670       pu->chan->name,
02671       S_OR(pu->chan->cid.cid_num, "<unknown>"),
02672       S_OR(pu->chan->cid.cid_name, "<unknown>")
02673       );
02674 }

static const char* real_ctx ( struct ast_channel transferer,
struct ast_channel transferee 
) [static]

Find the context for the transfer.

Parameters:
transferer 
transferee Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext.
Returns:
a context string

Definition at line 963 of file features.c.

References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, pbx_builtin_getvar_helper(), and s.

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00964 {
00965    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00966    if (ast_strlen_zero(s)) {
00967       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00968    }
00969    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
00970       s = transferer->macrocontext;
00971    }
00972    if (ast_strlen_zero(s)) {
00973       s = transferer->context;
00974    }
00975    return s;  
00976 }

static struct feature_group* register_group ( const char *  fgname  )  [static]

Add new feature group.

Parameters:
fgname feature group name.
Add new feature group to the feature group list insert at head of list.
Note:
This function MUST be called while feature_groups is locked.

Definition at line 1445 of file features.c.

References ast_calloc, ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_init, ast_string_field_set, ast_verb, feature_group_exten::entry, and LOG_NOTICE.

01446 {
01447    struct feature_group *fg;
01448 
01449    if (!fgname) {
01450       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
01451       return NULL;
01452    }
01453 
01454    if (!(fg = ast_calloc(1, sizeof(*fg))))
01455       return NULL;
01456 
01457    if (ast_string_field_init(fg, 128)) {
01458       ast_free(fg);
01459       return NULL;
01460    }
01461 
01462    ast_string_field_set(fg, gname, fgname);
01463 
01464    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
01465 
01466    ast_verb(2, "Registered group '%s'\n", fg->gname);
01467 
01468    return fg;
01469 }

static void register_group_feature ( struct feature_group fg,
const char *  exten,
struct ast_call_feature feature 
) [static]

Add feature to group.

Parameters:
fg feature group
exten 
feature feature to add.
Check fg and feature specified, add feature to list
Note:
This function MUST be called while feature_groups is locked.

Definition at line 1480 of file features.c.

References ast_calloc, ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_init, ast_string_field_set, ast_verb, feature_group_exten::entry, ast_call_feature::exten, feature_group_exten::feature, feature_group::features, feature_group::gname, LOG_NOTICE, S_OR, and ast_call_feature::sname.

01481 {
01482    struct feature_group_exten *fge;
01483 
01484    if (!fg) {
01485       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
01486       return;
01487    }
01488 
01489    if (!feature) {
01490       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
01491       return;
01492    }
01493 
01494    if (!(fge = ast_calloc(1, sizeof(*fge))))
01495       return;
01496 
01497    if (ast_string_field_init(fge, 128)) {
01498       ast_free(fge);
01499       return;
01500    }
01501 
01502    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
01503 
01504    fge->feature = feature;
01505 
01506    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);      
01507 
01508    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
01509                feature->sname, fg->gname, exten);
01510 }

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

Definition at line 1682 of file features.c.

References ast_copy_string(), ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, FEATURES_COUNT, and features_lock.

01683 {
01684    int x, res = -1;
01685 
01686    ast_rwlock_wrlock(&features_lock);
01687    for (x = 0; x < FEATURES_COUNT; x++) {
01688       if (strcasecmp(builtin_features[x].sname, name))
01689          continue;
01690 
01691       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01692       res = 0;
01693       break;
01694    }
01695    ast_rwlock_unlock(&features_lock);
01696 
01697    return res;
01698 }

static void set_bridge_features_on_config ( struct ast_bridge_config config,
const char *  features 
) [static]

Definition at line 2084 of file features.c.

References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), config, feature_group_exten::feature, and LOG_WARNING.

Referenced by ast_bridge_call().

02085 {
02086    const char *feature;
02087 
02088    if (ast_strlen_zero(features)) {
02089       return;
02090    }
02091 
02092    for (feature = features; *feature; feature++) {
02093       switch (*feature) {
02094       case 'T' :
02095       case 't' :
02096          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
02097          break;
02098       case 'K' :
02099       case 'k' :
02100          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
02101          break;
02102       case 'H' :
02103       case 'h' :
02104          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
02105          break;
02106       case 'W' :
02107       case 'w' :
02108          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
02109          break;
02110       default :
02111          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
02112       }
02113    }
02114 }

static void set_c_e_p ( struct ast_channel chan,
const char *  context,
const char *  ext,
int  pri 
) [static]

store context, extension and priority

Parameters:
chan,context,ext,pri 

Definition at line 250 of file features.c.

References ast_copy_string(), chan, ast_channel::context, ast_channel::exten, and ast_channel::priority.

Referenced by builtin_blindtransfer(), do_parking_thread(), and masq_park_call().

00251 {
00252    ast_copy_string(chan->context, context, sizeof(chan->context));
00253    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00254    chan->priority = pri;
00255 }

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

Definition at line 1847 of file features.c.

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, chan, config, feature_group_exten::feature, ast_call_feature::feature_mask, FEATURES_COUNT, features_lock, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

01848 {
01849    int x;
01850    
01851    ast_clear_flag(config, AST_FLAGS_ALL);
01852 
01853    ast_rwlock_rdlock(&features_lock);
01854    for (x = 0; x < FEATURES_COUNT; x++) {
01855       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01856          continue;
01857 
01858       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01859          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01860 
01861       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01862          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01863    }
01864    ast_rwlock_unlock(&features_lock);
01865    
01866    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01867       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01868 
01869       if (dynamic_features) {
01870          char *tmp = ast_strdupa(dynamic_features);
01871          char *tok;
01872          struct ast_call_feature *feature;
01873 
01874          /* while we have a feature */
01875          while ((tok = strsep(&tmp, "#"))) {
01876             AST_RWLIST_RDLOCK(&feature_list);
01877             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01878                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01879                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01880                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01881                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01882             }
01883             AST_RWLIST_UNLOCK(&feature_list);
01884          }
01885       }
01886    }
01887 }

static void set_peers ( struct ast_channel **  caller,
struct ast_channel **  callee,
struct ast_channel peer,
struct ast_channel chan,
int  sense 
) [static]

set caller and callee according to the direction

Parameters:
caller,callee,peer,chan,sense Detect who triggered feature and set callee/caller variables accordingly

Definition at line 681 of file features.c.

References chan, and FEATURE_SENSE_PEER.

Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().

00683 {
00684    if (sense == FEATURE_SENSE_PEER) {
00685       *caller = peer;
00686       *callee = chan;
00687    } else {
00688       *callee = peer;
00689       *caller = chan;
00690    }
00691 }

static void unmap_features ( void   )  [static]

Definition at line 1672 of file features.c.

References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, FEATURES_COUNT, and features_lock.

01673 {
01674    int x;
01675 
01676    ast_rwlock_wrlock(&features_lock);
01677    for (x = 0; x < FEATURES_COUNT; x++)
01678       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01679    ast_rwlock_unlock(&features_lock);
01680 }


Variable Documentation

int adsipark [static]

Definition at line 128 of file features.c.

Referenced by load_config().

char* app_bridge = "Bridge" [static]

Definition at line 3884 of file features.c.

unsigned int atxfercallbackretries [static]

Definition at line 137 of file features.c.

Referenced by load_config().

unsigned int atxferdropcall [static]

Definition at line 135 of file features.c.

Referenced by load_config().

unsigned int atxferloopdelay [static]

Definition at line 136 of file features.c.

Referenced by load_config().

int atxfernoanswertimeout [static]

Definition at line 134 of file features.c.

Referenced by load_config().

char* bridge_descrip [static]

Definition at line 3886 of file features.c.

struct ast_app_option bridge_exec_options[128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE } } [static]

Definition at line 3902 of file features.c.

Referenced by bridge_exec().

char* bridge_synopsis = "Bridge two channels" [static]

Definition at line 3885 of file features.c.

struct ast_call_feature builtin_features[] [static]

Definition at line 1410 of file features.c.

Referenced by ast_feature_request_and_dial(), ast_find_call_feature(), feature_interpret_helper(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().

struct ast_cli_entry cli_features[] [static]

Initial value:

 {
   { .handler =  handle_feature_show , .summary =  "Lists configured features" ,__VA_ARGS__ },
   { .handler =  handle_features_reload , .summary =  "Reloads configured features" ,__VA_ARGS__ },
   { .handler =  handle_parkedcalls , .summary =  "List currently parked calls" ,__VA_ARGS__ } .deprecate_cmd = &cli_show_parkedcalls_deprecated),
}

Definition at line 3720 of file features.c.

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

struct ast_cli_entry cli_show_parkedcalls_deprecated = { .handler = handle_parkedcalls_deprecated , .summary = "List currently parked calls." ,__VA_ARGS__ } [static]

Definition at line 3718 of file features.c.

int comebacktoorigin = 1 [static]

Definition at line 132 of file features.c.

Referenced by load_config().

char courtesytone[256] [static]

Courtesy tone

Definition at line 120 of file features.c.

Referenced by load_config(), and park_exec().

char* descrip [static]

Definition at line 144 of file features.c.

Referenced by aji_handle_presence(), ast_features_init(), and load_module().

char* descrip2 [static]

Definition at line 155 of file features.c.

Referenced by ast_features_init().

struct ast_datastore_info dial_features_info

Initial value:

 {
   .type = "dial-features",
   .destroy = dial_features_destroy,
   .duplicate = dial_features_duplicate,
 }

Definition at line 218 of file features.c.

Referenced by add_features_datastores(), builtin_atxfer(), do_parking_thread(), and park_exec().

int featuredigittimeout [static]

Definition at line 131 of file features.c.

Referenced by load_config().

ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static]

Definition at line 1408 of file features.c.

Referenced by ast_feature_request_and_dial(), ast_rdlock_call_features(), ast_unlock_call_features(), feature_interpret_helper(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().

char mandescr_bridge[] [static]

Definition at line 3507 of file features.c.

char mandescr_park[] [static]

Definition at line 3774 of file features.c.

struct ast_app* mixmonitor_app = NULL [static]

Definition at line 169 of file features.c.

Referenced by builtin_automixmonitor().

int mixmonitor_ok = 1 [static]

Definition at line 170 of file features.c.

struct ast_app* monitor_app = NULL [static]

Definition at line 166 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 167 of file features.c.

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 106 of file features.c.

Referenced by load_config().

char* parkcall = "Park" [static]

Definition at line 151 of file features.c.

Referenced by ast_features_init().

char* parkedcall = "ParkedCall" [static]

Definition at line 104 of file features.c.

Referenced by ast_features_init(), and park_call_full().

int parkedcallhangup = 0 [static]

Enable DTMF based disconnect on bridge when picking up parked calls

Definition at line 109 of file features.c.

Referenced by load_config(), and park_exec().

int parkedcallrecording = 0 [static]

Enable DTMF based recording on bridge when picking up parked calls

Definition at line 110 of file features.c.

Referenced by load_config(), and park_exec().

int parkedcallreparking = 0 [static]

Enable DTMF based parking on bridge when picking up parked calls

Definition at line 108 of file features.c.

Referenced by load_config(), and park_exec().

int parkedcalltransfers = 0 [static]

Enable DTMF based transfers on bridge when picking up parked calls

Definition at line 107 of file features.c.

Referenced by load_config(), and park_exec().

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 121 of file features.c.

Referenced by park_exec().

int parkfindnext [static]

Definition at line 126 of file features.c.

Referenced by load_config().

char parking_con[AST_MAX_EXTENSION] [static]

Context for which parking is made accessible

Definition at line 112 of file features.c.

Referenced by ast_features_init(), do_parking_thread(), handle_feature_show(), load_config(), park_call_full(), park_exec(), and park_space_reserve().

char parking_con_dial[AST_MAX_EXTENSION] [static]

Context for dialback for parking (KLUDGE)

Definition at line 113 of file features.c.

Referenced by do_parking_thread(), and load_config().

char parking_ext[AST_MAX_EXTENSION] [static]

Extension you type to park the call

Definition at line 114 of file features.c.

Referenced by ast_features_init(), ast_parking_ext(), handle_feature_show(), and load_config().

int parking_offset [static]

Definition at line 125 of file features.c.

int parking_start [static]

First available extension for parking

Definition at line 117 of file features.c.

Referenced by handle_feature_show(), and load_config().

int parking_stop [static]

Last available extension for parking

Definition at line 118 of file features.c.

Referenced by handle_feature_show(), and load_config().

pthread_t parking_thread [static]

Definition at line 224 of file features.c.

Referenced by ast_features_init().

int parkingtime = DEFAULT_PARK_TIME [static]

No more than 45 seconds parked before you do something with them

Definition at line 111 of file features.c.

char parkmohclass[MAX_MUSICCLASS] [static]

Music class used for parking

Definition at line 116 of file features.c.

Referenced by do_parking_thread(), load_config(), and park_call_full().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 115 of file features.c.

Referenced by ast_pickup_ext(), and load_config().

char* registrar = "features" [static]

Registrar for operations

Definition at line 139 of file features.c.

Referenced by do_parking_thread(), park_add_hints(), park_call_full(), pbx_load_module(), and pbx_load_users().

struct ast_app* stopmixmonitor_app = NULL [static]

Definition at line 172 of file features.c.

Referenced by builtin_automixmonitor().

int stopmixmonitor_ok = 1 [static]

Definition at line 173 of file features.c.

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

Definition at line 142 of file features.c.

Referenced by ast_features_init(), and load_module().

char* synopsis2 = "Park yourself" [static]

Definition at line 153 of file features.c.

Referenced by ast_features_init().

int transferdigittimeout [static]

Definition at line 130 of file features.c.

Referenced by load_config().

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 123 of file features.c.

Referenced by load_config().

char xfersound[256] [static]

Call transfer sound

Definition at line 122 of file features.c.

Referenced by action_bridge(), bridge_exec(), and load_config().


Generated on Thu Jul 9 13:41:18 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7