Wed Oct 28 11:52:23 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"

Include dependency graph for features.c:

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 void __fini_feature_groups (void)
static void __fini_feature_list (void)
static void __init_feature_groups (void)
static void __init_feature_list (void)
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 the call and set CDR
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.
struct 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.
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_list
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.
struct 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]
struct ast_parkinglotdefault_parkinglot
static char * descrip
static char * descrip2
struct ast_datastore_info dial_features_info
static int featuredigittimeout
static ast_rwlock_t features_lock = { 0 }
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)

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

04441      {
04442    BRIDGE_OPT_PLAYTONE = (1 << 0),
04443 };

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

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


Function Documentation

static void __fini_feature_groups ( void   )  [static]

Definition at line 87 of file features.c.

00096 {

static void __fini_feature_list ( void   )  [static]

Definition at line 1629 of file features.c.

01633 {

static void __init_feature_groups ( void   )  [static]

Definition at line 87 of file features.c.

00096 {

static void __init_feature_list ( void   )  [static]

Definition at line 1629 of file features.c.

01633 {

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 4089 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, ast_bridge_thread_obj::chan, do_bridge_masquerade(), errno, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, playtone(), ast_bridge_thread_obj::return_to_pbx, and xfersound.

Referenced by ast_features_init().

04090 {
04091    const char *channela = astman_get_header(m, "Channel1");
04092    const char *channelb = astman_get_header(m, "Channel2");
04093    const char *playtone = astman_get_header(m, "Tone");
04094    struct ast_channel *chana = NULL, *chanb = NULL;
04095    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
04096    struct ast_bridge_thread_obj *tobj = NULL;
04097 
04098    /* make sure valid channels were specified */
04099    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
04100       astman_send_error(s, m, "Missing channel parameter in request");
04101       return 0;
04102    }
04103 
04104    /* The same code must be executed for chana and chanb.  To avoid a
04105     * theoretical deadlock, this code is separated so both chana and chanb will
04106     * not hold locks at the same time. */
04107 
04108    /* Start with chana */
04109    chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
04110 
04111    /* send errors if any of the channels could not be found/locked */
04112    if (!chana) {
04113       char buf[256];
04114       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
04115       astman_send_error(s, m, buf);
04116       return 0;
04117    }
04118 
04119    /* Answer the channels if needed */
04120    if (chana->_state != AST_STATE_UP)
04121       ast_answer(chana);
04122 
04123    /* create the placeholder channels and grab the other channels */
04124    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04125       NULL, NULL, 0, "Bridge/%s", chana->name))) {
04126       astman_send_error(s, m, "Unable to create temporary channel!");
04127       ast_channel_unlock(chana);
04128       return 1;
04129    }
04130 
04131    do_bridge_masquerade(chana, tmpchana);
04132    ast_channel_unlock(chana);
04133    chana = NULL;
04134 
04135    /* now do chanb */
04136    chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
04137    /* send errors if any of the channels could not be found/locked */
04138    if (!chanb) {
04139       char buf[256];
04140       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
04141       ast_hangup(tmpchana);
04142       astman_send_error(s, m, buf);
04143       return 0;
04144    }
04145 
04146    /* Answer the channels if needed */
04147    if (chanb->_state != AST_STATE_UP)
04148       ast_answer(chanb);
04149 
04150    /* create the placeholder channels and grab the other channels */
04151    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04152       NULL, NULL, 0, "Bridge/%s", chanb->name))) {
04153       astman_send_error(s, m, "Unable to create temporary channels!");
04154       ast_hangup(tmpchana);
04155       ast_channel_unlock(chanb);
04156       return 1;
04157    }
04158    do_bridge_masquerade(chanb, tmpchanb);
04159    ast_channel_unlock(chanb);
04160    chanb = NULL;
04161 
04162    /* make the channels compatible, send error if we fail doing so */
04163    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
04164       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
04165       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
04166       ast_hangup(tmpchana);
04167       ast_hangup(tmpchanb);
04168       return 1;
04169    }
04170 
04171    /* setup the bridge thread object and start the bridge */
04172    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
04173       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
04174       astman_send_error(s, m, "Unable to spawn a new bridge thread");
04175       ast_hangup(tmpchana);
04176       ast_hangup(tmpchanb);
04177       return 1;
04178    }
04179 
04180    tobj->chan = tmpchana;
04181    tobj->peer = tmpchanb;
04182    tobj->return_to_pbx = 1;
04183 
04184    if (ast_true(playtone)) {
04185       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
04186          if (ast_waitstream(tmpchanb, "") < 0)
04187             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
04188       }
04189    }
04190 
04191    ast_bridge_call_thread_launch(tobj);
04192 
04193    astman_send_ack(s, m, "Launched bridge thread with success");
04194 
04195    return 0;
04196 }

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

Definition at line 2330 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(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, ast_dial_features::features_callee, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, ast_datastore::inheritance, ast_dial_features::is_caller, and LOG_WARNING.

Referenced by ast_bridge_call().

02331 {
02332    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
02333    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
02334 
02335    ast_channel_lock(caller);
02336    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
02337    ast_channel_unlock(caller);
02338    if (!ds_caller_features) {
02339       if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02340          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
02341          return;
02342       }
02343       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
02344          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02345          ast_datastore_free(ds_caller_features);
02346          return;
02347       }
02348       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
02349       caller_features->is_caller = 1;
02350       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
02351       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
02352       ds_caller_features->data = caller_features;
02353       ast_channel_lock(caller);
02354       ast_channel_datastore_add(caller, ds_caller_features);
02355       ast_channel_unlock(caller);
02356    } else {
02357       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
02358        * flags over from the atxfer to the caller */
02359       return;
02360    }
02361 
02362    ast_channel_lock(callee);
02363    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
02364    ast_channel_unlock(callee);
02365    if (!ds_callee_features) {
02366       if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02367          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
02368          return;
02369       }
02370       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
02371          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02372          ast_datastore_free(ds_callee_features);
02373          return;
02374       }
02375       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
02376       callee_features->is_caller = 0;
02377       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
02378       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
02379       ds_callee_features->data = callee_features;
02380       ast_channel_lock(callee);
02381       ast_channel_datastore_add(callee, ds_callee_features);
02382       ast_channel_unlock(callee);
02383    }
02384 
02385    return;
02386 }

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

