Fri Jun 19 12:10:34 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"
#include "asterisk/astobj2.h"

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  ast_dial_features
struct  ast_park_call_args
struct  ast_parkinglot
 Structure for parking lots which are put in a container. More...
struct  ast_parkinglot::parkinglot_parklist
struct  feature_group
struct  feature_group_exten
struct  feature_groups
struct  feature_list
struct  parkeduser
 Description of one parked call, added to a list while active, then removed. The list belongs to a parkinglot. More...

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_PARKINGLOT   "default"
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
#define FEATURES_COUNT   ARRAY_LEN(builtin_features)
#define HFS_FORMAT   "%-25s %-7s %-7s\n"
#define MAX_DIAL_FEATURE_OPTIONS   30

Enumerations

enum  { BRIDGE_OPT_PLAYTONE = (1 << 0) }
enum  ast_park_call_options { AST_PARK_OPT_RINGING = (1 << 0), AST_PARK_OPT_RANDOMIZE = (1 << 1), AST_PARK_OPT_SILENCE = (1 << 2) }

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.
static int ast_park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
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 struct ast_parkinglotbuild_parkinglot (char *name, struct ast_variable *var)
 Build parkinglot from configuration and chain it in.
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 struct ast_parkinglotcreate_parkinglot (char *name)
 Allocate parking lot structure.
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.
ast_parkinglotfind_parkinglot (const char *name)
 Find parkinglot by name.
static const char * findparkinglotname (struct ast_channel *chan)
 Find parking lot name from channel.
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 int load_config (void)
int manage_parkinglot (struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
 Run management on parkinglots, called once per parkinglot.
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, struct ast_park_call_args *args)
static int masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
static int masq_park_call_announce_args (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
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_exec (struct ast_channel *chan, void *data)
static int park_exec_full (struct ast_channel *chan, void *data, struct ast_parkinglot *parkinglot)
 Pickup parked call.
static struct parkeduserpark_space_reserve (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
static struct ast_parkinglotparkinglot_addref (struct ast_parkinglot *parkinglot)
static int parkinglot_cmp_cb (void *obj, void *arg, int flags)
static void parkinglot_destroy (void *obj)
 Destroy a parking lot.
static int parkinglot_hash_cb (const void *obj, const int flags)
static void parkinglot_unref (struct ast_parkinglot *parkinglot)
 Unreference parkinglot object. If no more references, then go ahead and delete it.
static struct ast_cdrpick_unlocked_cdr (struct ast_cdr *cdr)
 return the first unlocked cdr in a possible chain
static int play_message_in_bridged_call (struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile)
 Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages.
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 int comebacktoorigin = 1
static char courtesytone [256]
ast_parkinglotdefault_parkinglot
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 struct ast_app_option park_call_options [128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, }
static char * parkcall = PARK_APP_NAME
static char * parkedcall = "ParkedCall"
static int parkedplay = 0
char parking_ext [AST_MAX_EXTENSION]
static pthread_t parking_thread
static struct ao2_containerparkinglots
 The list of parking lots configured. Always at least one - the default parking lot.
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 68 of file features.c.

#define DEFAULT_ATXFER_CALLBACK_RETRIES   2

Definition at line 66 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_DROP_CALL   0

Definition at line 64 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_LOOP_DELAY   10000

Definition at line 65 of file features.c.

Referenced by load_config().

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

Definition at line 61 of file features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 62 of file features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 59 of file features.c.

Referenced by build_parkinglot(), and load_config().

#define DEFAULT_PARKINGLOT   "default"

Default parking lot

Definition at line 63 of file features.c.

Referenced by load_config().

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 60 of file features.c.

Referenced by load_config().

#define FEATURES_COUNT   ARRAY_LEN(builtin_features)

Definition at line 1604 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 69 of file features.c.

Referenced by manage_parkinglot().


Enumeration Type Documentation

anonymous enum

Enumerator:
BRIDGE_OPT_PLAYTONE 

Definition at line 4398 of file features.c.

04398      {
04399    BRIDGE_OPT_PLAYTONE = (1 << 0),
04400 };

enum ast_park_call_options

Options to pass to ast_park_call_full

Enumerator:
AST_PARK_OPT_RINGING  Provide ringing to the parked caller instead of music on hold
AST_PARK_OPT_RANDOMIZE  Randomly choose a parking spot for the caller instead of choosing the first one that is available.
AST_PARK_OPT_SILENCE  Do not announce the parking number

Definition at line 466 of file features.c.

00466                            {
00467    /*! Provide ringing to the parked caller instead of music on hold */
00468    AST_PARK_OPT_RINGING =   (1 << 0),
00469    /*! Randomly choose a parking spot for the caller instead of choosing
00470     *  the first one that is available. */
00471    AST_PARK_OPT_RANDOMIZE = (1 << 1),
00472    /*! Do not announce the parking number */
00473    AST_PARK_OPT_SILENCE = (1 << 2),
00474 };


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

04047 {
04048    const char *channela = astman_get_header(m, "Channel1");
04049    const char *channelb = astman_get_header(m, "Channel2");
04050    const char *playtone = astman_get_header(m, "Tone");
04051    struct ast_channel *chana = NULL, *chanb = NULL;
04052    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
04053    struct ast_bridge_thread_obj *tobj = NULL;
04054 
04055    /* make sure valid channels were specified */
04056    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
04057       astman_send_error(s, m, "Missing channel parameter in request");
04058       return 0;
04059    }
04060 
04061    /* The same code must be executed for chana and chanb.  To avoid a
04062     * theoretical deadlock, this code is separated so both chana and chanb will
04063     * not hold locks at the same time. */
04064 
04065    /* Start with chana */
04066    chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
04067 
04068    /* send errors if any of the channels could not be found/locked */
04069    if (!chana) {
04070       char buf[256];
04071       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
04072       astman_send_error(s, m, buf);
04073       return 0;
04074    }
04075 
04076    /* Answer the channels if needed */
04077    if (chana->_state != AST_STATE_UP)
04078       ast_answer(chana);
04079 
04080    /* create the placeholder channels and grab the other channels */
04081    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04082       NULL, NULL, 0, "Bridge/%s", chana->name))) {
04083       astman_send_error(s, m, "Unable to create temporary channel!");
04084       ast_channel_unlock(chana);
04085       return 1;
04086    }
04087 
04088    do_bridge_masquerade(chana, tmpchana);
04089    ast_channel_unlock(chana);
04090    chana = NULL;
04091 
04092    /* now do chanb */
04093    chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
04094    /* send errors if any of the channels could not be found/locked */
04095    if (!chanb) {
04096       char buf[256];
04097       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
04098       ast_hangup(tmpchana);
04099       astman_send_error(s, m, buf);
04100       return 0;
04101    }
04102 
04103    /* Answer the channels if needed */
04104    if (chanb->_state != AST_STATE_UP)
04105       ast_answer(chanb);
04106 
04107    /* create the placeholder channels and grab the other channels */
04108    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04109       NULL, NULL, 0, "Bridge/%s", chanb->name))) {
04110       astman_send_error(s, m, "Unable to create temporary channels!");
04111       ast_hangup(tmpchana);
04112       ast_channel_unlock(chanb);
04113       return 1;
04114    }
04115    do_bridge_masquerade(chanb, tmpchanb);
04116    ast_channel_unlock(chanb);
04117    chanb = NULL;
04118 
04119    /* make the channels compatible, send error if we fail doing so */
04120    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
04121       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
04122       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
04123       ast_hangup(tmpchana);
04124       ast_hangup(tmpchanb);
04125       return 1;
04126    }
04127 
04128    /* setup the bridge thread object and start the bridge */
04129    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
04130       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
04131       astman_send_error(s, m, "Unable to spawn a new bridge thread");
04132       ast_hangup(tmpchana);
04133       ast_hangup(tmpchanb);
04134       return 1;
04135    }
04136 
04137    tobj->chan = tmpchana;
04138    tobj->peer = tmpchanb;
04139    tobj->return_to_pbx = 1;
04140 
04141    if (ast_true(playtone)) {
04142       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
04143          if (ast_waitstream(tmpchanb, "") < 0)
04144             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
04145       }
04146    }
04147 
04148    ast_bridge_call_thread_launch(tobj);
04149 
04150    astman_send_ack(s, m, "Launched bridge thread with success");
04151 
04152    return 0;
04153 }

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

Definition at line 2310 of file features.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_datastore_alloc(), ast_datastore_free(), 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().

02311 {
02312    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
02313    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
02314 
02315    ast_channel_lock(caller);
02316    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
02317    ast_channel_unlock(caller);
02318    if (!ds_caller_features) {
02319       if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02320          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
02321          return;
02322       }
02323       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
02324          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02325          ast_datastore_free(ds_caller_features);
02326          return;
02327       }
02328       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
02329       caller_features->is_caller = 1;
02330       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
02331       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
02332       ds_caller_features->data = caller_features;
02333       ast_channel_lock(caller);
02334       ast_channel_datastore_add(caller, ds_caller_features);
02335       ast_channel_unlock(caller);
02336    } else {
02337       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
02338        * flags over from the atxfer to the caller */
02339       return;
02340    }
02341 
02342    ast_channel_lock(callee);
02343    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
02344    ast_channel_unlock(callee);
02345    if (!ds_callee_features) {
02346       if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02347          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
02348          return;
02349       }
02350       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
02351          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02352          ast_datastore_free(ds_callee_features);
02353          return;
02354       }
02355       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
02356       callee_features->is_caller = 0;
02357       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
02358       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
02359       ds_callee_features->data = callee_features;
02360       ast_channel_lock(callee);
02361       ast_channel_datastore_add(callee, ds_callee_features);
02362       ast_channel_unlock(callee);
02363    }
02364 
02365    return;
02366 }

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

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

Referenced by ast_park_call_full().

00405 {
00406    int res;
00407    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00408    char tmp[256];
00409    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00410 
00411    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00412    message[0] = tmp;
00413    res = ast_adsi_load_session(chan, NULL, 0, 1);
00414    if (res == -1)
00415       return res;
00416    return ast_adsi_print(chan, message, justify, 1);
00417 }

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 2377 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_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, 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_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, 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(), park_exec_full(), and try_calling().

