Wed Mar 3 22:54:52 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 4434 of file features.c.

04434      {
04435    BRIDGE_OPT_PLAYTONE = (1 << 0),
04436 };

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

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

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

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

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

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

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

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

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

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

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

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

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

References ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), 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().

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

int ast_features_init ( void   ) 

Provided by features.c

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

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

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4005 of file features.c.

References load_config().

Referenced by handle_features_reload().

04006 {
04007    int res;
04008    /* Release parking lot list */
04009    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04010    // TODO: I don't think any marking is necessary
04011 
04012    /* Reload configuration */
04013    res = load_config();
04014    
04015    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04016    return res;
04017 }

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

References FEATURES_COUNT, and ast_call_feature::sname.

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

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

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

00817 {
00818    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00819 }

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

References ast_park_call_full(), and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

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

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

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

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

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

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

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

References ast_rwlock_rdlock().

Referenced by handle_request_info().

01794 {
01795    ast_rwlock_rdlock(&features_lock);
01796 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_list

register new feature into feature_set

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

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

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

References ast_rwlock_unlock().

Referenced by handle_request_info().

01799 {
01800    ast_rwlock_unlock(&features_lock);
01801 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

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

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1732 of file features.c.

References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by load_config().

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

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

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

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

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

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

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

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

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

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

Referenced by builtin_atxfer().

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

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

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

Referenced by build_parkinglot().

03459 {
03460    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
03461 
03462    if (!name)
03463       return NULL;
03464 
03465    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
03466    if (!newlot)
03467       return NULL;
03468    
03469    ast_copy_string(newlot->name, name, sizeof(newlot->name));
03470 
03471    return newlot;
03472 }

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

04053 {
04054    ast_moh_stop(chan);
04055    ast_channel_lock(chan);
04056    ast_setstate(tmpchan, chan->_state);
04057    tmpchan->readformat = chan->readformat;
04058    tmpchan->writeformat = chan->writeformat;
04059    ast_channel_masquerade(tmpchan, chan);
04060    ast_channel_lock(tmpchan);
04061    ast_do_masquerade(tmpchan);
04062    /* when returning from bridge, the channel will continue at the next priority */
04063    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
04064    ast_channel_unlock(tmpchan);
04065    ast_channel_unlock(chan);
04066 }

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

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

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

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

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

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

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

find a call feature by name

Definition at line 1744 of file features.c.

References AST_RWLIST_TRAVERSE, and ast_call_feature::sname.

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

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

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

References AST_LIST_TRAVERSE.

Referenced by feature_interpret_helper().

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

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

Find parkinglot by name.

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

03162 {
03163    struct ast_parkinglot *parkinglot = NULL;
03164    struct ast_parkinglot tmp_parkinglot;
03165    
03166    if (ast_strlen_zero(name))
03167       return NULL;
03168 
03169    ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
03170 
03171    parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
03172 
03173    if (parkinglot && option_debug)
03174       ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
03175 
03176    return parkinglot;
03177 }

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

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

01141 {
01142    ast_indicate(chan, AST_CONTROL_UNHOLD);
01143 
01144    return ast_autoservice_stop(chan);
01145 }

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

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

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

Definition at line 4019 of file features.c.

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

04020 {
04021    switch (cmd) { 
04022    case CLI_INIT:
04023       e->command = "features reload";
04024       e->usage =
04025          "Usage: features reload\n"
04026          "       Reloads configured call features from features.conf\n";
04027       return NULL;
04028    case CLI_GENERATE:
04029       return NULL;
04030    }
04031    ast_features_reload();
04032 
04033    return CLI_SUCCESS;
04034 }

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

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

static int load_config ( void   )  [static]

Todo:
XXX var_name or app_args ?

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 826 of file features.c.

References masq_park_call().

Referenced by builtin_blindtransfer(), and builtin_parkcall().

00827 {
00828    return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
00829 }

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

References masq_park_call().

Referenced by park_call_exec().

00822 {
00823    return masq_park_call(rchan, peer, 0, NULL, 1, args);
00824 }

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

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

Referenced by load_config().

03592 {
03593    int numext;
03594    char device[AST_MAX_EXTENSION];
03595    char exten[10];
03596 
03597    for (numext = start; numext <= stop; numext++) {
03598       snprintf(exten, sizeof(exten), "%d", numext);
03599       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03600       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03601    }
03602 }

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

Park a call.

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

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

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

Definition at line 3435 of file features.c.

References default_parkinglot, and park_exec_full().

Referenced by ast_features_init().

03436 {
03437    return park_exec_full(chan, data, default_parkinglot);
03438 }

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

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

Referenced by park_exec().

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

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

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

Definition at line 3449 of file features.c.

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

Referenced by park_space_reserve().

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

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

03476 {
03477    struct ast_parkinglot *ruin = obj;
03478    struct ast_context *con;
03479    con = ast_context_find(ruin->parking_con);
03480    if (con)
03481       ast_context_destroy(con, registrar);
03482    ao2_unlink(parkinglots, ruin);
03483 }

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

03443 {
03444    int refcount = ao2_ref(parkinglot, -1);
03445    if (option_debug > 2)
03446       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
03447 }

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

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

02282 {
02283    struct ast_cdr *cdr_orig = cdr;
02284    while (cdr) {
02285       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02286          return cdr;
02287       cdr = cdr->next;
02288    }
02289    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
02290 }

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

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

Referenced by builtin_automonitor().

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

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

Output parking event to manager.

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

02884 {
02885    manager_event(EVENT_FLAG_CALL, s,
02886       "Exten: %s\r\n"
02887       "Channel: %s\r\n"
02888       "Parkinglot: %s\r\n"
02889       "CallerIDNum: %s\r\n"
02890       "CallerIDName: %s\r\n"
02891       "UniqueID: %s\r\n\r\n",
02892       pu->parkingexten, 
02893       pu->chan->name,
02894       pu->parkinglot->name,
02895       S_OR(pu->chan->cid.cid_num, "<unknown>"),
02896       S_OR(pu->chan->cid.cid_name, "<unknown>"),
02897       pu->chan->uniqueid
02898       );
02899 }

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

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

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

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

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

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

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

Definition at line 1889 of file features.c.

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

Referenced by load_config().

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

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

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

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

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

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

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

References FEATURE_SENSE_PEER.

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

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

static void unmap_features ( void   )  [static]

Definition at line 1879 of file features.c.

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

Referenced by load_config().

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


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

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

Definition at line 4423 of file features.c.

Definition at line 1616 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 4252 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 4036 of file features.c.

char mandescr_park[] [static]

Definition at line 4312 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 3 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1