References ADSI_JUST_CENT, ast_adsi_load_session, ast_adsi_print, and justify.

Referenced by ast_park_call_full().

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

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

bridge the call and set CDR

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

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::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_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_bridge_config::end_sound, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_frame::frametype, 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_bridge_config::play_warning, ast_channel::priority, ast_frame::ptr, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, ast_channel::visible_indication, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

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

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

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

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

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by action_bridge(), and builtin_atxfer().

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

02052                                                                                                                            {
02053 
02054    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02055 }

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

References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

02023                                                                                                                                               {
02024 
02025    char dynamic_features_buf[128];
02026    const char *peer_dynamic_features, *chan_dynamic_features;
02027    struct ast_flags features;
02028    struct ast_call_feature feature;
02029    if (sense == FEATURE_SENSE_CHAN) {
02030       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
02031    }
02032    else {
02033       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
02034    }
02035 
02036    ast_channel_lock(peer);
02037    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
02038    ast_channel_unlock(peer);
02039 
02040    ast_channel_lock(chan);
02041    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
02042    ast_channel_unlock(chan);
02043 
02044    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,""));
02045 
02046    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);
02047 
02048    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
02049 }

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, read]

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

References ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), ast_channel::call_forward, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_frame::frametype, len(), LOG_NOTICE, ast_channel::name, pbx_builtin_setvar_helper(), and ast_frame::subclass.

Referenced by builtin_atxfer().

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

int ast_features_init ( void   ) 

Provided by features.c

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

04579 {
04580    int res;
04581 
04582    ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
04583 
04584    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
04585 
04586    if ((res = load_config()))
04587       return res;
04588    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
04589    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
04590    res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
04591    if (!res)
04592       res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
04593    if (!res) {
04594       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
04595       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park); 
04596       ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
04597    }
04598 
04599    res |= ast_devstate_prov_add("Park", metermaidstate);
04600 
04601    return res;
04602 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4012 of file features.c.

References load_config().

Referenced by handle_features_reload().

04013 {
04014    int res;
04015    /* Release parking lot list */
04016    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04017    // TODO: I don't think any marking is necessary
04018 
04019    /* Reload configuration */
04020    res = load_config();
04021    
04022    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04023    return res;
04024 }

struct ast_call_feature* ast_find_call_feature ( const char *  name  )  [read]

look for a call feature entry by its sname

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

Definition at line 1805 of file features.c.

References FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), handle_request_info(), and load_config().

01806 {
01807    int x;
01808    for (x = 0; x < FEATURES_COUNT; x++) {
01809       if (!strcasecmp(name, builtin_features[x].sname))
01810          return &builtin_features[x];
01811    }
01812    return NULL;
01813 }

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

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

int ast_park_call ( struct ast_channel chan,
struct ast_channel peer,
int  timeout,
int *  extout 
)

Park a call.

Park a call and read back parked location.

Definition at line 752 of file features.c.

References ast_park_call_full(), and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

00753 {
00754    struct ast_park_call_args args = {
00755       .timeout = timeout,
00756       .extout = extout,
00757    };
00758 
00759    return ast_park_call_full(chan, peer, &args);
00760 }

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

Definition at line 607 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, 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, parkeduser::options_specified, 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, ast_park_call_args::return_pri, 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().

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

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

References parking_ext.

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

00244 {
00245    return parking_ext;
00246 }

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

04397 {
04398    struct ast_channel *cur = NULL;
04399    int res = -1;
04400 
04401    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04402       if (!cur->pbx && 
04403          (cur != chan) &&
04404          (chan->pickupgroup & cur->callgroup) &&
04405          ((cur->_state == AST_STATE_RINGING) ||
04406           (cur->_state == AST_STATE_RING))) {
04407             break;
04408       }
04409       ast_channel_unlock(cur);
04410    }
04411    if (cur) {
04412       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04413       res = ast_answer(chan);
04414       if (res)
04415          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04416       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04417       if (res)
04418          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04419       res = ast_channel_masquerade(cur, chan);
04420       if (res)
04421          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04422       ast_channel_unlock(cur);
04423    } else   {
04424       ast_debug(1, "No call pickup possible...\n");
04425    }
04426    return res;
04427 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 248 of file features.c.

References pickup_ext.

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

