Tue Mar 2 17:33:23 2010

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  feature_group
struct  feature_group_exten
struct  parkeduser
 Description of one parked call, added to a list while active, then removed. The list belongs to a parkinglot. More...

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_ATXFER_CALLBACK_RETRIES   2
#define DEFAULT_ATXFER_DROP_CALL   0
#define DEFAULT_ATXFER_LOOP_DELAY   10000
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000
#define DEFAULT_PARK_TIME   45000
#define DEFAULT_PARKINGLOT   "default"
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
#define FEATURES_COUNT   ARRAY_LEN(builtin_features)
#define HFS_FORMAT   "%-25s %-7s %-7s\n"
#define MAX_DIAL_FEATURE_OPTIONS   30

Enumerations

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

Functions

static int action_bridge (struct mansession *s, const struct message *m)
 Bridge channels together.
static void add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
 Announce call parking by ADSI.
 AST_APP_OPTIONS (bridge_exec_options, BEGIN_OPTIONS END_OPTIONS)
 AST_APP_OPTIONS (park_call_options, BEGIN_OPTIONS AST_APP_OPTION('r', AST_PARK_OPT_RINGING), AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE), AST_APP_OPTION('s', AST_PARK_OPT_SILENCE), END_OPTIONS)
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
static AST_RWLIST_HEAD_STATIC (feature_list, ast_call_feature)
static AST_RWLIST_HEAD_STATIC (feature_groups, feature_group)
 AST_RWLOCK_DEFINE_STATIC (features_lock)
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 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 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 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 4449 of file features.c.

04449      {
04450    BRIDGE_OPT_PLAYTONE = (1 << 0),
04451 };

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 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 4097 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_bridge_thread_obj::peer, playtone(), ast_bridge_thread_obj::return_to_pbx, and xfersound.

Referenced by ast_features_init().

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

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 }

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

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_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, 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(), parkeduser::chan, ast_call_feature::exten, f, FEATURES_COUNT, ast_frame::frametype, len(), LOG_NOTICE, 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 4584 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, parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), parkinglots, synopsis, and synopsis2.

Referenced by main().

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

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4020 of file features.c.

References load_config().

Referenced by handle_features_reload().

04021 {
04022    int res;
04023    /* Release parking lot list */
04024    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04025    // TODO: I don't think any marking is necessary
04026 
04027    /* Reload configuration */
04028    res = load_config();
04029    
04030    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04031    return res;
04032 }

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, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event, ast_parkinglot::mohclass, ast_parkinglot::name, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, ast_park_call_args::orig_chan_name, park_space_reserve(), ast_parkinglot::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, 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, and ast_channel_tech::type.

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 4404 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::pbx, and ast_channel::pickupgroup.

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

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

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 248 of file features.c.

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

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, 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 }

static AST_RWLIST_HEAD_STATIC ( feature_list  ,
ast_call_feature   
) [static]
static AST_RWLIST_HEAD_STATIC ( feature_groups  ,
feature_group   
) [static]
AST_RWLOCK_DEFINE_STATIC ( features_lock   ) 
void ast_unlock_call_features ( void   ) 

Definition at line 1800 of file features.c.

References ast_rwlock_unlock().

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, and AST_RWLIST_WRLOCK.

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, and ast_string_field_free_memory.

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 4466 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_OPT_PLAYTONE, ast_channel::context, do_bridge_masquerade(), EVENT_FLAG_CALL, ast_channel::exten, LOG_WARNING, manager_event, pbx_builtin_setvar_helper(), ast_channel::priority, and xfersound.

Referenced by ast_features_init().

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

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 3501 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, parkeduser::parkinglot, parkinglot_destroy(), parkinglot_unref(), parkinglots, ast_parkinglot::parkingtime, registrar, parkeduser::start, strdup, and ast_variable::value.

Referenced by load_config().

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

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(), LOG_NOTICE, LOG_WARNING, 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, 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, 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::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 2915 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().

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

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

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

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

Referenced by build_parkinglot().

03473 {
03474    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
03475 
03476    if (!name)
03477       return NULL;
03478 
03479    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
03480    if (!newlot)
03481       return NULL;
03482    
03483    ast_copy_string(newlot->name, name, sizeof(newlot->name));
03484    AST_LIST_HEAD_INIT(&newlot->parkings);
03485 
03486    return newlot;
03487 }

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

04068 {
04069    ast_moh_stop(chan);
04070    ast_channel_lock(chan);
04071    ast_setstate(tmpchan, chan->_state);
04072    tmpchan->readformat = chan->readformat;
04073    tmpchan->writeformat = chan->writeformat;
04074    ast_channel_masquerade(tmpchan, chan);
04075    ast_channel_lock(tmpchan);
04076    ast_do_masquerade(tmpchan);
04077    /* when returning from bridge, the channel will continue at the next priority */
04078    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
04079    ast_channel_unlock(tmpchan);
04080    ast_channel_unlock(chan);
04081 }

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

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

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, parkeduser::exten, ast_call_feature::feature_mask, FEATURES_COUNT, 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, 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.

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

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

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