02378 {
02379    /* Copy voice back and forth between the two channels.  Give the peer
02380       the ability to transfer calls with '#<extension' syntax. */
02381    struct ast_frame *f;
02382    struct ast_channel *who;
02383    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
02384    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
02385    char orig_channame[AST_MAX_EXTENSION];
02386    char orig_peername[AST_MAX_EXTENSION];
02387    int res;
02388    int diff;
02389    int hasfeatures=0;
02390    int hadfeatures=0;
02391    int autoloopflag;
02392    struct ast_option_header *aoh;
02393    struct ast_bridge_config backup_config;
02394    struct ast_cdr *bridge_cdr = NULL;
02395    struct ast_cdr *orig_peer_cdr = NULL;
02396    struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02397    struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02398    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02399    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02400 
02401    memset(&backup_config, 0, sizeof(backup_config));
02402 
02403    config->start_time = ast_tvnow();
02404 
02405    if (chan && peer) {
02406       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
02407       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
02408    } else if (chan) {
02409       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
02410    }
02411 
02412    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
02413    add_features_datastores(chan, peer, config);
02414 
02415    /* This is an interesting case.  One example is if a ringing channel gets redirected to
02416     * an extension that picks up a parked call.  This will make sure that the call taken
02417     * out of parking gets told that the channel it just got bridged to is still ringing. */
02418    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
02419       ast_indicate(peer, AST_CONTROL_RINGING);
02420    }
02421 
02422    if (monitor_ok) {
02423       const char *monitor_exec;
02424       struct ast_channel *src = NULL;
02425       if (!monitor_app) { 
02426          if (!(monitor_app = pbx_findapp("Monitor")))
02427             monitor_ok=0;
02428       }
02429       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
02430          src = chan;
02431       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
02432          src = peer;
02433       if (monitor_app && src) {
02434          char *tmp = ast_strdupa(monitor_exec);
02435          pbx_exec(src, monitor_app, tmp);
02436       }
02437    }
02438 
02439    set_config_flags(chan, peer, config);
02440    config->firstpass = 1;
02441 
02442    /* Answer if need be */
02443    if (chan->_state != AST_STATE_UP) {
02444       if (ast_raw_answer(chan, 1)) {
02445          return -1;
02446       }
02447    }
02448 
02449    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
02450    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
02451    orig_peer_cdr = peer_cdr;
02452    
02453    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
02454       
02455       if (chan_cdr) {
02456          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
02457          ast_cdr_update(chan);
02458          bridge_cdr = ast_cdr_dup(chan_cdr);
02459          ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
02460          ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
02461       } else {
02462          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
02463          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
02464          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
02465          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
02466          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
02467          ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
02468          ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
02469          ast_cdr_setcid(bridge_cdr, chan);
02470          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
02471          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
02472          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
02473          /* Destination information */
02474          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
02475          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
02476          if (peer_cdr) {
02477             bridge_cdr->start = peer_cdr->start;
02478             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02479          } else {
02480             ast_cdr_start(bridge_cdr);
02481          }
02482       }
02483       ast_debug(4,"bridge answer set, chan answer set\n");
02484       /* peer_cdr->answer will be set when a macro runs on the peer;
02485          in that case, the bridge answer will be delayed while the
02486          macro plays on the peer channel. The peer answered the call
02487          before the macro started playing. To the phone system,
02488          this is billable time for the call, even tho the caller
02489          hears nothing but ringing while the macro does its thing. */
02490       if (peer_cdr && !ast_tvzero(peer_cdr->answer)) {
02491          bridge_cdr->answer = peer_cdr->answer;
02492          chan_cdr->answer = peer_cdr->answer;
02493          bridge_cdr->disposition = peer_cdr->disposition;
02494          chan_cdr->disposition = peer_cdr->disposition;
02495       } else {
02496          ast_cdr_answer(bridge_cdr);
02497          ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
02498       }
02499       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02500          ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
02501          if (peer_cdr) {
02502             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
02503          }
02504       }
02505    }
02506    for (;;) {
02507       struct ast_channel *other; /* used later */
02508    
02509       res = ast_channel_bridge(chan, peer, config, &f, &who);
02510       
02511       /* When frame is not set, we are probably involved in a situation
02512          where we've timed out.
02513          When frame is set, we'll come this code twice; once for DTMF_BEGIN
02514          and also for DTMF_END. If we flow into the following 'if' for both, then 
02515          our wait times are cut in half, as both will subtract from the
02516          feature_timer. Not good!
02517       */
02518       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
02519          /* Update time limit for next pass */
02520          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
02521          if (res == AST_BRIDGE_RETRY) {
02522             /* The feature fully timed out but has not been updated. Skip
02523              * the potential round error from the diff calculation and
02524              * explicitly set to expired. */
02525             config->feature_timer = -1;
02526          } else {
02527             config->feature_timer -= diff;
02528          }
02529 
02530          if (hasfeatures) {
02531             /* Running on backup config, meaning a feature might be being
02532                activated, but that's no excuse to keep things going 
02533                indefinitely! */
02534             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
02535                ast_debug(1, "Timed out, realtime this time!\n");
02536                config->feature_timer = 0;
02537                who = chan;
02538                if (f)
02539                   ast_frfree(f);
02540                f = NULL;
02541                res = 0;
02542             } else if (config->feature_timer <= 0) {
02543                /* Not *really* out of time, just out of time for
02544                   digits to come in for features. */
02545                ast_debug(1, "Timed out for feature!\n");
02546                if (!ast_strlen_zero(peer_featurecode)) {
02547                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
02548                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
02549                }
02550                if (!ast_strlen_zero(chan_featurecode)) {
02551                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
02552                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
02553                }
02554                if (f)
02555                   ast_frfree(f);
02556                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02557                if (!hasfeatures) {
02558                   /* Restore original (possibly time modified) bridge config */
02559                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02560                   memset(&backup_config, 0, sizeof(backup_config));
02561                }
02562                hadfeatures = hasfeatures;
02563                /* Continue as we were */
02564                continue;
02565             } else if (!f) {
02566                /* The bridge returned without a frame and there is a feature in progress.
02567                 * However, we don't think the feature has quite yet timed out, so just
02568                 * go back into the bridge. */
02569                continue;
02570             }
02571          } else {
02572             if (config->feature_timer <=0) {
02573                /* We ran out of time */
02574                config->feature_timer = 0;
02575                who = chan;
02576                if (f)
02577                   ast_frfree(f);
02578                f = NULL;
02579                res = 0;
02580             }
02581          }
02582       }
02583       if (res < 0) {
02584          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
02585             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
02586          goto before_you_go;
02587       }
02588       
02589       if (!f || (f->frametype == AST_FRAME_CONTROL &&
02590             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
02591                f->subclass == AST_CONTROL_CONGESTION))) {
02592          res = -1;
02593          break;
02594       }
02595       /* many things should be sent to the 'other' channel */
02596       other = (who == chan) ? peer : chan;
02597       if (f->frametype == AST_FRAME_CONTROL) {
02598          switch (f->subclass) {
02599          case AST_CONTROL_RINGING:
02600          case AST_CONTROL_FLASH:
02601          case -1:
02602             ast_indicate(other, f->subclass);
02603             break;
02604          case AST_CONTROL_HOLD:
02605          case AST_CONTROL_UNHOLD:
02606             ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
02607             break;
02608          case AST_CONTROL_OPTION:
02609             aoh = f->data.ptr;
02610             /* Forward option Requests */
02611             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02612                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
02613                   f->datalen - sizeof(struct ast_option_header), 0);
02614             }
02615             break;
02616          }
02617       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02618          /* eat it */
02619       } else if (f->frametype == AST_FRAME_DTMF) {
02620          char *featurecode;
02621          int sense;
02622 
02623          hadfeatures = hasfeatures;
02624          /* This cannot overrun because the longest feature is one shorter than our buffer */
02625          if (who == chan) {
02626             sense = FEATURE_SENSE_CHAN;
02627             featurecode = chan_featurecode;
02628          } else  {
02629             sense = FEATURE_SENSE_PEER;
02630             featurecode = peer_featurecode;
02631          }
02632          /*! append the event to featurecode. we rely on the string being zero-filled, and
02633           * not overflowing it. 
02634           * \todo XXX how do we guarantee the latter ?
02635           */
02636          featurecode[strlen(featurecode)] = f->subclass;
02637          /* Get rid of the frame before we start doing "stuff" with the channels */
02638          ast_frfree(f);
02639          f = NULL;
02640          config->feature_timer = backup_config.feature_timer;
02641          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
02642          switch(res) {
02643          case AST_FEATURE_RETURN_PASSDIGITS:
02644             ast_dtmf_stream(other, who, featurecode, 0, 0);
02645             /* Fall through */
02646          case AST_FEATURE_RETURN_SUCCESS:
02647             memset(featurecode, 0, sizeof(chan_featurecode));
02648             break;
02649          }
02650          if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
02651             res = 0;
02652          } else 
02653             break;
02654          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02655          if (hadfeatures && !hasfeatures) {
02656             /* Restore backup */
02657             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02658             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02659          } else if (hasfeatures) {
02660             if (!hadfeatures) {
02661                /* Backup configuration */
02662                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02663                /* Setup temporary config options */
02664                config->play_warning = 0;
02665                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02666                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02667                config->warning_freq = 0;
02668                config->warning_sound = NULL;
02669                config->end_sound = NULL;
02670                config->start_sound = NULL;
02671                config->firstpass = 0;
02672             }
02673             config->start_time = ast_tvnow();
02674             config->feature_timer = featuredigittimeout;
02675             ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
02676          }
02677       }
02678       if (f)
02679          ast_frfree(f);
02680 
02681    }
02682    before_you_go:
02683 
02684    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02685       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
02686       if (bridge_cdr) {
02687          ast_cdr_discard(bridge_cdr);
02688          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
02689       }
02690       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
02691    }
02692 
02693    if (config->end_bridge_callback) {
02694       config->end_bridge_callback(config->end_bridge_callback_data);
02695    }
02696 
02697    /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 
02698     * if it were, then chan belongs to a different thread now, and might have been hung up long
02699      * ago.
02700     */
02701    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) &&
02702       ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02703       struct ast_cdr *swapper = NULL;
02704       char savelastapp[AST_MAX_EXTENSION];
02705       char savelastdata[AST_MAX_EXTENSION];
02706       char save_exten[AST_MAX_EXTENSION];
02707       int  save_prio;
02708       int  found = 0;   /* set if we find at least one match */
02709       int  spawn_error = 0;
02710       
02711       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02712       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02713       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02714          ast_cdr_end(bridge_cdr);
02715       }
02716       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
02717          dialplan code operate on it */
02718       ast_channel_lock(chan);
02719       if (bridge_cdr) {
02720          swapper = chan->cdr;
02721          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02722          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02723          chan->cdr = bridge_cdr;
02724       }
02725       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02726       save_prio = chan->priority;
02727       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02728       chan->priority = 1;
02729       ast_channel_unlock(chan);
02730       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) {
02731          chan->priority++;
02732       }
02733       if (found && spawn_error) {
02734          /* Something bad happened, or a hangup has been requested. */
02735          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02736          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02737       }
02738       /* swap it back */
02739       ast_channel_lock(chan);
02740       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02741       chan->priority = save_prio;
02742       if (bridge_cdr) {
02743          if (chan->cdr == bridge_cdr) {
02744             chan->cdr = swapper;
02745          } else {
02746             bridge_cdr = NULL;
02747          }
02748       }
02749       ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02750       ast_channel_unlock(chan);
02751       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
02752       if (bridge_cdr) {
02753          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02754          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02755       }
02756       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02757    }
02758    
02759    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
02760    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02761    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
02762       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02763 
02764    /* we can post the bridge CDR at this point */
02765    if (bridge_cdr) {
02766       ast_cdr_end(bridge_cdr);
02767       ast_cdr_detach(bridge_cdr);
02768    }
02769    
02770    /* do a specialized reset on the beginning channel
02771       CDR's, if they still exist, so as not to mess up
02772       issues in future bridges;
02773       
02774       Here are the rules of the game:
02775       1. The chan and peer channel pointers will not change
02776          during the life of the bridge.
02777       2. But, in transfers, the channel names will change.
02778          between the time the bridge is started, and the
02779          time the channel ends. 
02780          Usually, when a channel changes names, it will
02781          also change CDR pointers.
02782       3. Usually, only one of the two channels (chan or peer)
02783          will change names.
02784       4. Usually, if a channel changes names during a bridge,
02785          it is because of a transfer. Usually, in these situations,
02786          it is normal to see 2 bridges running simultaneously, and
02787          it is not unusual to see the two channels that change
02788          swapped between bridges.
02789       5. After a bridge occurs, we have 2 or 3 channels' CDRs
02790          to attend to; if the chan or peer changed names,
02791          we have the before and after attached CDR's.
02792    */
02793    
02794    if (new_chan_cdr) {
02795       struct ast_channel *chan_ptr = NULL;
02796  
02797       if (strcasecmp(orig_channame, chan->name) != 0) { 
02798          /* old channel */
02799          chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02800          if (chan_ptr) {
02801             if (!ast_bridged_channel(chan_ptr)) {
02802                struct ast_cdr *cur;
02803                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02804                   if (cur == chan_cdr) {
02805                      break;
02806                   }
02807                }
02808                if (cur)
02809                   ast_cdr_specialized_reset(chan_cdr,0);
02810             }
02811             ast_channel_unlock(chan_ptr);
02812          }
02813          /* new channel */
02814          ast_cdr_specialized_reset(new_chan_cdr,0);
02815       } else {
02816          ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr  */
02817       }
02818    }
02819    
02820    {
02821       struct ast_channel *chan_ptr = NULL;
02822       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02823       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))
02824          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
02825       if (strcasecmp(orig_peername, peer->name) != 0) { 
02826          /* old channel */
02827          chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02828          if (chan_ptr) {
02829             if (!ast_bridged_channel(chan_ptr)) {
02830                struct ast_cdr *cur;
02831                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02832                   if (cur == peer_cdr) {
02833                      break;
02834                   }
02835                }
02836                if (cur)
02837                   ast_cdr_specialized_reset(peer_cdr,0);
02838             }
02839             ast_channel_unlock(chan_ptr);
02840          }
02841          /* new channel */
02842          ast_cdr_specialized_reset(new_peer_cdr,0);
02843       } else {
02844          ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr  */
02845       }
02846    }
02847    
02848    return res;
02849 }

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

00340 {
00341    struct ast_bridge_thread_obj *tobj = data;
00342    int res;
00343 
00344    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00345    tobj->chan->data = tobj->peer->name;
00346    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00347    tobj->peer->data = tobj->chan->name;
00348 
00349    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00350 
00351    if (tobj->return_to_pbx) {
00352       if (!ast_check_hangup(tobj->peer)) {
00353          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00354          res = ast_pbx_start(tobj->peer);
00355          if (res != AST_PBX_SUCCESS)
00356             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00357       } else
00358          ast_hangup(tobj->peer);
00359       if (!ast_check_hangup(tobj->chan)) {
00360          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00361          res = ast_pbx_start(tobj->chan);
00362          if (res != AST_PBX_SUCCESS)
00363             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00364       } else
00365          ast_hangup(tobj->chan);
00366    } else {
00367       ast_hangup(tobj->chan);
00368       ast_hangup(tobj->peer);
00369    }
00370 
00371    ast_free(tobj);
00372 
00373    return NULL;
00374 }

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

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by action_bridge(), and builtin_atxfer().

00383 {
00384    pthread_t thread;
00385    pthread_attr_t attr;
00386    struct sched_param sched;
00387 
00388    pthread_attr_init(&attr);
00389    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00390    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00391    pthread_attr_destroy(&attr);
00392    memset(&sched, 0, sizeof(sched));
00393    pthread_setschedparam(thread, SCHED_RR, &sched);
00394 }

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

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

Referenced by detect_disconnect().

02042                                                                                                                            {
02043 
02044    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02045 }

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

02013                                                                                                                                               {
02014 
02015    char dynamic_features_buf[128];
02016    const char *peer_dynamic_features, *chan_dynamic_features;
02017    struct ast_flags features;
02018    struct ast_call_feature feature;
02019    if (sense == FEATURE_SENSE_CHAN) {
02020       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
02021    }
02022    else {
02023       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
02024    }
02025 
02026    ast_channel_lock(peer);
02027    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
02028    ast_channel_unlock(peer);
02029 
02030    ast_channel_lock(chan);
02031    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
02032    ast_channel_unlock(chan);
02033 
02034    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,""));
02035 
02036    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);
02037 
02038    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
02039 }

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

References ast_channel::_state, ast_call(), 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_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().

02101 {
02102    int state = 0;
02103    int cause = 0;
02104    int to;
02105    struct ast_channel *chan;
02106    struct ast_channel *monitor_chans[2];
02107    struct ast_channel *active_channel;
02108    int res = 0, ready = 0;
02109 
02110    if ((chan = ast_request(type, format, data, &cause))) {
02111       ast_set_callerid(chan, cid_num, cid_name, cid_num);
02112       ast_string_field_set(chan, language, language);
02113       ast_channel_inherit_variables(caller, chan); 
02114       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
02115          
02116       if (!ast_call(chan, data, timeout)) {
02117          struct timeval started;
02118          int x, len = 0;
02119          char *disconnect_code = NULL, *dialed_code = NULL;
02120 
02121          ast_indicate(caller, AST_CONTROL_RINGING);
02122          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
02123          ast_rwlock_rdlock(&features_lock);
02124          for (x = 0; x < FEATURES_COUNT; x++) {
02125             if (strcasecmp(builtin_features[x].sname, "disconnect"))
02126                continue;
02127 
02128             disconnect_code = builtin_features[x].exten;
02129             len = strlen(disconnect_code) + 1;
02130             dialed_code = alloca(len);
02131             memset(dialed_code, 0, len);
02132             break;
02133          }
02134          ast_rwlock_unlock(&features_lock);
02135          x = 0;
02136          started = ast_tvnow();
02137          to = timeout;
02138 
02139          ast_poll_channel_add(caller, chan);
02140 
02141          while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
02142             struct ast_frame *f = NULL;
02143 
02144             monitor_chans[0] = caller;
02145             monitor_chans[1] = chan;
02146             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
02147 
02148             /* see if the timeout has been violated */
02149             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
02150                state = AST_CONTROL_UNHOLD;
02151                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
02152                break; /*doh! timeout*/
02153             }
02154 
02155             if (!active_channel)
02156                continue;
02157 
02158             if (chan && (chan == active_channel)){
02159                f = ast_read(chan);
02160                if (f == NULL) { /*doh! where'd he go?*/
02161                   state = AST_CONTROL_HANGUP;
02162                   res = 0;
02163                   break;
02164                }
02165                
02166                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
02167                   if (f->subclass == AST_CONTROL_RINGING) {
02168                      state = f->subclass;
02169                      ast_verb(3, "%s is ringing\n", chan->name);
02170                      ast_indicate(caller, AST_CONTROL_RINGING);
02171                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
02172                      state = f->subclass;
02173                      ast_verb(3, "%s is busy\n", chan->name);
02174                      ast_indicate(caller, AST_CONTROL_BUSY);
02175                      ast_frfree(f);
02176                      f = NULL;
02177                      break;
02178                   } else if (f->subclass == AST_CONTROL_ANSWER) {
02179                      /* This is what we are hoping for */
02180                      state = f->subclass;
02181                      ast_frfree(f);
02182                      f = NULL;
02183                      ready=1;
02184                      break;
02185                   } else if (f->subclass != -1) {
02186                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
02187                   }
02188                   /* else who cares */
02189                }
02190 
02191             } else if (caller && (active_channel == caller)) {
02192                f = ast_read(caller);
02193                if (f == NULL) { /*doh! where'd he go?*/
02194                   if (!igncallerstate) {
02195                      if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
02196                         /* make this a blind transfer */
02197                         ready = 1;
02198                         break;
02199                      }
02200                      state = AST_CONTROL_HANGUP;
02201                      res = 0;
02202                      break;
02203                   }
02204                } else {
02205                
02206                   if (f->frametype == AST_FRAME_DTMF) {
02207                      dialed_code[x++] = f->subclass;
02208                      dialed_code[x] = '\0';
02209                      if (strlen(dialed_code) == len) {
02210                         x = 0;
02211                      } else if (x && strncmp(dialed_code, disconnect_code, x)) {
02212                         x = 0;
02213                         dialed_code[x] = '\0';
02214                      }
02215                      if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
02216                         /* Caller Canceled the call */
02217                         state = AST_CONTROL_UNHOLD;
02218                         ast_frfree(f);
02219                         f = NULL;
02220                         break;
02221                      }
02222                   }
02223                }
02224             }
02225             if (f)
02226                ast_frfree(f);
02227          } /* end while */
02228 
02229          ast_poll_channel_del(caller, chan);
02230 
02231       } else
02232          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
02233    } else {
02234       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
02235       switch(cause) {
02236       case AST_CAUSE_BUSY:
02237          state = AST_CONTROL_BUSY;
02238          break;
02239       case AST_CAUSE_CONGESTION:
02240          state = AST_CONTROL_CONGESTION;
02241          break;
02242       }
02243    }
02244    
02245    ast_indicate(caller, -1);
02246    if (chan && ready) {
02247       if (chan->_state == AST_STATE_UP) 
02248          state = AST_CONTROL_ANSWER;
02249       res = 0;
02250    } else if(chan) {
02251       res = -1;
02252       ast_hangup(chan);
02253       chan = NULL;
02254    } else {
02255       res = -1;
02256    }
02257    
02258    if (outstate)
02259       *outstate = state;
02260 
02261    return chan;
02262 }

int ast_features_init ( void   ) 

Provided by features.c

Definition at line 4535 of file features.c.

References action_bridge(), ao2_container_alloc, 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_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), parkinglots, synopsis, and synopsis2.

Referenced by main().

04536 {
04537    int res;
04538 
04539    ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
04540 
04541    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
04542 
04543    if ((res = load_config()))
04544       return res;
04545    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
04546    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
04547    res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
04548    if (!res)
04549       res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
04550    if (!res) {
04551       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
04552       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park); 
04553       ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
04554    }
04555 
04556    res |= ast_devstate_prov_add("Park", metermaidstate);
04557 
04558    return res;
04559 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 3969 of file features.c.

References load_config().

Referenced by handle_features_reload().

03970 {
03971    int res;
03972    /* Release parking lot list */
03973    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
03974    // TODO: I don't think any marking is necessary
03975 
03976    /* Reload configuration */
03977    res = load_config();
03978    
03979    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
03980    return res;
03981 }

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

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

01796 {
01797    int x;
01798    for (x = 0; x < FEATURES_COUNT; x++) {
01799       if (!strcasecmp(name, builtin_features[x].sname))
01800          return &builtin_features[x];
01801    }
01802    return NULL;
01803 }

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

References masq_park_call().

Referenced by handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().

00809 {
00810    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00811 }

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

References ast_park_call_full(), chan, and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