00249 {
00250    return pickup_ext;
00251 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1795 of file features.c.

References ast_rwlock_rdlock(), and features_lock.

Referenced by handle_request_info().

01796 {
01797    ast_rwlock_rdlock(&features_lock);
01798 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_list

register new feature into feature_set

Definition at line 1632 of file features.c.

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

Referenced by load_config().

01633 {
01634    if (!feature) {
01635       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01636       return;
01637    }
01638   
01639    AST_RWLIST_WRLOCK(&feature_list);
01640    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01641    AST_RWLIST_UNLOCK(&feature_list);
01642 
01643    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01644 }

void ast_unlock_call_features ( void   ) 

Definition at line 1800 of file features.c.

References ast_rwlock_unlock(), and features_lock.

Referenced by handle_request_info().

01801 {
01802    ast_rwlock_unlock(&features_lock);
01803 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

01721 {
01722    if (!feature) {
01723       return;
01724    }
01725 
01726    AST_RWLIST_WRLOCK(&feature_list);
01727    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01728    AST_RWLIST_UNLOCK(&feature_list);
01729 
01730    ast_free(feature);
01731 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1734 of file features.c.

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

Referenced by load_config().

01735 {
01736    struct ast_call_feature *feature;
01737 
01738    AST_RWLIST_WRLOCK(&feature_list);
01739    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01740       ast_free(feature);
01741    }
01742    AST_RWLIST_UNLOCK(&feature_list);
01743 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

Definition at line 1760 of file features.c.

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

Referenced by load_config().

01761 {
01762    struct feature_group *fg;
01763    struct feature_group_exten *fge;
01764 
01765    AST_RWLIST_WRLOCK(&feature_groups);
01766    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
01767       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
01768          ast_string_field_free_memory(fge);
01769          ast_free(fge);
01770       }
01771 
01772       ast_string_field_free_memory(fg);
01773       ast_free(fg);
01774    }
01775    AST_RWLIST_UNLOCK(&feature_groups);
01776 }

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

04459 {
04460    struct ast_channel *current_dest_chan, *final_dest_chan;
04461    char *tmp_data  = NULL;
04462    struct ast_flags opts = { 0, };
04463    struct ast_bridge_config bconfig = { { 0, }, };
04464 
04465    AST_DECLARE_APP_ARGS(args,
04466       AST_APP_ARG(dest_chan);
04467       AST_APP_ARG(options);
04468    );
04469    
04470    if (ast_strlen_zero(data)) {
04471       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
04472       return -1;
04473    }
04474 
04475    tmp_data = ast_strdupa(data);
04476    AST_STANDARD_APP_ARGS(args, tmp_data);
04477    if (!ast_strlen_zero(args.options))
04478       ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options);
04479 
04480    /* avoid bridge with ourselves */
04481    if (!strncmp(chan->name, args.dest_chan, 
04482       strlen(chan->name) < strlen(args.dest_chan) ? 
04483       strlen(chan->name) : strlen(args.dest_chan))) {
04484       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
04485       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04486                "Response: Failed\r\n"
04487                "Reason: Unable to bridge channel to itself\r\n"
04488                "Channel1: %s\r\n"
04489                "Channel2: %s\r\n",
04490                chan->name, args.dest_chan);
04491       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
04492       return 0;
04493    }
04494 
04495    /* make sure we have a valid end point */
04496    if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 
04497       strlen(args.dest_chan)))) {
04498       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
04499          "cannot get its lock\n", args.dest_chan);
04500       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04501                "Response: Failed\r\n"
04502                "Reason: Cannot grab end point\r\n"
04503                "Channel1: %s\r\n"
04504                "Channel2: %s\r\n", chan->name, args.dest_chan);
04505       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
04506       return 0;
04507    }
04508 
04509    /* answer the channel if needed */
04510    if (current_dest_chan->_state != AST_STATE_UP)
04511       ast_answer(current_dest_chan);
04512 
04513    /* try to allocate a place holder where current_dest_chan will be placed */
04514    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04515       NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) {
04516       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
04517       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04518                "Response: Failed\r\n"
04519                "Reason: cannot create placeholder\r\n"
04520                "Channel1: %s\r\n"
04521                "Channel2: %s\r\n", chan->name, args.dest_chan);
04522    }
04523    do_bridge_masquerade(current_dest_chan, final_dest_chan);
04524 
04525    ast_channel_unlock(current_dest_chan);
04526 
04527    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
04528    /* try to make compatible, send error if we fail */
04529    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
04530       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
04531       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04532                "Response: Failed\r\n"
04533                "Reason: Could not make channels compatible for bridge\r\n"
04534                "Channel1: %s\r\n"
04535                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04536       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
04537       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
04538       return 0;
04539    }
04540 
04541    /* Report that the bridge will be successfull */
04542    manager_event(EVENT_FLAG_CALL, "BridgeExec",
04543             "Response: Success\r\n"
04544             "Channel1: %s\r\n"
04545             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04546 
04547    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
04548    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
04549       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
04550          if (ast_waitstream(final_dest_chan, "") < 0)
04551             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
04552       }
04553    }
04554    
04555    /* do the bridge */
04556    ast_bridge_call(chan, final_dest_chan, &bconfig);
04557 
04558    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
04559    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
04560    if (!ast_check_hangup(final_dest_chan)) {
04561       ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 
04562          final_dest_chan->context, final_dest_chan->exten, 
04563          final_dest_chan->priority, final_dest_chan->name);
04564 
04565       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
04566          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
04567          ast_hangup(final_dest_chan);
04568       } else
04569          ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
04570    } else {
04571       ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name);
04572       ast_hangup(final_dest_chan);
04573    }
04574 
04575    return 0;
04576 }

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

Build parkinglot from configuration and chain it in.

Definition at line 3493 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_parkinglot::mohclass, ast_variable::name, ast_variable::next, option_debug, parkcall, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglot_destroy(), parkinglot_unref(), parkinglots, ast_parkinglot::parkingtime, registrar, strdup, and ast_variable::value.

Referenced by load_config().

03494 {
03495    struct ast_parkinglot *parkinglot;
03496    struct ast_context *con = NULL;
03497 
03498    struct ast_variable *confvar = var;
03499    int error = 0;
03500    int start = 0, end = 0;
03501    int oldparkinglot = 0;
03502 
03503    parkinglot = find_parkinglot(name);
03504    if (parkinglot)
03505       oldparkinglot = 1;
03506    else
03507       parkinglot = create_parkinglot(name);
03508 
03509    if (!parkinglot)
03510       return NULL;
03511 
03512    ao2_lock(parkinglot);
03513 
03514    if (option_debug)
03515       ast_log(LOG_DEBUG, "Building parking lot %s\n", name);
03516    
03517    /* Do some config stuff */
03518    while(confvar) {
03519       if (!strcasecmp(confvar->name, "context")) {
03520          ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
03521       } else if (!strcasecmp(confvar->name, "parkingtime")) {
03522          if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
03523             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
03524             parkinglot->parkingtime = DEFAULT_PARK_TIME;
03525          } else
03526             parkinglot->parkingtime = parkinglot->parkingtime * 1000;
03527       } else if (!strcasecmp(confvar->name, "parkpos")) {
03528          if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) {
03529             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);
03530             error = 1;
03531          } else {
03532             parkinglot->parking_start = start;
03533             parkinglot->parking_stop = end;
03534          }
03535       } else if (!strcasecmp(confvar->name, "findslot")) {
03536          parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next"));
03537       }
03538       confvar = confvar->next;
03539    }
03540    /* make sure parkingtime is set if not specified */
03541    if (parkinglot->parkingtime == 0) {
03542       parkinglot->parkingtime = DEFAULT_PARK_TIME;
03543    }
03544 
03545    if (!var) { /* Default parking lot */
03546       ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
03547       ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial));
03548       ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass));
03549    }
03550 
03551    /* Check for errors */
03552    if (ast_strlen_zero(parkinglot->parking_con)) {
03553       ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name);
03554       error = 1;
03555    }
03556 
03557    /* Create context */
03558    if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) {
03559       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
03560       error = 1;
03561    }
03562 
03563    /* Add a parking extension into the context */
03564    if (!error && !oldparkinglot) {
03565       if (!ast_strlen_zero(ast_parking_ext())) {
03566          if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
03567             error = 1;
03568       }
03569    }
03570 
03571    ao2_unlock(parkinglot);
03572 
03573    if (error) {
03574       ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
03575       parkinglot_destroy(parkinglot);
03576       return NULL;
03577    }
03578    if (option_debug)
03579       ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
03580 
03581 
03582    /* Move it into the list, if it wasn't already there */
03583    if (!oldparkinglot) {
03584       ao2_link(parkinglots, parkinglot);
03585    }
03586    parkinglot_unref(parkinglot);
03587 
03588    return parkinglot;
03589 }

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 1317 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, ast_bridge_thread_obj::bconfig, builtin_parkcall(), ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, ast_datastore::data, ast_bridge_config::end_bridge_callback_data_fixup, 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_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xferfailsound, and xfersound.

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

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 1026 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, 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.

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

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

References AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, 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.

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

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 1186 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, 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.

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

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

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

01137 {
01138    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
01139    return AST_FEATURE_RETURN_HANGUP;
01140 }

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

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

Referenced by builtin_atxfer().

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

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

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

02908 {
02909    int i = 0;
02910    enum {
02911       OPT_CALLEE_REDIRECT   = 't',
02912       OPT_CALLER_REDIRECT   = 'T',
02913       OPT_CALLEE_AUTOMON    = 'w',
02914       OPT_CALLER_AUTOMON    = 'W',
02915       OPT_CALLEE_DISCONNECT = 'h',
02916       OPT_CALLER_DISCONNECT = 'H',
02917       OPT_CALLEE_PARKCALL   = 'k',
02918       OPT_CALLER_PARKCALL   = 'K',
02919    };
02920 
02921    memset(options, 0, len);
02922    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02923       options[i++] = OPT_CALLER_REDIRECT;
02924    }
02925    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02926       options[i++] = OPT_CALLER_AUTOMON;
02927    }
02928    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02929       options[i++] = OPT_CALLER_DISCONNECT;
02930    }
02931    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02932       options[i++] = OPT_CALLER_PARKCALL;
02933    }
02934 
02935    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02936       options[i++] = OPT_CALLEE_REDIRECT;
02937    }
02938    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02939       options[i++] = OPT_CALLEE_AUTOMON;
02940    }
02941    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02942       options[i++] = OPT_CALLEE_DISCONNECT;
02943    }
02944    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02945       options[i++] = OPT_CALLEE_PARKCALL;
02946    }
02947 
02948    return options;
02949 }

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

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

Referenced by builtin_atxfer().

01292 {
01293    if (ast_channel_make_compatible(c, newchan) < 0) {
01294       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01295          c->name, newchan->name);
01296       ast_hangup(newchan);
01297       return -1;
01298    }
01299    return 0;
01300 }

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 294 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(), f, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.

Referenced by builtin_blindtransfer().

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

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

Allocate parking lot structure.

Definition at line 3464 of file features.c.

References ao2_alloc, ast_copy_string(), AST_LIST_HEAD_INIT, ast_parkinglot::name, parkinglot_destroy(), and ast_parkinglot::parkings.

Referenced by build_parkinglot().

03465 {
03466    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
03467 
03468    if (!name)
03469       return NULL;
03470 
03471    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
03472    if (!newlot)
03473       return NULL;
03474    
03475    ast_copy_string(newlot->name, name, sizeof(newlot->name));
03476    AST_LIST_HEAD_INIT(&newlot->parkings);
03477 
03478    return newlot;
03479 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 221 of file features.c.

References ast_free.

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

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

Definition at line 208 of file features.c.

References ast_calloc.

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

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 4059 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(), ast_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

Referenced by action_bridge(), and bridge_exec().

04060 {
04061    ast_moh_stop(chan);
04062    ast_channel_lock(chan);
04063    ast_setstate(tmpchan, chan->_state);
04064    tmpchan->readformat = chan->readformat;
04065    tmpchan->writeformat = chan->writeformat;
04066    ast_channel_masquerade(tmpchan, chan);
04067    ast_channel_lock(tmpchan);
04068    ast_do_masquerade(tmpchan);
04069    /* when returning from bridge, the channel will continue at the next priority */
04070    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
04071    ast_channel_unlock(tmpchan);
04072    ast_channel_unlock(chan);
04073 }

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

03133 {
03134    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
03135    fd_set nrfds, nefds; /* args for the next select */
03136    FD_ZERO(&rfds);
03137    FD_ZERO(&efds);
03138 
03139    for (;;) {
03140       int res = 0;
03141       int ms = -1;   /* select timeout, uninitialized */
03142       int max = -1;  /* max fd, none there yet */
03143       struct ao2_iterator iter;
03144       struct ast_parkinglot *curlot;
03145       FD_ZERO(&nrfds);
03146       FD_ZERO(&nefds);
03147       iter = ao2_iterator_init(parkinglots, 0);
03148 
03149       while ((curlot = ao2_iterator_next(&iter))) {
03150          res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max);
03151          ao2_ref(curlot, -1);
03152       }
03153 
03154       rfds = nrfds;
03155       efds = nefds;
03156       {
03157          struct timeval wait = ast_samp2tv(ms, 1000);
03158          /* Wait for something to happen */
03159          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
03160       }
03161       pthread_testcancel();
03162    }
03163    return NULL;   /* Never reached */
03164 }

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 1824 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, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().

Referenced by load_config().

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

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

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

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

find a call feature by name

Definition at line 1746 of file features.c.

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

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

01747 {
01748    struct ast_call_feature *tmp;
01749 
01750    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01751       if (!strcasecmp(tmp->sname, name)) {
01752          break;
01753       }
01754    }
01755 
01756    return tmp;
01757 }

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

Find a group by name.

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

Definition at line 1784 of file features.c.

References AST_LIST_TRAVERSE, and feature_group::gname.

Referenced by feature_interpret_helper().

01784                                                           {
01785    struct feature_group *fg = NULL;
01786 
01787    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
01788       if (!strcasecmp(fg->gname, name))
01789          break;
01790    }
01791 
01792    return fg;
01793 }

struct ast_parkinglot * find_parkinglot ( const char *  name  )  [read]

Find parkinglot by name.

