Thu Apr 8 01:22:31 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 4460 of file features.c.

04460      {
04461    BRIDGE_OPT_PLAYTONE = (1 << 0),
04462 };

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

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

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

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

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

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

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

02056                                                                                                                            {
02057 
02058    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02059 }

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

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

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

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

int ast_features_init ( void   ) 

Provided by features.c

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

04596 {
04597    int res;
04598 
04599    ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
04600 
04601    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
04602 
04603    if ((res = load_config()))
04604       return res;
04605    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
04606    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
04607    res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
04608    if (!res)
04609       res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
04610    if (!res) {
04611       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
04612       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park); 
04613       ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
04614    }
04615 
04616    res |= ast_devstate_prov_add("Park", metermaidstate);
04617 
04618    return res;
04619 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4031 of file features.c.

References load_config().

Referenced by handle_features_reload().

04032 {
04033    int res;
04034    /* Release parking lot list */
04035    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04036    // TODO: I don't think any marking is necessary
04037 
04038    /* Reload configuration */
04039    res = load_config();
04040    
04041    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04042    return res;
04043 }

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

References FEATURES_COUNT, and ast_call_feature::sname.

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

01810 {
01811    int x;
01812    for (x = 0; x < FEATURES_COUNT; x++) {
01813       if (!strcasecmp(name, builtin_features[x].sname))
01814          return &builtin_features[x];
01815    }
01816    return NULL;
01817 }

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

00823 {
00824    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00825 }

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

References ast_park_call_full(), and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

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

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

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

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

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

04416 {
04417    struct ast_channel *cur = NULL;
04418    int res = -1;
04419 
04420    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04421       if (!cur->pbx && 
04422          (cur != chan) &&
04423          (chan->pickupgroup & cur->callgroup) &&
04424          ((cur->_state == AST_STATE_RINGING) ||
04425           (cur->_state == AST_STATE_RING))) {
04426             break;
04427       }
04428       ast_channel_unlock(cur);
04429    }
04430    if (cur) {
04431       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04432       res = ast_answer(chan);
04433       if (res)
04434          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04435       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04436       if (res)
04437          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04438       res = ast_channel_masquerade(cur, chan);
04439       if (res)
04440          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04441       ast_channel_unlock(cur);
04442    } else   {
04443       ast_debug(1, "No call pickup possible...\n");
04444    }
04445    return res;
04446 }

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

References ast_rwlock_rdlock().

Referenced by handle_request_info().

01800 {
01801    ast_rwlock_rdlock(&features_lock);
01802 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_list

register new feature into feature_set

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

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

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

References ast_rwlock_unlock().

Referenced by handle_request_info().

01805 {
01806    ast_rwlock_unlock(&features_lock);
01807 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

01725 {
01726    if (!feature) {
01727       return;
01728    }
01729 
01730    AST_RWLIST_WRLOCK(&feature_list);
01731    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01732    AST_RWLIST_UNLOCK(&feature_list);
01733 
01734    ast_free(feature);
01735 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1738 of file features.c.

References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by load_config().

01739 {
01740    struct ast_call_feature *feature;
01741 
01742    AST_RWLIST_WRLOCK(&feature_list);
01743    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01744       ast_free(feature);
01745    }
01746    AST_RWLIST_UNLOCK(&feature_list);
01747 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

01141 {
01142    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
01143    return AST_FEATURE_RETURN_HANGUP;
01144 }

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

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

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

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

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

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

References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING.

Referenced by builtin_atxfer().

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

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

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

Referenced by build_parkinglot().

03484 {
03485    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
03486 
03487    if (!name)
03488       return NULL;
03489 
03490    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
03491    if (!newlot)
03492       return NULL;
03493    
03494    ast_copy_string(newlot->name, name, sizeof(newlot->name));
03495    AST_LIST_HEAD_INIT(&newlot->parkings);
03496 
03497    return newlot;
03498 }

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

04079 {
04080    ast_moh_stop(chan);
04081    ast_channel_lock(chan);
04082    ast_setstate(tmpchan, chan->_state);
04083    tmpchan->readformat = chan->readformat;
04084    tmpchan->writeformat = chan->writeformat;
04085    ast_channel_masquerade(tmpchan, chan);
04086    ast_channel_lock(tmpchan);
04087    ast_do_masquerade(tmpchan);
04088    /* when returning from bridge, the channel will continue at the next priority */
04089    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
04090    ast_channel_unlock(tmpchan);
04091    ast_channel_unlock(chan);
04092 }

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

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

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

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

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

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

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

find a call feature by name

Definition at line 1750 of file features.c.

References AST_RWLIST_TRAVERSE, and ast_call_feature::sname.

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

01751 {
01752    struct ast_call_feature *tmp;
01753 
01754    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01755       if (!strcasecmp(tmp->sname, name)) {
01756          break;
01757       }
01758    }
01759 
01760    return tmp;
01761 }

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

References AST_LIST_TRAVERSE.

Referenced by feature_interpret_helper().

01788                                                           {
01789    struct feature_group *fg = NULL;
01790 
01791    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
01792       if (!strcasecmp(fg->gname, name))
01793          break;
01794    }
01795 
01796    return fg;
01797 }

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

Find parkinglot by name.

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

03183 {
03184    struct ast_parkinglot *parkinglot = NULL;
03185    struct ast_parkinglot tmp_parkinglot;
03186    
03187    if (ast_strlen_zero(name))
03188       return NULL;
03189 
03190    ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
03191 
03192    parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
03193 
03194    if (parkinglot && option_debug)
03195       ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
03196 
03197    return parkinglot;
03198 }

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

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

01147 {
01148    ast_indicate(chan, AST_CONTROL_UNHOLD);
01149 
01150    return ast_autoservice_stop(chan);
01151 }

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

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

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

Definition at line 4045 of file features.c.

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

04046 {
04047    switch (cmd) { 
04048    case CLI_INIT:
04049       e->command = "features reload";
04050       e->usage =
04051          "Usage: features reload\n"
04052          "       Reloads configured call features from features.conf\n";
04053       return NULL;
04054    case CLI_GENERATE:
04055       return NULL;
04056    }
04057    ast_features_reload();
04058 
04059    return CLI_SUCCESS;
04060 }

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

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

static int load_config ( void   )  [static]

Todo:
XXX var_name or app_args ?

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

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

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

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

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

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

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

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

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

References ast_channel::amaflags, ast_channel_alloc, ast_channel_masquerade(), ast_copy_string(), 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_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, 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().

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

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

Definition at line 832 of file features.c.

References masq_park_call().

Referenced by builtin_blindtransfer(), and builtin_parkcall().

00833 {
00834    return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
00835 }

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

References masq_park_call().

Referenced by park_call_exec().

00828 {
00829    return masq_park_call(rchan, peer, 0, NULL, 1, args);
00830 }

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

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

Referenced by load_config().

03618 {
03619    int numext;
03620    char device[AST_MAX_EXTENSION];
03621    char exten[10];
03622 
03623    for (numext = start; numext <= stop; numext++) {
03624       snprintf(exten, sizeof(exten), "%d", numext);
03625       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03626       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03627    }
03628 }

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

Park a call.

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

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

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

Definition at line 3460 of file features.c.

References default_parkinglot, and park_exec_full().

Referenced by ast_features_init().

03461 {
03462    return park_exec_full(chan, data, default_parkinglot);
03463 }

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 3293 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_bridge_config::features_callee, ast_bridge_config::features_caller, ast_dial_features::features_caller, find_parkinglot(), findparkinglotname(), 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().

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

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             break;
00570          }
00571 
00572          AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
00573             if (cur->parkingnum == i) {
00574                break;
00575             }
00576          }
00577          if (!cur) {
00578             parking_space = i;
00579             break;
00580          }
00581       }
00582 
00583       if (i == start - 1 && cur) {
00584          ast_log(LOG_WARNING, "No more parking spaces\n");
00585          ast_free(pu);
00586          AST_LIST_UNLOCK(&parkinglot->parkings);
00587          parkinglot_unref(parkinglot);
00588          return NULL;
00589       }
00590       /* Set pointer for next parking */
00591       if (parkinglot->parkfindnext) 
00592          parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
00593       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00594    }
00595 
00596    pu->notquiteyet = 1;
00597    pu->parkingnum = parking_space;
00598    pu->parkinglot = parkinglot_addref(parkinglot);
00599    AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
00600    parkinglot_unref(parkinglot);
00601 
00602    return pu;
00603 }

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