00743 {
00744    struct ast_park_call_args args = {
00745       .timeout = timeout,
00746       .extout = extout,
00747    };
00748 
00749    return ast_park_call_full(chan, peer, &args);
00750 }

static int ast_park_call_full ( struct ast_channel chan,
struct ast_channel peer,
struct ast_park_call_args args 
) [static]

Definition at line 604 of file features.c.

References adsi_announce_park(), adsipark, 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_CONTROL_RINGING, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RINGING, AST_PARK_OPT_SILENCE, ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_test_flag, 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, ast_park_call_args::extout, ast_channel::language, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_park_call_args::orig_chan_name, park_space_reserve(), parkedcall, ast_parkinglot::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, ast_parkinglot::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, ast_park_call_args::pu, registrar, ast_park_call_args::return_con, ast_park_call_args::return_ext, S_OR, parkeduser::start, ast_channel::tech, ast_park_call_args::timeout, ast_channel_tech::type, and ast_channel::uniqueid.

Referenced by ast_park_call(), and masq_park_call().

00605 {
00606    struct ast_context *con;
00607    int parkingnum_copy;
00608    struct parkeduser *pu = args->pu;
00609    const char *event_from;
00610 
00611    if (pu == NULL)
00612       pu = park_space_reserve(chan, peer, args);
00613    if (pu == NULL)
00614       return 1; /* Continue execution if possible */
00615 
00616    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
00617    
00618    chan->appl = "Parked Call";
00619    chan->data = NULL; 
00620 
00621    pu->chan = chan;
00622    
00623    /* Put the parked channel on hold if we have two different channels */
00624    if (chan != peer) {
00625       if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
00626          ast_indicate(pu->chan, AST_CONTROL_RINGING);
00627       } else {
00628          ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00629             S_OR(pu->parkinglot->mohclass, NULL),
00630             !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
00631       }
00632    }
00633    
00634    pu->start = ast_tvnow();
00635    pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime;
00636    parkingnum_copy = pu->parkingnum;
00637    if (args->extout)
00638       *(args->extout) = pu->parkingnum;
00639 
00640    if (peer) { 
00641       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
00642          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
00643          and we need the callback name to be that of transferer.  Since local,1/2 have the same
00644          name we can be tricky and just grab the bridged channel from the other side of the local
00645       */
00646       if (!strcasecmp(peer->tech->type, "Local")) {
00647          struct ast_channel *tmpchan, *base_peer;
00648          char other_side[AST_CHANNEL_NAME];
00649          char *c;
00650          ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side));
00651          if ((c = strrchr(other_side, ';'))) {
00652             *++c = '1';
00653          }
00654          if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00655             if ((base_peer = ast_bridged_channel(tmpchan))) {
00656                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00657             }
00658             ast_channel_unlock(tmpchan);
00659          }
00660       } else {
00661          ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername));
00662       }
00663    }
00664 
00665    /* Remember what had been dialed, so that if the parking
00666       expires, we try to come back to the same place */
00667    ast_copy_string(pu->context, 
00668       S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 
00669       sizeof(pu->context));
00670    ast_copy_string(pu->exten, 
00671       S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 
00672       sizeof(pu->exten));
00673    pu->priority = pu->priority ? pu->priority : 
00674       (chan->macropriority ? chan->macropriority : chan->priority);
00675 
00676    /* If parking a channel directly, don't quiet yet get parking running on it.
00677     * All parking lot entries are put into the parking lot with notquiteyet on. */
00678    if (peer != chan) 
00679       pu->notquiteyet = 0;
00680 
00681    /* Wake up the (presumably select()ing) thread */
00682    pthread_kill(parking_thread, SIGURG);
00683    ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00684 
00685    if (peer) {
00686       event_from = peer->name;
00687    } else {
00688       event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
00689    }
00690 
00691    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00692       "Exten: %s\r\n"
00693       "Channel: %s\r\n"
00694       "Parkinglot: %s\r\n"
00695       "From: %s\r\n"
00696       "Timeout: %ld\r\n"
00697       "CallerIDNum: %s\r\n"
00698       "CallerIDName: %s\r\n"
00699       "Uniqueid: %s\r\n",
00700       pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "",
00701       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00702       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00703       S_OR(pu->chan->cid.cid_name, "<unknown>"),
00704       pu->chan->uniqueid
00705       );
00706 
00707    if (peer && adsipark && ast_adsi_available(peer)) {
00708       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00709       ast_adsi_unload_session(peer);
00710    }
00711 
00712    con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar);
00713    if (!con)   /* Still no context? Bad */
00714       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con);
00715    if (con) {
00716       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
00717          notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE);
00718    }
00719 
00720    AST_LIST_UNLOCK(&pu->parkinglot->parkings);
00721 
00722    /* Only say number if it's a number and the channel hasn't been masqueraded away */
00723    if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
00724       /* 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. */
00725       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00726       /* Tell the peer channel the number of the parking space */
00727       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00728       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00729    }
00730    if (peer == chan) { /* pu->notquiteyet = 1 */
00731       /* Wake up parking thread if we're really done */
00732       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00733          S_OR(pu->parkinglot->mohclass, NULL),
00734          !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
00735       pu->notquiteyet = 0;
00736       pthread_kill(parking_thread, SIGURG);
00737    }
00738    return 0;
00739 }

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

References parking_ext.

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

00243 {
00244    return parking_ext;
00245 }

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

04354 {
04355    struct ast_channel *cur = NULL;
04356    int res = -1;
04357 
04358    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04359       if (!cur->pbx && 
04360          (cur != chan) &&
04361          (chan->pickupgroup & cur->callgroup) &&
04362          ((cur->_state == AST_STATE_RINGING) ||
04363           (cur->_state == AST_STATE_RING))) {
04364             break;
04365       }
04366       ast_channel_unlock(cur);
04367    }
04368    if (cur) {
04369       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04370       res = ast_answer(chan);
04371       if (res)
04372          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04373       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04374       if (res)
04375          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04376       res = ast_channel_masquerade(cur, chan);
04377       if (res)
04378          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04379       ast_channel_unlock(cur);
04380    } else   {
04381       ast_debug(1, "No call pickup possible...\n");
04382    }
04383    return res;
04384 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 247 of file features.c.

References pickup_ext.

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

00248 {
00249    return pickup_ext;
00250 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1785 of file features.c.

References ast_rwlock_rdlock(), and features_lock.

Referenced by handle_request_info().

01786 {
01787    ast_rwlock_rdlock(&features_lock);
01788 }

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

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

01623 {
01624    if (!feature) {
01625       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01626       return;
01627    }
01628   
01629    AST_RWLIST_WRLOCK(&feature_list);
01630    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01631    AST_RWLIST_UNLOCK(&feature_list);
01632 
01633    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01634 }

void ast_unlock_call_features ( void   ) 

Definition at line 1790 of file features.c.

References ast_rwlock_unlock(), and features_lock.

Referenced by handle_request_info().

01791 {
01792    ast_rwlock_unlock(&features_lock);
01793 }

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

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

01711 {
01712    if (!feature) {
01713       return;
01714    }
01715 
01716    AST_RWLIST_WRLOCK(&feature_list);
01717    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01718    AST_RWLIST_UNLOCK(&feature_list);
01719 
01720    ast_free(feature);
01721 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1724 of file features.c.

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

01725 {
01726    struct ast_call_feature *feature;
01727 
01728    AST_RWLIST_WRLOCK(&feature_list);
01729    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01730       ast_free(feature);
01731    }
01732    AST_RWLIST_UNLOCK(&feature_list);
01733 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

Definition at line 1750 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.

01751 {
01752    struct feature_group *fg;
01753    struct feature_group_exten *fge;
01754 
01755    AST_RWLIST_WRLOCK(&feature_groups);
01756    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
01757       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
01758          ast_string_field_free_memory(fge);
01759          ast_free(fge);
01760       }
01761 
01762       ast_string_field_free_memory(fg);
01763       ast_free(fg);
01764    }
01765    AST_RWLIST_UNLOCK(&feature_groups);
01766 }

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

04416 {
04417    struct ast_channel *current_dest_chan, *final_dest_chan;
04418    char *tmp_data  = NULL;
04419    struct ast_flags opts = { 0, };
04420    struct ast_bridge_config bconfig = { { 0, }, };
04421 
04422    AST_DECLARE_APP_ARGS(args,
04423       AST_APP_ARG(dest_chan);
04424       AST_APP_ARG(options);
04425    );
04426    
04427    if (ast_strlen_zero(data)) {
04428       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
04429       return -1;
04430    }
04431 
04432    tmp_data = ast_strdupa(data);
04433    AST_STANDARD_APP_ARGS(args, tmp_data);
04434    if (!ast_strlen_zero(args.options))
04435       ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options);
04436 
04437    /* avoid bridge with ourselves */
04438    if (!strncmp(chan->name, args.dest_chan, 
04439       strlen(chan->name) < strlen(args.dest_chan) ? 
04440       strlen(chan->name) : strlen(args.dest_chan))) {
04441       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
04442       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04443                "Response: Failed\r\n"
04444                "Reason: Unable to bridge channel to itself\r\n"
04445                "Channel1: %s\r\n"
04446                "Channel2: %s\r\n",
04447                chan->name, args.dest_chan);
04448       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
04449       return 0;
04450    }
04451 
04452    /* make sure we have a valid end point */
04453    if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 
04454       strlen(args.dest_chan)))) {
04455       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
04456          "cannot get its lock\n", args.dest_chan);
04457       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04458                "Response: Failed\r\n"
04459                "Reason: Cannot grab end point\r\n"
04460                "Channel1: %s\r\n"
04461                "Channel2: %s\r\n", chan->name, args.dest_chan);
04462       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
04463       return 0;
04464    }
04465 
04466    /* answer the channel if needed */
04467    if (current_dest_chan->_state != AST_STATE_UP)
04468       ast_answer(current_dest_chan);
04469 
04470    /* try to allocate a place holder where current_dest_chan will be placed */
04471    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04472       NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) {
04473       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
04474       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04475                "Response: Failed\r\n"
04476                "Reason: cannot create placeholder\r\n"
04477                "Channel1: %s\r\n"
04478                "Channel2: %s\r\n", chan->name, args.dest_chan);
04479    }
04480    do_bridge_masquerade(current_dest_chan, final_dest_chan);
04481 
04482    ast_channel_unlock(current_dest_chan);
04483 
04484    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
04485    /* try to make compatible, send error if we fail */
04486    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
04487       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
04488       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04489                "Response: Failed\r\n"
04490                "Reason: Could not make channels compatible for bridge\r\n"
04491                "Channel1: %s\r\n"
04492                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04493       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
04494       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
04495       return 0;
04496    }
04497 
04498    /* Report that the bridge will be successfull */
04499    manager_event(EVENT_FLAG_CALL, "BridgeExec",
04500             "Response: Success\r\n"
04501             "Channel1: %s\r\n"
04502             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04503 
04504    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
04505    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
04506       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
04507          if (ast_waitstream(final_dest_chan, "") < 0)
04508             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
04509       }
04510    }
04511    
04512    /* do the bridge */
04513    ast_bridge_call(chan, final_dest_chan, &bconfig);
04514 
04515    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
04516    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
04517    if (!ast_check_hangup(final_dest_chan)) {
04518       ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 
04519          final_dest_chan->context, final_dest_chan->exten, 
04520          final_dest_chan->priority, final_dest_chan->name);
04521 
04522       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
04523          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
04524          ast_hangup(final_dest_chan);
04525       } else
04526          ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
04527    } else {
04528       ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name);
04529       ast_hangup(final_dest_chan);
04530    }
04531 
04532    return 0;
04533 }

static struct ast_parkinglot* build_parkinglot ( char *  name,
struct ast_variable var 
) [static]

Build parkinglot from configuration and chain it in.

Definition at line 3450 of file features.c.