Definition at line 3167 of file features.c.

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

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

03168 {
03169    struct ast_parkinglot *parkinglot = NULL;
03170    struct ast_parkinglot tmp_parkinglot;
03171    
03172    if (ast_strlen_zero(name))
03173       return NULL;
03174 
03175    ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
03176 
03177    parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
03178 
03179    if (parkinglot && option_debug)
03180       ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
03181 
03182    return parkinglot;
03183 }

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

Find parking lot name from channel.

Definition at line 421 of file features.c.

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

Referenced by park_exec_full(), and park_space_reserve().

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

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 1142 of file features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

01143 {
01144    ast_indicate(chan, AST_CONTROL_UNHOLD);
01145 
01146    return ast_autoservice_stop(chan);
01147 }

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

03953 {
03954    int i;
03955    struct ast_call_feature *feature;
03956    struct ao2_iterator iter;
03957    struct ast_parkinglot *curlot;
03958 #define HFS_FORMAT "%-25s %-7s %-7s\n"
03959 
03960    switch (cmd) {
03961    
03962    case CLI_INIT:
03963       e->command = "features show";
03964       e->usage =
03965          "Usage: features show\n"
03966          "       Lists configured features\n";
03967       return NULL;
03968    case CLI_GENERATE:
03969       return NULL;
03970    }
03971 
03972    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
03973    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03974 
03975    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
03976 
03977    ast_rwlock_rdlock(&features_lock);
03978    for (i = 0; i < FEATURES_COUNT; i++)
03979       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
03980    ast_rwlock_unlock(&features_lock);
03981 
03982    ast_cli(a->fd, "\n");
03983    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
03984    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03985    if (AST_RWLIST_EMPTY(&feature_list)) {
03986       ast_cli(a->fd, "(none)\n");
03987    } else {
03988       AST_RWLIST_RDLOCK(&feature_list);
03989       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
03990          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
03991       }
03992       AST_RWLIST_UNLOCK(&feature_list);
03993    }
03994 
03995    // loop through all the parking lots
03996    iter = ao2_iterator_init(parkinglots, 0);
03997 
03998    while ((curlot = ao2_iterator_next(&iter))) {
03999       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
04000       ast_cli(a->fd, "------------\n");
04001       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", parking_ext);
04002       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->parking_con);
04003       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
04004       ast_cli(a->fd,"\n");
04005       ao2_ref(curlot, -1);
04006    }
04007 
04008 
04009    return CLI_SUCCESS;
04010 }

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

Definition at line 4026 of file features.c.

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

04027 {
04028    switch (cmd) { 
04029    case CLI_INIT:
04030       e->command = "features reload";
04031       e->usage =
04032          "Usage: features reload\n"
04033          "       Reloads configured call features from features.conf\n";
04034       return NULL;
04035    case CLI_GENERATE:
04036       return NULL;
04037    }
04038    ast_features_reload();
04039 
04040    return CLI_SUCCESS;
04041 }

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

04210 {
04211    struct parkeduser *cur;
04212    int numparked = 0;
04213    struct ao2_iterator iter;
04214    struct ast_parkinglot *curlot;
04215 
04216    switch (cmd) {
04217    case CLI_INIT:
04218       e->command = "parkedcalls show";
04219       e->usage =
04220          "Usage: parkedcalls show\n"
04221          "       List currently parked calls\n";
04222       return NULL;
04223    case CLI_GENERATE:
04224       return NULL;
04225    }
04226 
04227    if (a->argc > e->args)
04228       return CLI_SHOWUSAGE;
04229 
04230    ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
04231       , "Context", "Extension", "Pri", "Timeout");
04232 
04233    iter = ao2_iterator_init(parkinglots, 0);
04234    while ((curlot = ao2_iterator_next(&iter))) {
04235       int lotparked = 0;
04236       ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name);
04237 
04238       AST_LIST_LOCK(&curlot->parkings);
04239       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04240          ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
04241             ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
04242             ,cur->priority,
04243             (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
04244          numparked++;
04245          numparked += lotparked;
04246       }
04247       AST_LIST_UNLOCK(&curlot->parkings);
04248       if (lotparked)
04249          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
04250 
04251       ao2_ref(curlot, -1);
04252    }
04253 
04254    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
04255 
04256    return CLI_SUCCESS;
04257 }

static int load_config ( void   )  [static]

Todo:
XXX var_name or app_args ?

Definition at line 3611 of file features.c.