Definition at line 3474 of file features.c.

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

Referenced by park_space_reserve().

03475 {
03476    int refcount = ao2_ref(parkinglot, +1);
03477    if (option_debug > 2)
03478       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
03479    return parkinglot;
03480 }

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

03502 {
03503    struct ast_parkinglot *ruin = obj;
03504    struct ast_context *con;
03505    con = ast_context_find(ruin->parking_con);
03506    if (con)
03507       ast_context_destroy(con, registrar);
03508    ao2_unlink(parkinglots, ruin);
03509 }

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

03468 {
03469    int refcount = ao2_ref(parkinglot, -1);
03470    if (option_debug > 2)
03471       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
03472 }

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

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

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

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

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

Referenced by builtin_automonitor().

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

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

Output parking event to manager.

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

02905 {
02906    manager_event(EVENT_FLAG_CALL, s,
02907       "Exten: %s\r\n"
02908       "Channel: %s\r\n"
02909       "Parkinglot: %s\r\n"
02910       "CallerIDNum: %s\r\n"
02911       "CallerIDName: %s\r\n"
02912       "UniqueID: %s\r\n\r\n",
02913       pu->parkingexten, 
02914       pu->chan->name,
02915       pu->parkinglot->name,
02916       S_OR(pu->chan->cid.cid_num, "<unknown>"),
02917       S_OR(pu->chan->cid.cid_name, "<unknown>"),
02918       pu->chan->uniqueid
02919       );
02920 }

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

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

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

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

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

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

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

Definition at line 1895 of file features.c.

References ast_copy_string(), ast_rwlock_unlock(), ast_rwlock_wrlock(), parkeduser::exten, and FEATURES_COUNT.

Referenced by load_config().

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

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

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

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

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

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

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

References FEATURE_SENSE_PEER.

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

00845 {
00846    if (sense == FEATURE_SENSE_PEER) {
00847       *caller = peer;
00848       *callee = chan;
00849    } else {
00850       *callee = peer;
00851       *caller = chan;
00852    }
00853 }

static void unmap_features ( void   )  [static]

Definition at line 1885 of file features.c.

References ast_rwlock_unlock(), ast_rwlock_wrlock(), parkeduser::exten, and FEATURES_COUNT.

Referenced by load_config().

01886 {
01887    int x;
01888 
01889    ast_rwlock_wrlock(&features_lock);
01890    for (x = 0; x < FEATURES_COUNT; x++)
01891       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01892    ast_rwlock_unlock(&features_lock);
01893 }


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

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

Definition at line 4449 of file features.c.

Definition at line 1622 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 4278 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 4062 of file features.c.

char mandescr_park[] [static]

Definition at line 4338 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 8 Apr 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1