References ao2_link, ao2_lock(), ao2_unlock(), ast_add_extension2(), ast_context_find_or_create(), ast_copy_string(), ast_free_ptr, ast_log(), ast_parking_ext(), ast_strlen_zero(), create_parkinglot(), DEFAULT_PARK_TIME, find_parkinglot(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, option_debug, parkcall, parkinglot, parkinglot_destroy(), parkinglot_unref(), parkinglots, registrar, strdup, ast_variable::value, and var.

Referenced by load_config().

03451 {
03452    struct ast_parkinglot *parkinglot;
03453    struct ast_context *con = NULL;
03454 
03455    struct ast_variable *confvar = var;
03456    int error = 0;
03457    int start = 0, end = 0;
03458    int oldparkinglot = 0;
03459 
03460    parkinglot = find_parkinglot(name);
03461    if (parkinglot)
03462       oldparkinglot = 1;
03463    else
03464       parkinglot = create_parkinglot(name);
03465 
03466    if (!parkinglot)
03467       return NULL;
03468 
03469    ao2_lock(parkinglot);
03470 
03471    if (option_debug)
03472       ast_log(LOG_DEBUG, "Building parking lot %s\n", name);
03473    
03474    /* Do some config stuff */
03475    while(confvar) {
03476       if (!strcasecmp(confvar->name, "context")) {
03477          ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
03478       } else if (!strcasecmp(confvar->name, "parkingtime")) {
03479          if ((sscanf(confvar->value, "%d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
03480             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
03481             parkinglot->parkingtime = DEFAULT_PARK_TIME;
03482          } else
03483             parkinglot->parkingtime = parkinglot->parkingtime * 1000;
03484       } else if (!strcasecmp(confvar->name, "parkpos")) {
03485          if (sscanf(confvar->value, "%d-%d", &start, &end) != 2) {
03486             ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", confvar->lineno);
03487             error = 1;
03488          } else {
03489             parkinglot->parking_start = start;
03490             parkinglot->parking_stop = end;
03491          }
03492       } else if (!strcasecmp(confvar->name, "findslot")) {
03493          parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next"));
03494       }
03495       confvar = confvar->next;
03496    }
03497    /* make sure parkingtime is set if not specified */
03498    if (parkinglot->parkingtime == 0) {
03499       parkinglot->parkingtime = DEFAULT_PARK_TIME;
03500    }
03501 
03502    if (!var) { /* Default parking lot */
03503       ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
03504       ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial));
03505       ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass));
03506    }
03507 
03508    /* Check for errors */
03509    if (ast_strlen_zero(parkinglot->parking_con)) {
03510       ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name);
03511       error = 1;
03512    }
03513 
03514    /* Create context */
03515    if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) {
03516       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
03517       error = 1;
03518    }
03519 
03520    /* Add a parking extension into the context */
03521    if (!oldparkinglot) {
03522       if (!ast_strlen_zero(ast_parking_ext())) {
03523          if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
03524             error = 1;
03525       }
03526    }
03527 
03528    ao2_unlock(parkinglot);
03529 
03530    if (error) {
03531       ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
03532       parkinglot_destroy(parkinglot);
03533       return NULL;
03534    }
03535    if (option_debug)
03536       ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
03537 
03538 
03539    /* Move it into the list, if it wasn't already there */
03540    if (!oldparkinglot) {
03541       ao2_link(parkinglots, parkinglot);
03542    }
03543    parkinglot_unref(parkinglot);
03544 
03545    return parkinglot;
03546 }

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 1307 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_FEATURE_RETURN_SUCCESS, 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(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, 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, 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, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xferfailsound, and xfersound.

01308 {
01309    struct ast_channel *transferer;
01310    struct ast_channel *transferee;
01311    const char *transferer_real_context;
01312    char xferto[256] = "";
01313    int res;
01314    int outstate=0;
01315    struct ast_channel *newchan;
01316    struct ast_channel *xferchan;
01317    struct ast_bridge_thread_obj *tobj;
01318    struct ast_bridge_config bconfig;
01319    struct ast_frame *f;
01320    int l;
01321    struct ast_datastore *features_datastore;
01322    struct ast_dial_features *dialfeatures = NULL;
01323 
01324    ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
01325    set_peers(&transferer, &transferee, peer, chan, sense);
01326    transferer_real_context = real_ctx(transferer, transferee);
01327    /* Start autoservice on chan while we talk to the originator */
01328    ast_autoservice_start(transferee);
01329    ast_indicate(transferee, AST_CONTROL_HOLD);
01330    
01331    /* Transfer */
01332    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01333    if (res < 0) {
01334       finishup(transferee);
01335       return res;
01336    }
01337    if (res > 0) /* If they've typed a digit already, handle it */
01338       xferto[0] = (char) res;
01339 
01340    /* this is specific of atxfer */
01341    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01342    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
01343       finishup(transferee);
01344       return res;
01345    }
01346    if (res == 0) {
01347       ast_log(LOG_WARNING, "Did not read data.\n");
01348       finishup(transferee);
01349       if (ast_stream_and_wait(transferer, "beeperr", ""))
01350          return -1;
01351       return AST_FEATURE_RETURN_SUCCESS;
01352    }
01353 
01354    /* valid extension, res == 1 */
01355    if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01356       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
01357       finishup(transferee);
01358       if (ast_stream_and_wait(transferer, "beeperr", ""))
01359          return -1;
01360       return AST_FEATURE_RETURN_SUCCESS;
01361    }
01362 
01363    /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of
01364     * the different variables for handling this properly with a builtin_atxfer */
01365    if (!strcmp(xferto, ast_parking_ext())) {
01366       finishup(transferee);
01367       return builtin_parkcall(chan, peer, config, code, sense, data);
01368    }
01369 
01370    l = strlen(xferto);
01371    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);   /* append context */
01372 
01373    /* If we are performing an attended transfer and we have two channels involved then
01374       copy sound file information to play upon attended transfer completion */
01375    if (transferee) {
01376       const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
01377       const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
01378 
01379       if (!ast_strlen_zero(chan1_attended_sound)) {
01380          pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
01381       }
01382       if (!ast_strlen_zero(chan2_attended_sound)) {
01383          pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
01384       }
01385    }
01386 
01387    newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01388       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01389 
01390    if (!ast_check_hangup(transferer)) {
01391       /* Transferer is up - old behaviour */
01392       ast_indicate(transferer, -1);
01393       if (!newchan) {
01394          finishup(transferee);
01395          /* any reason besides user requested cancel and busy triggers the failed sound */
01396          if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
01397             ast_stream_and_wait(transferer, xferfailsound, ""))
01398             return -1;
01399          if (ast_stream_and_wait(transferer, xfersound, ""))
01400             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01401          return AST_FEATURE_RETURN_SUCCESS;
01402       }
01403 
01404       if (check_compat(transferer, newchan)) {
01405          /* we do mean transferee here, NOT transferer */
01406          finishup(transferee);
01407          return -1;
01408       }
01409       memset(&bconfig,0,sizeof(struct ast_bridge_config));
01410       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
01411       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
01412       res = ast_bridge_call(transferer, newchan, &bconfig);
01413       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
01414          ast_hangup(newchan);
01415          if (ast_stream_and_wait(transferer, xfersound, ""))
01416             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01417          finishup(transferee);
01418          transferer->_softhangup = 0;
01419          return AST_FEATURE_RETURN_SUCCESS;
01420       }
01421       if (check_compat(transferee, newchan)) {
01422          finishup(transferee);
01423          return -1;
01424       }
01425       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01426 
01427       if ((ast_autoservice_stop(transferee) < 0)
01428        || (ast_waitfordigit(transferee, 100) < 0)
01429        || (ast_waitfordigit(newchan, 100) < 0)
01430        || ast_check_hangup(transferee)
01431        || ast_check_hangup(newchan)) {
01432          ast_hangup(newchan);
01433          return -1;
01434       }
01435       xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01436       if (!xferchan) {
01437          ast_hangup(newchan);
01438          return -1;
01439       }
01440       /* Make formats okay */
01441       xferchan->visible_indication = transferer->visible_indication;
01442       xferchan->readformat = transferee->readformat;
01443       xferchan->writeformat = transferee->writeformat;
01444       ast_channel_masquerade(xferchan, transferee);
01445       ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01446       xferchan->_state = AST_STATE_UP;
01447       ast_clear_flag(xferchan, AST_FLAGS_ALL);
01448       xferchan->_softhangup = 0;
01449       if ((f = ast_read(xferchan)))
01450          ast_frfree(f);
01451       newchan->_state = AST_STATE_UP;
01452       ast_clear_flag(newchan, AST_FLAGS_ALL);
01453       newchan->_softhangup = 0;
01454       if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01455          ast_hangup(xferchan);
01456          ast_hangup(newchan);
01457          return -1;
01458       }
01459 
01460       ast_channel_lock(newchan);
01461       if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
01462             dialfeatures = features_datastore->data;
01463       }
01464       ast_channel_unlock(newchan);
01465 
01466       if (dialfeatures) {
01467          /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
01468             I don't currently understand, the abilities of newchan seem to be stored on the caller side */
01469          ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01470          dialfeatures = NULL;
01471       }
01472 
01473       ast_channel_lock(xferchan);
01474       if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
01475          dialfeatures = features_datastore->data;
01476       }
01477       ast_channel_unlock(xferchan);
01478     
01479       if (dialfeatures) {
01480          ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01481       }
01482     
01483       tobj->chan = newchan;
01484       tobj->peer = xferchan;
01485       tobj->bconfig = *config;
01486 
01487       if (tobj->bconfig.end_bridge_callback_data_fixup) {
01488          tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01489       }
01490 
01491       if (ast_stream_and_wait(newchan, xfersound, ""))
01492          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01493       ast_bridge_call_thread_launch(tobj);
01494       return -1;      /* XXX meaning the channel is bridged ? */
01495    } else if (!ast_check_hangup(transferee)) {
01496       /* act as blind transfer */
01497       if (ast_autoservice_stop(transferee) < 0) {
01498          ast_hangup(newchan);
01499          return -1;
01500       }
01501 
01502       if (!newchan) {
01503          unsigned int tries = 0;
01504          char *transferer_tech, *transferer_name = ast_strdupa(transferer->name);
01505 
01506          transferer_tech = strsep(&transferer_name, "/");
01507          transferer_name = strsep(&transferer_name, "-");
01508 
01509          if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
01510             ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name);
01511             if (ast_stream_and_wait(transferee, "beeperr", ""))
01512                return -1;
01513             return AST_FEATURE_RETURN_SUCCESS;
01514          }
01515 
01516          ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name);
01517          newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01518             transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01519          while (!newchan && !atxferdropcall && tries < atxfercallbackretries) {
01520             /* Trying to transfer again */
01521             ast_autoservice_start(transferee);
01522             ast_indicate(transferee, AST_CONTROL_HOLD);
01523 
01524             newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01525                xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01526             if (ast_autoservice_stop(transferee) < 0) {
01527                if (newchan)
01528                   ast_hangup(newchan);
01529                return -1;
01530             }
01531             if (!newchan) {
01532                /* Transfer failed, sleeping */
01533                ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay);
01534                ast_safe_sleep(transferee, atxferloopdelay);
01535                ast_debug(1, "Trying to callback...\n");
01536                newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01537                   transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01538             }
01539             tries++;
01540          }
01541       }
01542       if (!newchan)
01543          return -1;
01544 
01545       /* newchan is up, we should prepare transferee and bridge them */
01546       if (check_compat(transferee, newchan)) {
01547          finishup(transferee);
01548          return -1;
01549       }
01550       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01551 
01552       if ((ast_waitfordigit(transferee, 100) < 0)
01553          || (ast_waitfordigit(newchan, 100) < 0)
01554          || ast_check_hangup(transferee)
01555          || ast_check_hangup(newchan)) {
01556          ast_hangup(newchan);
01557          return -1;
01558       }
01559 
01560       xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01561       if (!xferchan) {
01562          ast_hangup(newchan);
01563          return -1;
01564       }
01565       /* Make formats okay */
01566       xferchan->visible_indication = transferer->visible_indication;
01567       xferchan->readformat = transferee->readformat;
01568       xferchan->writeformat = transferee->writeformat;
01569       ast_channel_masquerade(xferchan, transferee);
01570       ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01571       xferchan->_state = AST_STATE_UP;
01572       ast_clear_flag(xferchan, AST_FLAGS_ALL);
01573       xferchan->_softhangup = 0;
01574       if ((f = ast_read(xferchan)))
01575          ast_frfree(f);
01576       newchan->_state = AST_STATE_UP;
01577       ast_clear_flag(newchan, AST_FLAGS_ALL);
01578       newchan->_softhangup = 0;
01579       if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01580          ast_hangup(xferchan);
01581          ast_hangup(newchan);
01582          return -1;
01583       }
01584       tobj->chan = newchan;
01585       tobj->peer = xferchan;
01586       tobj->bconfig = *config;
01587 
01588       if (tobj->bconfig.end_bridge_callback_data_fixup) {
01589          tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01590       }
01591 
01592       if (ast_stream_and_wait(newchan, xfersound, ""))
01593          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01594       ast_bridge_call_thread_launch(tobj);
01595       return -1;      /* XXX meaning the channel is bridged ? */
01596    } else {
01597       /* Transferee hung up */
01598       finishup(transferee);
01599       return -1;
01600    }
01601 }

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 1016 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_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, courtesytone, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), stopmixmonitor_app, and stopmixmonitor_ok.

01017 {
01018    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01019    int x = 0;
01020    size_t len;
01021    struct ast_channel *caller_chan, *callee_chan;
01022    const char *mixmonitor_spy_type = "MixMonitor";
01023    int count = 0;
01024 
01025    if (!mixmonitor_ok) {
01026       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01027       return -1;
01028    }
01029 
01030    if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
01031       mixmonitor_ok = 0;
01032       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01033       return -1;
01034    }
01035 
01036    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01037 
01038    if (!ast_strlen_zero(courtesytone)) {
01039       if (ast_autoservice_start(callee_chan))
01040          return -1;
01041       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
01042          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01043          ast_autoservice_stop(callee_chan);
01044          return -1;
01045       }
01046       if (ast_autoservice_stop(callee_chan))
01047          return -1;
01048    }
01049 
01050    ast_channel_lock(callee_chan);
01051    count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01052    ast_channel_unlock(callee_chan);
01053 
01054    /* This means a mixmonitor is attached to the channel, running or not is unknown. */
01055    if (count > 0) {
01056       
01057       ast_verb(3, "User hit '%s' to stop recording call.\n", code);
01058 
01059       /* Make sure they are running */
01060       ast_channel_lock(callee_chan);
01061       count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01062       ast_channel_unlock(callee_chan);
01063       if (count > 0) {
01064          if (!stopmixmonitor_ok) {
01065             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01066             return -1;
01067          }
01068          if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
01069             stopmixmonitor_ok = 0;
01070             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01071             return -1;
01072          } else {
01073             pbx_exec(callee_chan, stopmixmonitor_app, "");
01074             return AST_FEATURE_RETURN_SUCCESS;
01075          }
01076       }
01077       
01078       ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 
01079    }        
01080 
01081    if (caller_chan && callee_chan) {
01082       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
01083       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
01084 
01085       if (!touch_format)
01086          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
01087 
01088       if (!touch_monitor)
01089          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
01090 
01091       if (touch_monitor) {
01092          len = strlen(touch_monitor) + 50;
01093          args = alloca(len);
01094          touch_filename = alloca(len);
01095          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
01096          snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
01097       } else {
01098          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
01099          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
01100          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01101          args = alloca(len);
01102          touch_filename = alloca(len);
01103          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
01104          snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
01105       }
01106 
01107       for( x = 0; x < strlen(args); x++) {
01108          if (args[x] == '/')
01109             args[x] = '-';
01110       }
01111 
01112       ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
01113 
01114       pbx_exec(callee_chan, mixmonitor_app, args);
01115       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01116       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01117       return AST_FEATURE_RETURN_SUCCESS;
01118    
01119    }
01120 
01121    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
01122    return -1;
01123 
01124 }

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:
AST_FEATURE_RETURN_SUCCESS on success.
-1 on error.

Definition at line 923 of file features.c.

References AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, courtesytone, len(), LOG_ERROR, LOG_NOTICE, ast_channel::monitor, monitor_app, monitor_ok, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_OR, set_peers(), and ast_channel_monitor::stop.

00924 {
00925    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00926    int x = 0;
00927    size_t len;
00928    struct ast_channel *caller_chan, *callee_chan;
00929    const char *automon_message_start = NULL;
00930    const char *automon_message_stop = NULL;
00931 
00932    if (!monitor_ok) {
00933       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00934       return -1;
00935    }
00936 
00937    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00938       monitor_ok = 0;
00939       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00940       return -1;
00941    }
00942 
00943    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00944    if (caller_chan) {   /* Find extra messages */
00945       automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
00946       automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
00947    }
00948 
00949    if (!ast_strlen_zero(courtesytone)) {  /* Play courtesy tone if configured */
00950       if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
00951          return -1;
00952       }
00953    }
00954    
00955    if (callee_chan->monitor) {
00956       ast_verb(4, "User hit '%s' to stop recording call.\n", code);
00957       if (!ast_strlen_zero(automon_message_stop)) {
00958          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
00959       }
00960       callee_chan->monitor->stop(callee_chan, 1);
00961       return AST_FEATURE_RETURN_SUCCESS;
00962    }
00963 
00964    if (caller_chan && callee_chan) {
00965       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00966       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00967       const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
00968 
00969       if (!touch_format)
00970          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00971 
00972       if (!touch_monitor)
00973          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00974    
00975       if (!touch_monitor_prefix)
00976          touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
00977    
00978       if (touch_monitor) {
00979          len = strlen(touch_monitor) + 50;
00980          args = alloca(len);
00981          touch_filename = alloca(len);
00982          snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
00983          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
00984       } else {
00985          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00986          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00987          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00988          args = alloca(len);
00989          touch_filename = alloca(len);
00990          snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
00991          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
00992       }
00993 
00994       for(x = 0; x < strlen(args); x++) {
00995          if (args[x] == '/')
00996             args[x] = '-';
00997       }
00998       
00999       ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
01000 
01001       pbx_exec(callee_chan, monitor_app, args);
01002       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01003       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01004 
01005       if (!ast_strlen_zero(automon_message_start)) {  /* Play start message for both channels */
01006          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
01007       }
01008    
01009       return AST_FEATURE_RETURN_SUCCESS;
01010    }
01011    
01012    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
01013    return -1;
01014 }

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:
AST_FEATURE_RETURN_SUCCESS. 
-1 on failure.

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

Definition at line 1176 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_FEATURE_RETURN_PARKFAILED, AST_FEATURE_RETURN_SUCCESS, 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, 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(), set_peers(), transferdigittimeout, and xferfailsound.

01177 {
01178    struct ast_channel *transferer;
01179    struct ast_channel *transferee;
01180    const char *transferer_real_context;
01181    char xferto[256];
01182    int res, parkstatus = 0;
01183 
01184    set_peers(&transferer, &transferee, peer, chan, sense);
01185    transferer_real_context = real_ctx(transferer, transferee);
01186    /* Start autoservice on chan while we talk to the originator */
01187    ast_autoservice_start(transferee);
01188    ast_indicate(transferee, AST_CONTROL_HOLD);
01189 
01190    memset(xferto, 0, sizeof(xferto));
01191 
01192    /* Transfer */
01193    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01194    if (res < 0) {
01195       finishup(transferee);
01196       return -1; /* error ? */
01197    }
01198    if (res > 0)   /* If they've typed a digit already, handle it */
01199       xferto[0] = (char) res;
01200 
01201    ast_stopstream(transferer);
01202    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01203    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
01204       finishup(transferee);
01205       return res;
01206    }
01207    if (!strcmp(xferto, ast_parking_ext())) {
01208       res = finishup(transferee);
01209       if (res)
01210          res = -1;
01211       else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) {   /* success */
01212          /* We return non-zero, but tell the PBX not to hang the channel when
01213             the thread dies -- We have to be careful now though.  We are responsible for 
01214             hanging up the channel, else it will never be hung up! */
01215 
01216          return 0;
01217       } else {
01218          ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01219       }
01220       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
01221    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01222       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01223       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01224       res=finishup(transferee);
01225       if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
01226          transferer->cdr=ast_cdr_alloc();
01227          if (transferer->cdr) {
01228             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
01229             ast_cdr_start(transferer->cdr);
01230          }
01231       }
01232       if (transferer->cdr) {
01233          struct ast_cdr *swap = transferer->cdr;
01234          ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01235                transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 
01236                transferer->cdr->channel, transferer->cdr->dstchannel);
01237          ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01238                transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01239          ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01240          /* swap cdrs-- it will save us some time & work */
01241          transferer->cdr = transferee->cdr;
01242          transferee->cdr = swap;
01243       }
01244       if (!transferee->pbx) {
01245          /* Doh!  Use our handy async_goto functions */
01246          ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01247                         ,transferee->name, xferto, transferer_real_context);
01248          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01249             ast_log(LOG_WARNING, "Async goto failed :-(\n");
01250       } else {
01251          /* Set the channel's new extension, since it exists, using transferer context */
01252          ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
01253          ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01254          set_c_e_p(transferee, transferer_real_context, xferto, 0);
01255       }
01256       check_goto_on_transfer(transferer);
01257       return res;
01258    } else {
01259       ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
01260    }
01261    if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
01262       finishup(transferee);
01263       return -1;
01264    }
01265    ast_stopstream(transferer);
01266    res = finishup(transferee);
01267    if (res) {
01268       ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01269       return res;
01270    }
01271    return AST_FEATURE_RETURN_SUCCESS;
01272 }

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

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