References adsipark, ao2_lock(), ao2_unlock(), ast_call_feature::app, app, ast_call_feature::app_args, ARRAY_LEN, ast_add_extension2(), ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load2(), ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FEATURE_FLAG_ONPEER, AST_FEATURE_FLAG_ONSELF, ast_find_call_feature(), ast_log(), ast_parking_ext(), ast_register_feature(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_unregister_groups(), ast_variable_browse(), ast_verb, atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, 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, ast_call_feature::exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_MOH_LEN, FEATURE_SNAME_LEN, featuredigittimeout, find_dynamic_feature(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_parkinglot::mohclass, ast_variable::name, ast_variable::next, notify_metermaids(), ast_call_feature::operation, option_debug, park_add_hints(), ast_parkinglot::parkaddhints, parkcall, ast_parkinglot::parkedcallhangup, ast_parkinglot::parkedcallrecording, ast_parkinglot::parkedcallreparking, ast_parkinglot::parkedcalltransfers, parkedplay, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, parking_ext, ast_parkinglot::parking_offset, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, ast_parkinglot::parkingtime, pickup_ext, register_group(), register_group_feature(), registrar, remap_feature(), ast_call_feature::sname, strsep(), transferdigittimeout, unmap_features(), ast_variable::value, var, xferfailsound, and xfersound.

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

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

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 2952 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_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, 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, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, ast_frame::frametype, free, ast_channel::generatordata, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, 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(), parkeduser::start, and ast_frame::subclass.

Referenced by do_parking_thread().

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

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 4334 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(), and buf.

Referenced by ast_features_init().

04335 {
04336    const char *channel = astman_get_header(m, "Channel");
04337    const char *channel2 = astman_get_header(m, "Channel2");
04338    const char *timeout = astman_get_header(m, "Timeout");
04339    char buf[BUFSIZ];
04340    int to = 0;
04341    int res = 0;
04342    int parkExt = 0;
04343    struct ast_channel *ch1, *ch2;
04344 
04345    if (ast_strlen_zero(channel)) {
04346       astman_send_error(s, m, "Channel not specified");
04347       return 0;
04348    }
04349 
04350    if (ast_strlen_zero(channel2)) {
04351       astman_send_error(s, m, "Channel2 not specified");
04352       return 0;
04353    }
04354 
04355    ch1 = ast_get_channel_by_name_locked(channel);
04356    if (!ch1) {
04357       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
04358       astman_send_error(s, m, buf);
04359       return 0;
04360    }
04361 
04362    ch2 = ast_get_channel_by_name_locked(channel2);
04363    if (!ch2) {
04364       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
04365       astman_send_error(s, m, buf);
04366       ast_channel_unlock(ch1);
04367       return 0;
04368    }
04369 
04370    if (!ast_strlen_zero(timeout)) {
04371       sscanf(timeout, "%30d", &to);
04372    }
04373 
04374    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
04375    if (!res) {
04376       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
04377       astman_send_ack(s, m, "Park successful");
04378    } else {
04379       astman_send_error(s, m, "Park failure");
04380    }
04381 
04382    ast_channel_unlock(ch1);
04383    ast_channel_unlock(ch2);
04384 
04385    return 0;
04386 }

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 4273 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_OR, and parkeduser::start.

Referenced by ast_features_init().

04274 {
04275    struct parkeduser *cur;
04276    const char *id = astman_get_header(m, "ActionID");
04277    char idText[256] = "";
04278    struct ao2_iterator iter;
04279    struct ast_parkinglot *curlot;
04280 
04281    if (!ast_strlen_zero(id))
04282       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04283 
04284    astman_send_ack(s, m, "Parked calls will follow");
04285 
04286    iter = ao2_iterator_init(parkinglots, 0);
04287    while ((curlot = ao2_iterator_next(&iter))) {
04288 
04289       AST_LIST_LOCK(&curlot->parkings);
04290       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04291          astman_append(s, "Event: ParkedCall\r\n"
04292             "Exten: %d\r\n"
04293             "Channel: %s\r\n"
04294             "From: %s\r\n"
04295             "Timeout: %ld\r\n"
04296             "CallerIDNum: %s\r\n"
04297             "CallerIDName: %s\r\n"
04298             "%s"
04299             "\r\n",
04300             cur->parkingnum, cur->chan->name, cur->peername,
04301             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
04302             S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
04303             S_OR(cur->chan->cid.cid_name, ""),
04304             idText);
04305       }
04306       AST_LIST_UNLOCK(&curlot->parkings);
04307       ao2_ref(curlot, -1);
04308    }
04309 
04310    astman_append(s,
04311       "Event: ParkedCallsComplete\r\n"
04312       "%s"
04313       "\r\n",idText);
04314 
04315 
04316    return RESULT_SUCCESS;
04317 }

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

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

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

Definition at line 828 of file features.c.

References masq_park_call().

Referenced by builtin_blindtransfer(), and builtin_parkcall().

00829 {
00830    return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
00831 }

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

References masq_park_call().

Referenced by park_call_exec().

00824 {
00825    return masq_park_call(rchan, peer, 0, NULL, 1, args);
00826 }

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

metermaids callback from devicestate.c

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

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

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

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

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

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

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

References ast_add_extension(), PRIORITY_HINT, and registrar.

Referenced by load_config().

03599 {
03600    int numext;
03601    char device[AST_MAX_EXTENSION];
03602    char exten[10];
03603 
03604    for (numext = start; numext <= stop; numext++) {
03605       snprintf(exten, sizeof(exten), "%d", numext);
03606       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03607       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03608    }
03609 }

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

Park a call.

Definition at line 3192 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(), ast_channel::exten, ast_flags::flags, ast_park_call_args::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().

03193 {
03194    /* Cache the original channel name in case we get masqueraded in the middle
03195     * of a park--it is still theoretically possible for a transfer to happen before
03196     * we get here, but it is _really_ unlikely */
03197    char *orig_chan_name = ast_strdupa(chan->name);
03198    char orig_exten[AST_MAX_EXTENSION];
03199    int orig_priority = chan->priority;
03200 
03201    /* Data is unused at the moment but could contain a parking
03202       lot context eventually */
03203    int res = 0;
03204 
03205    char *parse = NULL;
03206    AST_DECLARE_APP_ARGS(app_args,
03207       AST_APP_ARG(timeout);
03208       AST_APP_ARG(return_con);
03209       AST_APP_ARG(return_ext);
03210       AST_APP_ARG(return_pri);
03211       AST_APP_ARG(options);
03212    );
03213 
03214    parse = ast_strdupa(data);
03215    AST_STANDARD_APP_ARGS(app_args, parse);
03216 
03217    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
03218 
03219    /* Setup the exten/priority to be s/1 since we don't know
03220       where this call should return */
03221    strcpy(chan->exten, "s");
03222    chan->priority = 1;
03223 
03224    /* Answer if call is not up */
03225    if (chan->_state != AST_STATE_UP)
03226       res = ast_answer(chan);
03227 
03228    /* Sleep to allow VoIP streams to settle down */
03229    if (!res)
03230       res = ast_safe_sleep(chan, 1000);
03231 
03232    /* Park the call */
03233    if (!res) {
03234       struct ast_park_call_args args = {
03235          .orig_chan_name = orig_chan_name,
03236       };
03237       struct ast_flags flags = { 0 };
03238 
03239       if (parse) {
03240          if (!ast_strlen_zero(app_args.timeout)) {
03241             if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
03242                ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
03243                args.timeout = 0;
03244             }
03245          }
03246          if (!ast_strlen_zero(app_args.return_con)) {
03247             args.return_con = app_args.return_con;
03248          }
03249          if (!ast_strlen_zero(app_args.return_ext)) {
03250             args.return_ext = app_args.return_ext;
03251          }
03252          if (!ast_strlen_zero(app_args.return_pri)) {
03253             if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
03254                ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
03255                args.return_pri = 0;
03256             }
03257          }
03258       }
03259 
03260       ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
03261       args.flags = flags.flags;
03262 
03263       res = masq_park_call_announce_args(chan, chan, &args);
03264       /* Continue on in the dialplan */
03265       if (res == 1) {
03266          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
03267          chan->priority = orig_priority;
03268          res = 0;
03269       } else if (!res) {
03270          res = 1;
03271       }
03272    }
03273 
03274    return res;
03275 }

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