03176 {
03177    struct ast_parkinglot *parkinglot = NULL;
03178    struct ast_parkinglot tmp_parkinglot;
03179    
03180    if (ast_strlen_zero(name))
03181       return NULL;
03182 
03183    ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
03184 
03185    parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
03186 
03187    if (parkinglot && option_debug)
03188       ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
03189 
03190    return parkinglot;
03191 }

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(), parkeduser::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 3960 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, 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.

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

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

Definition at line 4034 of file features.c.

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

04035 {
04036    switch (cmd) { 
04037    case CLI_INIT:
04038       e->command = "features reload";
04039       e->usage =
04040          "Usage: features reload\n"
04041          "       Reloads configured call features from features.conf\n";
04042       return NULL;
04043    case CLI_GENERATE:
04044       return NULL;
04045    }
04046    ast_features_reload();
04047 
04048    return CLI_SUCCESS;
04049 }

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 4217 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_parkinglot::name, parkeduser::parkingexten, parkinglots, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.

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

static int load_config ( void   )  [static]

Todo:
XXX var_name or app_args ?

Definition at line 3619 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_MAX_EXTENSION, 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, parkeduser::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, register_group(), register_group_feature(), registrar, remap_feature(), ast_call_feature::sname, parkeduser::start, strsep(), transferdigittimeout, unmap_features(), ast_variable::value, var, xferfailsound, and xfersound.

Referenced by ast_features_init(), and ast_features_reload().

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

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 2960 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_EXTENSION, 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, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, 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().

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

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

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

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 4281 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, parkinglots, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, S_OR, and parkeduser::start.

Referenced by ast_features_init().

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

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::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(), parkeduser::chan, ast_channel::context, ast_channel::exten, ast_park_call_args::extout, f, LOG_WARNING, 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(peer->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, parkeduser::context, parkeduser::exten, 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 3606 of file features.c.

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

Referenced by load_config().

03607 {
03608    int numext;
03609    char device[AST_MAX_EXTENSION];
03610    char exten[10];
03611 
03612    for (numext = start; numext <= stop; numext++) {
03613       snprintf(exten, sizeof(exten), "%d", numext);
03614       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03615       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03616    }
03617 }

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

Park a call.

Definition at line 3200 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_MAX_EXTENSION, 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_park_call_args::orig_chan_name, orig_exten(), 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().

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

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

Definition at line 3449 of file features.c.

References default_parkinglot, and park_exec_full().

Referenced by ast_features_init().

03450 {
03451    return park_exec_full(chan, data, default_parkinglot);
03452 }

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 3286 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, LOG_WARNING, manager_event, notify_metermaids(), ast_parkinglot::parkedcallhangup, ast_parkinglot::parkedcallrecording, ast_parkinglot::parkedcallreparking, ast_parkinglot::parkedcalltransfers, parkedplay, ast_parkinglot::parking_con, parkeduser::parkingexten, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), and S_OR.

Referenced by park_exec().

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

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_strdupa, 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, pbx_builtin_getvar_helper(), S_OR, and parkeduser::start.

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 = parkinglot_addref(default_parkinglot);
00513    }
00514 
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 = ast_strdupa(S_OR(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_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
00548          AST_LIST_UNLOCK(&parkinglot->parkings);
00549          parkinglot_unref(parkinglot);
00550          ast_free(pu);
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_addref(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 3463 of file features.c.

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

Referenced by park_space_reserve().

03464 {
03465    int refcount = ao2_ref(parkinglot, +1);
03466    if (option_debug > 2)
03467       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
03468    return parkinglot;
03469 }

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, ast_parkinglot::name, and parkeduser::parkinglot.

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

03491 {
03492    struct ast_parkinglot *ruin = obj;
03493    struct ast_context *con;
03494    con = ast_context_find(ruin->parking_con);
03495    if (con)
03496       ast_context_destroy(con, registrar);
03497    ao2_unlink(parkinglots, ruin);
03498 }

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(), ast_parkinglot::name, and parkeduser::parkinglot.

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

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

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 2897 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, parkeduser::parkingexten, parkeduser::parkinglot, and S_OR.

Referenced by manage_parkinglot().

02898 {
02899    manager_event(EVENT_FLAG_CALL, s,
02900       "Exten: %s\r\n"
02901       "Channel: %s\r\n"
02902       "Parkinglot: %s\r\n"
02903       "CallerIDNum: %s\r\n"
02904       "CallerIDName: %s\r\n"
02905       "UniqueID: %s\r\n\r\n",
02906       pu->parkingexten, 
02907       pu->chan->name,
02908       pu->parkinglot->name,
02909       S_OR(pu->chan->cid.cid_num, "<unknown>"),
02910       S_OR(pu->chan->cid.cid_name, "<unknown>"),
02911       pu->chan->uniqueid
02912       );
02913 }

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, 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, 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(), parkeduser::exten, and FEATURES_COUNT.

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, 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(), parkeduser::exten, and FEATURES_COUNT.

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

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

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

char mandescr_bridge[] [static]

Definition at line 4051 of file features.c.

char mandescr_park[] [static]

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

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.

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.

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 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1