01127 {
01128    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
01129    return AST_FEATURE_RETURN_HANGUP;
01130 }

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

00854 {
00855    struct ast_channel *parker;
00856    struct ast_channel *parkee;
00857    int res = 0;
00858 
00859    set_peers(&parker, &parkee, peer, chan, sense);
00860    /* we used to set chan's exten and priority to "s" and 1
00861       here, but this generates (in some cases) an invalid
00862       extension, and if "s" exists, could errantly
00863       cause execution of extensions you don't expect. It
00864       makes more sense to let nature take its course
00865       when chan finishes, and let the pbx do its thing
00866       and hang up when the park is over.
00867    */
00868    if (chan->_state != AST_STATE_UP)
00869       res = ast_answer(chan);
00870    if (!res)
00871       res = ast_safe_sleep(chan, 1000);
00872 
00873    if (!res) { /* one direction used to call park_call.... */
00874       res = masq_park_call_announce(parkee, parker, 0, NULL);
00875       /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
00876    }
00877 
00878    return res;
00879 }

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

Definition at line 2870 of file features.c.

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

Referenced by manage_parkinglot().

02871 {
02872    int i = 0;
02873    enum {
02874       OPT_CALLEE_REDIRECT   = 't',
02875       OPT_CALLER_REDIRECT   = 'T',
02876       OPT_CALLEE_AUTOMON    = 'w',
02877       OPT_CALLER_AUTOMON    = 'W',
02878       OPT_CALLEE_DISCONNECT = 'h',
02879       OPT_CALLER_DISCONNECT = 'H',
02880       OPT_CALLEE_PARKCALL   = 'k',
02881       OPT_CALLER_PARKCALL   = 'K',
02882    };
02883 
02884    memset(options, 0, len);
02885    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02886       options[i++] = OPT_CALLER_REDIRECT;
02887    }
02888    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02889       options[i++] = OPT_CALLER_AUTOMON;
02890    }
02891    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02892       options[i++] = OPT_CALLER_DISCONNECT;
02893    }
02894    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02895       options[i++] = OPT_CALLER_PARKCALL;
02896    }
02897 
02898    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02899       options[i++] = OPT_CALLEE_REDIRECT;
02900    }
02901    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02902       options[i++] = OPT_CALLEE_AUTOMON;
02903    }
02904    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02905       options[i++] = OPT_CALLEE_DISCONNECT;
02906    }
02907    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02908       options[i++] = OPT_CALLEE_PARKCALL;
02909    }
02910 
02911    return options;
02912 }

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

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

Referenced by builtin_atxfer().

01282 {
01283    if (ast_channel_make_compatible(c, newchan) < 0) {
01284       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01285          c->name, newchan->name);
01286       ast_hangup(newchan);
01287       return -1;
01288    }
01289    return 0;
01290 }

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

00294 {
00295    struct ast_channel *xferchan;
00296    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00297    char *x, *goto_on_transfer;
00298    struct ast_frame *f;
00299 
00300    if (ast_strlen_zero(val))
00301       return;
00302 
00303    goto_on_transfer = ast_strdupa(val);
00304 
00305    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name)))
00306       return;
00307 
00308    for (x = goto_on_transfer; x && *x; x++) {
00309       if (*x == '^')
00310          *x = '|';
00311    }
00312    /* Make formats okay */
00313    xferchan->readformat = chan->readformat;
00314    xferchan->writeformat = chan->writeformat;
00315    ast_channel_masquerade(xferchan, chan);
00316    ast_parseable_goto(xferchan, goto_on_transfer);
00317    xferchan->_state = AST_STATE_UP;
00318    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00319    xferchan->_softhangup = 0;
00320    if ((f = ast_read(xferchan))) {
00321       ast_frfree(f);
00322       f = NULL;
00323       ast_pbx_start(xferchan);
00324    } else {
00325       ast_hangup(xferchan);
00326    }
00327 }

static struct ast_parkinglot* create_parkinglot ( char *  name  )  [static]

Allocate parking lot structure.

Definition at line 3422 of file features.c.

References ao2_alloc, ast_copy_string(), and parkinglot_destroy().

Referenced by build_parkinglot().

03423 {
03424    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
03425 
03426    if (!name)
03427       return NULL;
03428 
03429    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
03430    if (!newlot)
03431       return NULL;
03432    
03433    ast_copy_string(newlot->name, name, sizeof(newlot->name));
03434 
03435    return newlot;
03436 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 220 of file features.c.

References ast_free.

00221  {
00222    struct ast_dial_features *df = data;
00223    if (df) {
00224       ast_free(df);
00225    }
00226  }

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

Definition at line 207 of file features.c.

References ast_calloc.

00208 {
00209    struct ast_dial_features *df = data, *df_copy;
00210  
00211    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00212       return NULL;
00213    }
00214  
00215    memcpy(df_copy, df, sizeof(*df));
00216  
00217    return df_copy;
00218  }

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

04017 {
04018    ast_moh_stop(chan);
04019    ast_channel_lock(chan);
04020    ast_setstate(tmpchan, chan->_state);
04021    tmpchan->readformat = chan->readformat;
04022    tmpchan->writeformat = chan->writeformat;
04023    ast_channel_masquerade(tmpchan, chan);
04024    ast_channel_lock(tmpchan);
04025    ast_do_masquerade(tmpchan);
04026    /* when returning from bridge, the channel will continue at the next priority */
04027    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
04028    ast_channel_unlock(tmpchan);
04029    ast_channel_unlock(chan);
04030 }

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

Definition at line 3090 of file features.c.

References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_samp2tv(), ast_select(), manage_parkinglot(), and parkinglots.

Referenced by ast_features_init().

03091 {
03092    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
03093    fd_set nrfds, nefds; /* args for the next select */
03094    FD_ZERO(&rfds);
03095    FD_ZERO(&efds);
03096 
03097    for (;;) {
03098       int res = 0;
03099       int ms = -1;   /* select timeout, uninitialized */
03100       int max = -1;  /* max fd, none there yet */
03101       struct ao2_iterator iter;
03102       struct ast_parkinglot *curlot;
03103       FD_ZERO(&nrfds);
03104       FD_ZERO(&nefds);
03105       iter = ao2_iterator_init(parkinglots, 0);
03106 
03107       while ((curlot = ao2_iterator_next(&iter))) {
03108          res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max);
03109          ao2_ref(curlot, -1);
03110       }
03111 
03112       rfds = nrfds;
03113       efds = nefds;
03114       {
03115          struct timeval wait = ast_samp2tv(ms, 1000);
03116          /* Wait for something to happen */
03117          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
03118       }
03119       pthread_testcancel();
03120    }
03121    return NULL;   /* Never reached */
03122 }

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:
AST_FEATURE_RETURN_NO_HANGUP_PEER 
-1 error.
-2 when an application cannot be found.

Todo:
XXX should probably return res

Definition at line 1814 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_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, chan, feature_group_exten::feature, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().

01815 {
01816    struct ast_app *app;
01817    struct ast_call_feature *feature = data;
01818    struct ast_channel *work, *idle;
01819    int res;
01820 
01821    if (!feature) { /* shouldn't ever happen! */
01822       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01823       return -1; 
01824    }
01825 
01826    if (sense == FEATURE_SENSE_CHAN) {
01827       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01828          return AST_FEATURE_RETURN_KEEPTRYING;
01829       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01830          work = chan;
01831          idle = peer;
01832       } else {
01833          work = peer;
01834          idle = chan;
01835       }
01836    } else {
01837       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01838          return AST_FEATURE_RETURN_KEEPTRYING;
01839       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01840          work = peer;
01841          idle = chan;
01842       } else {
01843          work = chan;
01844          idle = peer;
01845       }
01846    }
01847 
01848    if (!(app = pbx_findapp(feature->app))) {
01849       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01850       return -2;
01851    }
01852 
01853    ast_autoservice_start(idle);
01854    
01855    if (!ast_strlen_zero(feature->moh_class))
01856       ast_moh_start(idle, feature->moh_class, NULL);
01857 
01858    res = pbx_exec(work, app, feature->app_args);
01859 
01860    if (!ast_strlen_zero(feature->moh_class))
01861       ast_moh_stop(idle);
01862 
01863    ast_autoservice_stop(idle);
01864 
01865    if (res) {
01866       return AST_FEATURE_RETURN_SUCCESSBREAK;
01867    }
01868    return AST_FEATURE_RETURN_SUCCESS;  /*! \todo XXX should probably return res */
01869 }

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

01912 {
01913    int x;
01914    struct feature_group *fg = NULL;
01915    struct feature_group_exten *fge;
01916    struct ast_call_feature *tmpfeature;
01917    char *tmp, *tok;
01918    int res = AST_FEATURE_RETURN_PASSDIGITS;
01919    int feature_detected = 0;
01920 
01921    if (!(peer && chan && config) && operation) {
01922       return -1; /* can not run feature operation */
01923    }
01924 
01925    ast_rwlock_rdlock(&features_lock);
01926    for (x = 0; x < FEATURES_COUNT; x++) {
01927       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
01928           !ast_strlen_zero(builtin_features[x].exten)) {
01929          /* Feature is up for consideration */
01930          if (!strcmp(builtin_features[x].exten, code)) {
01931             ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
01932             if (operation) {
01933                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01934             }
01935             memcpy(feature, &builtin_features[x], sizeof(feature));
01936             feature_detected = 1;
01937             break;
01938          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01939             if (res == AST_FEATURE_RETURN_PASSDIGITS)
01940                res = AST_FEATURE_RETURN_STOREDIGITS;
01941          }
01942       }
01943    }
01944    ast_rwlock_unlock(&features_lock);
01945 
01946    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
01947       return res;
01948    }
01949 
01950    tmp = dynamic_features_buf;
01951 
01952    while ((tok = strsep(&tmp, "#"))) {
01953       AST_RWLIST_RDLOCK(&feature_groups);
01954 
01955       fg = find_group(tok);
01956 
01957       if (fg) {
01958          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
01959             if (strcasecmp(fge->exten, code))
01960                continue;
01961             if (operation) {
01962                res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
01963             }
01964             memcpy(feature, fge->feature, sizeof(feature));
01965             if (res != AST_FEATURE_RETURN_KEEPTRYING) {
01966                AST_RWLIST_UNLOCK(&feature_groups);
01967                break;
01968             }
01969             res = AST_FEATURE_RETURN_PASSDIGITS;
01970          }
01971          if (fge)
01972             break;
01973       }
01974 
01975       AST_RWLIST_UNLOCK(&feature_groups);
01976 
01977       AST_RWLIST_RDLOCK(&feature_list);
01978 
01979       if (!(tmpfeature = find_dynamic_feature(tok))) {
01980          AST_RWLIST_UNLOCK(&feature_list);
01981          continue;
01982       }
01983 
01984       /* Feature is up for consideration */
01985       if (!strcmp(tmpfeature->exten, code)) {
01986          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
01987          if (operation) {
01988             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
01989          }
01990          memcpy(feature, tmpfeature, sizeof(feature));
01991          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
01992             AST_RWLIST_UNLOCK(&feature_list);
01993             break;
01994          }
01995          res = AST_FEATURE_RETURN_PASSDIGITS;
01996       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
01997          res = AST_FEATURE_RETURN_STOREDIGITS;
01998 
01999       AST_RWLIST_UNLOCK(&feature_list);
02000    }
02001 
02002    return res;
02003 }

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

find a call feature by name

Definition at line 1736 of file features.c.

References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.

Referenced by feature_interpret_helper(), and set_config_flags().

01737 {
01738    struct ast_call_feature *tmp;
01739 
01740    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01741       if (!strcasecmp(tmp->sname, name)) {
01742          break;
01743       }
01744    }
01745 
01746    return tmp;
01747 }

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

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

Referenced by feature_interpret_helper().

01774                                                           {
01775    struct feature_group *fg = NULL;
01776 
01777    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
01778       if (!strcasecmp(fg->gname, name))
01779          break;
01780    }
01781 
01782    return fg;
01783 }

struct ast_parkinglot * find_parkinglot ( const char *  name  ) 

Find parkinglot by name.

Definition at line 3125 of file features.c.

References ao2_find, ast_copy_string(), ast_log(), ast_strlen_zero(), LOG_DEBUG, ast_parkinglot::name, OBJ_POINTER, option_debug, parkinglot, and parkinglots.

Referenced by build_parkinglot(), park_exec_full(), and park_space_reserve().

03126 {
03127    struct ast_parkinglot *parkinglot = NULL;
03128    struct ast_parkinglot tmp_parkinglot;
03129    
03130    if (ast_strlen_zero(name))
03131       return NULL;
03132 
03133    ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
03134 
03135    parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
03136 
03137    if (parkinglot && option_debug)
03138       ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
03139 
03140    return parkinglot;
03141 }

static const char* findparkinglotname ( struct ast_channel chan  )  [static]

Find parking lot name from channel.

Definition at line 420 of file features.c.

References ast_strlen_zero(), chan, ast_channel::parkinglot, parkinglot, and pbx_builtin_getvar_helper().

Referenced by park_exec_full(), and park_space_reserve().

00421 {
00422    const char *temp, *parkinglot = NULL;
00423 
00424    /* Check if the channel has a parking lot */
00425    if (!ast_strlen_zero(chan->parkinglot))
00426       parkinglot = chan->parkinglot;
00427 
00428    /* Channel variables override everything */
00429 
00430    if ((temp  = pbx_builtin_getvar_helper(chan, "PARKINGLOT")))
00431       return temp;
00432 
00433    return parkinglot;
00434 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 1132 of file features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

01133 {
01134    ast_indicate(chan, AST_CONTROL_UNHOLD);
01135 
01136    return ast_autoservice_stop(chan);
01137 }

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

References ao2_iterator_init(), ao2_iterator_next, ao2_ref, 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, ast_parkinglot::name, ast_parkinglot::parking_con, parking_ext, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglots, ast_call_feature::sname, and ast_cli_entry::usage.

03910 {
03911    int i;
03912    struct ast_call_feature *feature;
03913    struct ao2_iterator iter;
03914    struct ast_parkinglot *curlot;
03915 #define HFS_FORMAT "%-25s %-7s %-7s\n"
03916 
03917    switch (cmd) {
03918    
03919    case CLI_INIT:
03920       e->command = "features show";
03921       e->usage =
03922          "Usage: features show\n"
03923          "       Lists configured features\n";
03924       return NULL;
03925    case CLI_GENERATE:
03926       return NULL;
03927    }
03928 
03929    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
03930    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03931 
03932    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
03933 
03934    ast_rwlock_rdlock(&features_lock);
03935    for (i = 0; i < FEATURES_COUNT; i++)
03936       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
03937    ast_rwlock_unlock(&features_lock);
03938 
03939    ast_cli(a->fd, "\n");
03940    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
03941    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03942    if (AST_RWLIST_EMPTY(&feature_list)) {
03943       ast_cli(a->fd, "(none)\n");
03944    } else {
03945       AST_RWLIST_RDLOCK(&feature_list);
03946       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
03947          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
03948       }
03949       AST_RWLIST_UNLOCK(&feature_list);
03950    }
03951 
03952    // loop through all the parking lots
03953    iter = ao2_iterator_init(parkinglots, 0);
03954 
03955    while ((curlot = ao2_iterator_next(&iter))) {
03956       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
03957       ast_cli(a->fd, "------------\n");
03958       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", parking_ext);
03959       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->parking_con);
03960       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
03961       ast_cli(a->fd,"\n");
03962       ao2_ref(curlot, -1);
03963    }
03964 
03965 
03966    return CLI_SUCCESS;
03967 }

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

Definition at line 3983 of file features.c.

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

03984 {
03985    switch (cmd) { 
03986    case CLI_INIT:
03987       e->command = "features reload";
03988       e->usage =
03989          "Usage: features reload\n"
03990          "       Reloads configured call features from features.conf\n";
03991       return NULL;
03992    case CLI_GENERATE:
03993       return NULL;
03994    }
03995    ast_features_reload();
03996 
03997    return CLI_SUCCESS;
03998 }

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

References ao2_iterator_init(), ao2_iterator_next, ao2_ref, 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, ast_channel::name, ast_parkinglot::name, parkeduser::parkingexten, parkinglots, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.