Definition at line 3441 of file features.c.

References default_parkinglot, and park_exec_full().

Referenced by ast_features_init().

03442 {
03443    return park_exec_full(chan, data, default_parkinglot);
03444 }

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 3278 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(), ast_channel::cdr, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, courtesytone, ast_datastore::data, default_parkinglot, EVENT_FLAG_CALL, ast_dial_features::features_callee, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_dial_features::features_caller, find_parkinglot(), findparkinglotname(), ast_dial_features::is_caller, ast_channel::language, LOG_WARNING, manager_event, ast_channel::name, notify_metermaids(), ast_parkinglot::parkedcallhangup, ast_parkinglot::parkedcallrecording, ast_parkinglot::parkedcallreparking, ast_parkinglot::parkedcalltransfers, parkedplay, ast_parkinglot::parking_con, parkeduser::parkingexten, parkeduser::parkingnum, ast_parkinglot::parkings, ast_channel::pbx, pbx_builtin_setvar_helper(), and S_OR.

Referenced by park_exec().

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

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

Note:
The API forces us to specify a numeric parking slot, even though the architecture would tend to support non-numeric extensions (as are possible with SIP, for example). Hence, we enforce that limitation here. If extout was not numeric, we could permit arbitrary non-numeric extensions.

Definition at line 494 of file features.c.

References ast_calloc, ast_channel_lock, ast_channel_unlock, ast_exists_extension(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strlen_zero(), ast_test_flag, default_parkinglot, find_parkinglot(), findparkinglotname(), free, LOG_DEBUG, LOG_WARNING, ast_parkinglot::name, parkeduser::notquiteyet, option_debug, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, ast_parkinglot::parking_offset, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, ast_parkinglot::parkings, and pbx_builtin_getvar_helper().

Referenced by ast_park_call_full(), and masq_park_call().

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

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

Definition at line 3455 of file features.c.

References ao2_ref, ast_log(), LOG_DEBUG, ast_parkinglot::name, and option_debug.

Referenced by park_space_reserve().

03456 {
03457    int refcount = ao2_ref(parkinglot, +1);
03458    if (option_debug > 2)
03459       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
03460    return parkinglot;
03461 }

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

Definition at line 268 of file features.c.

References CMP_MATCH, CMP_STOP, and ast_parkinglot::name.

Referenced by ast_features_init().

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

static void parkinglot_destroy ( void *  obj  )  [static]

Destroy a parking lot.

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

03483 {
03484    struct ast_parkinglot *ruin = obj;
03485    struct ast_context *con;
03486    con = ast_context_find(ruin->parking_con);
03487    if (con)
03488       ast_context_destroy(con, registrar);
03489    ao2_unlink(parkinglots, ruin);
03490 }

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

Definition at line 261 of file features.c.

References ast_str_case_hash(), and ast_parkinglot::name.

Referenced by ast_features_init().

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

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

References ao2_ref, ast_log(), LOG_DEBUG, ast_parkinglot::name, and option_debug.

Referenced by build_parkinglot(), and park_space_reserve().

03449 {
03450    int refcount = ao2_ref(parkinglot, -1);
03451    if (option_debug > 2)
03452       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
03453 }

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

return the first unlocked cdr in a possible chain

Definition at line 2287 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

02288 {
02289    struct ast_cdr *cdr_orig = cdr;
02290    while (cdr) {
02291       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02292          return cdr;
02293       cdr = cdr->next;
02294    }
02295    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
02296 }

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

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

Referenced by builtin_automonitor().

00895 {
00896    /* First play for caller, put other channel on auto service */
00897    if (ast_autoservice_start(callee_chan))
00898       return -1;
00899    if (ast_stream_and_wait(caller_chan, audiofile, "")) {
00900       ast_log(LOG_WARNING, "Failed to play automon message!\n");
00901       ast_autoservice_stop(callee_chan);
00902       return -1;
00903    }
00904    if (ast_autoservice_stop(callee_chan))
00905       return -1;
00906    /* Then play for callee, put other channel on auto service */
00907    if (ast_autoservice_start(caller_chan))
00908       return -1;
00909    if (ast_stream_and_wait(callee_chan, audiofile, "")) {
00910       ast_log(LOG_WARNING, "Failed to play automon message !\n");
00911       ast_autoservice_stop(caller_chan);
00912       return -1;
00913    }
00914    if (ast_autoservice_stop(caller_chan))
00915       return -1;
00916    return(0);
00917 }

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

Output parking event to manager.

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

02890 {
02891    manager_event(EVENT_FLAG_CALL, s,
02892       "Exten: %s\r\n"
02893       "Channel: %s\r\n"
02894       "Parkinglot: %s\r\n"
02895       "CallerIDNum: %s\r\n"
02896       "CallerIDName: %s\r\n"
02897       "UniqueID: %s\r\n\r\n",
02898       pu->parkingexten, 
02899       pu->chan->name,
02900       pu->parkinglot->name,
02901       S_OR(pu->chan->cid.cid_num, "<unknown>"),
02902       S_OR(pu->chan->cid.cid_name, "<unknown>"),
02903       pu->chan->uniqueid
02904       );
02905 }

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

01158 {
01159    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
01160    if (ast_strlen_zero(s)) {
01161       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
01162    }
01163    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
01164       s = transferer->macrocontext;
01165    }
01166    if (ast_strlen_zero(s)) {
01167       s = transferer->context;
01168    }
01169    return s;  
01170 }

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

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 1653 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::gname, and LOG_NOTICE.

Referenced by load_config().

01654 {
01655    struct feature_group *fg;
01656 
01657    if (!fgname) {
01658       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
01659       return NULL;
01660    }
01661 
01662    if (!(fg = ast_calloc(1, sizeof(*fg))))
01663       return NULL;
01664 
01665    if (ast_string_field_init(fg, 128)) {
01666       ast_free(fg);
01667       return NULL;
01668    }
01669 
01670    ast_string_field_set(fg, gname, fgname);
01671 
01672    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
01673 
01674    ast_verb(2, "Registered group '%s'\n", fg->gname);
01675 
01676    return fg;
01677 }

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 1688 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, ast_call_feature::exten, feature_group_exten::feature, feature_group::features, feature_group::gname, LOG_NOTICE, S_OR, and ast_call_feature::sname.