04167 {
04168    struct parkeduser *cur;
04169    int numparked = 0;
04170    struct ao2_iterator iter;
04171    struct ast_parkinglot *curlot;
04172 
04173    switch (cmd) {
04174    case CLI_INIT:
04175       e->command = "parkedcalls show";
04176       e->usage =
04177          "Usage: parkedcalls show\n"
04178          "       List currently parked calls\n";
04179       return NULL;
04180    case CLI_GENERATE:
04181       return NULL;
04182    }
04183 
04184    if (a->argc > e->args)
04185       return CLI_SHOWUSAGE;
04186 
04187    ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
04188       , "Context", "Extension", "Pri", "Timeout");
04189 
04190    iter = ao2_iterator_init(parkinglots, 0);
04191    while ((curlot = ao2_iterator_next(&iter))) {
04192       int lotparked = 0;
04193       ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name);
04194 
04195       AST_LIST_LOCK(&curlot->parkings);
04196       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04197          ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
04198             ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
04199             ,cur->priority,
04200             (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
04201          numparked++;
04202          numparked += lotparked;
04203       }
04204       AST_LIST_UNLOCK(&curlot->parkings);
04205       if (lotparked)
04206          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
04207 
04208       ao2_ref(curlot, -1);
04209    }
04210 
04211    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
04212 
04213    return CLI_SUCCESS;
04214 }

static int load_config ( void   )  [static]

Definition at line 3568 of file features.c.

References adsipark, ao2_lock(), ao2_unlock(), ast_config_load2(), ast_copy_string(), ast_log(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, config_flags, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_TIME, DEFAULT_PARKINGLOT, default_parkinglot, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_DEBUG, LOG_ERROR, LOG_WARNING, option_debug, ast_parkinglot::parkaddhints, ast_parkinglot::parkedcallhangup, ast_parkinglot::parkedcallrecording, ast_parkinglot::parkedcallreparking, ast_parkinglot::parkedcalltransfers, ast_parkinglot::parking_con, parking_ext, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.

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

03569 {
03570    int start = 0, end = 0;
03571    int res;
03572    int i;
03573    struct ast_context *con = NULL;
03574    struct ast_config *cfg = NULL;
03575    struct ast_variable *var = NULL;
03576    struct feature_group *fg = NULL;
03577    struct ast_flags config_flags = { 0 };
03578    char old_parking_ext[AST_MAX_EXTENSION];
03579    char old_parking_con[AST_MAX_EXTENSION] = "";
03580    char *ctg; 
03581    static const char *categories[] = { 
03582       /* Categories in features.conf that are not
03583        * to be parsed as group categories
03584        */
03585       "general",
03586       "featuremap",
03587       "applicationmap"
03588    };
03589 
03590    if (default_parkinglot) {
03591       strcpy(old_parking_con, default_parkinglot->parking_con);
03592       strcpy(old_parking_ext, parking_ext);
03593    } else {
03594       default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
03595       if (default_parkinglot) {
03596          ao2_lock(default_parkinglot);
03597          default_parkinglot->parking_start = 701;
03598          default_parkinglot->parking_stop = 750;
03599          default_parkinglot->parking_offset = 0;
03600          default_parkinglot->parkfindnext = 0;
03601          default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
03602          ao2_unlock(default_parkinglot);
03603       }
03604    }
03605    if (default_parkinglot) {
03606       if (option_debug)
03607          ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n");
03608    } else {
03609       ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n");
03610       return -1;
03611    }
03612    
03613 
03614    /* Reset to defaults */
03615    strcpy(parking_ext, "700");
03616    strcpy(pickup_ext, "*8");
03617    courtesytone[0] = '\0';
03618    strcpy(xfersound, "beep");
03619    strcpy(xferfailsound, "pbx-invalid");
03620    adsipark = 0;
03621    comebacktoorigin = 1;
03622 
03623    default_parkinglot->parkaddhints = 0;
03624    default_parkinglot->parkedcalltransfers = 0;
03625    default_parkinglot->parkedcallreparking = 0;
03626    default_parkinglot->parkedcallrecording = 0;
03627    default_parkinglot->parkedcallhangup = 0;
03628 
03629    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03630    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03631    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03632    atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03633    atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
03634    atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03635 
03636    cfg = ast_config_load2("features.conf", "features", config_flags);
03637    if (!cfg) {
03638       ast_log(LOG_WARNING,"Could not load features.conf\n");
03639       return 0;
03640    }
03641    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03642       if (!strcasecmp(var->name, "parkext")) {
03643          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
03644       } else if (!strcasecmp(var->name, "context")) {
03645          ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con));
03646       } else if (!strcasecmp(var->name, "parkingtime")) {
03647          if ((sscanf(var->value, "%d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) {
03648             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
03649             default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
03650          } else
03651             default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000;
03652       } else if (!strcasecmp(var->name, "parkpos")) {
03653          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
03654             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);
03655          } else if (default_parkinglot) {
03656             default_parkinglot->parking_start = start;
03657             default_parkinglot->parking_stop = end;
03658          } else {
03659             ast_log(LOG_WARNING, "No default parking lot!\n");
03660          }
03661       } else if (!strcasecmp(var->name, "findslot")) {
03662          default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next"));
03663       } else if (!strcasecmp(var->name, "parkinghints")) {
03664          default_parkinglot->parkaddhints = ast_true(var->value);
03665       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
03666          if (!strcasecmp(var->value, "both"))
03667             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
03668          else if (!strcasecmp(var->value, "caller"))
03669             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
03670          else if (!strcasecmp(var->value, "callee"))
03671             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
03672       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
03673          if (!strcasecmp(var->value, "both"))
03674             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
03675          else if (!strcasecmp(var->value, "caller"))
03676             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
03677          else if (!strcasecmp(var->value, "callee"))
03678             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
03679       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
03680          if (!strcasecmp(var->value, "both"))
03681             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
03682          else if (!strcasecmp(var->value, "caller"))
03683             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
03684          else if (!strcasecmp(var->value, "callee"))
03685             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
03686       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
03687          if (!strcasecmp(var->value, "both"))
03688             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
03689          else if (!strcasecmp(var->value, "caller"))
03690             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
03691          else if (!strcasecmp(var->value, "callee"))
03692             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
03693       } else if (!strcasecmp(var->name, "adsipark")) {
03694          adsipark = ast_true(var->value);
03695       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03696          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03697             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03698             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03699          } else
03700             transferdigittimeout = transferdigittimeout * 1000;
03701       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03702          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03703             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03704             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03705          }
03706       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03707          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03708             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03709             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03710          } else
03711             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03712       } else if (!strcasecmp(var->name, "atxferloopdelay")) {
03713          if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
03714             ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
03715             atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03716          } else 
03717             atxferloopdelay *= 1000;
03718       } else if (!strcasecmp(var->name, "atxferdropcall")) {
03719          atxferdropcall = ast_true(var->value);
03720       } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
03721          if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
03722             ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
03723             atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03724          }
03725       } else if (!strcasecmp(var->name, "courtesytone")) {
03726          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03727       }  else if (!strcasecmp(var->name, "parkedplay")) {
03728          if (!strcasecmp(var->value, "both"))
03729             parkedplay = 2;
03730          else if (!strcasecmp(var->value, "parked"))
03731             parkedplay = 1;
03732          else
03733             parkedplay = 0;
03734       } else if (!strcasecmp(var->name, "xfersound")) {
03735          ast_copy_string(xfersound, var->value, sizeof(xfersound));
03736       } else if (!strcasecmp(var->name, "xferfailsound")) {
03737          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03738       } else if (!strcasecmp(var->name, "pickupexten")) {
03739          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03740       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
03741          comebacktoorigin = ast_true(var->value);
03742       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03743          ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass));
03744       }
03745    }
03746 
03747    unmap_features();
03748    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03749       if (remap_feature(var->name, var->value))
03750          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03751    }
03752 
03753    /* Map a key combination to an application*/
03754    ast_unregister_features();
03755    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03756       char *tmp_val = ast_strdupa(var->value);
03757       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
03758       struct ast_call_feature *feature;
03759 
03760       /* strsep() sets the argument to NULL if match not found, and it
03761        * is safe to use it with a NULL argument, so we don't check
03762        * between calls.
03763        */
03764       exten = strsep(&tmp_val,",");
03765       activatedby = strsep(&tmp_val,",");
03766       app = strsep(&tmp_val,",");
03767       app_args = strsep(&tmp_val,",");
03768       moh_class = strsep(&tmp_val,",");
03769 
03770       activateon = strsep(&activatedby, "/");   
03771 
03772       /*! \todo XXX var_name or app_args ? */
03773       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03774          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03775             app, exten, activateon, var->name);
03776          continue;
03777       }
03778 
03779       AST_RWLIST_RDLOCK(&feature_list);
03780       if ((feature = find_dynamic_feature(var->name))) {
03781          AST_RWLIST_UNLOCK(&feature_list);
03782          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03783          continue;
03784       }
03785       AST_RWLIST_UNLOCK(&feature_list);
03786             
03787       if (!(feature = ast_calloc(1, sizeof(*feature))))
03788          continue;               
03789 
03790       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03791       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03792       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03793       
03794       if (app_args) 
03795          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03796 
03797       if (moh_class)
03798          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03799          
03800       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03801       feature->operation = feature_exec_app;
03802       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03803 
03804       /* Allow caller and calle to be specified for backwards compatability */
03805       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03806          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03807       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03808          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03809       else {
03810          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03811             " must be 'self', or 'peer'\n", var->name);
03812          continue;
03813       }
03814 
03815       if (ast_strlen_zero(activatedby))
03816          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03817       else if (!strcasecmp(activatedby, "caller"))
03818          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03819       else if (!strcasecmp(activatedby, "callee"))
03820          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03821       else if (!strcasecmp(activatedby, "both"))
03822          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03823       else {
03824          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03825             " must be 'caller', or 'callee', or 'both'\n", var->name);
03826          continue;
03827       }
03828 
03829       ast_register_feature(feature);
03830          
03831       ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
03832    }
03833 
03834    ast_unregister_groups();
03835    AST_RWLIST_WRLOCK(&feature_groups);
03836 
03837    ctg = NULL;
03838    while ((ctg = ast_category_browse(cfg, ctg))) {
03839       /* Is this a parkinglot definition ? */
03840       if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
03841          ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
03842          if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg)))
03843             ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
03844          else
03845             ast_debug(1, "Configured parking context %s\n", ctg);
03846          continue;   
03847       }
03848       /* No, check if it's a group */
03849       for (i = 0; i < ARRAY_LEN(categories); i++) {
03850          if (!strcasecmp(categories[i], ctg))
03851             break;
03852       }
03853 
03854       if (i < ARRAY_LEN(categories)) 
03855          continue;
03856 
03857       if (!(fg = register_group(ctg)))
03858          continue;
03859 
03860       for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
03861          struct ast_call_feature *feature;
03862 
03863          AST_RWLIST_RDLOCK(&feature_list);
03864          if (!(feature = find_dynamic_feature(var->name)) && 
03865              !(feature = ast_find_call_feature(var->name))) {
03866             AST_RWLIST_UNLOCK(&feature_list);
03867             ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
03868             continue;
03869          }
03870          AST_RWLIST_UNLOCK(&feature_list);
03871 
03872          register_group_feature(fg, var->value, feature);
03873       }
03874    }
03875 
03876    AST_RWLIST_UNLOCK(&feature_groups);
03877 
03878    ast_config_destroy(cfg);
03879 
03880    /* Remove the old parking extension */
03881    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03882       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0))
03883             notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE);
03884       ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03885    }
03886    
03887    if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) {
03888       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con);
03889       return -1;
03890    }
03891    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03892    if (default_parkinglot->parkaddhints)
03893       park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop);
03894    if (!res)
03895       notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE);
03896    return res;
03897 
03898 }

int manage_parkinglot ( struct ast_parkinglot curlot,
fd_set *  rfds,
fd_set *  efds,
fd_set *  nrfds,
fd_set *  nefds,
int *  fs,
int *  max 
)

Run management on parkinglots, called once per parkinglot.

Definition at line 2915 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_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, ast_log(), AST_MAX_FDS, ast_pbx_start(), ast_read(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, buf, callback_dialoptions(), parkeduser::chan, chan, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, free, parkeduser::list, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), and parkeduser::start.

Referenced by do_parking_thread().

02916 {
02917 
02918    struct parkeduser *pu;
02919    int res = 0;
02920    char parkingslot[AST_MAX_EXTENSION];
02921 
02922    /* Lock parking list */
02923    AST_LIST_LOCK(&curlot->parkings);
02924    AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
02925       struct ast_channel *chan = pu->chan;   /* shorthand */
02926       int tms;        /* timeout for this item */
02927       int x;          /* fd index in channel */
02928       struct ast_context *con;
02929 
02930       if (pu->notquiteyet) { /* Pretend this one isn't here yet */
02931          continue;
02932       }
02933       tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
02934       if (tms > pu->parkingtime) {
02935          /* Stop music on hold */
02936          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
02937          /* Get chan, exten from derived kludge */
02938          if (pu->peername[0]) {
02939             char *peername = ast_strdupa(pu->peername);
02940             char *cp = strrchr(peername, '-');
02941             char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */
02942             int i;
02943 
02944             if (cp) 
02945                *cp = 0;
02946             ast_copy_string(peername_flat,peername,sizeof(peername_flat));
02947             for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
02948                if (peername_flat[i] == '/') 
02949                   peername_flat[i]= '0';
02950             }
02951             con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
02952             if (!con) {
02953                ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
02954             }
02955             if (con) {
02956                char returnexten[AST_MAX_EXTENSION];
02957                struct ast_datastore *features_datastore;
02958                struct ast_dial_features *dialfeatures = NULL;
02959 
02960                ast_channel_lock(chan);
02961 
02962                if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
02963                   dialfeatures = features_datastore->data;
02964 
02965                ast_channel_unlock(chan);
02966 
02967                if (!strncmp(peername, "Parked/", 7)) {
02968                   peername += 7;
02969                }
02970 
02971                if (dialfeatures) {
02972                   char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
02973                   snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
02974                } else { /* Existing default */
02975                   ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name);
02976                   snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
02977                }
02978 
02979                ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
02980             }
02981             if (comebacktoorigin) {
02982                set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1);
02983             } else {
02984                ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
02985                snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
02986                pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
02987                set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
02988             }
02989          } else {
02990             /* They've been waiting too long, send them back to where they came.  Theoretically they
02991                should have their original extensions and such, but we copy to be on the safe side */
02992             set_c_e_p(chan, pu->context, pu->exten, pu->priority);
02993          }
02994          post_manager_event("ParkedCallTimeOut", pu);
02995 
02996          ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, pu->chan->exten, pu->chan->priority);
02997          /* Start up the PBX, or hang them up */
02998          if (ast_pbx_start(chan))  {
02999             ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
03000             ast_hangup(chan);
03001          }
03002          /* And take them out of the parking lot */
03003          con = ast_context_find(pu->parkinglot->parking_con);
03004          if (con) {
03005             if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03006                ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
03007             else
03008                notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
03009          } else
03010             ast_log(LOG_WARNING, "Whoa, no parking context?\n");
03011          AST_LIST_REMOVE_CURRENT(list);
03012          free(pu);
03013       } else { /* still within parking time, process descriptors */
03014          for (x = 0; x < AST_MAX_FDS; x++) {
03015             struct ast_frame *f;
03016 
03017             if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds))) 
03018                continue;
03019             
03020             if (FD_ISSET(chan->fds[x], efds))
03021                ast_set_flag(chan, AST_FLAG_EXCEPTION);
03022             else
03023                ast_clear_flag(chan, AST_FLAG_EXCEPTION);
03024             chan->fdno = x;
03025 
03026             /* See if they need servicing */
03027             f = ast_read(pu->chan);
03028             /* Hangup? */
03029             if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
03030                if (f)
03031                   ast_frfree(f);
03032                post_manager_event("ParkedCallGiveUp", pu);
03033 
03034                /* There's a problem, hang them up*/
03035                ast_verb(2, "%s got tired of being parked\n", chan->name);
03036                ast_hangup(chan);
03037                /* And take them out of the parking lot */
03038                con = ast_context_find(curlot->parking_con);
03039                if (con) {
03040                   if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03041                      ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
03042                   else
03043                      notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
03044                } else
03045                   ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
03046                AST_LIST_REMOVE_CURRENT(list);
03047                free(pu);
03048                break;
03049             } else {
03050                /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
03051                ast_frfree(f);
03052                if (pu->moh_trys < 3 && !chan->generatordata) {
03053                   ast_debug(1, "MOH on parked call stopped by outside source.  Restarting on channel %s.\n", chan->name);
03054                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
03055                      S_OR(curlot->mohclass, NULL),
03056                      (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0));
03057                   pu->moh_trys++;
03058                }
03059                goto std;   /* XXX Ick: jumping into an else statement??? XXX */
03060             }
03061          } /* End for */
03062          if (x >= AST_MAX_FDS) {
03063 std:           for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
03064                if (chan->fds[x] > -1) {
03065                   FD_SET(chan->fds[x], nrfds);
03066                   FD_SET(chan->fds[x], nefds);
03067                   if (chan->fds[x] > *max)
03068                      *max = chan->fds[x];
03069                }
03070             }
03071             /* Keep track of our shortest wait */
03072             if (tms < *ms || *ms < 0)
03073                *ms = tms;
03074          }
03075       }
03076    }
03077    AST_LIST_TRAVERSE_SAFE_END;
03078    AST_LIST_UNLOCK(&curlot->parkings);
03079    return res;
03080 }

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

04292 {
04293    const char *channel = astman_get_header(m, "Channel");
04294    const char *channel2 = astman_get_header(m, "Channel2");
04295    const char *timeout = astman_get_header(m, "Timeout");
04296    char buf[BUFSIZ];
04297    int to = 0;
04298    int res = 0;
04299    int parkExt = 0;
04300    struct ast_channel *ch1, *ch2;
04301 
04302    if (ast_strlen_zero(channel)) {
04303       astman_send_error(s, m, "Channel not specified");
04304       return 0;
04305    }
04306 
04307    if (ast_strlen_zero(channel2)) {
04308       astman_send_error(s, m, "Channel2 not specified");
04309       return 0;
04310    }
04311 
04312    ch1 = ast_get_channel_by_name_locked(channel);
04313    if (!ch1) {
04314       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
04315       astman_send_error(s, m, buf);
04316       return 0;
04317    }
04318 
04319    ch2 = ast_get_channel_by_name_locked(channel2);
04320    if (!ch2) {
04321       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
04322       astman_send_error(s, m, buf);
04323       ast_channel_unlock(ch1);
04324       return 0;
04325    }
04326 
04327    if (!ast_strlen_zero(timeout)) {
04328       sscanf(timeout, "%d", &to);
04329    }
04330 
04331    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
04332    if (!res) {
04333       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
04334       astman_send_ack(s, m, "Park successful");
04335    } else {
04336       astman_send_error(s, m, "Park failure");
04337    }
04338 
04339    ast_channel_unlock(ch1);
04340    ast_channel_unlock(ch2);
04341 
04342    return 0;
04343 }

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

References ao2_iterator_init(), ao2_iterator_next, ao2_ref, 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, ast_channel::name, parkinglots, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.

Referenced by ast_features_init().

04231 {
04232    struct parkeduser *cur;
04233    const char *id = astman_get_header(m, "ActionID");
04234    char idText[256] = "";
04235    struct ao2_iterator iter;
04236    struct ast_parkinglot *curlot;
04237 
04238    if (!ast_strlen_zero(id))
04239       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04240 
04241    astman_send_ack(s, m, "Parked calls will follow");
04242 
04243    iter = ao2_iterator_init(parkinglots, 0);
04244    while ((curlot = ao2_iterator_next(&iter))) {
04245 
04246       AST_LIST_LOCK(&curlot->parkings);
04247       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04248          astman_append(s, "Event: ParkedCall\r\n"
04249             "Exten: %d\r\n"
04250             "Channel: %s\r\n"
04251             "From: %s\r\n"
04252             "Timeout: %ld\r\n"
04253             "CallerIDNum: %s\r\n"
04254             "CallerIDName: %s\r\n"
04255             "%s"
04256             "\r\n",
04257             cur->parkingnum, cur->chan->name, cur->peername,
04258             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
04259             S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
04260             S_OR(cur->chan->cid.cid_name, ""),
04261             idText);
04262       }
04263       AST_LIST_UNLOCK(&curlot->parkings);
04264       ao2_ref(curlot, -1);
04265    }
04266 
04267    astman_append(s,
04268       "Event: ParkedCallsComplete\r\n"
04269       "%s"
04270       "\r\n",idText);
04271 
04272 
04273    return RESULT_SUCCESS;
04274 }

static int masq_park_call ( struct ast_channel rchan,
struct ast_channel peer,
int  timeout,
int *  extout,
int  play_announcement,
struct ast_park_call_args args 
) [static]

Definition at line 752 of file features.c.

References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), AST_FEATURE_RETURN_PARKFAILED, ast_frfree, ast_hangup(), ast_log(), ast_park_call_full(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), chan, ast_channel::context, ast_channel::exten, ast_park_call_args::extout, f, LOG_WARNING, ast_channel::name, ast_park_call_args::orig_chan_name, park_space_reserve(), ast_channel::priority, ast_park_call_args::pu, ast_channel::readformat, set_c_e_p(), ast_park_call_args::timeout, and ast_channel::writeformat.

Referenced by ast_masq_park_call(), masq_park_call_announce(), and masq_park_call_announce_args().

00753 {
00754    struct ast_channel *chan;
00755    struct ast_frame *f;
00756    int park_status;
00757    struct ast_park_call_args park_args = {0,};
00758 
00759    if (!args) {
00760       args = &park_args;
00761       args->timeout = timeout;
00762       args->extout = extout;
00763    }
00764 
00765    if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
00766       if (peer)
00767          ast_stream_and_wait(peer, "beeperr", "");
00768       return AST_FEATURE_RETURN_PARKFAILED;
00769    }
00770 
00771    /* Make a new, fake channel that we'll use to masquerade in the real one */
00772    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00773       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00774       return -1;
00775    }
00776 
00777    /* Make formats okay */
00778    chan->readformat = rchan->readformat;
00779    chan->writeformat = rchan->writeformat;
00780    ast_channel_masquerade(chan, rchan);
00781 
00782    /* Setup the extensions and such */
00783    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00784 
00785    /* Make the masq execute */
00786    if ((f = ast_read(chan)))
00787       ast_frfree(f);
00788 
00789    if (peer == rchan) {
00790       peer = chan;
00791    }
00792 
00793    if (!play_announcement && args == &park_args) {
00794       args->orig_chan_name = ast_strdupa(chan->name);
00795    }
00796 
00797    park_status = ast_park_call_full(chan, peer, args);
00798    if (park_status == 1) {
00799    /* would be nice to play "invalid parking extension" */
00800       ast_hangup(chan);
00801       return -1;
00802    }
00803 
00804    return 0;
00805 }

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

Definition at line 818 of file features.c.

References masq_park_call().

Referenced by builtin_blindtransfer(), and builtin_parkcall().

00819 {
00820    return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
00821 }

static int masq_park_call_announce_args ( struct ast_channel rchan,
struct ast_channel peer,
struct ast_park_call_args args 
) [static]

Definition at line 813 of file features.c.

References masq_park_call().

Referenced by park_call_exec().

00814 {
00815    return masq_park_call(rchan, peer, 0, NULL, 1, args);
00816 }

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

metermaids callback from devicestate.c

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

00447 {
00448    char *context;
00449    char *exten;
00450 
00451    context = ast_strdupa(data);
00452 
00453    exten = strsep(&context, "@");
00454    if (!context)
00455       return AST_DEVICE_INVALID;
00456    
00457    ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
00458 
00459    if (!ast_exists_extension(NULL, context, exten, 1, NULL))
00460       return AST_DEVICE_NOT_INUSE;
00461 
00462    return AST_DEVICE_INUSE;
00463 }

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

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

Referenced by ast_park_call_full(), manage_parkinglot(), and park_exec_full().

00438 {
00439    ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
00440       exten, context, devstate2str(state));
00441 
00442    ast_devstate_changed(state, "park:%s@%s", exten, context);
00443 }

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

References ast_add_extension(), PRIORITY_HINT, and registrar.

03556 {
03557    int numext;
03558    char device[AST_MAX_EXTENSION];
03559    char exten[10];
03560 
03561    for (numext = start; numext <= stop; numext++) {
03562       snprintf(exten, sizeof(exten), "%d", numext);
03563       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03564       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03565    }
03566 }

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

Park a call.

Definition at line 3150 of file features.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), chan, ast_channel::exten, ast_park_call_args::flags, ast_flags::flags, LOG_WARNING, masq_park_call_announce_args(), ast_channel::name, ast_park_call_args::orig_chan_name, orig_exten(), park_call_options, parse(), ast_channel::priority, ast_park_call_args::return_con, ast_park_call_args::return_ext, ast_park_call_args::return_pri, and ast_park_call_args::timeout.

Referenced by ast_features_init().

03151 {
03152    /* Cache the original channel name in case we get masqueraded in the middle
03153     * of a park--it is still theoretically possible for a transfer to happen before
03154     * we get here, but it is _really_ unlikely */
03155    char *orig_chan_name = ast_strdupa(chan->name);
03156    char orig_exten[AST_MAX_EXTENSION];
03157    int orig_priority = chan->priority;
03158 
03159    /* Data is unused at the moment but could contain a parking
03160       lot context eventually */
03161    int res = 0;
03162 
03163    char *parse = NULL;
03164    AST_DECLARE_APP_ARGS(app_args,
03165       AST_APP_ARG(timeout);
03166       AST_APP_ARG(return_con);
03167       AST_APP_ARG(return_ext);
03168       AST_APP_ARG(return_pri);
03169       AST_APP_ARG(options);
03170    );
03171 
03172    parse = ast_strdupa(data);
03173    AST_STANDARD_APP_ARGS(app_args, parse);
03174 
03175    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
03176 
03177    /* Setup the exten/priority to be s/1 since we don't know
03178       where this call should return */
03179    strcpy(chan->exten, "s");
03180    chan->priority = 1;
03181 
03182    /* Answer if call is not up */
03183    if (chan->_state != AST_STATE_UP)
03184       res = ast_answer(chan);
03185 
03186    /* Sleep to allow VoIP streams to settle down */
03187    if (!res)
03188       res = ast_safe_sleep(chan, 1000);
03189 
03190    /* Park the call */
03191    if (!res) {
03192       struct ast_park_call_args args = {
03193          .orig_chan_name = orig_chan_name,
03194       };
03195       struct ast_flags flags = { 0 };
03196 
03197       if (parse) {
03198          if (!ast_strlen_zero(app_args.timeout)) {
03199             if (sscanf(app_args.timeout, "%d", &args.timeout) != 1) {
03200                ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
03201                args.timeout = 0;
03202             }
03203          }
03204          if (!ast_strlen_zero(app_args.return_con)) {
03205             args.return_con = app_args.return_con;
03206          }
03207          if (!ast_strlen_zero(app_args.return_ext)) {
03208             args.return_ext = app_args.return_ext;
03209          }
03210          if (!ast_strlen_zero(app_args.return_pri)) {
03211             if (sscanf(app_args.return_pri, "%d", &args.return_pri) != 1) {
03212                ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
03213                args.return_pri = 0;
03214             }
03215          }
03216       }
03217 
03218       ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
03219       args.flags = flags.flags;
03220 
03221       res = masq_park_call_announce_args(chan, chan, &args);
03222       /* Continue on in the dialplan */
03223       if (res == 1) {
03224          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
03225          chan->priority = orig_priority;
03226          res = 0;
03227       } else if (!res) {
03228          res = 1;
03229       }
03230    }
03231 
03232    return res;
03233 }

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

Definition at line 3399 of file features.c.

References chan, default_parkinglot, and park_exec_full().

Referenced by ast_features_init().

03400 {
03401    return park_exec_full(chan, data, default_parkinglot);
03402 }

static int park_exec_full ( struct ast_channel chan,
void *  data,
struct ast_parkinglot parkinglot 
) [static]

Pickup parked call.

Todo:
XXX we would like to wait on both!

Todo:
XXX Play a message XXX

Definition at line 3236 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(), parkeduser::chan, chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, ast_datastore::data, default_parkinglot, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_callee, ast_dial_features::features_caller, find_parkinglot(), findparkinglotname(), ast_dial_features::is_caller, LOG_WARNING, manager_event, ast_channel::name, notify_metermaids(), parkedplay, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), and S_OR.

Referenced by park_exec().

03237 {
03238    int res = 0;
03239    struct ast_channel *peer=NULL;
03240    struct parkeduser *pu;
03241    struct ast_context *con;
03242    int park = 0;
03243    struct ast_bridge_config config;
03244 
03245    if (data)
03246       park = atoi((char *)data);
03247 
03248    parkinglot = find_parkinglot(findparkinglotname(chan));  
03249    if (!parkinglot)
03250       parkinglot = default_parkinglot;
03251 
03252    AST_LIST_LOCK(&parkinglot->parkings);
03253    AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
03254       if (!data || pu->parkingnum == park) {
03255          if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
03256             AST_LIST_UNLOCK(&parkinglot->parkings);
03257             return -1;
03258          }
03259          AST_LIST_REMOVE_CURRENT(list);
03260          break;
03261       }
03262    }
03263    AST_LIST_TRAVERSE_SAFE_END;
03264    AST_LIST_UNLOCK(&parkinglot->parkings);
03265 
03266    if (pu) {
03267       peer = pu->chan;
03268       con = ast_context_find(parkinglot->parking_con);
03269       if (con) {
03270          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03271             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
03272          else
03273             notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
03274       } else
03275          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
03276 
03277       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
03278          "Exten: %s\r\n"
03279          "Channel: %s\r\n"
03280          "From: %s\r\n"
03281          "CallerIDNum: %s\r\n"
03282          "CallerIDName: %s\r\n",
03283          pu->parkingexten, pu->chan->name, chan->name,
03284          S_OR(pu->chan->cid.cid_num, "<unknown>"),
03285          S_OR(pu->chan->cid.cid_name, "<unknown>")
03286          );
03287 
03288       ast_free(pu);
03289    }
03290    /* JK02: it helps to answer the channel if not already up */
03291    if (chan->_state != AST_STATE_UP)
03292       ast_answer(chan);
03293 
03294    //XXX Why do we unlock here ?
03295    // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain
03296    //ASTOBJ_UNLOCK(parkinglot);
03297 
03298    if (peer) {
03299       struct ast_datastore *features_datastore;
03300       struct ast_dial_features *dialfeatures = NULL;
03301 
03302       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
03303 
03304       if (!ast_strlen_zero(courtesytone)) {
03305          int error = 0;
03306          ast_indicate(peer, AST_CONTROL_UNHOLD);
03307          if (parkedplay == 0) {
03308             error = ast_stream_and_wait(chan, courtesytone, "");
03309          } else if (parkedplay == 1) {
03310             error = ast_stream_and_wait(peer, courtesytone, "");
03311          } else if (parkedplay == 2) {
03312             if (!ast_streamfile(chan, courtesytone, chan->language) &&
03313                   !ast_streamfile(peer, courtesytone, chan->language)) {
03314                /*! \todo XXX we would like to wait on both! */
03315                res = ast_waitstream(chan, "");
03316                if (res >= 0)
03317                   res = ast_waitstream(peer, "");
03318                if (res < 0)
03319                   error = 1;
03320             }
03321          }
03322          if (error) {
03323             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
03324             ast_hangup(peer);
03325             return -1;
03326          }
03327       } else
03328          ast_indicate(peer, AST_CONTROL_UNHOLD);
03329 
03330       res = ast_channel_make_compatible(chan, peer);
03331       if (res < 0) {
03332          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
03333          ast_hangup(peer);
03334          return -1;
03335       }
03336       /* This runs sorta backwards, since we give the incoming channel control, as if it
03337          were the person called. */
03338       ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
03339 
03340       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03341       ast_cdr_setdestchan(chan->cdr, peer->name);
03342       memset(&config, 0, sizeof(struct ast_bridge_config));
03343 
03344       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
03345       ast_channel_lock(peer);
03346       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
03347          dialfeatures = features_datastore->data;
03348       }
03349       ast_channel_unlock(peer);
03350 
03351       if (dialfeatures) {
03352          ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL);
03353       }
03354 
03355       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03356          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
03357       }
03358       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03359          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
03360       }
03361       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03362          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
03363       }
03364       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03365          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
03366       }
03367       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03368          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
03369       }
03370       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03371          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
03372       }
03373       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03374          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
03375       }
03376       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03377          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
03378       }
03379 
03380       res = ast_bridge_call(chan, peer, &config);
03381 
03382       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03383       ast_cdr_setdestchan(chan->cdr, peer->name);
03384 
03385       /* Simulate the PBX hanging up */
03386       ast_hangup(peer);
03387       return res;
03388    } else {
03389       /*! \todo XXX Play a message XXX */
03390       if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
03391          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
03392       ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
03393       res = -1;
03394    }
03395 
03396    return res;
03397 }

static struct parkeduser* park_space_reserve ( struct ast_channel chan,
struct ast_channel peer,
struct ast_park_call_args args 
) [static]