Referenced by load_config().

01689 {
01690    struct feature_group_exten *fge;
01691 
01692    if (!fg) {
01693       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
01694       return;
01695    }
01696 
01697    if (!feature) {
01698       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
01699       return;
01700    }
01701 
01702    if (!(fge = ast_calloc(1, sizeof(*fge))))
01703       return;
01704 
01705    if (ast_string_field_init(fge, 128)) {
01706       ast_free(fge);
01707       return;
01708    }
01709 
01710    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
01711 
01712    fge->feature = feature;
01713 
01714    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);      
01715 
01716    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
01717                feature->sname, fg->gname, exten);
01718 }

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

Definition at line 1891 of file features.c.

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

Referenced by load_config().

01892 {
01893    int x, res = -1;
01894 
01895    ast_rwlock_wrlock(&features_lock);
01896    for (x = 0; x < FEATURES_COUNT; x++) {
01897       if (strcasecmp(builtin_features[x].sname, name))
01898          continue;
01899 
01900       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01901       res = 0;
01902       break;
01903    }
01904    ast_rwlock_unlock(&features_lock);
01905 
01906    return res;
01907 }

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

Definition at line 2298 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(), ast_bridge_config::features_caller, and LOG_WARNING.

Referenced by ast_bridge_call().

02299 {
02300    const char *feature;
02301 
02302    if (ast_strlen_zero(features)) {
02303       return;
02304    }
02305 
02306    for (feature = features; *feature; feature++) {
02307       switch (*feature) {
02308       case 'T' :
02309       case 't' :
02310          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
02311          break;
02312       case 'K' :
02313       case 'k' :
02314          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
02315          break;
02316       case 'H' :
02317       case 'h' :
02318          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
02319          break;
02320       case 'W' :
02321       case 'w' :
02322          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
02323          break;
02324       default :
02325          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
02326       }
02327    }
02328 }

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

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

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

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

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

Definition at line 2057 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, ast_call_feature::feature_mask, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, features_lock, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

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

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

References FEATURE_SENSE_PEER.

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

00841 {
00842    if (sense == FEATURE_SENSE_PEER) {
00843       *caller = peer;
00844       *callee = chan;
00845    } else {
00846       *callee = peer;
00847       *caller = chan;
00848    }
00849 }

static void unmap_features ( void   )  [static]

Definition at line 1881 of file features.c.

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

Referenced by load_config().

01882 {
01883    int x;
01884 
01885    ast_rwlock_wrlock(&features_lock);
01886    for (x = 0; x < FEATURES_COUNT; x++)
01887       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01888    ast_rwlock_unlock(&features_lock);
01889 }


Variable Documentation

int adsipark [static]

Definition at line 143 of file features.c.

Referenced by ast_park_call_full(), and load_config().

char* app_bridge = "Bridge" [static]

Definition at line 4429 of file features.c.

unsigned int atxfercallbackretries [static]

Definition at line 152 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferdropcall [static]

Definition at line 150 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferloopdelay [static]

Definition at line 151 of file features.c.

Referenced by builtin_atxfer(), and load_config().

int atxfernoanswertimeout [static]

Definition at line 149 of file features.c.

Referenced by builtin_atxfer(), and load_config().

char* bridge_descrip [static]

Definition at line 4431 of file features.c.

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

Definition at line 4447 of file features.c.

Referenced by bridge_exec().

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

Definition at line 4430 of file features.c.

Definition at line 1618 of file features.c.

struct ast_cli_entry cli_features[] [static]

Initial value:

 {
   AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
   AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
   AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
}

Definition at line 4259 of file features.c.

int comebacktoorigin = 1 [static]

Definition at line 147 of file features.c.

Referenced by load_config(), and manage_parkinglot().

char courtesytone[256] [static]

Courtesy tone

Definition at line 138 of file features.c.

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

Definition at line 135 of file features.c.

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

char* descrip [static]

Definition at line 159 of file features.c.

Referenced by aji_handle_presence(), and ast_features_init().

char* descrip2 [static]

Definition at line 170 of file features.c.

Referenced by ast_features_init().

Initial value:

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

Definition at line 229 of file features.c.

int featuredigittimeout [static]

Definition at line 146 of file features.c.

Referenced by ast_bridge_call(), and load_config().

ast_rwlock_t features_lock = { 0 } [static]

char mandescr_bridge[] [static]

Definition at line 4043 of file features.c.

char mandescr_park[] [static]

Definition at line 4319 of file features.c.

struct ast_app* mixmonitor_app = NULL [static]

Definition at line 195 of file features.c.

Referenced by builtin_automixmonitor().

int mixmonitor_ok = 1 [static]

Definition at line 196 of file features.c.

Referenced by builtin_automixmonitor().

struct ast_app* monitor_app = NULL [static]

Definition at line 192 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

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

Referenced by park_call_exec().

char* parkcall = PARK_APP_NAME [static]

Definition at line 166 of file features.c.

Referenced by ast_features_init(), build_parkinglot(), and load_config().

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

Referenced by load_config(), and park_exec_full().

char parking_ext[AST_MAX_EXTENSION]

Extension you type to park the call

Definition at line 136 of file features.c.

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

pthread_t parking_thread [static]

Definition at line 201 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 133 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 154 of file features.c.

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

struct ast_app* stopmixmonitor_app = NULL [static]

Definition at line 198 of file features.c.

Referenced by builtin_automixmonitor().

int stopmixmonitor_ok = 1 [static]

Definition at line 199 of file features.c.

Referenced by builtin_automixmonitor().

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

Definition at line 157 of file features.c.

Referenced by ast_features_init().

char* synopsis2 = "Park yourself" [static]

Definition at line 168 of file features.c.

Referenced by ast_features_init().

int transferdigittimeout [static]

Definition at line 145 of file features.c.

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

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 141 of file features.c.

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

char xfersound[256] [static]

Call transfer sound

Definition at line 140 of file features.c.

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


Generated on Wed Oct 28 11:52:24 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6