Definition at line 493 of file features.c.

References ast_calloc, ast_exists_extension(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strlen_zero(), ast_test_flag, chan, default_parkinglot, find_parkinglot(), findparkinglotname(), free, parkeduser::list, LOG_DEBUG, LOG_WARNING, option_debug, parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, and pbx_builtin_getvar_helper().

Referenced by ast_park_call_full(), and masq_park_call().

00495 {
00496    struct parkeduser *pu;
00497    int i, parking_space = -1, parking_range;
00498    const char *parkinglotname = NULL;
00499    const char *parkingexten;
00500    struct ast_parkinglot *parkinglot = NULL;
00501    
00502    if (peer)
00503       parkinglotname = findparkinglotname(peer);
00504 
00505    if (parkinglotname) {
00506       if (option_debug)
00507          ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname);
00508       parkinglot = find_parkinglot(parkinglotname);   
00509    }
00510    if (!parkinglot)
00511       parkinglot = default_parkinglot;
00512 
00513    parkinglot_addref(parkinglot);
00514    if (option_debug)
00515       ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name);
00516 
00517    /* Allocate memory for parking data */
00518    if (!(pu = ast_calloc(1, sizeof(*pu)))) {
00519       parkinglot_unref(parkinglot);
00520       return NULL;
00521    }
00522 
00523    /* Lock parking list */
00524    AST_LIST_LOCK(&parkinglot->parkings);
00525    /* Check for channel variable PARKINGEXTEN */
00526    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00527    if (!ast_strlen_zero(parkingexten)) {
00528       /*!\note The API forces us to specify a numeric parking slot, even
00529        * though the architecture would tend to support non-numeric extensions
00530        * (as are possible with SIP, for example).  Hence, we enforce that
00531        * limitation here.  If extout was not numeric, we could permit
00532        * arbitrary non-numeric extensions.
00533        */
00534         if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) {
00535          AST_LIST_UNLOCK(&parkinglot->parkings);
00536          parkinglot_unref(parkinglot);
00537             free(pu);
00538             ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00539             return NULL;
00540         }
00541         snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00542 
00543       if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) {
00544          AST_LIST_UNLOCK(&parkinglot->parkings);
00545          parkinglot_unref(parkinglot);
00546          ast_free(pu);
00547          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
00548          return NULL;
00549       }
00550    } else {
00551       int start;
00552       struct parkeduser *cur = NULL;
00553 
00554       /* Select parking space within range */
00555       parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1;
00556 
00557       if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
00558          start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1);
00559       } else {
00560          start = parkinglot->parking_start;
00561       }
00562 
00563       for (i = start; 1; i++) {
00564          if (i == parkinglot->parking_stop + 1) {
00565             i = parkinglot->parking_start - 1;
00566             continue;
00567          }
00568 
00569          AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
00570             if (cur->parkingnum == i) {
00571                break;
00572             }
00573          }
00574 
00575          if (!cur || i == start - 1) {
00576             parking_space = i;
00577             break;
00578          }
00579       }
00580 
00581       if (i == start - 1 && cur) {
00582          ast_log(LOG_WARNING, "No more parking spaces\n");
00583          ast_free(pu);
00584          AST_LIST_UNLOCK(&parkinglot->parkings);
00585          parkinglot_unref(parkinglot);
00586          return NULL;
00587       }
00588       /* Set pointer for next parking */
00589       if (parkinglot->parkfindnext) 
00590          parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
00591       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00592    }
00593 
00594    pu->notquiteyet = 1;
00595    pu->parkingnum = parking_space;
00596    pu->parkinglot = parkinglot;
00597    AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
00598    parkinglot_unref(parkinglot);
00599 
00600    return pu;
00601 }

static struct ast_parkinglot * parkinglot_addref ( struct ast_parkinglot parkinglot  )  [static]

Definition at line 3413 of file features.c.

References ao2_ref, ast_log(), LOG_DEBUG, option_debug, and parkinglot.

Referenced by park_space_reserve().

03414 {
03415    int refcount = ao2_ref(parkinglot, +1);
03416    if (option_debug > 2)
03417       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
03418    return parkinglot;
03419 }

static int parkinglot_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 267 of file features.c.

References CMP_MATCH, CMP_STOP, and parkinglot.

Referenced by ast_features_init().

00268 {
00269    struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg;
00270 
00271    return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00272 }

static void parkinglot_destroy ( void *  obj  )  [static]

Destroy a parking lot.

Definition at line 3439 of file features.c.

References ao2_unlink, ast_context_destroy(), ast_context_find(), ast_parkinglot::parking_con, parkinglots, and registrar.

Referenced by build_parkinglot(), and create_parkinglot().

03440 {
03441    struct ast_parkinglot *ruin = obj;
03442    struct ast_context *con;
03443    con = ast_context_find(ruin->parking_con);
03444    if (con)
03445       ast_context_destroy(con, registrar);
03446    ao2_unlink(parkinglots, ruin);
03447 }

static int parkinglot_hash_cb ( const void *  obj,
const int  flags 
) [static]

Definition at line 260 of file features.c.

References ast_str_case_hash(), and parkinglot.

Referenced by ast_features_init().

00261 {
00262    const struct ast_parkinglot *parkinglot = obj;
00263 
00264    return ast_str_case_hash(parkinglot->name);
00265 }

static void parkinglot_unref ( struct ast_parkinglot parkinglot  )  [static]

Unreference parkinglot object. If no more references, then go ahead and delete it.

Definition at line 3406 of file features.c.

References ao2_ref, ast_log(), LOG_DEBUG, option_debug, and parkinglot.

Referenced by build_parkinglot(), and park_space_reserve().

03407 {
03408    int refcount = ao2_ref(parkinglot, -1);
03409    if (option_debug > 2)
03410       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
03411 }

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

return the first unlocked cdr in a possible chain

Definition at line 2267 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

02268 {
02269    struct ast_cdr *cdr_orig = cdr;
02270    while (cdr) {
02271       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02272          return cdr;
02273       cdr = cdr->next;
02274    }
02275    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
02276 }

static int play_message_in_bridged_call ( struct ast_channel caller_chan,
struct ast_channel callee_chan,
const char *  audiofile 
) [static]

Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages.

Definition at line 884 of file features.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_stream_and_wait(), and LOG_WARNING.

Referenced by builtin_automonitor().

00885 {
00886    /* First play for caller, put other channel on auto service */
00887    if (ast_autoservice_start(callee_chan))
00888       return -1;
00889    if (ast_stream_and_wait(caller_chan, audiofile, "")) {
00890       ast_log(LOG_WARNING, "Failed to play automon message!\n");
00891       ast_autoservice_stop(callee_chan);
00892       return -1;
00893    }
00894    if (ast_autoservice_stop(callee_chan))
00895       return -1;
00896    /* Then play for callee, put other channel on auto service */
00897    if (ast_autoservice_start(caller_chan))
00898       return -1;
00899    if (ast_stream_and_wait(callee_chan, audiofile, "")) {
00900       ast_log(LOG_WARNING, "Failed to play automon message !\n");
00901       ast_autoservice_stop(caller_chan);
00902       return -1;
00903    }
00904    if (ast_autoservice_stop(caller_chan))
00905       return -1;
00906    return(0);
00907 }

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

Output parking event to manager.

Definition at line 2852 of file features.c.

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

Referenced by manage_parkinglot().

02853 {
02854    manager_event(EVENT_FLAG_CALL, s,
02855       "Exten: %s\r\n"
02856       "Channel: %s\r\n"
02857       "Parkinglot: %s\r\n"
02858       "CallerIDNum: %s\r\n"
02859       "CallerIDName: %s\r\n"
02860       "UniqueID: %s\r\n\r\n",
02861       pu->parkingexten, 
02862       pu->chan->name,
02863       pu->parkinglot->name,
02864       S_OR(pu->chan->cid.cid_num, "<unknown>"),
02865       S_OR(pu->chan->cid.cid_name, "<unknown>"),
02866       pu->chan->uniqueid
02867       );
02868 }

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

01148 {
01149    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
01150    if (ast_strlen_zero(s)) {
01151       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
01152    }
01153    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
01154       s = transferer->macrocontext;
01155    }
01156    if (ast_strlen_zero(s)) {
01157       s = transferer->context;
01158    }
01159    return s;  
01160 }

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 1643 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.

01644 {
01645    struct feature_group *fg;
01646 
01647    if (!fgname) {
01648       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
01649       return NULL;
01650    }
01651 
01652    if (!(fg = ast_calloc(1, sizeof(*fg))))
01653       return NULL;
01654 
01655    if (ast_string_field_init(fg, 128)) {
01656       ast_free(fg);
01657       return NULL;
01658    }
01659 
01660    ast_string_field_set(fg, gname, fgname);
01661 
01662    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
01663 
01664    ast_verb(2, "Registered group '%s'\n", fg->gname);
01665 
01666    return fg;
01667 }

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 1678 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.

01679 {
01680    struct feature_group_exten *fge;
01681 
01682    if (!fg) {
01683       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
01684       return;
01685    }
01686 
01687    if (!feature) {
01688       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
01689       return;
01690    }
01691 
01692    if (!(fge = ast_calloc(1, sizeof(*fge))))
01693       return;
01694 
01695    if (ast_string_field_init(fge, 128)) {
01696       ast_free(fge);
01697       return;
01698    }
01699 
01700    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
01701 
01702    fge->feature = feature;
01703 
01704    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);      
01705 
01706    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
01707                feature->sname, fg->gname, exten);
01708 }

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

Definition at line 1881 of file features.c.

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

01882 {
01883    int x, res = -1;
01884 
01885    ast_rwlock_wrlock(&features_lock);
01886    for (x = 0; x < FEATURES_COUNT; x++) {
01887       if (strcasecmp(builtin_features[x].sname, name))
01888          continue;
01889 
01890       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01891       res = 0;
01892       break;
01893    }
01894    ast_rwlock_unlock(&features_lock);
01895 
01896    return res;
01897 }

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

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

02279 {
02280    const char *feature;
02281 
02282    if (ast_strlen_zero(features)) {
02283       return;
02284    }
02285 
02286    for (feature = features; *feature; feature++) {
02287       switch (*feature) {
02288       case 'T' :
02289       case 't' :
02290          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
02291          break;
02292       case 'K' :
02293       case 'k' :
02294          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
02295          break;
02296       case 'H' :
02297       case 'h' :
02298          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
02299          break;
02300       case 'W' :
02301       case 'w' :
02302          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
02303          break;
02304       default :
02305          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
02306       }
02307    }
02308 }

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

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

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

00279 {
00280    ast_copy_string(chan->context, context, sizeof(chan->context));
00281    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00282    chan->priority = pri;
00283 }

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

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

02048 {
02049    int x;
02050    
02051    ast_clear_flag(config, AST_FLAGS_ALL);
02052 
02053    ast_rwlock_rdlock(&features_lock);
02054    for (x = 0; x < FEATURES_COUNT; x++) {
02055       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
02056          continue;
02057 
02058       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
02059          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02060 
02061       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
02062          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02063    }
02064    ast_rwlock_unlock(&features_lock);
02065    
02066    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
02067       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
02068 
02069       if (dynamic_features) {
02070          char *tmp = ast_strdupa(dynamic_features);
02071          char *tok;
02072          struct ast_call_feature *feature;
02073 
02074          /* while we have a feature */
02075          while ((tok = strsep(&tmp, "#"))) {
02076             AST_RWLIST_RDLOCK(&feature_list);
02077             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
02078                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
02079                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02080                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
02081                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02082             }
02083             AST_RWLIST_UNLOCK(&feature_list);
02084          }
02085       }
02086    }
02087 }

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

References chan, and FEATURE_SENSE_PEER.

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

00831 {
00832    if (sense == FEATURE_SENSE_PEER) {
00833       *caller = peer;
00834       *callee = chan;
00835    } else {
00836       *callee = peer;
00837       *caller = chan;
00838    }
00839 }

static void unmap_features ( void   )  [static]

Definition at line 1871 of file features.c.

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

01872 {
01873    int x;
01874 
01875    ast_rwlock_wrlock(&features_lock);
01876    for (x = 0; x < FEATURES_COUNT; x++)
01877       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01878    ast_rwlock_unlock(&features_lock);
01879 }


Variable Documentation

int adsipark [static]

Definition at line 142 of file features.c.

Referenced by ast_park_call_full(), and load_config().

char* app_bridge = "Bridge" [static]

Definition at line 4386 of file features.c.

unsigned int atxfercallbackretries [static]

Definition at line 151 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferdropcall [static]

Definition at line 149 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferloopdelay [static]

Definition at line 150 of file features.c.

Referenced by builtin_atxfer(), and load_config().

int atxfernoanswertimeout [static]

Definition at line 148 of file features.c.

Referenced by builtin_atxfer(), and load_config().

char* bridge_descrip [static]

Definition at line 4388 of file features.c.

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

Definition at line 4404 of file features.c.

Referenced by bridge_exec().

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

Definition at line 4387 of file features.c.

struct ast_call_feature builtin_features[] [static]

Definition at line 1608 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__ },
}

Definition at line 4216 of file features.c.

Referenced by ast_features_init().

int comebacktoorigin = 1 [static]

Definition at line 146 of file features.c.

Referenced by load_config(), and manage_parkinglot().

char courtesytone[256] [static]

Courtesy tone

Definition at line 137 of file features.c.

Referenced by builtin_automixmonitor(), builtin_automonitor(), load_config(), and park_exec_full().

struct ast_parkinglot* default_parkinglot

Definition at line 134 of file features.c.

Referenced by load_config(), park_exec(), park_exec_full(), and park_space_reserve().

char* descrip [static]

Definition at line 158 of file features.c.

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

char* descrip2 [static]

Definition at line 169 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 228 of file features.c.

Referenced by add_features_datastores(), builtin_atxfer(), manage_parkinglot(), and park_exec_full().

int featuredigittimeout [static]

Definition at line 145 of file features.c.

Referenced by ast_bridge_call(), and load_config().

ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static]

Definition at line 1606 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 4000 of file features.c.

char mandescr_park[] [static]

Definition at line 4276 of file features.c.

struct ast_app* mixmonitor_app = NULL [static]

Definition at line 194 of file features.c.

Referenced by builtin_automixmonitor().

int mixmonitor_ok = 1 [static]

Definition at line 195 of file features.c.

Referenced by builtin_automixmonitor().

struct ast_app* monitor_app = NULL [static]

Definition at line 191 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 192 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

struct ast_app_option park_call_options[128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } [static]

Definition at line 3147 of file features.c.

Referenced by park_call_exec().

char* parkcall = PARK_APP_NAME [static]

Definition at line 165 of file features.c.

Referenced by ast_features_init(), and build_parkinglot().

char* parkedcall = "ParkedCall" [static]

Definition at line 89 of file features.c.

Referenced by ast_features_init(), and ast_park_call_full().

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 138 of file features.c.

Referenced by park_exec_full().

char parking_ext[AST_MAX_EXTENSION]

Extension you type to park the call

Definition at line 135 of file features.c.

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

pthread_t parking_thread [static]

Definition at line 200 of file features.c.

Referenced by ast_features_init(), and ast_park_call_full().

struct ao2_container* parkinglots [static]

The list of parking lots configured. Always at least one - the default parking lot.

Definition at line 132 of file features.c.

Referenced by ast_features_init(), build_parkinglot(), do_parking_thread(), find_parkinglot(), handle_feature_show(), handle_parkedcalls(), manager_parking_status(), and parkinglot_destroy().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 91 of file features.c.

Referenced by ast_pickup_ext(), and load_config().

char* registrar = "features" [static]

Registrar for operations

Definition at line 153 of file features.c.

Referenced by ast_park_call_full(), build_parkinglot(), manage_parkinglot(), park_add_hints(), parkinglot_destroy(), pbx_load_module(), and pbx_load_users().

struct ast_app* stopmixmonitor_app = NULL [static]

Definition at line 197 of file features.c.

Referenced by builtin_automixmonitor().

int stopmixmonitor_ok = 1 [static]

Definition at line 198 of file features.c.

Referenced by builtin_automixmonitor().

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

Definition at line 156 of file features.c.

Referenced by ast_features_init(), and load_module().

char* synopsis2 = "Park yourself" [static]

Definition at line 167 of file features.c.

Referenced by ast_features_init().

int transferdigittimeout [static]

Definition at line 144 of file features.c.

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

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 140 of file features.c.

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

char xfersound[256] [static]

Call transfer sound

Definition at line 139 of file features.c.

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


Generated on Fri Jun 19 12:10:34 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7