Wed Apr 6 11:30:04 2011

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 <signal.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 "asterisk/cel.h"
#include "asterisk/test.h"

Go to the source code of this file.

Data Structures

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

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_ATXFER_CALLBACK_RETRIES   2
#define DEFAULT_ATXFER_DROP_CALL   0
#define DEFAULT_ATXFER_LOOP_DELAY   10000
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000
#define DEFAULT_PARK_EXTENSION   "700"
#define DEFAULT_PARK_TIME   45000
#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), OPT_CALLEE_HANGUP = (1 << 1), OPT_CALLER_HANGUP = (1 << 2), OPT_DURATION_LIMIT = (1 << 3),
  OPT_DURATION_STOP = (1 << 4), OPT_CALLEE_TRANSFER = (1 << 5), OPT_CALLER_TRANSFER = (1 << 6), OPT_CALLEE_MONITOR = (1 << 7),
  OPT_CALLER_MONITOR = (1 << 8), OPT_CALLEE_PARK = (1 << 9), OPT_CALLER_PARK = (1 << 10), OPT_CALLEE_KILL = (1 << 11)
}
enum  { OPT_ARG_DURATION_LIMIT = 0, OPT_ARG_DURATION_STOP, OPT_ARG_ARRAY_SIZE }
enum  ast_park_call_options { AST_PARK_OPT_RINGING = (1 << 0), AST_PARK_OPT_RANDOMIZE = (1 << 1), AST_PARK_OPT_SILENCE = (1 << 2) }

Functions

static int action_bridge (struct mansession *s, const struct message *m)
 Bridge channels together.
static void add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
 Announce call parking by ADSI.
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
int ast_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit)
 parse L option and read associated channel variables to set warning, warning frequency, and timelimit
void ast_channel_log (char *title, struct ast_channel *chan)
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature)
 detect a feature before bridging
int ast_features_init (void)
int ast_features_reload (void)
 Reload call features from features.conf.
ast_call_featureast_find_call_feature (const char *name)
 look for a call feature entry by its sname
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, const char *parkexten, int *extout)
 Park a call and read back parked location.
int ast_parking_ext_valid (const char *exten_str, struct ast_channel *chan, const char *context)
 Determine if parking extension exists in a given context.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
const char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_rdlock_call_features (void)
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unlock_call_features (void)
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
 Remove all features in the list.
static void ast_unregister_groups (void)
 Remove all feature groups in the list.
static void atxfer_fail_cleanup (struct ast_channel *transferee, struct ast_channel *transferer, struct ast_party_connected_line *connected_line)
static void * bridge_call_thread (void *data)
 bridge the call
static void bridge_call_thread_launch (void *data)
 create thread for the parked call
static int bridge_exec (struct ast_channel *chan, const char *data)
 Bridge channels.
static struct ast_parkinglotbuild_parkinglot (char *name, struct ast_variable *var)
 Build parkinglot from configuration and chain it in if it doesn't already exist.
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const 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, const char *code, int sense, void *data)
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const 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, const 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, const char *code, int sense, void *data)
static int builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const 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_parkinglotcopy_parkinglot (const char *name, const struct ast_parkinglot *parkinglot)
 Copy parkinglot and store it with new name.
static struct ast_parkinglotcreate_parkinglot (const 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, const char *code, int sense, void *data)
 exec an app by feature
static int feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense)
 Check the dynamic features.
static int feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const 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_channelfeature_request_and_dial (struct ast_channel *caller, const char *caller_name, struct ast_channel *requestor, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *language)
static int find_channel_by_group (void *obj, void *arg, void *data, int flags)
static struct ast_call_featurefind_dynamic_feature (const char *name)
 find a call feature by name
static struct feature_groupfind_group (const char *name)
 Find a group by name.
ast_parkinglotfind_parkinglot (const char *name)
 Find parkinglot by name.
static int find_parkinglot_by_exten_cb (void *obj, void *args, int flags)
static int find_parkinglot_by_position_cb (void *obj, void *args, int flags)
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, const struct pollfd *pfds, const int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
 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, 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, const char *data)
 Park a call.
static int park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
static int park_exec (struct ast_channel *chan, const char *data)
static int park_exec_full (struct ast_channel *chan, const char *data)
 Pickup parked call.
static struct parkeduserpark_space_reserve (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
static int parkcall_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, 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 int parkinglot_is_marked_cb (void *obj, void *arg, int flags)
static int parkinglot_markall_cb (void *obj, void *arg, 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 struct ast_app_option bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, }
static struct ast_call_feature builtin_features []
static struct ast_cli_entry cli_features []
static int comebacktoorigin = 1
static char courtesytone [256]
ast_parkinglotdefault_parkinglot
static struct ast_datastore_info dial_features_info
static int featuredigittimeout
static ast_rwlock_t features_lock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RWLOCK_INITIALIZER }
static struct ast_appmixmonitor_app = NULL
static int mixmonitor_ok = 1
static struct ast_appmonitor_app = NULL
static int monitor_ok = 1
static struct ast_app_option park_call_options [128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, }
static char * parkcall = PARK_APP_NAME
static char * parkedcall = "ParkedCall"
static int parkeddynamic = 0
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 pickupfailsound [256]
static char pickupsound [256]
static char * registrar = "features"
static struct ast_appstopmixmonitor_app = NULL
static int stopmixmonitor_ok = 1
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 353 of file features.c.

#define DEFAULT_ATXFER_CALLBACK_RETRIES   2

Definition at line 351 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_DROP_CALL   0

Do not drop call.

Definition at line 349 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_LOOP_DELAY   10000

ms

Definition at line 350 of file features.c.

Referenced by load_config().

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

ms

Definition at line 347 of file features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

ms

Definition at line 348 of file features.c.

Referenced by load_config().

#define DEFAULT_PARK_EXTENSION   "700"

Definition at line 345 of file features.c.

Referenced by build_parkinglot(), and load_config().

#define DEFAULT_PARK_TIME   45000

ms

Definition at line 344 of file features.c.

Referenced by build_parkinglot(), and load_config().

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

ms

Definition at line 346 of file features.c.

Referenced by load_config().

#define FEATURES_COUNT   ARRAY_LEN(builtin_features)

Definition at line 2431 of file features.c.

Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().

#define HFS_FORMAT   "%-25s %-7s %-7s\n"

Referenced by handle_feature_show().

#define MAX_DIAL_FEATURE_OPTIONS   30

Definition at line 354 of file features.c.

Referenced by manage_parkinglot().


Enumeration Type Documentation

anonymous enum

Enumerator:
BRIDGE_OPT_PLAYTONE 
OPT_CALLEE_HANGUP 
OPT_CALLER_HANGUP 
OPT_DURATION_LIMIT 
OPT_DURATION_STOP 
OPT_CALLEE_TRANSFER 
OPT_CALLER_TRANSFER 
OPT_CALLEE_MONITOR 
OPT_CALLER_MONITOR 
OPT_CALLEE_PARK 
OPT_CALLER_PARK 
OPT_CALLEE_KILL 

Definition at line 5643 of file features.c.

05643      {
05644    BRIDGE_OPT_PLAYTONE = (1 << 0),
05645    OPT_CALLEE_HANGUP =  (1 << 1),
05646    OPT_CALLER_HANGUP =  (1 << 2),
05647    OPT_DURATION_LIMIT = (1 << 3),
05648    OPT_DURATION_STOP =  (1 << 4),
05649    OPT_CALLEE_TRANSFER = (1 << 5),
05650    OPT_CALLER_TRANSFER = (1 << 6),
05651    OPT_CALLEE_MONITOR = (1 << 7),
05652    OPT_CALLER_MONITOR = (1 << 8),
05653    OPT_CALLEE_PARK = (1 << 9),
05654    OPT_CALLER_PARK = (1 << 10),
05655    OPT_CALLEE_KILL = (1 << 11),
05656 };

anonymous enum

Enumerator:
OPT_ARG_DURATION_LIMIT 
OPT_ARG_DURATION_STOP 
OPT_ARG_ARRAY_SIZE 

Definition at line 5658 of file features.c.

05658      {
05659    OPT_ARG_DURATION_LIMIT = 0,
05660    OPT_ARG_DURATION_STOP,
05661    /* note: this entry _MUST_ be the last one in the enum */
05662    OPT_ARG_ARRAY_SIZE,
05663 };

enum ast_park_call_options

Options to pass to 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 884 of file features.c.

00884                            {
00885    /*! Provide ringing to the parked caller instead of music on hold */
00886    AST_PARK_OPT_RINGING =   (1 << 0),
00887    /*! Randomly choose a parking spot for the caller instead of choosing
00888     *  the first one that is available. */
00889    AST_PARK_OPT_RANDOMIZE = (1 << 1),
00890    /*! Do not announce the parking number */
00891    AST_PARK_OPT_SILENCE = (1 << 2),
00892 };


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

References ast_channel::_state, ast_answer(), ast_calloc, ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_make_compatible(), ast_channel_unref, ast_hangup(), ast_log(), ast_manager_event_multichan, AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), bridge_call_thread_launch(), do_bridge_masquerade(), errno, EVENT_FLAG_CALL, LOG_WARNING, ast_channel::name, playtone(), and xfersound.

Referenced by ast_features_init().

05248 {
05249    const char *channela = astman_get_header(m, "Channel1");
05250    const char *channelb = astman_get_header(m, "Channel2");
05251    const char *playtone = astman_get_header(m, "Tone");
05252    struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
05253    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
05254    struct ast_bridge_thread_obj *tobj = NULL;
05255 
05256    /* make sure valid channels were specified */
05257    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
05258       astman_send_error(s, m, "Missing channel parameter in request");
05259       return 0;
05260    }
05261 
05262    /* Start with chana */
05263    chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
05264 
05265    /* send errors if any of the channels could not be found/locked */
05266    if (!chana) {
05267       char buf[256];
05268       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
05269       astman_send_error(s, m, buf);
05270       return 0;
05271    }
05272 
05273    /* Answer the channels if needed */
05274    if (chana->_state != AST_STATE_UP)
05275       ast_answer(chana);
05276 
05277    /* create the placeholder channels and grab the other channels */
05278    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
05279       NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
05280       astman_send_error(s, m, "Unable to create temporary channel!");
05281       chana = ast_channel_unref(chana);
05282       return 1;
05283    }
05284 
05285    do_bridge_masquerade(chana, tmpchana);
05286 
05287    chana = ast_channel_unref(chana);
05288 
05289    /* now do chanb */
05290    chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
05291    /* send errors if any of the channels could not be found/locked */
05292    if (!chanb) {
05293       char buf[256];
05294       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
05295       ast_hangup(tmpchana);
05296       astman_send_error(s, m, buf);
05297       return 0;
05298    }
05299 
05300    /* Answer the channels if needed */
05301    if (chanb->_state != AST_STATE_UP)
05302       ast_answer(chanb);
05303 
05304    /* create the placeholder channels and grab the other channels */
05305    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
05306       NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
05307       astman_send_error(s, m, "Unable to create temporary channels!");
05308       ast_hangup(tmpchana);
05309       chanb = ast_channel_unref(chanb);
05310       return 1;
05311    }
05312 
05313    do_bridge_masquerade(chanb, tmpchanb);
05314 
05315    chanb = ast_channel_unref(chanb);
05316 
05317    /* make the channels compatible, send error if we fail doing so */
05318    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
05319       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
05320       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
05321       ast_hangup(tmpchana);
05322       ast_hangup(tmpchanb);
05323       return 1;
05324    }
05325 
05326    /* setup the bridge thread object and start the bridge */
05327    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
05328       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
05329       astman_send_error(s, m, "Unable to spawn a new bridge thread");
05330       ast_hangup(tmpchana);
05331       ast_hangup(tmpchanb);
05332       return 1;
05333    }
05334 
05335    tobj->chan = tmpchana;
05336    tobj->peer = tmpchanb;
05337    tobj->return_to_pbx = 1;
05338 
05339    if (ast_true(playtone)) {
05340       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
05341          if (ast_waitstream(tmpchanb, "") < 0)
05342             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
05343       }
05344    }
05345 
05346    chans[0] = tmpchana;
05347    chans[1] = tmpchanb;
05348 
05349    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
05350             "Response: Success\r\n"
05351             "Channel1: %s\r\n"
05352             "Channel2: %s\r\n", tmpchana->name, tmpchanb->name);
05353 
05354    bridge_call_thread_launch(tobj);
05355 
05356    astman_send_ack(s, m, "Launched bridge thread with success");
05357 
05358    return 0;
05359 }

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

Definition at line 3320 of file features.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_datastore_alloc, ast_datastore_free(), AST_FLAGS_ALL, ast_log(), config, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, and LOG_WARNING.

Referenced by ast_bridge_call().

03321 {
03322    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
03323    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
03324 
03325    ast_channel_lock(caller);
03326    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
03327    ast_channel_unlock(caller);
03328    if (!ds_caller_features) {
03329       if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03330          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
03331          return;
03332       }
03333       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
03334          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03335          ast_datastore_free(ds_caller_features);
03336          return;
03337       }
03338       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
03339       caller_features->is_caller = 1;
03340       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
03341       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
03342       ds_caller_features->data = caller_features;
03343       ast_channel_lock(caller);
03344       ast_channel_datastore_add(caller, ds_caller_features);
03345       ast_channel_unlock(caller);
03346    } else {
03347       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
03348        * flags over from the atxfer to the caller */
03349       return;
03350    }
03351 
03352    ast_channel_lock(callee);
03353    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
03354    ast_channel_unlock(callee);
03355    if (!ds_callee_features) {
03356       if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
03357          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
03358          return;
03359       }
03360       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
03361          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
03362          ast_datastore_free(ds_callee_features);
03363          return;
03364       }
03365       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
03366       callee_features->is_caller = 0;
03367       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
03368       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
03369       ds_callee_features->data = callee_features;
03370       ast_channel_lock(callee);
03371       ast_channel_datastore_add(callee, ds_callee_features);
03372       ast_channel_unlock(callee);
03373    }
03374 
03375    return;
03376 }

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

References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.

Referenced by park_call_full().

00823 {
00824    int res;
00825    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00826    char tmp[256];
00827    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00828 
00829    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00830    message[0] = tmp;
00831    res = ast_adsi_load_session(chan, NULL, 0, 1);
00832    if (res == -1)
00833       return res;
00834    return ast_adsi_print(chan, message, justify, 1);
00835 }

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

Bridge a call, optionally allowing redirection.

Parameters:
chan,peer,config Set start time, check for two channels,check if monitor on check for feature activation, create new CDR
Return values:
res on success.
-1 on failure to bridge.

append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.

Todo:
XXX how do we guarantee the latter ?

Definition at line 3387 of file features.c.

References ast_channel::_state, ast_cdr::accountcode, ast_channel::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_appenduserfield(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_bridge(), ast_channel_connected_line_macro(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_log(), ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_clear_flag, AST_CONTROL_AOC, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, 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_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::caller, ast_channel::cdr, ast_cdr::channel, config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_party_caller::id, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_COR, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_party_number::str, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, ast_party_number::valid, and ast_channel::visible_indication.

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

03388 {
03389    /* Copy voice back and forth between the two channels.  Give the peer
03390       the ability to transfer calls with '#<extension' syntax. */
03391    struct ast_frame *f;
03392    struct ast_channel *who;
03393    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
03394    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
03395    char orig_channame[AST_MAX_EXTENSION];
03396    char orig_peername[AST_MAX_EXTENSION];
03397    int res;
03398    int diff;
03399    int hasfeatures=0;
03400    int hadfeatures=0;
03401    int autoloopflag;
03402    int we_disabled_peer_cdr = 0;
03403    struct ast_option_header *aoh;
03404    struct ast_cdr *bridge_cdr = NULL;
03405    struct ast_cdr *orig_peer_cdr = NULL;
03406    struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */
03407    struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */
03408    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
03409    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
03410 
03411    if (chan && peer) {
03412       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
03413       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
03414    } else if (chan) {
03415       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
03416    }
03417 
03418    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
03419    add_features_datastores(chan, peer, config);
03420 
03421    /* This is an interesting case.  One example is if a ringing channel gets redirected to
03422     * an extension that picks up a parked call.  This will make sure that the call taken
03423     * out of parking gets told that the channel it just got bridged to is still ringing. */
03424    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
03425       ast_indicate(peer, AST_CONTROL_RINGING);
03426    }
03427 
03428    if (monitor_ok) {
03429       const char *monitor_exec;
03430       struct ast_channel *src = NULL;
03431       if (!monitor_app) {
03432          if (!(monitor_app = pbx_findapp("Monitor")))
03433             monitor_ok=0;
03434       }
03435       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
03436          src = chan;
03437       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
03438          src = peer;
03439       if (monitor_app && src) {
03440          char *tmp = ast_strdupa(monitor_exec);
03441          pbx_exec(src, monitor_app, tmp);
03442       }
03443    }
03444 
03445    set_config_flags(chan, peer, config);
03446 
03447    /* Answer if need be */
03448    if (chan->_state != AST_STATE_UP) {
03449       if (ast_raw_answer(chan, 1)) {
03450          return -1;
03451       }
03452    }
03453 
03454 #ifdef FOR_DEBUG
03455    /* show the two channels and cdrs involved in the bridge for debug & devel purposes */
03456    ast_channel_log("Pre-bridge CHAN Channel info", chan);
03457    ast_channel_log("Pre-bridge PEER Channel info", peer);
03458 #endif
03459    /* two channels are being marked as linked here */
03460    ast_channel_set_linkgroup(chan,peer);
03461 
03462    /* copy the userfield from the B-leg to A-leg if applicable */
03463    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
03464       char tmp[256];
03465       if (!ast_strlen_zero(chan->cdr->userfield)) {
03466          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
03467          ast_cdr_appenduserfield(chan, tmp);
03468       } else
03469          ast_cdr_setuserfield(chan, peer->cdr->userfield);
03470       /* Don't delete the CDR; just disable it. */
03471       ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03472       we_disabled_peer_cdr = 1;
03473    }
03474    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
03475    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
03476    orig_peer_cdr = peer_cdr;
03477    
03478    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
03479       
03480       if (chan_cdr) {
03481          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
03482          ast_cdr_update(chan);
03483          bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
03484          /* rip any forked CDR's off of the chan_cdr and attach
03485           * them to the bridge_cdr instead */
03486          bridge_cdr->next = chan_cdr->next;
03487          chan_cdr->next = NULL;
03488          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03489          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03490          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
03491             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03492          }
03493          ast_cdr_setaccount(peer, chan->accountcode);
03494 
03495       } else {
03496          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
03497          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
03498          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
03499          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
03500          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
03501          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
03502          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
03503          ast_cdr_setcid(bridge_cdr, chan);
03504          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
03505          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
03506          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
03507          /* Destination information */
03508          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
03509          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
03510          if (peer_cdr) {
03511             bridge_cdr->start = peer_cdr->start;
03512             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
03513          } else {
03514             ast_cdr_start(bridge_cdr);
03515          }
03516       }
03517       ast_debug(4,"bridge answer set, chan answer set\n");
03518       /* peer_cdr->answer will be set when a macro runs on the peer;
03519          in that case, the bridge answer will be delayed while the
03520          macro plays on the peer channel. The peer answered the call
03521          before the macro started playing. To the phone system,
03522          this is billable time for the call, even tho the caller
03523          hears nothing but ringing while the macro does its thing. */
03524 
03525       /* Another case where the peer cdr's time will be set, is when
03526          A self-parks by pickup up phone and dialing 700, then B
03527          picks up A by dialing its parking slot; there may be more 
03528          practical paths that get the same result, tho... in which
03529          case you get the previous answer time from the Park... which
03530          is before the bridge's start time, so I added in the 
03531          tvcmp check to the if below */
03532 
03533       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
03534          ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
03535          ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
03536          if (chan_cdr) {
03537             ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
03538             ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
03539          }
03540       } else {
03541          ast_cdr_answer(bridge_cdr);
03542          if (chan_cdr) {
03543             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
03544          }
03545       }
03546       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
03547          if (chan_cdr) {
03548             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
03549          }
03550          if (peer_cdr) {
03551             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
03552          }
03553       }
03554       /* the DIALED flag may be set if a dialed channel is transfered
03555        * and then bridged to another channel.  In order for the
03556        * bridge CDR to be written, the DIALED flag must not be
03557        * present. */
03558       ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
03559    }
03560    ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL);
03561    for (;;) {
03562       struct ast_channel *other; /* used later */
03563    
03564       res = ast_channel_bridge(chan, peer, config, &f, &who);
03565       
03566       /* When frame is not set, we are probably involved in a situation
03567          where we've timed out.
03568          When frame is set, we'll come this code twice; once for DTMF_BEGIN
03569          and also for DTMF_END. If we flow into the following 'if' for both, then 
03570          our wait times are cut in half, as both will subtract from the
03571          feature_timer. Not good!
03572       */
03573       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
03574          /* Update feature timer for next pass */
03575          diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
03576          if (res == AST_BRIDGE_RETRY) {
03577             /* The feature fully timed out but has not been updated. Skip
03578              * the potential round error from the diff calculation and
03579              * explicitly set to expired. */
03580             config->feature_timer = -1;
03581          } else {
03582             config->feature_timer -= diff;
03583          }
03584 
03585          if (hasfeatures) {
03586             if (config->feature_timer <= 0) {
03587                /* Not *really* out of time, just out of time for
03588                   digits to come in for features. */
03589                ast_debug(1, "Timed out for feature!\n");
03590                if (!ast_strlen_zero(peer_featurecode)) {
03591                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
03592                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
03593                }
03594                if (!ast_strlen_zero(chan_featurecode)) {
03595                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
03596                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
03597                }
03598                if (f)
03599                   ast_frfree(f);
03600                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03601                if (!hasfeatures) {
03602                   /* No more digits expected - reset the timer */
03603                   config->feature_timer = 0;
03604                }
03605                hadfeatures = hasfeatures;
03606                /* Continue as we were */
03607                continue;
03608             } else if (!f) {
03609                /* The bridge returned without a frame and there is a feature in progress.
03610                 * However, we don't think the feature has quite yet timed out, so just
03611                 * go back into the bridge. */
03612                continue;
03613             }
03614          } else {
03615             if (config->feature_timer <=0) {
03616                /* We ran out of time */
03617                config->feature_timer = 0;
03618                who = chan;
03619                if (f)
03620                   ast_frfree(f);
03621                f = NULL;
03622                res = 0;
03623             }
03624          }
03625       }
03626       if (res < 0) {
03627          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
03628             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
03629          }
03630          goto before_you_go;
03631       }
03632       
03633       if (!f || (f->frametype == AST_FRAME_CONTROL &&
03634             (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
03635                f->subclass.integer == AST_CONTROL_CONGESTION))) {
03636          res = -1;
03637          break;
03638       }
03639       /* many things should be sent to the 'other' channel */
03640       other = (who == chan) ? peer : chan;
03641       if (f->frametype == AST_FRAME_CONTROL) {
03642          switch (f->subclass.integer) {
03643          case AST_CONTROL_RINGING:
03644          case AST_CONTROL_FLASH:
03645          case -1:
03646             ast_indicate(other, f->subclass.integer);
03647             break;
03648          case AST_CONTROL_CONNECTED_LINE:
03649             if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
03650                break;
03651             }
03652             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03653             break;
03654          case AST_CONTROL_REDIRECTING:
03655             if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
03656                break;
03657             }
03658             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03659             break;
03660          case AST_CONTROL_AOC:
03661          case AST_CONTROL_HOLD:
03662          case AST_CONTROL_UNHOLD:
03663             ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
03664             break;
03665          case AST_CONTROL_OPTION:
03666             aoh = f->data.ptr;
03667             /* Forward option Requests */
03668             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
03669                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
03670                   f->datalen - sizeof(struct ast_option_header), 0);
03671             }
03672             break;
03673          }
03674       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
03675          /* eat it */
03676       } else if (f->frametype == AST_FRAME_DTMF) {
03677          char *featurecode;
03678          int sense;
03679 
03680          hadfeatures = hasfeatures;
03681          /* This cannot overrun because the longest feature is one shorter than our buffer */
03682          if (who == chan) {
03683             sense = FEATURE_SENSE_CHAN;
03684             featurecode = chan_featurecode;
03685          } else  {
03686             sense = FEATURE_SENSE_PEER;
03687             featurecode = peer_featurecode;
03688          }
03689          /*! append the event to featurecode. we rely on the string being zero-filled, and
03690           * not overflowing it. 
03691           * \todo XXX how do we guarantee the latter ?
03692           */
03693          featurecode[strlen(featurecode)] = f->subclass.integer;
03694          /* Get rid of the frame before we start doing "stuff" with the channels */
03695          ast_frfree(f);
03696          f = NULL;
03697          config->feature_timer = 0;
03698          res = feature_interpret(chan, peer, config, featurecode, sense);
03699          switch(res) {
03700          case AST_FEATURE_RETURN_PASSDIGITS:
03701             ast_dtmf_stream(other, who, featurecode, 0, 0);
03702             /* Fall through */
03703          case AST_FEATURE_RETURN_SUCCESS:
03704             memset(featurecode, 0, sizeof(chan_featurecode));
03705             break;
03706          }
03707          if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
03708             res = 0;
03709          } else {
03710             break;
03711          }
03712          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03713          if (hadfeatures && !hasfeatures) {
03714             /* Feature completed or timed out */
03715             config->feature_timer = 0;
03716          } else if (hasfeatures) {
03717             if (config->timelimit) {
03718                /* No warning next time - we are waiting for future */
03719                ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
03720             }
03721             config->feature_start_time = ast_tvnow();
03722             config->feature_timer = featuredigittimeout;
03723             ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
03724          }
03725       }
03726       if (f)
03727          ast_frfree(f);
03728 
03729    }
03730    ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL);
03731    before_you_go:
03732 
03733    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
03734       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
03735       if (bridge_cdr) {
03736          ast_cdr_discard(bridge_cdr);
03737          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
03738       }
03739       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
03740    }
03741 
03742    if (config->end_bridge_callback) {
03743       config->end_bridge_callback(config->end_bridge_callback_data);
03744    }
03745 
03746    /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 
03747     * if it were, then chan belongs to a different thread now, and might have been hung up long
03748      * ago.
03749     */
03750    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN)
03751       && ast_exists_extension(chan, chan->context, "h", 1,
03752          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
03753       struct ast_cdr *swapper = NULL;
03754       char savelastapp[AST_MAX_EXTENSION];
03755       char savelastdata[AST_MAX_EXTENSION];
03756       char save_exten[AST_MAX_EXTENSION];
03757       int  save_prio;
03758       int  found = 0;   /* set if we find at least one match */
03759       int  spawn_error = 0;
03760       
03761       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
03762       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
03763       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
03764          ast_cdr_end(bridge_cdr);
03765       }
03766       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
03767          dialplan code operate on it */
03768       ast_channel_lock(chan);
03769       if (bridge_cdr) {
03770          swapper = chan->cdr;
03771          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
03772          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
03773          chan->cdr = bridge_cdr;
03774       }
03775       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
03776       save_prio = chan->priority;
03777       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
03778       chan->priority = 1;
03779       ast_channel_unlock(chan);
03780       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten,
03781          chan->priority,
03782          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
03783          &found, 1)) == 0) {
03784          chan->priority++;
03785       }
03786       if (spawn_error
03787          && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority,
03788             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
03789             || ast_check_hangup(chan))) {
03790          /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */
03791          spawn_error = 0;
03792       }
03793       if (found && spawn_error) {
03794          /* Something bad happened, or a hangup has been requested. */
03795          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03796          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03797       }
03798       /* swap it back */
03799       ast_channel_lock(chan);
03800       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
03801       chan->priority = save_prio;
03802       if (bridge_cdr) {
03803          if (chan->cdr == bridge_cdr) {
03804             chan->cdr = swapper;
03805          } else {
03806             bridge_cdr = NULL;
03807          }
03808       }
03809       if (!spawn_error) {
03810          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
03811       }
03812       ast_channel_unlock(chan);
03813       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
03814       if (bridge_cdr) {
03815          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
03816          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
03817       }
03818       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03819    }
03820    
03821    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
03822    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
03823    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
03824       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
03825 
03826    /* we can post the bridge CDR at this point */
03827    if (bridge_cdr) {
03828       ast_cdr_end(bridge_cdr);
03829       ast_cdr_detach(bridge_cdr);
03830    }
03831    
03832    /* do a specialized reset on the beginning channel
03833       CDR's, if they still exist, so as not to mess up
03834       issues in future bridges;
03835       
03836       Here are the rules of the game:
03837       1. The chan and peer channel pointers will not change
03838          during the life of the bridge.
03839       2. But, in transfers, the channel names will change.
03840          between the time the bridge is started, and the
03841          time the channel ends. 
03842          Usually, when a channel changes names, it will
03843          also change CDR pointers.
03844       3. Usually, only one of the two channels (chan or peer)
03845          will change names.
03846       4. Usually, if a channel changes names during a bridge,
03847          it is because of a transfer. Usually, in these situations,
03848          it is normal to see 2 bridges running simultaneously, and
03849          it is not unusual to see the two channels that change
03850          swapped between bridges.
03851       5. After a bridge occurs, we have 2 or 3 channels' CDRs
03852          to attend to; if the chan or peer changed names,
03853          we have the before and after attached CDR's.
03854    */
03855 
03856    if (new_chan_cdr) {
03857       struct ast_channel *chan_ptr = NULL;
03858 
03859       if (strcasecmp(orig_channame, chan->name) != 0) { 
03860          /* old channel */
03861          if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
03862             ast_channel_lock(chan_ptr);
03863             if (!ast_bridged_channel(chan_ptr)) {
03864                struct ast_cdr *cur;
03865                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03866                   if (cur == chan_cdr) {
03867                      break;
03868                   }
03869                }
03870                if (cur) {
03871                   ast_cdr_specialized_reset(chan_cdr, 0);
03872                }
03873             }
03874             ast_channel_unlock(chan_ptr);
03875             chan_ptr = ast_channel_unref(chan_ptr);
03876          }
03877          /* new channel */
03878          ast_cdr_specialized_reset(new_chan_cdr, 0);
03879       } else {
03880          ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr  */
03881       }
03882    }
03883 
03884    {
03885       struct ast_channel *chan_ptr = NULL;
03886       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
03887       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))
03888          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
03889       if (strcasecmp(orig_peername, peer->name) != 0) { 
03890          /* old channel */
03891          if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
03892             ast_channel_lock(chan_ptr);
03893             if (!ast_bridged_channel(chan_ptr)) {
03894                struct ast_cdr *cur;
03895                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03896                   if (cur == peer_cdr) {
03897                      break;
03898                   }
03899                }
03900                if (cur) {
03901                   ast_cdr_specialized_reset(peer_cdr, 0);
03902                }
03903             }
03904             ast_channel_unlock(chan_ptr);
03905             chan_ptr = ast_channel_unref(chan_ptr);
03906          }
03907          /* new channel */
03908          if (new_peer_cdr) {
03909             ast_cdr_specialized_reset(new_peer_cdr, 0);
03910          }
03911       } else {
03912          if (we_disabled_peer_cdr) {
03913             ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED);
03914          }
03915          ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr  */
03916       }
03917    }
03918    
03919    return res;
03920 }

int ast_bridge_timelimit ( struct ast_channel chan,
struct ast_bridge_config config,
char *  parse,
struct timeval *  calldurationlimit 
)

parse L option and read associated channel variables to set warning, warning frequency, and timelimit

Note:
caller must be aware of freeing memory for warning_sound, end_sound, and start_sound

Definition at line 5680 of file features.c.

References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, config, LOG_WARNING, pbx_builtin_getvar_helper(), S_OR, strsep(), and var.

Referenced by bridge_exec(), and dial_exec_full().

05682 {
05683    char *stringp = ast_strdupa(parse);
05684    char *limit_str, *warning_str, *warnfreq_str;
05685    const char *var;
05686    int play_to_caller = 0, play_to_callee = 0;
05687    int delta;
05688 
05689    limit_str = strsep(&stringp, ":");
05690    warning_str = strsep(&stringp, ":");
05691    warnfreq_str = strsep(&stringp, ":");
05692 
05693    config->timelimit = atol(limit_str);
05694    if (warning_str)
05695       config->play_warning = atol(warning_str);
05696    if (warnfreq_str)
05697       config->warning_freq = atol(warnfreq_str);
05698 
05699    if (!config->timelimit) {
05700       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
05701       config->timelimit = config->play_warning = config->warning_freq = 0;
05702       config->warning_sound = NULL;
05703       return -1; /* error */
05704    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
05705       int w = config->warning_freq;
05706 
05707       /* If the first warning is requested _after_ the entire call would end,
05708          and no warning frequency is requested, then turn off the warning. If
05709          a warning frequency is requested, reduce the 'first warning' time by
05710          that frequency until it falls within the call's total time limit.
05711          Graphically:
05712               timelim->|    delta        |<-playwarning
05713          0__________________|_________________|
05714                 | w  |    |    |    |
05715 
05716          so the number of intervals to cut is 1+(delta-1)/w
05717       */
05718 
05719       if (w == 0) {
05720          config->play_warning = 0;
05721       } else {
05722          config->play_warning -= w * ( 1 + (delta-1)/w );
05723          if (config->play_warning < 1)
05724             config->play_warning = config->warning_freq = 0;
05725       }
05726    }
05727    
05728    ast_channel_lock(chan);
05729 
05730    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
05731    play_to_caller = var ? ast_true(var) : 1;
05732 
05733    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
05734    play_to_callee = var ? ast_true(var) : 0;
05735 
05736    if (!play_to_caller && !play_to_callee)
05737       play_to_caller = 1;
05738 
05739    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
05740    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
05741 
05742    /* The code looking at config wants a NULL, not just "", to decide
05743     * that the message should not be played, so we replace "" with NULL.
05744     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
05745     * not found.
05746     */
05747 
05748    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
05749    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05750 
05751    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
05752    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
05753 
05754    ast_channel_unlock(chan);
05755 
05756    /* undo effect of S(x) in case they are both used */
05757    calldurationlimit->tv_sec = 0;
05758    calldurationlimit->tv_usec = 0;
05759 
05760    /* more efficient to do it like S(x) does since no advanced opts */
05761    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
05762       calldurationlimit->tv_sec = config->timelimit / 1000;
05763       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
05764       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
05765          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
05766       config->timelimit = play_to_caller = play_to_callee =
05767       config->play_warning = config->warning_freq = 0;
05768    } else {
05769       ast_verb(4, "Limit Data for this call:\n");
05770       ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
05771       ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
05772       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
05773       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
05774       ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
05775       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
05776       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
05777       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
05778    }
05779    if (play_to_caller)
05780       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
05781    if (play_to_callee)
05782       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
05783    return 0;
05784 }

void ast_channel_log ( char *  title,
struct ast_channel chan 
)

Definition at line 3255 of file features.c.

References ast_log(), and LOG_NOTICE.

Referenced by ast_bridge_call().

03256 {
03257        ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
03258        ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
03259                        chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
03260        ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
03261                        chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
03262        ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
03263                        chan->masq, chan->masqr,
03264                        chan->_bridge, chan->uniqueid, chan->linkedid);
03265        if (chan->masqr)
03266                ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
03267                                chan->masqr->name, chan->masqr->cdr);
03268        if (chan->_bridge)
03269                ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
03270 
03271    ast_log(LOG_NOTICE, "===== done ====\n");
03272 }

int ast_feature_detect ( struct ast_channel chan,
struct ast_flags features,
const char *  code,
struct ast_call_feature feature 
)

detect a feature before bridging

Parameters:
chan 
features an ast_flags ptr
code ptr of input code
feature 
Return values:
ast_call_feature ptr to be set if found

Definition at line 2872 of file features.c.

References feature_group_exten::feature, and feature_interpret_helper().

Referenced by detect_disconnect().

02872                                                                                                                                  {
02873 
02874    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02875 }

int ast_features_init ( void   ) 

Provided by features.c

Definition at line 5955 of file features.c.

References action_bridge(), ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register_xml, ast_pthread_create, ast_register_application2(), AST_TEST_REGISTER, bridge_exec(), cli_features, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), and parkinglots.

Referenced by main().

05956 {
05957    int res;
05958 
05959    ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
05960 
05961    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
05962 
05963    if ((res = load_config()))
05964       return res;
05965    ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
05966    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
05967    res = ast_register_application2(parkedcall, park_exec, NULL, NULL, NULL);
05968    if (!res)
05969       res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
05970    if (!res) {
05971       ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
05972       ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
05973       ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
05974    }
05975 
05976    res |= ast_devstate_prov_add("Park", metermaidstate);
05977 #ifdef TEST_FRAMEWORK
05978    res |= AST_TEST_REGISTER(features_test);
05979 #endif
05980 
05981    return res;
05982 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 5179 of file features.c.

References ao2_t_callback, load_config(), OBJ_NODATA, OBJ_UNLINK, parkinglot_is_marked_cb(), parkinglot_markall_cb(), and parkinglots.

Referenced by handle_features_reload().

05180 {
05181    int res;
05182 
05183    ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, "callback to mark all parkinglots");
05184    res = load_config(); /* Reload configuration */
05185    ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, "callback to remove all marked parkinglots");
05186    
05187    return res;
05188 }

struct ast_call_feature* ast_find_call_feature ( const char *  name  ) 

look for a call feature entry by its sname

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

Definition at line 2614 of file features.c.

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

02615 {
02616    int x;
02617    for (x = 0; x < FEATURES_COUNT; x++) {
02618       if (!strcasecmp(name, builtin_features[x].sname))
02619          return &builtin_features[x];
02620    }
02621    return NULL;
02622 }

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

References masq_park_call().

Referenced by __analog_ss_thread(), analog_ss_thread(), handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), mgcp_ss(), parkandannounce_exec(), and rpt_exec().

01300 {
01301    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
01302 }

int ast_park_call ( struct ast_channel chan,
struct ast_channel host,
int  timeout,
const char *  parkexten,
int *  extout 
)

Park a call and read back parked location.

Parameters:
chan the channel to actually be parked
host the channel which will have the parked location read to.
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want.
Park the channel chan, and read back the parked location to the host. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context)
Return values:
0 on success.
-1 on failure.

Definition at line 1225 of file features.c.

References ao2_callback, args, find_parkinglot_by_exten_cb(), park_call_full(), and parkinglots.

Referenced by iax_park_thread(), and sip_park_thread().

01226 {
01227    struct ast_parkinglot *found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, (void *) parkexten);
01228 
01229    struct ast_park_call_args args = {
01230       .timeout = timeout,
01231       .extout = extout,
01232       .parkinglot = found_lot,
01233    };
01234 
01235    return park_call_full(chan, peer, &args);
01236 }

int ast_parking_ext_valid ( const char *  exten_str,
struct ast_channel chan,
const char *  context 
)

Determine if parking extension exists in a given context.

Return values:
0 if extension does not exist
1 if extension does exist

Definition at line 643 of file features.c.

References ast_get_extension_app(), E_MATCH, feature_group_exten::exten, PARK_APP_NAME, pbx_find_extension(), and pbx_find_info::stacklen.

Referenced by __analog_ss_thread(), analog_ss_thread(), dp_lookup(), handle_request_refer(), mgcp_ss(), and socket_process().

00644 {
00645    struct ast_exten *exten;
00646    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
00647    const char *app_at_exten;
00648 
00649    exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, E_MATCH);
00650    if (!exten) {
00651       return 0;
00652    }
00653 
00654    app_at_exten = ast_get_extension_app(exten);
00655    if (!app_at_exten || strcmp(PARK_APP_NAME, app_at_exten)) {
00656       return 0;
00657    }
00658 
00659    return 1;
00660 }

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

References ast_answer(), ast_channel_callback(), ast_channel_connected_line_macro(), ast_channel_lock_both, ast_channel_masquerade(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_unref, ast_channel_update_connected_line(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_manager_event_multichan, ast_party_connected_line_collect_caller(), ast_queue_control(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_channel::caller, ast_channel::connected, EVENT_FLAG_CALL, find_channel_by_group(), LOG_WARNING, ast_channel::name, pickupfailsound, pickupsound, and ast_party_connected_line::source.

Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), handle_request_invite(), mgcp_ss(), and pickup_exec().

05579 {
05580    struct ast_channel *cur, *chans[2] = { chan, };
05581    struct ast_party_connected_line connected_caller;
05582    int res;
05583    const char *chan_name;
05584    const char *cur_name;
05585 
05586    if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
05587       ast_debug(1, "No call pickup possible...\n");
05588       if (!ast_strlen_zero(pickupfailsound)) {
05589          ast_stream_and_wait(chan, pickupfailsound, "");
05590       }
05591       return -1;
05592    }
05593 
05594    chans[1] = cur;
05595 
05596    ast_channel_lock_both(cur, chan);
05597 
05598    cur_name = ast_strdupa(cur->name);
05599    chan_name = ast_strdupa(chan->name);
05600 
05601    ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name);
05602 
05603    connected_caller = cur->connected;
05604    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05605    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
05606       ast_channel_update_connected_line(chan, &connected_caller, NULL);
05607    }
05608 
05609    ast_party_connected_line_collect_caller(&connected_caller, &chan->caller);
05610    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
05611    ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
05612 
05613    ast_channel_unlock(cur);
05614    ast_channel_unlock(chan);
05615 
05616    if (ast_answer(chan)) {
05617       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
05618    }
05619 
05620    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
05621       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
05622    }
05623 
05624    if ((res = ast_channel_masquerade(cur, chan))) {
05625       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name);
05626    }
05627 
05628    if (!ast_strlen_zero(pickupsound)) {
05629       ast_stream_and_wait(cur, pickupsound, "");
05630    }
05631 
05632    /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
05633    ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
05634       "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, cur->name);
05635 
05636    cur = ast_channel_unref(cur);
05637 
05638    return res;
05639 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 662 of file features.c.

References pickup_ext.

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

00663 {
00664    return pickup_ext;
00665 }

void ast_rdlock_call_features ( void   ) 

Definition at line 2604 of file features.c.

References ast_rwlock_rdlock, and features_lock.

Referenced by handle_request_info().

02605 {
02606    ast_rwlock_rdlock(&features_lock);
02607 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_set

Parameters:
feature an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call.

Definition at line 2448 of file features.c.

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

02449 {
02450    if (!feature) {
02451       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
02452       return;
02453    }
02454   
02455    AST_RWLIST_WRLOCK(&feature_list);
02456    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
02457    AST_RWLIST_UNLOCK(&feature_list);
02458 
02459    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
02460 }

void ast_unlock_call_features ( void   ) 

Definition at line 2609 of file features.c.

References ast_rwlock_unlock, and features_lock.

Referenced by handle_request_info().

02610 {
02611    ast_rwlock_unlock(&features_lock);
02612 }

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

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

02529 {
02530    if (!feature) {
02531       return;
02532    }
02533 
02534    AST_RWLIST_WRLOCK(&feature_list);
02535    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02536    AST_RWLIST_UNLOCK(&feature_list);
02537 
02538    ast_free(feature);
02539 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 2542 of file features.c.

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

02543 {
02544    struct ast_call_feature *feature;
02545 
02546    AST_RWLIST_WRLOCK(&feature_list);
02547    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
02548       ast_free(feature);
02549    }
02550    AST_RWLIST_UNLOCK(&feature_list);
02551 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

Definition at line 2568 of file features.c.

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

02569 {
02570    struct feature_group *fg;
02571    struct feature_group_exten *fge;
02572 
02573    AST_RWLIST_WRLOCK(&feature_groups);
02574    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
02575       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
02576          ast_string_field_free_memory(fge);
02577          ast_free(fge);
02578       }
02579 
02580       ast_string_field_free_memory(fg);
02581       ast_free(fg);
02582    }
02583    AST_RWLIST_UNLOCK(&feature_groups);
02584 }

static void atxfer_fail_cleanup ( struct ast_channel transferee,
struct ast_channel transferer,
struct ast_party_connected_line connected_line 
) [static]

Definition at line 1987 of file features.c.

References ast_channel_connected_line_macro(), ast_channel_update_connected_line(), ast_party_connected_line_free(), and finishup().

Referenced by builtin_atxfer().

01988 {
01989    finishup(transferee);
01990 
01991    /*
01992     * Restore party B connected line info about party A.
01993     *
01994     * Party B was the caller to party C and is the last known mode
01995     * for party B.
01996     */
01997    if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
01998       ast_channel_update_connected_line(transferer, connected_line, NULL);
01999    }
02000    ast_party_connected_line_free(connected_line);
02001 }

static void* 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 757 of file features.c.

References ast_channel::appl, ast_bridge_call(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, LOG_VERBOSE, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.

Referenced by bridge_call_thread_launch().

00758 {
00759    struct ast_bridge_thread_obj *tobj = data;
00760    int res;
00761 
00762    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00763    tobj->chan->data = tobj->peer->name;
00764    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00765    tobj->peer->data = tobj->chan->name;
00766 
00767    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00768 
00769    if (tobj->return_to_pbx) {
00770       if (!ast_check_hangup(tobj->peer)) {
00771          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00772          res = ast_pbx_start(tobj->peer);
00773          if (res != AST_PBX_SUCCESS)
00774             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00775       } else
00776          ast_hangup(tobj->peer);
00777       if (!ast_check_hangup(tobj->chan)) {
00778          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00779          res = ast_pbx_start(tobj->chan);
00780          if (res != AST_PBX_SUCCESS)
00781             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00782       } else
00783          ast_hangup(tobj->chan);
00784    } else {
00785       ast_hangup(tobj->chan);
00786       ast_hangup(tobj->peer);
00787    }
00788 
00789    ast_free(tobj);
00790 
00791    return NULL;
00792 }

static void bridge_call_thread_launch ( void *  data  )  [static]

create thread for the parked call

Parameters:
data Create thread and attributes, call bridge_call_thread

Definition at line 800 of file features.c.

References ast_pthread_create, bridge_call_thread(), and thread.

Referenced by action_bridge(), and builtin_atxfer().

00801 {
00802    pthread_t thread;
00803    pthread_attr_t attr;
00804    struct sched_param sched;
00805 
00806    pthread_attr_init(&attr);
00807    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00808    ast_pthread_create(&thread, &attr, bridge_call_thread, data);
00809    pthread_attr_destroy(&attr);
00810    memset(&sched, 0, sizeof(sched));
00811    pthread_setschedparam(thread, SCHED_RR, &sched);
00812 }

static int bridge_exec ( struct ast_channel chan,
const char *  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 5796 of file features.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_bridge_timelimit(), ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_make_compatible(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_free, ast_hangup(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_pbx_start(), AST_PBX_SUCCESS, ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, ast_channel::context, do_bridge_masquerade(), ast_bridge_config::end_sound, EVENT_FLAG_CALL, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_channel::name, OPT_ARG_ARRAY_SIZE, OPT_ARG_DURATION_LIMIT, OPT_CALLEE_HANGUP, OPT_CALLEE_KILL, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DURATION_LIMIT, pbx_builtin_setvar_helper(), ast_channel::priority, ast_bridge_config::start_sound, ast_bridge_config::warning_sound, and xfersound.

Referenced by ast_features_init().

05797 {
05798    struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
05799    char *tmp_data  = NULL;
05800    struct ast_flags opts = { 0, };
05801    struct ast_bridge_config bconfig = { { 0, }, };
05802    char *opt_args[OPT_ARG_ARRAY_SIZE];
05803    struct timeval calldurationlimit = { 0, };
05804 
05805    AST_DECLARE_APP_ARGS(args,
05806       AST_APP_ARG(dest_chan);
05807       AST_APP_ARG(options);
05808    );
05809    
05810    if (ast_strlen_zero(data)) {
05811       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
05812       return -1;
05813    }
05814 
05815    tmp_data = ast_strdupa(data);
05816    AST_STANDARD_APP_ARGS(args, tmp_data);
05817    if (!ast_strlen_zero(args.options))
05818       ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
05819 
05820    /* avoid bridge with ourselves */
05821    if (!strcmp(chan->name, args.dest_chan)) {
05822       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
05823       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05824                "Response: Failed\r\n"
05825                "Reason: Unable to bridge channel to itself\r\n"
05826                "Channel1: %s\r\n"
05827                "Channel2: %s\r\n",
05828                chan->name, args.dest_chan);
05829       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
05830       return 0;
05831    }
05832 
05833    /* make sure we have a valid end point */
05834    if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
05835          strlen(args.dest_chan)))) {
05836       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
05837          "cannot get its lock\n", args.dest_chan);
05838       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05839                "Response: Failed\r\n"
05840                "Reason: Cannot grab end point\r\n"
05841                "Channel1: %s\r\n"
05842                "Channel2: %s\r\n", chan->name, args.dest_chan);
05843       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
05844       return 0;
05845    }
05846 
05847    /* answer the channel if needed */
05848    if (current_dest_chan->_state != AST_STATE_UP) {
05849       ast_answer(current_dest_chan);
05850    }
05851 
05852    /* try to allocate a place holder where current_dest_chan will be placed */
05853    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
05854       NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
05855       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
05856       ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
05857                "Response: Failed\r\n"
05858                "Reason: cannot create placeholder\r\n"
05859                "Channel1: %s\r\n"
05860                "Channel2: %s\r\n", chan->name, args.dest_chan);
05861    }
05862 
05863    ast_channel_unlock(current_dest_chan);
05864 
05865    do_bridge_masquerade(current_dest_chan, final_dest_chan);
05866 
05867    chans[0] = current_dest_chan;
05868    chans[1] = final_dest_chan;
05869 
05870    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
05871    /* try to make compatible, send error if we fail */
05872    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
05873       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
05874       ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
05875                "Response: Failed\r\n"
05876                "Reason: Could not make channels compatible for bridge\r\n"
05877                "Channel1: %s\r\n"
05878                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05879       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
05880       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
05881       current_dest_chan = ast_channel_unref(current_dest_chan);
05882       return 0;
05883    }
05884 
05885    /* Report that the bridge will be successfull */
05886    ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
05887             "Response: Success\r\n"
05888             "Channel1: %s\r\n"
05889             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05890 
05891    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
05892    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
05893       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
05894          if (ast_waitstream(final_dest_chan, "") < 0)
05895             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
05896       }
05897    }
05898    
05899    current_dest_chan = ast_channel_unref(current_dest_chan);
05900    
05901    if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
05902       if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
05903          goto done;
05904    }
05905 
05906    if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
05907       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
05908    if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
05909       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
05910    if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
05911       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
05912    if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
05913       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
05914    if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
05915       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
05916    if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 
05917       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
05918    if (ast_test_flag(&opts, OPT_CALLEE_PARK))
05919       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
05920    if (ast_test_flag(&opts, OPT_CALLER_PARK))
05921       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
05922 
05923    ast_bridge_call(chan, final_dest_chan, &bconfig);
05924 
05925    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
05926    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
05927    if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) {
05928       ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 
05929          final_dest_chan->context, final_dest_chan->exten, 
05930          final_dest_chan->priority, final_dest_chan->name);
05931 
05932       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
05933          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
05934          ast_hangup(final_dest_chan);
05935       } else
05936          ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
05937    } else {
05938       ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name);
05939       ast_hangup(final_dest_chan);
05940    }
05941 done:
05942    if (bconfig.warning_sound) {
05943       ast_free((char *)bconfig.warning_sound);
05944    }
05945    if (bconfig.end_sound) {
05946       ast_free((char *)bconfig.end_sound);
05947    }
05948    if (bconfig.start_sound) {
05949       ast_free((char *)bconfig.start_sound);
05950    }
05951 
05952    return 0;
05953 }

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

Build parkinglot from configuration and chain it in if it doesn't already exist.

Definition at line 4602 of file features.c.

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

Referenced by load_config().

04603 {
04604    struct ast_parkinglot *parkinglot;
04605    struct ast_context *con = NULL;
04606 
04607    struct ast_variable *confvar = var;
04608    int error = 0;
04609    int start = 0, end = 0;
04610    int oldparkinglot = 0;
04611 
04612    parkinglot = find_parkinglot(name);
04613    if (parkinglot)
04614       oldparkinglot = 1;
04615    else
04616       parkinglot = create_parkinglot(name);
04617 
04618    if (!parkinglot)
04619       return NULL;
04620 
04621    ao2_lock(parkinglot);
04622 
04623    ast_debug(1, "Building parking lot %s\n", name);
04624 
04625    /* Do some config stuff */
04626    while(confvar) {
04627       if (!strcasecmp(confvar->name, "context")) {
04628          ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
04629       } else if (!strcasecmp(confvar->name, "parkext")) {
04630          ast_copy_string(parkinglot->parkext, confvar->value, sizeof(parkinglot->parkext));
04631       } else if (!strcasecmp(confvar->name, "parkingtime")) {
04632          if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
04633             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
04634             parkinglot->parkingtime = DEFAULT_PARK_TIME;
04635          } else
04636             parkinglot->parkingtime = parkinglot->parkingtime * 1000;
04637       } else if (!strcasecmp(confvar->name, "parkpos")) {
04638          if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) {
04639             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);
04640             error = 1;
04641          } else {
04642             parkinglot->parking_start = start;
04643             parkinglot->parking_stop = end;
04644          }
04645       } else if (!strcasecmp(confvar->name, "findslot")) {
04646          parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next"));
04647       } else if (!strcasecmp(confvar->name, "parkedcalltransfers")) {
04648                         ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04649                         if (!strcasecmp(confvar->value, "both"))
04650                                 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
04651                         else if (!strcasecmp(confvar->value, "caller"))
04652                                 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
04653                         else if (!strcasecmp(confvar->value, "callee"))
04654                                 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
04655                 } else if (!strcasecmp(confvar->name, "parkedcallreparking")) {
04656                         ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04657                         if (!strcasecmp(confvar->value, "both"))
04658                                 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
04659                         else if (!strcasecmp(confvar->value, "caller"))
04660                                 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
04661                         else if (!strcasecmp(confvar->value, "callee"))
04662                                 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
04663                 } else if (!strcasecmp(confvar->name, "parkedcallhangup")) {
04664                         ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04665                         if (!strcasecmp(confvar->value, "both"))
04666                                 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
04667                         else if (!strcasecmp(confvar->value, "caller"))
04668                                 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
04669                         else if (!strcasecmp(confvar->value, "callee"))
04670                                 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
04671                 } else if (!strcasecmp(confvar->name, "parkedcallrecording")) {
04672                         ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value);
04673                         if (!strcasecmp(confvar->value, "both"))
04674                                 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
04675                         else if (!strcasecmp(confvar->value, "caller"))
04676                                 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
04677                         else if (!strcasecmp(confvar->value, "callee"))
04678                                 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
04679                 }
04680       confvar = confvar->next;
04681    }
04682    /* make sure parkingtime is set if not specified */
04683    if (parkinglot->parkingtime == 0) {
04684       parkinglot->parkingtime = DEFAULT_PARK_TIME;
04685    }
04686    if (ast_strlen_zero(parkinglot->parkext)) {
04687       ast_debug(2, "no parkext specified for %s - setting it to %s\n", parkinglot->name, DEFAULT_PARK_EXTENSION);
04688       ast_copy_string(parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(parkinglot->parkext));
04689    }
04690 
04691    if (!var) { /* Default parking lot */
04692       ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
04693       ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial));
04694       ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass));
04695    }
04696 
04697    /* Check for errors */
04698    if (ast_strlen_zero(parkinglot->parking_con)) {
04699       ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name);
04700       error = 1;
04701    }
04702 
04703    /* Create context */
04704    if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) {
04705       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
04706       error = 1;
04707    }
04708 
04709    /* Add a parking extension into the context */
04710    if (!error && !oldparkinglot) {
04711       if (!ast_strlen_zero(parkinglot->parkext)) {
04712          if (ast_add_extension2(con, 1, parkinglot->parkext, 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
04713             error = 1;
04714       }
04715    }
04716 
04717    /* Add parking hints */
04718    if (parkinglot->parkaddhints)
04719       park_add_hints(parkinglot->parking_con, parkinglot->parking_start, parkinglot->parking_stop);
04720 
04721    ao2_unlock(parkinglot);
04722 
04723    if (error) {
04724       ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
04725       parkinglot_destroy(parkinglot);
04726       parkinglot_unref(parkinglot);
04727       return NULL;
04728    }
04729    ast_debug(1, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
04730    parkinglot->the_mark = 0;
04731 
04732    /* Move it into the list, if it wasn't already there */
04733    if (!oldparkinglot) {
04734       ao2_link(parkinglots, parkinglot);
04735    }
04736    parkinglot_unref(parkinglot);
04737 
04738    return parkinglot;
04739 }

static int builtin_atxfer ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const 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 2018 of file features.c.

References ast_channel::_state, ao2_callback, args, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_calloc, AST_CEL_ATTENDEDTRANSFER, ast_cel_report_event(), ast_channel_alloc, ast_channel_connected_line_macro(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_channel_update_connected_line(), ast_check_hangup(), ast_clear_flag, ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_do_masquerade(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAGS_ALL, ast_hangup(), ast_indicate(), ast_log(), ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), atxfer_fail_cleanup(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, bridge_call_thread_launch(), ast_channel::caller, check_compat(), config, ast_channel::connected, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, feature_request_and_dial(), ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, find_parkinglot_by_exten_cb(), finishup(), ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, parkcall_helper(), parkinglot, parkinglots, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_party_connected_line::source, strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xferfailsound, and xfersound.

02019 {
02020    struct ast_channel *transferer;/* Party B */
02021    struct ast_channel *transferee;/* Party A */
02022    const char *transferer_real_context;
02023    char xferto[256] = "";
02024    int res;
02025    int outstate=0;
02026    struct ast_channel *newchan;
02027    struct ast_channel *xferchan;
02028    struct ast_bridge_thread_obj *tobj;
02029    struct ast_bridge_config bconfig;
02030    int l;
02031    struct ast_party_connected_line connected_line;
02032    struct ast_datastore *features_datastore;
02033    struct ast_dial_features *dialfeatures = NULL;
02034    struct ast_parkinglot *parkinglot;
02035    char *transferer_tech;
02036    char *transferer_name;
02037    char *transferer_name_orig;
02038    char *dash;
02039 
02040    ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
02041    set_peers(&transferer, &transferee, peer, chan, sense);
02042    transferer_real_context = real_ctx(transferer, transferee);
02043 
02044    /* Start autoservice on transferee while we talk to the transferer */
02045    ast_autoservice_start(transferee);
02046    ast_indicate(transferee, AST_CONTROL_HOLD);
02047 
02048    /* Transfer */
02049    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
02050    if (res < 0) {
02051       finishup(transferee);
02052       return -1;
02053    }
02054    if (res > 0) /* If they've typed a digit already, handle it */
02055       xferto[0] = (char) res;
02056 
02057    /* this is specific of atxfer */
02058    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
02059    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
02060       finishup(transferee);
02061       return -1;
02062    }
02063    l = strlen(xferto);
02064    if (res == 0) {
02065       if (l) {
02066          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
02067             xferto, transferer_real_context);
02068       } else {
02069          /* Does anyone care about this case? */
02070          ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
02071       }
02072       ast_stream_and_wait(transferer, "pbx-invalid", "");
02073       finishup(transferee);
02074       return AST_FEATURE_RETURN_SUCCESS;
02075    }
02076 
02077    /* If we are attended transfering to parking, just use parkcall_helper instead of trying to track all of
02078     * the different variables for handling this properly with a builtin_atxfer */
02079    parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
02080    if (parkinglot) {
02081       struct ast_park_call_args args = {
02082          .parkinglot = parkinglot,
02083       };
02084       finishup(transferee);
02085       return parkcall_helper(chan, peer, config, code, sense, &args);
02086    }
02087 
02088    /* Append context to dialed transfer number. */
02089    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
02090 
02091    /* If we are performing an attended transfer and we have two channels involved then
02092       copy sound file information to play upon attended transfer completion */
02093    if (transferee) {
02094       const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02095       const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
02096 
02097       if (!ast_strlen_zero(chan1_attended_sound)) {
02098          pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
02099       }
02100       if (!ast_strlen_zero(chan2_attended_sound)) {
02101          pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
02102       }
02103    }
02104 
02105    /* Extract redial transferer information from the channel name. */
02106    transferer_name_orig = ast_strdupa(transferer->name);
02107    transferer_name = ast_strdupa(transferer_name_orig);
02108    transferer_tech = strsep(&transferer_name, "/");
02109    dash = strrchr(transferer_name, '-');
02110    if (dash) {
02111       /* Trim off channel name sequence/serial number. */
02112       *dash = '\0';
02113    }
02114 
02115    /* Stop autoservice so we can monitor all parties involved in the transfer. */
02116    if (ast_autoservice_stop(transferee) < 0) {
02117       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02118       return -1;
02119    }
02120 
02121    /* Save connected line info for party B about party A in case transfer fails. */
02122    ast_party_connected_line_init(&connected_line);
02123    ast_channel_lock(transferer);
02124    ast_party_connected_line_copy(&connected_line, &transferer->connected);
02125    ast_channel_unlock(transferer);
02126    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02127 
02128    /* Dial party C */
02129    newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
02130       transferee, "Local", ast_best_codec(transferer->nativeformats), xferto,
02131       atxfernoanswertimeout, &outstate, transferer->language);
02132    ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
02133 
02134    if (!ast_check_hangup(transferer)) {
02135       int hangup_dont = 0;
02136 
02137       /* Transferer (party B) is up */
02138       ast_debug(1, "Actually doing an attended transfer.\n");
02139 
02140       /* Start autoservice on transferee while the transferer deals with party C. */
02141       ast_autoservice_start(transferee);
02142 
02143       ast_indicate(transferer, -1);
02144       if (!newchan) {
02145          /* any reason besides user requested cancel and busy triggers the failed sound */
02146          switch (outstate) {
02147          case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */
02148          case AST_CONTROL_BUSY:
02149          case AST_CONTROL_CONGESTION:
02150             if (ast_stream_and_wait(transferer, xfersound, "")) {
02151                ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02152             }
02153             break;
02154          default:
02155             if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02156                ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02157             }
02158             break;
02159          }
02160          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02161          return AST_FEATURE_RETURN_SUCCESS;
02162       }
02163 
02164       if (check_compat(transferer, newchan)) {
02165          if (ast_stream_and_wait(transferer, xferfailsound, "")) {
02166             ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
02167          }
02168          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02169          return AST_FEATURE_RETURN_SUCCESS;
02170       }
02171       memset(&bconfig,0,sizeof(struct ast_bridge_config));
02172       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
02173       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
02174 
02175       /* ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we don't
02176          want that to happen here because we're also in another bridge already
02177        */
02178       if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) {
02179          hangup_dont = 1;
02180       }
02181       /* Let party B and party C talk as long as they want. */
02182       ast_bridge_call(transferer, newchan, &bconfig);
02183       if (hangup_dont) {
02184          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
02185       }
02186 
02187       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
02188          ast_hangup(newchan);
02189          if (ast_stream_and_wait(transferer, xfersound, "")) {
02190             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02191          }
02192          atxfer_fail_cleanup(transferee, transferer, &connected_line);
02193          return AST_FEATURE_RETURN_SUCCESS;
02194       }
02195 
02196       /* Transferer (party B) is confirmed hung up at this point. */
02197       if (check_compat(transferee, newchan)) {
02198          finishup(transferee);
02199          ast_party_connected_line_free(&connected_line);
02200          return -1;
02201       }
02202 
02203       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02204       if ((ast_autoservice_stop(transferee) < 0)
02205          || (ast_waitfordigit(transferee, 100) < 0)
02206          || (ast_waitfordigit(newchan, 100) < 0)
02207          || ast_check_hangup(transferee)
02208          || ast_check_hangup(newchan)) {
02209          ast_hangup(newchan);
02210          ast_party_connected_line_free(&connected_line);
02211          return -1;
02212       }
02213    } else if (!ast_check_hangup(transferee)) {
02214       /* Transferer (party B) has hung up at this point.  Doing blonde transfer. */
02215       ast_debug(1, "Actually doing a blonde transfer.\n");
02216 
02217       if (!newchan && !atxferdropcall) {
02218          /* Party C is not available, try to call party B back. */
02219          unsigned int tries = 0;
02220 
02221          if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
02222             ast_log(LOG_WARNING,
02223                "Transferer channel name: '%s' cannot be used for callback.\n",
02224                transferer_name_orig);
02225             ast_indicate(transferee, AST_CONTROL_UNHOLD);
02226             ast_party_connected_line_free(&connected_line);
02227             return -1;
02228          }
02229 
02230          tries = 0;
02231          for (;;) {
02232             /* Try to get party B back. */
02233             ast_debug(1, "We're trying to callback %s/%s\n",
02234                transferer_tech, transferer_name);
02235             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02236                transferee, transferee, transferer_tech,
02237                ast_best_codec(transferee->nativeformats), transferer_name,
02238                atxfernoanswertimeout, &outstate, transferer->language);
02239             ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
02240                !!newchan, outstate);
02241             if (newchan || ast_check_hangup(transferee)) {
02242                break;
02243             }
02244 
02245             ++tries;
02246             if (atxfercallbackretries <= tries) {
02247                /* No more callback tries remaining. */
02248                break;
02249             }
02250 
02251             if (atxferloopdelay) {
02252                /* Transfer failed, sleeping */
02253                ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n",
02254                   atxferloopdelay);
02255                ast_safe_sleep(transferee, atxferloopdelay);
02256                if (ast_check_hangup(transferee)) {
02257                   ast_party_connected_line_free(&connected_line);
02258                   return -1;
02259                }
02260             }
02261 
02262             /* Retry dialing party C. */
02263             ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
02264             newchan = feature_request_and_dial(transferer, transferer_name_orig,
02265                transferer, transferee, "Local",
02266                ast_best_codec(transferee->nativeformats), xferto,
02267                atxfernoanswertimeout, &outstate, transferer->language);
02268             ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
02269                !!newchan, outstate);
02270             if (newchan || ast_check_hangup(transferee)) {
02271                break;
02272             }
02273          }
02274       }
02275       ast_indicate(transferee, AST_CONTROL_UNHOLD);
02276       if (!newchan) {
02277          /* No party C or could not callback party B. */
02278          ast_party_connected_line_free(&connected_line);
02279          return -1;
02280       }
02281 
02282       /* newchan is up, we should prepare transferee and bridge them */
02283       if (ast_check_hangup(newchan)) {
02284          ast_hangup(newchan);
02285          ast_party_connected_line_free(&connected_line);
02286          return -1;
02287       }
02288       if (check_compat(transferee, newchan)) {
02289          ast_party_connected_line_free(&connected_line);
02290          return -1;
02291       }
02292    } else {
02293       /*
02294        * Both the transferer and transferee have hungup.  If newchan
02295        * is up, hang it up as it has no one to talk to.
02296        */
02297       ast_debug(1, "Everyone is hungup.\n");
02298       if (newchan) {
02299          ast_hangup(newchan);
02300       }
02301       ast_party_connected_line_free(&connected_line);
02302       return -1;
02303    }
02304 
02305    /* Initiate the channel transfer of party A to party C (or recalled party B). */
02306    ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
02307 
02308    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name);
02309    if (!xferchan) {
02310       ast_hangup(newchan);
02311       ast_party_connected_line_free(&connected_line);
02312       return -1;
02313    }
02314 
02315    /* Give party A a momentary ringback tone during transfer. */
02316    xferchan->visible_indication = AST_CONTROL_RINGING;
02317 
02318    /* Make formats okay */
02319    xferchan->readformat = transferee->readformat;
02320    xferchan->writeformat = transferee->writeformat;
02321 
02322    ast_channel_masquerade(xferchan, transferee);
02323    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
02324    xferchan->_state = AST_STATE_UP;
02325    ast_clear_flag(xferchan, AST_FLAGS_ALL);
02326 
02327    /* Do the masquerade manually to make sure that is is completed. */
02328    ast_do_masquerade(xferchan);
02329 
02330    newchan->_state = AST_STATE_UP;
02331    ast_clear_flag(newchan, AST_FLAGS_ALL);
02332    tobj = ast_calloc(1, sizeof(*tobj));
02333    if (!tobj) {
02334       ast_hangup(xferchan);
02335       ast_hangup(newchan);
02336       ast_party_connected_line_free(&connected_line);
02337       return -1;
02338    }
02339 
02340    ast_channel_lock(newchan);
02341    if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
02342       dialfeatures = features_datastore->data;
02343    }
02344    ast_channel_unlock(newchan);
02345 
02346    if (dialfeatures) {
02347       /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
02348          I don't currently understand, the abilities of newchan seem to be stored on the caller side */
02349       ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02350       dialfeatures = NULL;
02351    }
02352 
02353    ast_channel_lock(xferchan);
02354    if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
02355       dialfeatures = features_datastore->data;
02356    }
02357    ast_channel_unlock(xferchan);
02358 
02359    if (dialfeatures) {
02360       ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
02361    }
02362 
02363    tobj->chan = newchan;
02364    tobj->peer = xferchan;
02365    tobj->bconfig = *config;
02366 
02367    if (tobj->bconfig.end_bridge_callback_data_fixup) {
02368       tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
02369    }
02370 
02371    /*
02372     * xferchan is transferee, and newchan is the transfer target
02373     * So...in a transfer, who is the caller and who is the callee?
02374     *
02375     * When the call is originally made, it is clear who is caller and callee.
02376     * When a transfer occurs, it is my humble opinion that the transferee becomes
02377     * the caller, and the transfer target is the callee.
02378     *
02379     * The problem is that these macros were set with the intention of the original
02380     * caller and callee taking those roles.  A transfer can totally mess things up,
02381     * to be technical.  What sucks even more is that you can't effectively change
02382     * the macros in the dialplan during the call from the transferer to the transfer
02383     * target because the transferee is stuck with whatever role he originally had.
02384     *
02385     * I think the answer here is just to make sure that it is well documented that
02386     * during a transfer, the transferee is the "caller" and the transfer target
02387     * is the "callee."
02388     *
02389     * This means that if party B calls party A, and party B transfers party A to
02390     * party C, then A has switched roles for the call.  Now party A will have the
02391     * caller macro called on his channel instead of the callee macro.
02392     *
02393     * Luckily, the method by which the party B to party C bridge is
02394     * launched above ensures that the transferee is the "chan" on
02395     * the bridge and the transfer target is the "peer," so my idea
02396     * for the roles post-transfer does not require extensive code
02397     * changes.
02398     */
02399 
02400    /* Transfer party C connected line to party A */
02401    ast_channel_lock(transferer);
02402    /*
02403     * Due to a limitation regarding when callerID is set on a Local channel,
02404     * we use the transferer's connected line information here.
02405     */
02406    ast_party_connected_line_copy(&connected_line, &transferer->connected);
02407    ast_channel_unlock(transferer);
02408    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02409    if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
02410       ast_channel_update_connected_line(xferchan, &connected_line, NULL);
02411    }
02412 
02413    /* Transfer party A connected line to party C */
02414    ast_channel_lock(xferchan);
02415    ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller);
02416    ast_channel_unlock(xferchan);
02417    connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
02418    if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
02419       ast_channel_update_connected_line(newchan, &connected_line, NULL);
02420    }
02421 
02422    if (ast_stream_and_wait(newchan, xfersound, ""))
02423       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
02424    bridge_call_thread_launch(tobj);
02425 
02426    ast_party_connected_line_free(&connected_line);
02427    return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */
02428 }

static int builtin_automixmonitor ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
void *  data 
) [static]

Definition at line 1683 of file features.c.

References args, AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_ignore(), 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_FRAME_DTMF_END, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, ast_channel::name, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_COR, S_OR, set_peers(), stopmixmonitor_app, stopmixmonitor_ok, ast_party_number::str, and ast_party_number::valid.

01684 {
01685    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01686    int x = 0;
01687    size_t len;
01688    struct ast_channel *caller_chan, *callee_chan;
01689    const char *mixmonitor_spy_type = "MixMonitor";
01690    int count = 0;
01691 
01692    if (!mixmonitor_ok) {
01693       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01694       return -1;
01695    }
01696 
01697    if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
01698       mixmonitor_ok = 0;
01699       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01700       return -1;
01701    }
01702 
01703    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01704 
01705    if (!ast_strlen_zero(courtesytone)) {
01706       if (ast_autoservice_start(callee_chan))
01707          return -1;
01708       ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
01709       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
01710          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01711          ast_autoservice_stop(callee_chan);
01712          return -1;
01713       }
01714       if (ast_autoservice_stop(callee_chan))
01715          return -1;
01716    }
01717 
01718    ast_channel_lock(callee_chan);
01719    count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01720    ast_channel_unlock(callee_chan);
01721 
01722    /* This means a mixmonitor is attached to the channel, running or not is unknown. */
01723    if (count > 0) {
01724       
01725       ast_verb(3, "User hit '%s' to stop recording call.\n", code);
01726 
01727       /* Make sure they are running */
01728       ast_channel_lock(callee_chan);
01729       count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01730       ast_channel_unlock(callee_chan);
01731       if (count > 0) {
01732          if (!stopmixmonitor_ok) {
01733             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01734             return -1;
01735          }
01736          if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
01737             stopmixmonitor_ok = 0;
01738             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01739             return -1;
01740          } else {
01741             pbx_exec(callee_chan, stopmixmonitor_app, "");
01742             return AST_FEATURE_RETURN_SUCCESS;
01743          }
01744       }
01745       
01746       ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 
01747    }        
01748 
01749    if (caller_chan && callee_chan) {
01750       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
01751       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
01752 
01753       if (!touch_format)
01754          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
01755 
01756       if (!touch_monitor)
01757          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
01758 
01759       if (touch_monitor) {
01760          len = strlen(touch_monitor) + 50;
01761          args = alloca(len);
01762          touch_filename = alloca(len);
01763          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
01764          snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
01765       } else {
01766          caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
01767             caller_chan->caller.id.number.str, caller_chan->name));
01768          callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
01769             callee_chan->caller.id.number.str, callee_chan->name));
01770          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01771          args = alloca(len);
01772          touch_filename = alloca(len);
01773          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
01774          snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
01775       }
01776 
01777       for( x = 0; x < strlen(args); x++) {
01778          if (args[x] == '/')
01779             args[x] = '-';
01780       }
01781 
01782       ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
01783 
01784       pbx_exec(callee_chan, mixmonitor_app, args);
01785       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01786       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01787       return AST_FEATURE_RETURN_SUCCESS;
01788    
01789    }
01790 
01791    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
01792    return -1;
01793 
01794 }

static int builtin_automonitor ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const 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 1588 of file features.c.

References args, AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, LOG_NOTICE, ast_channel::monitor, monitor_app, monitor_ok, ast_channel::name, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_COR, S_OR, set_peers(), ast_channel_monitor::stop, ast_party_number::str, and ast_party_number::valid.

01589 {
01590    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01591    int x = 0;
01592    size_t len;
01593    struct ast_channel *caller_chan, *callee_chan;
01594    const char *automon_message_start = NULL;
01595    const char *automon_message_stop = NULL;
01596 
01597    if (!monitor_ok) {
01598       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
01599       return -1;
01600    }
01601 
01602    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
01603       monitor_ok = 0;
01604       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
01605       return -1;
01606    }
01607 
01608    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01609    if (caller_chan) {   /* Find extra messages */
01610       automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
01611       automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
01612    }
01613 
01614    if (!ast_strlen_zero(courtesytone)) {  /* Play courtesy tone if configured */
01615       if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
01616          return -1;
01617       }
01618    }
01619    
01620    if (callee_chan->monitor) {
01621       ast_verb(4, "User hit '%s' to stop recording call.\n", code);
01622       if (!ast_strlen_zero(automon_message_stop)) {
01623          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
01624       }
01625       callee_chan->monitor->stop(callee_chan, 1);
01626       return AST_FEATURE_RETURN_SUCCESS;
01627    }
01628 
01629    if (caller_chan && callee_chan) {
01630       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
01631       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
01632       const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
01633 
01634       if (!touch_format)
01635          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
01636 
01637       if (!touch_monitor)
01638          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
01639    
01640       if (!touch_monitor_prefix)
01641          touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
01642    
01643       if (touch_monitor) {
01644          len = strlen(touch_monitor) + 50;
01645          args = alloca(len);
01646          touch_filename = alloca(len);
01647          snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
01648          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
01649       } else {
01650          caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid,
01651             caller_chan->caller.id.number.str, caller_chan->name));
01652          callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid,
01653             callee_chan->caller.id.number.str, callee_chan->name));
01654          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01655          args = alloca(len);
01656          touch_filename = alloca(len);
01657          snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
01658          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
01659       }
01660 
01661       for(x = 0; x < strlen(args); x++) {
01662          if (args[x] == '/')
01663             args[x] = '-';
01664       }
01665       
01666       ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
01667 
01668       pbx_exec(callee_chan, monitor_app, args);
01669       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01670       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01671 
01672       if (!ast_strlen_zero(automon_message_start)) {  /* Play start message for both channels */
01673          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
01674       }
01675    
01676       return AST_FEATURE_RETURN_SUCCESS;
01677    }
01678    
01679    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
01680    return -1;
01681 }

static int builtin_blindtransfer ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const 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 1846 of file features.c.

References ao2_callback, args, ast_app_dtget(), ast_async_goto(), ast_autoservice_ignore(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CEL_BLINDTRANSFER, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_update_connected_line(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), AST_FEATURE_RETURN_PARKFAILED, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FRAME_DTMF_END, ast_indicate(), ast_log(), ast_set_flag, ast_stopstream(), ast_stream_and_wait(), ast_verb, ast_channel::cdr, ast_cdr::channel, check_goto_on_transfer(), ast_channel::connected, ast_cdr::dstchannel, find_parkinglot_by_exten_cb(), finishup(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, masq_park_call_announce(), ast_channel::name, parkinglots, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), S_COR, set_c_e_p(), set_peers(), transferdigittimeout, and xferfailsound.

01847 {
01848    struct ast_channel *transferer;
01849    struct ast_channel *transferee;
01850    const char *transferer_real_context;
01851    struct ast_parkinglot *found_lot = NULL;
01852    char xferto[256];
01853    int res, parkstatus = 0;
01854 
01855    set_peers(&transferer, &transferee, peer, chan, sense);
01856    transferer_real_context = real_ctx(transferer, transferee);
01857    /* Start autoservice on chan while we talk to the originator */
01858    ast_autoservice_start(transferee);
01859    ast_autoservice_ignore(transferee, AST_FRAME_DTMF_END);
01860    ast_indicate(transferee, AST_CONTROL_HOLD);
01861 
01862    memset(xferto, 0, sizeof(xferto));
01863 
01864    /* Transfer */
01865    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01866    if (res < 0) {
01867       finishup(transferee);
01868       return -1; /* error ? */
01869    }
01870    if (res > 0)   /* If they've typed a digit already, handle it */
01871       xferto[0] = (char) res;
01872 
01873    ast_stopstream(transferer);
01874    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01875    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
01876       finishup(transferee);
01877       return res;
01878    }
01879 
01880    found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
01881    if (found_lot) {
01882       struct ast_park_call_args args = {
01883          .parkinglot = found_lot,
01884       };
01885       res = finishup(transferee);
01886       if (res)
01887          res = -1;
01888       else if (!(parkstatus = masq_park_call_announce(transferee, transferer, &args))) {  /* success */
01889          /* We return non-zero, but tell the PBX not to hang the channel when
01890             the thread dies -- We have to be careful now though.  We are responsible for 
01891             hanging up the channel, else it will never be hung up! */
01892 
01893          return 0;
01894       } else {
01895          ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01896       }
01897       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
01898    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1,
01899       S_COR(transferer->caller.id.number.valid, transferer->caller.id.number.str, NULL))) {
01900       ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
01901       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01902       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01903       res=finishup(transferee);
01904       if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
01905          transferer->cdr=ast_cdr_alloc();
01906          if (transferer->cdr) {
01907             ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */
01908             ast_cdr_start(transferer->cdr);
01909          }
01910       }
01911       if (transferer->cdr) {
01912          struct ast_cdr *swap = transferer->cdr;
01913          ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01914                transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 
01915                transferer->cdr->channel, transferer->cdr->dstchannel);
01916          ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01917                transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01918          ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01919          /* swap cdrs-- it will save us some time & work */
01920          transferer->cdr = transferee->cdr;
01921          transferee->cdr = swap;
01922       }
01923       if (!transferee->pbx) {
01924          /* Doh!  Use our handy async_goto functions */
01925          ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01926                         ,transferee->name, xferto, transferer_real_context);
01927          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01928             ast_log(LOG_WARNING, "Async goto failed :-(\n");
01929       } else {
01930          /* Set the channel's new extension, since it exists, using transferer context */
01931          ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
01932          ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01933          if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) {
01934             ast_channel_update_connected_line(transferer, &transferer->connected, NULL);
01935          }
01936          set_c_e_p(transferee, transferer_real_context, xferto, 0);
01937       }
01938       check_goto_on_transfer(transferer);
01939       return res;
01940    } else {
01941       ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
01942    }
01943    if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { /* Play 'extension does not exist' */
01944       finishup(transferee);
01945       return -1;
01946    }
01947    ast_stopstream(transferer);
01948    res = finishup(transferee);
01949    if (res) {
01950       ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01951       return res;
01952    }
01953    return AST_FEATURE_RETURN_SUCCESS;
01954 }

static int builtin_disconnect ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
void *  data 
) [static]

Definition at line 1796 of file features.c.

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

01797 {
01798    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
01799    return AST_FEATURE_RETURN_HANGUP;
01800 }

static int builtin_parkcall ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const 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 1539 of file features.c.

References config, and parkcall_helper().

01540 {
01541    return parkcall_helper(chan, peer, config, code, sense, NULL);
01542 }

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

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

03942 {
03943    int i = 0;
03944    enum {
03945       OPT_CALLEE_REDIRECT   = 't',
03946       OPT_CALLER_REDIRECT   = 'T',
03947       OPT_CALLEE_AUTOMON    = 'w',
03948       OPT_CALLER_AUTOMON    = 'W',
03949       OPT_CALLEE_DISCONNECT = 'h',
03950       OPT_CALLER_DISCONNECT = 'H',
03951       OPT_CALLEE_PARKCALL   = 'k',
03952       OPT_CALLER_PARKCALL   = 'K',
03953    };
03954 
03955    memset(options, 0, len);
03956    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
03957       options[i++] = OPT_CALLER_REDIRECT;
03958    }
03959    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
03960       options[i++] = OPT_CALLER_AUTOMON;
03961    }
03962    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
03963       options[i++] = OPT_CALLER_DISCONNECT;
03964    }
03965    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
03966       options[i++] = OPT_CALLER_PARKCALL;
03967    }
03968 
03969    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
03970       options[i++] = OPT_CALLEE_REDIRECT;
03971    }
03972    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
03973       options[i++] = OPT_CALLEE_AUTOMON;
03974    }
03975    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
03976       options[i++] = OPT_CALLEE_DISCONNECT;
03977    }
03978    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
03979       options[i++] = OPT_CALLEE_PARKCALL;
03980    }
03981 
03982    return options;
03983 }

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

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

Referenced by builtin_atxfer().

01964 {
01965    if (ast_channel_make_compatible(c, newchan) < 0) {
01966       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01967          c->name, newchan->name);
01968       ast_hangup(newchan);
01969       return -1;
01970    }
01971    return 0;
01972 }

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

References ast_channel::_softhangup, ast_channel::_state, ast_channel_alloc, ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), f, ast_channel::linkedid, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.

Referenced by builtin_blindtransfer().

00709 {
00710    struct ast_channel *xferchan;
00711    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00712    char *x, *goto_on_transfer;
00713    struct ast_frame *f;
00714 
00715    if (ast_strlen_zero(val))
00716       return;
00717 
00718    goto_on_transfer = ast_strdupa(val);
00719 
00720    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, "%s", chan->name)))
00721       return;
00722 
00723    for (x = goto_on_transfer; x && *x; x++) {
00724       if (*x == '^')
00725          *x = '|';
00726    }
00727    /* Make formats okay */
00728    xferchan->readformat = chan->readformat;
00729    xferchan->writeformat = chan->writeformat;
00730    ast_channel_masquerade(xferchan, chan);
00731    ast_parseable_goto(xferchan, goto_on_transfer);
00732    xferchan->_state = AST_STATE_UP;
00733    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00734    xferchan->_softhangup = 0;
00735    if ((f = ast_read(xferchan))) {
00736       ast_frfree(f);
00737       f = NULL;
00738       ast_pbx_start(xferchan);
00739    } else {
00740       ast_hangup(xferchan);
00741    }
00742 }

struct ast_parkinglot * copy_parkinglot ( const char *  name,
const struct ast_parkinglot parkinglot 
) [static]

Copy parkinglot and store it with new name.

Definition at line 4246 of file features.c.

References ao2_ref, ast_copy_string(), ast_debug, AST_LIST_HEAD_INIT, ast_strlen_zero(), create_parkinglot(), find_parkinglot(), ast_parkinglot::name, parkinglot, and ast_parkinglot::parkings.

Referenced by park_space_reserve().

04246                                                                                                   {
04247    struct ast_parkinglot *copylot;
04248 
04249    if (ast_strlen_zero(name)) { /* No name specified */
04250       return NULL;
04251    }
04252    if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
04253       if (copylot) {
04254          ao2_ref(copylot, -1);
04255       }
04256       return NULL;
04257    }
04258 
04259    copylot = create_parkinglot(name);
04260    ast_debug(1, "Building parking lot %s\n", name);
04261 
04262    memcpy(copylot, parkinglot, sizeof(struct ast_parkinglot));
04263    ast_copy_string(copylot->name, name, sizeof(copylot->name));
04264    AST_LIST_HEAD_INIT(&copylot->parkings);
04265 
04266    return copylot;
04267 }

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

Allocate parking lot structure.

Definition at line 4555 of file features.c.

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

Referenced by build_parkinglot(), and copy_parkinglot().

04556 {
04557    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
04558 
04559    if (!name)
04560       return NULL;
04561 
04562    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
04563    if (!newlot)
04564       return NULL;
04565    
04566    ast_copy_string(newlot->name, name, sizeof(newlot->name));
04567    AST_LIST_HEAD_INIT(&newlot->parkings);
04568 
04569    return newlot;
04570 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 596 of file features.c.

References ast_free.

00597 {
00598    struct ast_dial_features *df = data;
00599    if (df) {
00600       ast_free(df);
00601    }
00602 }

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

Definition at line 583 of file features.c.

References ast_calloc.

00584 {
00585    struct ast_dial_features *df = data, *df_copy;
00586  
00587    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00588       return NULL;
00589    }
00590  
00591    memcpy(df_copy, df, sizeof(*df));
00592  
00593    return df_copy;
00594 }

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

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

05216 {
05217    ast_moh_stop(chan);
05218    ast_channel_lock_both(chan, tmpchan);
05219    ast_setstate(tmpchan, chan->_state);
05220    tmpchan->readformat = chan->readformat;
05221    tmpchan->writeformat = chan->writeformat;
05222    ast_channel_masquerade(tmpchan, chan);
05223    ast_channel_unlock(chan);
05224    ast_channel_unlock(tmpchan);
05225 
05226    /* must be done without any channel locks held */
05227    ast_do_masquerade(tmpchan);
05228 
05229    /* when returning from bridge, the channel will continue at the next priority */
05230    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
05231 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_free, ast_poll, manage_parkinglot(), and parkinglots.

Referenced by ast_features_init().

04197 {
04198    struct pollfd *pfds = NULL, *new_pfds = NULL;
04199    int nfds = 0, new_nfds = 0;
04200 
04201    for (;;) {
04202       struct ao2_iterator iter;
04203       struct ast_parkinglot *curlot;
04204       int ms = -1;   /* poll2 timeout, uninitialized */
04205       iter = ao2_iterator_init(parkinglots, 0);
04206 
04207       while ((curlot = ao2_iterator_next(&iter))) {
04208          manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
04209          ao2_ref(curlot, -1);
04210       }
04211       ao2_iterator_destroy(&iter);
04212 
04213       /* Recycle */
04214       ast_free(pfds);
04215       pfds = new_pfds;
04216       nfds = new_nfds;
04217       new_pfds = NULL;
04218       new_nfds = 0;
04219 
04220       /* Wait for something to happen */
04221       ast_poll(pfds, nfds, ms);
04222       pthread_testcancel();
04223    }
04224    /* If this WERE reached, we'd need to free(pfds) */
04225    return NULL;   /* Never reached */
04226 }

static int feature_exec_app ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const 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 2633 of file features.c.

References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_ignore(), 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_FRAME_DTMF_END, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, feature_group_exten::feature, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_channel::name, pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), and ast_call_feature::sname.

02634 {
02635    struct ast_app *app;
02636    struct ast_call_feature *feature = data;
02637    struct ast_channel *work, *idle;
02638    int res;
02639 
02640    if (!feature) { /* shouldn't ever happen! */
02641       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
02642       return -1; 
02643    }
02644 
02645    if (sense == FEATURE_SENSE_CHAN) {
02646       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
02647          return AST_FEATURE_RETURN_KEEPTRYING;
02648       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02649          work = chan;
02650          idle = peer;
02651       } else {
02652          work = peer;
02653          idle = chan;
02654       }
02655    } else {
02656       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
02657          return AST_FEATURE_RETURN_KEEPTRYING;
02658       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02659          work = peer;
02660          idle = chan;
02661       } else {
02662          work = chan;
02663          idle = peer;
02664       }
02665    }
02666 
02667    if (!(app = pbx_findapp(feature->app))) {
02668       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
02669       return -2;
02670    }
02671 
02672    ast_autoservice_start(idle);
02673    ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
02674    
02675    if(work && idle) {
02676       pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name);
02677       pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name);
02678       pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
02679       pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
02680    }
02681 
02682    if (!ast_strlen_zero(feature->moh_class))
02683       ast_moh_start(idle, feature->moh_class, NULL);
02684 
02685    res = pbx_exec(work, app, feature->app_args);
02686 
02687    if (!ast_strlen_zero(feature->moh_class))
02688       ast_moh_stop(idle);
02689 
02690    ast_autoservice_stop(idle);
02691 
02692    if (res) {
02693       return AST_FEATURE_RETURN_SUCCESSBREAK;
02694    }
02695    return AST_FEATURE_RETURN_SUCCESS;  /*! \todo XXX should probably return res */
02696 }

static int feature_interpret ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const 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 2843 of file features.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, config, feature_group_exten::feature, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

02843                                                                                                                                                 {
02844 
02845    char dynamic_features_buf[128];
02846    const char *peer_dynamic_features, *chan_dynamic_features;
02847    struct ast_flags features;
02848    struct ast_call_feature feature;
02849    if (sense == FEATURE_SENSE_CHAN) {
02850       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
02851    }
02852    else {
02853       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
02854    }
02855 
02856    ast_channel_lock(peer);
02857    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
02858    ast_channel_unlock(peer);
02859 
02860    ast_channel_lock(chan);
02861    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
02862    ast_channel_unlock(chan);
02863 
02864    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,""));
02865 
02866    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);
02867 
02868    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
02869 }

static int feature_interpret_helper ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const 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_buf,features,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 2736 of file features.c.

References ast_debug, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_STOREDIGITS, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_strlen_zero(), ast_test_flag, ast_verb, builtin_features, config, feature_group_exten::entry, ast_call_feature::exten, feature_group_exten::exten, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), find_group(), ast_call_feature::fname, ast_call_feature::operation, ast_call_feature::sname, and strsep().

Referenced by ast_feature_detect(), and feature_interpret().

02739 {
02740    int x;
02741    struct feature_group *fg = NULL;
02742    struct feature_group_exten *fge;
02743    struct ast_call_feature *tmpfeature;
02744    char *tmp, *tok;
02745    int res = AST_FEATURE_RETURN_PASSDIGITS;
02746    int feature_detected = 0;
02747 
02748    if (!(peer && chan && config) && operation) {
02749       return -1; /* can not run feature operation */
02750    }
02751 
02752    ast_rwlock_rdlock(&features_lock);
02753    for (x = 0; x < FEATURES_COUNT; x++) {
02754       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
02755           !ast_strlen_zero(builtin_features[x].exten)) {
02756          /* Feature is up for consideration */
02757          if (!strcmp(builtin_features[x].exten, code)) {
02758             ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
02759             if (operation) {
02760                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
02761             }
02762             memcpy(feature, &builtin_features[x], sizeof(feature));
02763             feature_detected = 1;
02764             break;
02765          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
02766             if (res == AST_FEATURE_RETURN_PASSDIGITS)
02767                res = AST_FEATURE_RETURN_STOREDIGITS;
02768          }
02769       }
02770    }
02771    ast_rwlock_unlock(&features_lock);
02772 
02773    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
02774       return res;
02775    }
02776 
02777    tmp = dynamic_features_buf;
02778 
02779    while ((tok = strsep(&tmp, "#"))) {
02780       AST_RWLIST_RDLOCK(&feature_groups);
02781 
02782       fg = find_group(tok);
02783 
02784       if (fg) {
02785          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
02786             if (!strcmp(fge->exten, code)) {
02787                if (operation) {
02788                   res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
02789                }
02790                memcpy(feature, fge->feature, sizeof(feature));
02791                if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02792                   AST_RWLIST_UNLOCK(&feature_groups);
02793                   break;
02794                }
02795                res = AST_FEATURE_RETURN_PASSDIGITS;
02796             } else if (!strncmp(fge->exten, code, strlen(code))) {
02797                res = AST_FEATURE_RETURN_STOREDIGITS;
02798             }
02799          }
02800          if (fge) {
02801             break;
02802          }
02803       }
02804 
02805       AST_RWLIST_UNLOCK(&feature_groups);
02806 
02807       AST_RWLIST_RDLOCK(&feature_list);
02808 
02809       if (!(tmpfeature = find_dynamic_feature(tok))) {
02810          AST_RWLIST_UNLOCK(&feature_list);
02811          continue;
02812       }
02813 
02814       /* Feature is up for consideration */
02815       if (!strcmp(tmpfeature->exten, code)) {
02816          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
02817          if (operation) {
02818             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
02819          }
02820          memcpy(feature, tmpfeature, sizeof(feature));
02821          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02822             AST_RWLIST_UNLOCK(&feature_list);
02823             break;
02824          }
02825          res = AST_FEATURE_RETURN_PASSDIGITS;
02826       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
02827          res = AST_FEATURE_RETURN_STOREDIGITS;
02828 
02829       AST_RWLIST_UNLOCK(&feature_list);
02830    }
02831 
02832    return res;
02833 }

static struct ast_channel * feature_request_and_dial ( struct ast_channel caller,
const char *  caller_name,
struct ast_channel requestor,
struct ast_channel transferee,
const char *  type,
int  format,
void *  data,
int  timeout,
int *  outstate,
const char *  language 
) [static]

Definition at line 2972 of file features.c.

References ast_channel::_state, ast_autoservice_start(), ast_autoservice_stop(), ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_connected_line_macro(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_redirecting_macro(), ast_channel_set_connected_line(), ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), ast_connected_line_parse_data(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_PROGRESS, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_frisolate(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_is_deferrable_frame(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_party_connected_line_free(), ast_party_connected_line_set_init(), ast_poll_channel_add(), ast_poll_channel_del(), ast_queue_frame_head(), ast_read(), ast_request(), ast_rwlock_rdlock, ast_rwlock_unlock, AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), builtin_features, ast_channel::call_forward, ast_channel::caller, cause, connected, ast_channel::connected, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_channel::hangupcause, LOG_NOTICE, ast_channel::name, and pbx_builtin_setvar_helper().

Referenced by builtin_atxfer().

02976 {
02977    int state = 0;
02978    int cause = 0;
02979    int to;
02980    int caller_hungup;
02981    int transferee_hungup;
02982    struct ast_channel *chan;
02983    struct ast_channel *monitor_chans[3];
02984    struct ast_channel *active_channel;
02985    int res;
02986    int ready = 0;
02987    struct timeval started;
02988    int x, len = 0;
02989    char *disconnect_code = NULL, *dialed_code = NULL;
02990    struct ast_frame *f;
02991    AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
02992 
02993    caller_hungup = ast_check_hangup(caller);
02994 
02995    if (!(chan = ast_request(type, format, requestor, data, &cause))) {
02996       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
02997       switch (cause) {
02998       case AST_CAUSE_BUSY:
02999          state = AST_CONTROL_BUSY;
03000          break;
03001       case AST_CAUSE_CONGESTION:
03002          state = AST_CONTROL_CONGESTION;
03003          break;
03004       default:
03005          state = 0;
03006          break;
03007       }
03008       goto done;
03009    }
03010 
03011    ast_string_field_set(chan, language, language);
03012    ast_channel_inherit_variables(caller, chan);
03013    pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
03014 
03015    ast_channel_lock(chan);
03016    ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller);
03017    ast_channel_unlock(chan);
03018 
03019    if (ast_call(chan, data, timeout)) {
03020       ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
03021       switch (chan->hangupcause) {
03022       case AST_CAUSE_BUSY:
03023          state = AST_CONTROL_BUSY;
03024          break;
03025       case AST_CAUSE_CONGESTION:
03026          state = AST_CONTROL_CONGESTION;
03027          break;
03028       default:
03029          state = 0;
03030          break;
03031       }
03032       goto done;
03033    }
03034 
03035    /* support dialing of the featuremap disconnect code while performing an attended tranfer */
03036    ast_rwlock_rdlock(&features_lock);
03037    for (x = 0; x < FEATURES_COUNT; x++) {
03038       if (strcasecmp(builtin_features[x].sname, "disconnect"))
03039          continue;
03040 
03041       disconnect_code = builtin_features[x].exten;
03042       len = strlen(disconnect_code) + 1;
03043       dialed_code = alloca(len);
03044       memset(dialed_code, 0, len);
03045       break;
03046    }
03047    ast_rwlock_unlock(&features_lock);
03048    x = 0;
03049    started = ast_tvnow();
03050    to = timeout;
03051    AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
03052 
03053    ast_poll_channel_add(caller, chan);
03054 
03055    transferee_hungup = 0;
03056    while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) {
03057       int num_chans = 0;
03058 
03059       monitor_chans[num_chans++] = transferee;
03060       monitor_chans[num_chans++] = chan;
03061       if (!caller_hungup) {
03062          if (ast_check_hangup(caller)) {
03063             caller_hungup = 1;
03064 
03065 #if defined(ATXFER_NULL_TECH)
03066             /* Change caller's name to ensure that it will remain unique. */
03067             set_new_chan_name(caller);
03068 
03069             /*
03070              * Get rid of caller's physical technology so it is free for
03071              * other calls.
03072              */
03073             set_null_chan_tech(caller);
03074 #endif   /* defined(ATXFER_NULL_TECH) */
03075          } else {
03076             /* caller is not hungup so monitor it. */
03077             monitor_chans[num_chans++] = caller;
03078          }
03079       }
03080 
03081       /* see if the timeout has been violated */
03082       if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
03083          state = AST_CONTROL_UNHOLD;
03084          ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name);
03085          break; /*doh! timeout*/
03086       }
03087 
03088       active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
03089       if (!active_channel)
03090          continue;
03091 
03092       f = NULL;
03093       if (transferee == active_channel) {
03094          struct ast_frame *dup_f;
03095 
03096          f = ast_read(transferee);
03097          if (f == NULL) { /*doh! where'd he go?*/
03098             transferee_hungup = 1;
03099             state = 0;
03100             break;
03101          }
03102          if (ast_is_deferrable_frame(f)) {
03103             dup_f = ast_frisolate(f);
03104             if (dup_f) {
03105                if (dup_f == f) {
03106                   f = NULL;
03107                }
03108                AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
03109             }
03110          }
03111       } else if (chan == active_channel) {
03112          if (!ast_strlen_zero(chan->call_forward)) {
03113             state = 0;
03114             chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
03115             if (!chan) {
03116                break;
03117             }
03118             continue;
03119          }
03120          f = ast_read(chan);
03121          if (f == NULL) { /*doh! where'd he go?*/
03122             switch (chan->hangupcause) {
03123             case AST_CAUSE_BUSY:
03124                state = AST_CONTROL_BUSY;
03125                break;
03126             case AST_CAUSE_CONGESTION:
03127                state = AST_CONTROL_CONGESTION;
03128                break;
03129             default:
03130                state = 0;
03131                break;
03132             }
03133             break;
03134          }
03135 
03136          if (f->frametype == AST_FRAME_CONTROL) {
03137             if (f->subclass.integer == AST_CONTROL_RINGING) {
03138                ast_verb(3, "%s is ringing\n", chan->name);
03139                ast_indicate(caller, AST_CONTROL_RINGING);
03140             } else if (f->subclass.integer == AST_CONTROL_BUSY) {
03141                state = f->subclass.integer;
03142                ast_verb(3, "%s is busy\n", chan->name);
03143                ast_indicate(caller, AST_CONTROL_BUSY);
03144                ast_frfree(f);
03145                break;
03146             } else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
03147                state = f->subclass.integer;
03148                ast_verb(3, "%s is congested\n", chan->name);
03149                ast_indicate(caller, AST_CONTROL_CONGESTION);
03150                ast_frfree(f);
03151                break;
03152             } else if (f->subclass.integer == AST_CONTROL_ANSWER) {
03153                /* This is what we are hoping for */
03154                state = f->subclass.integer;
03155                ast_frfree(f);
03156                ready=1;
03157                break;
03158             } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
03159                if (caller_hungup) {
03160                   struct ast_party_connected_line connected;
03161 
03162                   /* Just save it for the transfer. */
03163                   ast_party_connected_line_set_init(&connected, &caller->connected);
03164                   res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
03165                      &connected);
03166                   if (!res) {
03167                      ast_channel_set_connected_line(caller, &connected, NULL);
03168                   }
03169                   ast_party_connected_line_free(&connected);
03170                } else {
03171                   ast_autoservice_start(transferee);
03172                   if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
03173                      ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
03174                         f->data.ptr, f->datalen);
03175                   }
03176                   ast_autoservice_stop(transferee);
03177                }
03178             } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
03179                if (!caller_hungup) {
03180                   ast_autoservice_start(transferee);
03181                   if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
03182                      ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
03183                         f->data.ptr, f->datalen);
03184                   }
03185                   ast_autoservice_stop(transferee);
03186                }
03187             } else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) {
03188                ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
03189             }
03190             /* else who cares */
03191          } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03192             ast_write(caller, f);
03193          }
03194       } else if (caller == active_channel) {
03195          f = ast_read(caller);
03196          if (f) {
03197             if (f->frametype == AST_FRAME_DTMF) {
03198                dialed_code[x++] = f->subclass.integer;
03199                dialed_code[x] = '\0';
03200                if (strlen(dialed_code) == len) {
03201                   x = 0;
03202                } else if (x && strncmp(dialed_code, disconnect_code, x)) {
03203                   x = 0;
03204                   dialed_code[x] = '\0';
03205                }
03206                if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
03207                   /* Caller Canceled the call */
03208                   state = AST_CONTROL_UNHOLD;
03209                   ast_frfree(f);
03210                   break;
03211                }
03212             } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
03213                ast_write(chan, f);
03214             }
03215          }
03216       }
03217       if (f)
03218          ast_frfree(f);
03219    } /* end while */
03220 
03221    ast_poll_channel_del(caller, chan);
03222 
03223    /*
03224     * We need to free all the deferred frames, but we only need to
03225     * queue the deferred frames if no hangup was received.
03226     */
03227    ast_channel_lock(transferee);
03228    transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
03229    while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
03230       if (!transferee_hungup) {
03231          ast_queue_frame_head(transferee, f);
03232       }
03233       ast_frfree(f);
03234    }
03235    ast_channel_unlock(transferee);
03236 
03237 done:
03238    ast_indicate(caller, -1);
03239    if (chan && ready) {
03240       if (chan->_state == AST_STATE_UP)
03241          state = AST_CONTROL_ANSWER;
03242    } else if (chan) {
03243       ast_hangup(chan);
03244       chan = NULL;
03245    }
03246 
03247    if (outstate)
03248       *outstate = state;
03249 
03250    return chan;
03251 }

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

Definition at line 5554 of file features.c.

References ast_channel::_state, AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, CMP_MATCH, CMP_STOP, ast_channel::pbx, and ast_channel::pickupgroup.

Referenced by ast_pickup_call().

05555 {
05556    struct ast_channel *c = data;
05557    struct ast_channel *chan = obj;
05558 
05559    int i = !chan->pbx &&
05560       /* Accessing 'chan' here is safe without locking, because there is no way for
05561          the channel do disappear from under us at this point.  pickupgroup *could*
05562          change while we're here, but that isn't a problem. */
05563       (c != chan) &&
05564       (chan->pickupgroup & c->callgroup) &&
05565       ((chan->_state == AST_STATE_RINGING) || (chan->_state == AST_STATE_RING));
05566 
05567    return i ? CMP_MATCH | CMP_STOP : 0;
05568 }

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

find a call feature by name

Definition at line 2554 of file features.c.

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

Referenced by feature_interpret_helper(), and set_config_flags().

02555 {
02556    struct ast_call_feature *tmp;
02557 
02558    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
02559       if (!strcasecmp(tmp->sname, name)) {
02560          break;
02561       }
02562    }
02563 
02564    return tmp;
02565 }

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

Find a group by name.

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

Definition at line 2592 of file features.c.

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

Referenced by feature_interpret_helper().

02593 {
02594    struct feature_group *fg = NULL;
02595 
02596    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
02597       if (!strcasecmp(fg->gname, name))
02598          break;
02599    }
02600 
02601    return fg;
02602 }

struct ast_parkinglot * find_parkinglot ( const char *  name  ) 

Find parkinglot by name.

Definition at line 4229 of file features.c.

References ao2_find, ast_debug, ast_strlen_zero(), parkinglot, and parkinglots.

Referenced by build_parkinglot(), copy_parkinglot(), manager_park(), and park_space_reserve().

04230 {
04231    struct ast_parkinglot *parkinglot;
04232 
04233    if (ast_strlen_zero(name)) {
04234       return NULL;
04235    }
04236 
04237    parkinglot = ao2_find(parkinglots, (void *) name, 0);
04238    if (parkinglot) {
04239       ast_debug(1, "Found Parkinglot: %s\n", parkinglot->name);
04240    }
04241 
04242    return parkinglot;
04243 }

static int find_parkinglot_by_exten_cb ( void *  obj,
void *  args,
int  flags 
) [static]

Definition at line 631 of file features.c.

References CMP_MATCH, CMP_STOP, and parkinglot.

Referenced by ast_park_call(), builtin_atxfer(), builtin_blindtransfer(), and park_call_exec().

00632 {
00633    struct ast_parkinglot *parkinglot = obj;
00634    const char *parkext = args;
00635 
00636    if (!strcmp(parkinglot->parkext, parkext)) {
00637       return CMP_MATCH | CMP_STOP;
00638    }
00639 
00640    return 0;
00641 }

static int find_parkinglot_by_position_cb ( void *  obj,
void *  args,
int  flags 
) [static]

Definition at line 619 of file features.c.

References CMP_MATCH, CMP_STOP, and parkinglot.

Referenced by park_exec_full().

00620 {
00621    struct ast_parkinglot *parkinglot = obj;
00622    int *parkpos = args;
00623 
00624    if (*parkpos >= parkinglot->parking_start && *parkpos <= parkinglot->parking_stop) {
00625       return CMP_MATCH | CMP_STOP;
00626    }
00627 
00628    return 0;
00629 }

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

Find parking lot name from channel.

Definition at line 838 of file features.c.

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

Referenced by park_space_reserve().

00839 {
00840    const char *temp, *parkinglot = NULL;
00841 
00842    /* Check if the channel has a parking lot */
00843    if (!ast_strlen_zero(chan->parkinglot))
00844       parkinglot = chan->parkinglot;
00845 
00846    /* Channel variables override everything */
00847 
00848    if ((temp  = pbx_builtin_getvar_helper(chan, "PARKINGLOT")))
00849       return temp;
00850 
00851    return parkinglot;
00852 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 1802 of file features.c.

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

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

01803 {
01804    ast_indicate(chan, AST_CONTROL_UNHOLD);
01805 
01806    return ast_autoservice_stop(chan);
01807 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), AST_LIST_TRAVERSE, ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, builtin_features, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, feature_group_exten::entry, feature_group_exten::exten, ast_call_feature::exten, ast_cli_args::fd, feature_group_exten::feature, feature_group::features, FEATURES_COUNT, features_lock, ast_call_feature::fname, feature_group::gname, HFS_FORMAT, ast_parkinglot::mohclass, ast_parkinglot::name, ast_parkinglot::parkext, ast_parkinglot::parking_con, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglots, ast_parkinglot::parkingtime, ast_call_feature::sname, and ast_cli_entry::usage.

05089 {
05090    int i;
05091    struct ast_call_feature *feature;
05092    struct ao2_iterator iter;
05093    struct ast_parkinglot *curlot;
05094 #define HFS_FORMAT "%-25s %-7s %-7s\n"
05095 
05096    switch (cmd) {
05097    
05098    case CLI_INIT:
05099       e->command = "features show";
05100       e->usage =
05101          "Usage: features show\n"
05102          "       Lists configured features\n";
05103       return NULL;
05104    case CLI_GENERATE:
05105       return NULL;
05106    }
05107 
05108    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
05109    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
05110 
05111    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
05112 
05113    ast_rwlock_rdlock(&features_lock);
05114    for (i = 0; i < FEATURES_COUNT; i++)
05115       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
05116    ast_rwlock_unlock(&features_lock);
05117 
05118    ast_cli(a->fd, "\n");
05119    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
05120    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
05121    if (AST_RWLIST_EMPTY(&feature_list)) {
05122       ast_cli(a->fd, "(none)\n");
05123    } else {
05124       AST_RWLIST_RDLOCK(&feature_list);
05125       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
05126          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
05127       }
05128       AST_RWLIST_UNLOCK(&feature_list);
05129    }
05130 
05131    ast_cli(a->fd, "\nFeature Groups:\n");
05132    ast_cli(a->fd, "---------------\n");
05133    if (AST_RWLIST_EMPTY(&feature_groups)) {
05134       ast_cli(a->fd, "(none)\n");
05135    } else {
05136       struct feature_group *fg;
05137       struct feature_group_exten *fge;
05138 
05139       AST_RWLIST_RDLOCK(&feature_groups);
05140       AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
05141          ast_cli(a->fd, "===> Group: %s\n", fg->gname);
05142          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
05143             ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
05144          }
05145       }
05146       AST_RWLIST_UNLOCK(&feature_groups);
05147    }
05148 
05149    iter = ao2_iterator_init(parkinglots, 0);
05150    while ((curlot = ao2_iterator_next(&iter))) {
05151       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
05152       ast_cli(a->fd, "------------\n");
05153       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", curlot->parkext);
05154       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->parking_con);
05155       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
05156       ast_cli(a->fd,"%-22s:      %d\n", "Parkingtime", curlot->parkingtime);
05157       ast_cli(a->fd,"%-22s:      %s\n", "MusicOnHold class", curlot->mohclass);
05158       ast_cli(a->fd,"\n");
05159       ao2_ref(curlot, -1);
05160    }
05161    ao2_iterator_destroy(&iter);
05162 
05163    return CLI_SUCCESS;
05164 }

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

Definition at line 5190 of file features.c.

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

05191 {
05192    switch (cmd) { 
05193    case CLI_INIT:
05194       e->command = "features reload";
05195       e->usage =
05196          "Usage: features reload\n"
05197          "       Reloads configured call features from features.conf\n";
05198       return NULL;
05199    case CLI_GENERATE:
05200       return NULL;
05201    }
05202    ast_features_reload();
05203 
05204    return CLI_SUCCESS;
05205 }

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

References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_entry::args, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, parkeduser::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, parkeduser::context, ESS, parkeduser::exten, ast_cli_args::fd, ast_channel::name, ast_parkinglot::name, parkeduser::parkingexten, parkinglots, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.

05373 {
05374    struct parkeduser *cur;
05375    int numparked = 0;
05376    struct ao2_iterator iter;
05377    struct ast_parkinglot *curlot;
05378 
05379    switch (cmd) {
05380    case CLI_INIT:
05381       e->command = "parkedcalls show";
05382       e->usage =
05383          "Usage: parkedcalls show\n"
05384          "       List currently parked calls\n";
05385       return NULL;
05386    case CLI_GENERATE:
05387       return NULL;
05388    }
05389 
05390    if (a->argc > e->args)
05391       return CLI_SHOWUSAGE;
05392 
05393    ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
05394       , "Context", "Extension", "Pri", "Timeout");
05395 
05396    iter = ao2_iterator_init(parkinglots, 0);
05397    while ((curlot = ao2_iterator_next(&iter))) {
05398       int lotparked = 0;
05399       /* subtract ref for iterator and for configured parking lot */
05400       ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, ao2_ref(curlot, 0) - 2);
05401 
05402       AST_LIST_LOCK(&curlot->parkings);
05403       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
05404          ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
05405             ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
05406             ,cur->priority,
05407             (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
05408          numparked++;
05409          numparked += lotparked;
05410       }
05411       AST_LIST_UNLOCK(&curlot->parkings);
05412       if (lotparked)
05413          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
05414 
05415       ao2_ref(curlot, -1);
05416    }
05417 
05418    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
05419 
05420    return CLI_SUCCESS;
05421 }

static int load_config ( void   )  [static]

Definition at line 4741 of file features.c.

References adsipark, ao2_lock, ao2_unlock, ast_config_load2(), ast_copy_string(), ast_debug, ast_log(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_EXTENSION, DEFAULT_PARK_TIME, DEFAULT_PARKINGLOT, default_parkinglot, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_ERROR, LOG_WARNING, parkeddynamic, pickup_ext, pickupfailsound, pickupsound, transferdigittimeout, var, xferfailsound, and xfersound.

04742 {
04743    int start = 0, end = 0;
04744    int res;
04745    int i;
04746    struct ast_context *con = NULL;
04747    struct ast_config *cfg = NULL;
04748    struct ast_variable *var = NULL;
04749    struct feature_group *fg = NULL;
04750    struct ast_flags config_flags = { 0 };
04751    char *ctg; 
04752    static const char * const categories[] = { 
04753       /* Categories in features.conf that are not
04754        * to be parsed as group categories
04755        */
04756       "general",
04757       "featuremap",
04758       "applicationmap"
04759    };
04760 
04761    default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
04762    if (default_parkinglot) {
04763       ao2_lock(default_parkinglot);
04764       ast_copy_string(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(default_parkinglot->parkext));
04765       default_parkinglot->parking_start = 701;
04766       default_parkinglot->parking_stop = 750;
04767       default_parkinglot->parking_offset = 0;
04768       default_parkinglot->parkfindnext = 0;
04769       default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
04770       ao2_unlock(default_parkinglot);
04771    }
04772    
04773    if (default_parkinglot) {
04774       ast_debug(1, "Configuration of default parkinglot done.\n");
04775    } else {
04776       ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n");
04777       return -1;
04778    }
04779 
04780    /* Reset to defaults */
04781    strcpy(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION);
04782    strcpy(pickup_ext, "*8");
04783    courtesytone[0] = '\0';
04784    strcpy(xfersound, "beep");
04785    strcpy(xferfailsound, "pbx-invalid");
04786    pickupsound[0] = '\0';
04787    pickupfailsound[0] = '\0';
04788    adsipark = 0;
04789    comebacktoorigin = 1;
04790    parkeddynamic = 0;
04791 
04792    default_parkinglot->parkaddhints = 0;
04793    default_parkinglot->parkedcalltransfers = 0;
04794    default_parkinglot->parkedcallreparking = 0;
04795    default_parkinglot->parkedcallrecording = 0;
04796    default_parkinglot->parkedcallhangup = 0;
04797 
04798    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04799    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04800    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04801    atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04802    atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
04803    atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04804 
04805    cfg = ast_config_load2("features.conf", "features", config_flags);
04806    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
04807       ast_log(LOG_WARNING,"Could not load features.conf\n");
04808       return 0;
04809    }
04810    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04811       if (!strcasecmp(var->name, "parkext")) {
04812          ast_copy_string(default_parkinglot->parkext, var->value, sizeof(default_parkinglot->parkext));
04813       } else if (!strcasecmp(var->name, "context")) {
04814          ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con));
04815       } else if (!strcasecmp(var->name, "parkingtime")) {
04816          if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) {
04817             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
04818             default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
04819          } else
04820             default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000;
04821       } else if (!strcasecmp(var->name, "parkpos")) {
04822          if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
04823             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);
04824          } else if (default_parkinglot) {
04825             default_parkinglot->parking_start = start;
04826             default_parkinglot->parking_stop = end;
04827          } else {
04828             ast_log(LOG_WARNING, "No default parking lot!\n");
04829          }
04830       } else if (!strcasecmp(var->name, "findslot")) {
04831          default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next"));
04832       } else if (!strcasecmp(var->name, "parkinghints")) {
04833          default_parkinglot->parkaddhints = ast_true(var->value);
04834       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
04835          if (!strcasecmp(var->value, "both"))
04836             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
04837          else if (!strcasecmp(var->value, "caller"))
04838             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
04839          else if (!strcasecmp(var->value, "callee"))
04840             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
04841       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
04842          if (!strcasecmp(var->value, "both"))
04843             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
04844          else if (!strcasecmp(var->value, "caller"))
04845             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
04846          else if (!strcasecmp(var->value, "callee"))
04847             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
04848       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
04849          if (!strcasecmp(var->value, "both"))
04850             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
04851          else if (!strcasecmp(var->value, "caller"))
04852             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
04853          else if (!strcasecmp(var->value, "callee"))
04854             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
04855       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
04856          if (!strcasecmp(var->value, "both"))
04857             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
04858          else if (!strcasecmp(var->value, "caller"))
04859             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
04860          else if (!strcasecmp(var->value, "callee"))
04861             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
04862       } else if (!strcasecmp(var->name, "parkeddynamic")) {
04863          parkeddynamic = ast_true(var->value);
04864       } else if (!strcasecmp(var->name, "adsipark")) {
04865          adsipark = ast_true(var->value);
04866       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
04867          if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
04868             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
04869             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04870          } else
04871             transferdigittimeout = transferdigittimeout * 1000;
04872       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
04873          if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
04874             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
04875             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04876          }
04877       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
04878          if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
04879             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
04880             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04881          } else
04882             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
04883       } else if (!strcasecmp(var->name, "atxferloopdelay")) {
04884          if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
04885             ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
04886             atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04887          } else 
04888             atxferloopdelay *= 1000;
04889       } else if (!strcasecmp(var->name, "atxferdropcall")) {
04890          atxferdropcall = ast_true(var->value);
04891       } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
04892          if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
04893             ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
04894             atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04895          }
04896       } else if (!strcasecmp(var->name, "courtesytone")) {
04897          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
04898       }  else if (!strcasecmp(var->name, "parkedplay")) {
04899          if (!strcasecmp(var->value, "both"))
04900             parkedplay = 2;
04901          else if (!strcasecmp(var->value, "parked"))
04902             parkedplay = 1;
04903          else
04904             parkedplay = 0;
04905       } else if (!strcasecmp(var->name, "xfersound")) {
04906          ast_copy_string(xfersound, var->value, sizeof(xfersound));
04907       } else if (!strcasecmp(var->name, "xferfailsound")) {
04908          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
04909       } else if (!strcasecmp(var->name, "pickupexten")) {
04910          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
04911       } else if (!strcasecmp(var->name, "pickupsound")) {
04912          ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
04913       } else if (!strcasecmp(var->name, "pickupfailsound")) {
04914          ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
04915       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
04916          comebacktoorigin = ast_true(var->value);
04917       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
04918          ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass));
04919       }
04920    }
04921 
04922    unmap_features();
04923    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
04924       if (remap_feature(var->name, var->value))
04925          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
04926    }
04927 
04928    /* Map a key combination to an application*/
04929    ast_unregister_features();
04930    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
04931       char *tmp_val = ast_strdupa(var->value);
04932       char *activateon; 
04933       struct ast_call_feature *feature;
04934       AST_DECLARE_APP_ARGS(args,
04935          AST_APP_ARG(exten);
04936          AST_APP_ARG(activatedby);
04937          AST_APP_ARG(app);
04938          AST_APP_ARG(app_args);
04939          AST_APP_ARG(moh_class);
04940       );
04941 
04942       AST_STANDARD_APP_ARGS(args, tmp_val);
04943       if (strchr(args.app, '(')) {
04944          /* New syntax */
04945          args.moh_class = args.app_args;
04946          args.app_args = strchr(args.app, '(');
04947          *args.app_args++ = '\0';
04948          if (args.app_args[strlen(args.app_args) - 1] == ')') {
04949             args.app_args[strlen(args.app_args) - 1] = '\0';
04950          }
04951       }
04952 
04953       activateon = strsep(&args.activatedby, "/"); 
04954 
04955       /*! \todo XXX var_name or app_args ? */
04956       if (ast_strlen_zero(args.app) || ast_strlen_zero(args.exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
04957          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
04958             args.app, args.exten, activateon, var->name);
04959          continue;
04960       }
04961 
04962       AST_RWLIST_RDLOCK(&feature_list);
04963       if ((feature = find_dynamic_feature(var->name))) {
04964          AST_RWLIST_UNLOCK(&feature_list);
04965          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
04966          continue;
04967       }
04968       AST_RWLIST_UNLOCK(&feature_list);
04969             
04970       if (!(feature = ast_calloc(1, sizeof(*feature)))) {
04971          continue;
04972       }
04973 
04974       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
04975       ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
04976       ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
04977       
04978       if (args.app_args) {
04979          ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
04980       }
04981 
04982       if (args.moh_class) {
04983          ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
04984       }
04985 
04986       ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
04987       feature->operation = feature_exec_app;
04988       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
04989 
04990       /* Allow caller and calle to be specified for backwards compatability */
04991       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
04992          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
04993       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
04994          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
04995       else {
04996          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
04997             " must be 'self', or 'peer'\n", var->name);
04998          continue;
04999       }
05000 
05001       if (ast_strlen_zero(args.activatedby))
05002          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05003       else if (!strcasecmp(args.activatedby, "caller"))
05004          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
05005       else if (!strcasecmp(args.activatedby, "callee"))
05006          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
05007       else if (!strcasecmp(args.activatedby, "both"))
05008          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
05009       else {
05010          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
05011             " must be 'caller', or 'callee', or 'both'\n", var->name);
05012          continue;
05013       }
05014 
05015       ast_register_feature(feature);
05016 
05017       ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, args.app, args.app_args, args.exten);
05018    }
05019 
05020    ast_unregister_groups();
05021    AST_RWLIST_WRLOCK(&feature_groups);
05022 
05023    ctg = NULL;
05024    while ((ctg = ast_category_browse(cfg, ctg))) {
05025       /* Is this a parkinglot definition ? */
05026       if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
05027          ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
05028          if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg)))
05029             ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
05030          else
05031             ast_debug(1, "Configured parking context %s\n", ctg);
05032          continue;   
05033       }
05034       /* No, check if it's a group */
05035       for (i = 0; i < ARRAY_LEN(categories); i++) {
05036          if (!strcasecmp(categories[i], ctg))
05037             break;
05038       }
05039 
05040       if (i < ARRAY_LEN(categories)) 
05041          continue;
05042 
05043       if (!(fg = register_group(ctg)))
05044          continue;
05045 
05046       for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
05047          struct ast_call_feature *feature;
05048 
05049          AST_RWLIST_RDLOCK(&feature_list);
05050          if (!(feature = find_dynamic_feature(var->name)) && 
05051              !(feature = ast_find_call_feature(var->name))) {
05052             AST_RWLIST_UNLOCK(&feature_list);
05053             ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
05054             continue;
05055          }
05056          AST_RWLIST_UNLOCK(&feature_list);
05057 
05058          register_group_feature(fg, var->value, feature);
05059       }
05060    }
05061 
05062    AST_RWLIST_UNLOCK(&feature_groups);
05063 
05064    ast_config_destroy(cfg);
05065 
05066    if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) {
05067       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con);
05068       return -1;
05069    }
05070    res = ast_add_extension2(con, 1, default_parkinglot->parkext, 1, NULL, NULL, parkcall, NULL, NULL, registrar);
05071    if (default_parkinglot->parkaddhints)
05072       park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop);
05073    if (!res)
05074       notify_metermaids(default_parkinglot->parkext, default_parkinglot->parking_con, AST_DEVICE_INUSE); 
05075    return res;
05076 
05077 }

int manage_parkinglot ( struct ast_parkinglot curlot,
const struct pollfd *  pfds,
const int  nfds,
struct pollfd **  new_pfds,
int *  new_nfds,
int *  fs 
)

Run management on parkinglots, called once per parkinglot.

Definition at line 3986 of file features.c.

References ast_add_extension2(), AST_CEL_PARK_END, ast_cel_report_event(), 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_debug, AST_DEVICE_NOT_INUSE, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, ast_log(), ast_pbx_start(), ast_read(), ast_realloc, ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, callback_dialoptions(), parkeduser::chan, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, free, ast_channel::generatordata, parkeduser::list, LOG_ERROR, LOG_NOTICE, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_unref(), parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), and parkeduser::start.

Referenced by do_parking_thread().

03987 {
03988    struct parkeduser *pu;
03989    int res = 0;
03990    char parkingslot[AST_MAX_EXTENSION];
03991 
03992    /* Lock parking list */
03993    AST_LIST_LOCK(&curlot->parkings);
03994    AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
03995       struct ast_channel *chan = pu->chan;   /* shorthand */
03996       int tms;        /* timeout for this item */
03997       int x;          /* fd index in channel */
03998       struct ast_context *con;
03999 
04000       if (pu->notquiteyet) { /* Pretend this one isn't here yet */
04001          continue;
04002       }
04003       tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
04004       if (tms > pu->parkingtime) {
04005          /* Stop music on hold */
04006          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
04007          /* Get chan, exten from derived kludge */
04008          if (pu->peername[0]) {
04009             char *peername = ast_strdupa(pu->peername);
04010             char *dash = strrchr(peername, '-');
04011             char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
04012             int i;
04013 
04014             if (dash) {
04015                *dash = '\0';
04016             }
04017 
04018             peername_flat = ast_strdupa(peername);
04019             for (i = 0; peername_flat[i]; i++) {
04020                if (peername_flat[i] == '/') {
04021                   peername_flat[i]= '_';
04022                }
04023             }
04024 
04025             con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
04026             if (!con) {
04027                ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
04028             } else {
04029                char returnexten[AST_MAX_EXTENSION];
04030                struct ast_datastore *features_datastore;
04031                struct ast_dial_features *dialfeatures = NULL;
04032 
04033                ast_channel_lock(chan);
04034 
04035                if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
04036                   dialfeatures = features_datastore->data;
04037 
04038                ast_channel_unlock(chan);
04039 
04040                if (!strncmp(peername, "Parked/", 7)) {
04041                   peername += 7;
04042                }
04043 
04044                if (dialfeatures) {
04045                   char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
04046                   snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
04047                } else { /* Existing default */
04048                   ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", chan->name);
04049                   snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
04050                }
04051 
04052                ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
04053             }
04054             if (pu->options_specified == 1) {
04055                /* Park() was called with overriding return arguments, respect those arguments */
04056                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04057             } else {
04058                if (comebacktoorigin) {
04059                   set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1);
04060                } else {
04061                   snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
04062                   pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
04063                   set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
04064                }
04065             }
04066          } else {
04067             /* They've been waiting too long, send them back to where they came.  Theoretically they
04068                should have their original extensions and such, but we copy to be on the safe side */
04069             set_c_e_p(chan, pu->context, pu->exten, pu->priority);
04070          }
04071          post_manager_event("ParkedCallTimeOut", pu);
04072          ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
04073 
04074          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);
04075          /* Start up the PBX, or hang them up */
04076          if (ast_pbx_start(chan))  {
04077             ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
04078             ast_hangup(chan);
04079          }
04080          /* And take them out of the parking lot */
04081          con = ast_context_find(pu->parkinglot->parking_con);
04082          if (con) {
04083             if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04084                ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
04085             else
04086                notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
04087          } else
04088             ast_log(LOG_WARNING, "Whoa, no parking context?\n");
04089          AST_LIST_REMOVE_CURRENT(list);
04090          free(pu);
04091       } else { /* still within parking time, process descriptors */
04092          for (x = 0; x < AST_MAX_FDS; x++) {
04093             struct ast_frame *f;
04094             int y;
04095 
04096             if (chan->fds[x] == -1) {
04097                continue;   /* nothing on this descriptor */
04098             }
04099 
04100             for (y = 0; y < nfds; y++) {
04101                if (pfds[y].fd == chan->fds[x]) {
04102                   /* Found poll record! */
04103                   break;
04104                }
04105             }
04106             if (y == nfds) {
04107                /* Not found */
04108                continue;
04109             }
04110 
04111             if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
04112                /* Next x */
04113                continue;
04114             }
04115 
04116             if (pfds[y].revents & POLLERR) {
04117                ast_set_flag(chan, AST_FLAG_EXCEPTION);
04118             } else {
04119                ast_clear_flag(chan, AST_FLAG_EXCEPTION);
04120             }
04121             chan->fdno = x;
04122 
04123             /* See if they need servicing */
04124             f = ast_read(pu->chan);
04125             /* Hangup? */
04126             if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer ==  AST_CONTROL_HANGUP))) {
04127                if (f)
04128                   ast_frfree(f);
04129                post_manager_event("ParkedCallGiveUp", pu);
04130                ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", NULL);
04131 
04132                /* There's a problem, hang them up*/
04133                ast_verb(2, "%s got tired of being parked\n", chan->name);
04134                ast_hangup(chan);
04135                /* And take them out of the parking lot */
04136                con = ast_context_find(curlot->parking_con);
04137                if (con) {
04138                   if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04139                      ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
04140                   else
04141                      notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
04142                } else
04143                   ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
04144                AST_LIST_REMOVE_CURRENT(list);
04145                parkinglot_unref(pu->parkinglot);
04146                free(pu);
04147                break;
04148             } else {
04149                /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
04150                ast_frfree(f);
04151                if (pu->moh_trys < 3 && !chan->generatordata) {
04152                   ast_debug(1, "MOH on parked call stopped by outside source.  Restarting on channel %s.\n", chan->name);
04153                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
04154                      S_OR(curlot->mohclass, NULL),
04155                      (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0));
04156                   pu->moh_trys++;
04157                }
04158                goto std;   /* XXX Ick: jumping into an else statement??? XXX */
04159             }
04160          } /* End for */
04161          if (x >= AST_MAX_FDS) {
04162 std:        for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */
04163                if (chan->fds[x] > -1) {
04164                   void *tmp = ast_realloc(*new_pfds, (*new_nfds + 1) * sizeof(struct pollfd));
04165                   if (!tmp) {
04166                      continue;
04167                   }
04168                   *new_pfds = tmp;
04169                   (*new_pfds)[*new_nfds].fd = chan->fds[x];
04170                   (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
04171                   (*new_pfds)[*new_nfds].revents = 0;
04172                   (*new_nfds)++;
04173                }
04174             }
04175             /* Keep track of our shortest wait */
04176             if (tms < *ms || *ms < 0) {
04177                *ms = tms;
04178             }
04179          }
04180       }
04181    }
04182    AST_LIST_TRAVERSE_SAFE_END;
04183    AST_LIST_UNLOCK(&curlot->parkings);
04184 
04185    return res;
04186 }

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

References args, ast_channel_get_by_name(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), CHANNEL_DEADLOCK_AVOIDANCE, find_parkinglot(), and masq_park_call().

Referenced by ast_features_init().

05492 {
05493    const char *channel = astman_get_header(m, "Channel");
05494    const char *channel2 = astman_get_header(m, "Channel2");
05495    const char *timeout = astman_get_header(m, "Timeout");
05496    const char *parkinglotname = astman_get_header(m, "Parkinglot");
05497    char buf[BUFSIZ];
05498    int res = 0;
05499    struct ast_channel *ch1, *ch2;
05500    struct ast_park_call_args args = {0,};
05501 
05502    if (ast_strlen_zero(channel)) {
05503       astman_send_error(s, m, "Channel not specified");
05504       return 0;
05505    }
05506 
05507    if (ast_strlen_zero(channel2)) {
05508       astman_send_error(s, m, "Channel2 not specified");
05509       return 0;
05510    }
05511 
05512    if (!(ch1 = ast_channel_get_by_name(channel))) {
05513       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
05514       astman_send_error(s, m, buf);
05515       return 0;
05516    }
05517 
05518    if (!(ch2 = ast_channel_get_by_name(channel2))) {
05519       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
05520       astman_send_error(s, m, buf);
05521       ast_channel_unref(ch1);
05522       return 0;
05523    }
05524 
05525    if (!ast_strlen_zero(timeout)) {
05526       sscanf(timeout, "%30d", &args.timeout);
05527    }
05528    if (!ast_strlen_zero(parkinglotname)) {
05529       args.parkinglot = find_parkinglot(parkinglotname);
05530    }
05531 
05532    ast_channel_lock(ch1);
05533    while (ast_channel_trylock(ch2)) {
05534       CHANNEL_DEADLOCK_AVOIDANCE(ch1);
05535    }
05536 
05537    res = masq_park_call(ch1, ch2, 0, NULL, 0, &args);
05538    if (!res) {
05539       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
05540       astman_send_ack(s, m, "Park successful");
05541    } else {
05542       astman_send_error(s, m, "Park failure");
05543    }
05544 
05545    ast_channel_unlock(ch1);
05546    ast_channel_unlock(ch2);
05547 
05548    ch1 = ast_channel_unref(ch1);
05549    ch2 = ast_channel_unref(ch2);
05550 
05551    return 0;
05552 }

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 5437 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(), ast_channel::caller, parkeduser::chan, ast_party_caller::id, ast_party_id::name, ast_channel::name, ast_party_id::number, parkinglots, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, S_COR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.

Referenced by ast_features_init().

05438 {
05439    struct parkeduser *cur;
05440    const char *id = astman_get_header(m, "ActionID");
05441    char idText[256] = "";
05442    struct ao2_iterator iter;
05443    struct ast_parkinglot *curlot;
05444 
05445    if (!ast_strlen_zero(id))
05446       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
05447 
05448    astman_send_ack(s, m, "Parked calls will follow");
05449 
05450    iter = ao2_iterator_init(parkinglots, 0);
05451    while ((curlot = ao2_iterator_next(&iter))) {
05452 
05453       AST_LIST_LOCK(&curlot->parkings);
05454       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
05455          astman_append(s, "Event: ParkedCall\r\n"
05456             "Exten: %d\r\n"
05457             "Channel: %s\r\n"
05458             "From: %s\r\n"
05459             "Timeout: %ld\r\n"
05460             "CallerIDNum: %s\r\n"
05461             "CallerIDName: %s\r\n"
05462             "%s"
05463             "\r\n",
05464             cur->parkingnum, cur->chan->name, cur->peername,
05465             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
05466             S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""),   /* XXX in other places it is <unknown> */
05467             S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
05468             idText);
05469       }
05470       AST_LIST_UNLOCK(&curlot->parkings);
05471       ao2_ref(curlot, -1);
05472    }
05473 
05474    astman_append(s,
05475       "Event: ParkedCallsComplete\r\n"
05476       "%s"
05477       "\r\n",idText);
05478 
05479 
05480    return RESULT_SUCCESS;
05481 }

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]

Parameters:
rchan is the transferee
peer is the transferer

Definition at line 1242 of file features.c.

References ast_channel::accountcode, ast_channel::amaflags, args, ast_channel_alloc, ast_channel_masquerade(), ast_copy_string(), AST_FEATURE_RETURN_PARKFAILED, ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), ast_channel::context, ast_channel::exten, f, ast_channel::linkedid, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, ast_channel::name, park_call_full(), park_space_reserve(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

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

01243 {
01244    struct ast_channel *chan;
01245    struct ast_frame *f;
01246    struct ast_park_call_args park_args = {0,};
01247 
01248    if (!args) {
01249       args = &park_args;
01250       args->timeout = timeout;
01251       args->extout = extout;
01252    }
01253 
01254    if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
01255       if (peer) {
01256          ast_stream_and_wait(peer, "pbx-parkingfailed", "");
01257       }
01258       return AST_FEATURE_RETURN_PARKFAILED;
01259    }
01260 
01261    /* Make a new, fake channel that we'll use to masquerade in the real one */
01262    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s",rchan->name))) {
01263       ast_log(LOG_WARNING, "Unable to create parked channel\n");
01264       return -1;
01265    }
01266 
01267    /* Make formats okay */
01268    chan->readformat = rchan->readformat;
01269    chan->writeformat = rchan->writeformat;
01270    ast_channel_masquerade(chan, rchan);
01271 
01272    /* Setup the extensions and such */
01273    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
01274 
01275    /* Setup the macro extension and such */
01276    ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext));
01277    ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten));
01278    chan->macropriority = rchan->macropriority;
01279 
01280    /* Make the masq execute */
01281    if ((f = ast_read(chan)))
01282       ast_frfree(f);
01283 
01284    if (peer == rchan) {
01285       peer = chan;
01286    }
01287 
01288    if (peer && (!play_announcement && args == &park_args)) {
01289       args->orig_chan_name = ast_strdupa(peer->name);
01290    }
01291 
01292    /* parking space reserved, return code check unnecessary */
01293    park_call_full(chan, peer, args);
01294 
01295    return 0;
01296 }

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

Definition at line 1304 of file features.c.

References args, and masq_park_call().

Referenced by builtin_blindtransfer(), park_call_exec(), and parkcall_helper().

01305 {
01306    return masq_park_call(rchan, peer, 0, NULL, 1, args);
01307 }

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

metermaids callback from devicestate.c

Definition at line 864 of file features.c.

References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_strdupa, and strsep().

Referenced by ast_features_init().

00865 {
00866    char *context;
00867    char *exten;
00868 
00869    context = ast_strdupa(data);
00870 
00871    exten = strsep(&context, "@");
00872    if (!context)
00873       return AST_DEVICE_INVALID;
00874    
00875    ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
00876 
00877    if (!ast_exists_extension(NULL, context, exten, 1, NULL))
00878       return AST_DEVICE_NOT_INUSE;
00879 
00880    return AST_DEVICE_INUSE;
00881 }

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

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

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

00856 {
00857    ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
00858       exten, context, ast_devstate2str(state));
00859 
00860    ast_devstate_changed(state, "park:%s@%s", exten, context);
00861 }

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

References ast_add_extension(), PRIORITY_HINT, and registrar.

Referenced by build_parkinglot().

04589 {
04590    int numext;
04591    char device[AST_MAX_EXTENSION];
04592    char exten[10];
04593 
04594    for (numext = start; numext <= stop; numext++) {
04595       snprintf(exten, sizeof(exten), "%d", numext);
04596       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
04597       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
04598    }
04599 }

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

Park a call.

Definition at line 4276 of file features.c.

References ast_channel::_state, ao2_callback, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_channel::exten, find_parkinglot_by_exten_cb(), ast_flags::flags, LOG_WARNING, masq_park_call_announce(), ast_channel::name, orig_exten(), park_call_options, parkinglots, parse(), and ast_channel::priority.

Referenced by ast_features_init().

04277 {
04278    /* Cache the original channel name in case we get masqueraded in the middle
04279     * of a park--it is still theoretically possible for a transfer to happen before
04280     * we get here, but it is _really_ unlikely */
04281    char *orig_chan_name = ast_strdupa(chan->name);
04282    char orig_exten[AST_MAX_EXTENSION];
04283    int orig_priority = chan->priority;
04284 
04285    /* Data is unused at the moment but could contain a parking
04286       lot context eventually */
04287    int res = 0;
04288 
04289    char *parse = NULL;
04290    AST_DECLARE_APP_ARGS(app_args,
04291       AST_APP_ARG(timeout);
04292       AST_APP_ARG(return_con);
04293       AST_APP_ARG(return_ext);
04294       AST_APP_ARG(return_pri);
04295       AST_APP_ARG(options);
04296    );
04297 
04298    parse = ast_strdupa(data);
04299    AST_STANDARD_APP_ARGS(app_args, parse);
04300 
04301    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
04302 
04303    /* Setup the exten/priority to be s/1 since we don't know
04304       where this call should return */
04305    strcpy(chan->exten, "s");
04306    chan->priority = 1;
04307 
04308    /* Answer if call is not up */
04309    if (chan->_state != AST_STATE_UP)
04310       res = ast_answer(chan);
04311 
04312    /* Sleep to allow VoIP streams to settle down */
04313    if (!res)
04314       res = ast_safe_sleep(chan, 1000);
04315 
04316    /* Park the call */
04317    if (!res) {
04318       struct ast_park_call_args args = {
04319          .orig_chan_name = orig_chan_name,
04320       };
04321       struct ast_flags flags = { 0 };
04322 
04323       if (parse) {
04324          if (!ast_strlen_zero(app_args.timeout)) {
04325             if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
04326                ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
04327                args.timeout = 0;
04328             }
04329          }
04330          if (!ast_strlen_zero(app_args.return_con)) {
04331             args.return_con = app_args.return_con;
04332          }
04333          if (!ast_strlen_zero(app_args.return_ext)) {
04334             args.return_ext = app_args.return_ext;
04335          }
04336          if (!ast_strlen_zero(app_args.return_pri)) {
04337             if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
04338                ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
04339                args.return_pri = 0;
04340             }
04341          }
04342       }
04343 
04344       ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
04345       args.flags = flags.flags;
04346 
04347       args.parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &orig_exten);
04348       res = masq_park_call_announce(chan, chan, &args);
04349       /* Continue on in the dialplan */
04350       if (res == 1) {
04351          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
04352          chan->priority = orig_priority;
04353          res = 0;
04354       } else if (!res) {
04355          res = 1;
04356       }
04357    }
04358 
04359    return res;
04360 }

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

Definition at line 1076 of file features.c.

References adsi_announce_park(), adsipark, ast_channel::appl, args, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_bridged_channel(), AST_CEL_PARK_START, ast_cel_report_event(), ast_channel_get_by_name(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_unlock, ast_channel_unref, 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_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), ast_manager_event, 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, ast_channel::caller, parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, ast_party_caller::id, ast_channel::language, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, ast_parkinglot::mohclass, ast_party_id::name, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkeduser::options_specified, park_space_reserve(), parkedcall, ast_parkinglot::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, ast_parkinglot::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, registrar, S_COR, S_OR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_channel::tech, ast_channel_tech::type, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.

Referenced by ast_park_call(), and masq_park_call().

01077 {
01078    struct ast_context *con;
01079    int parkingnum_copy;
01080    struct parkeduser *pu = args->pu;
01081    const char *event_from;
01082 
01083    if (pu == NULL)
01084       args->pu = pu = park_space_reserve(chan, peer, args);
01085    if (pu == NULL)
01086       return 1; /* Continue execution if possible */
01087 
01088    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
01089 
01090    chan->appl = "Parked Call";
01091    chan->data = NULL;
01092 
01093    pu->chan = chan;
01094 
01095    /* Put the parked channel on hold if we have two different channels */
01096    if (chan != peer) {
01097       if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
01098          ast_indicate(pu->chan, AST_CONTROL_RINGING);
01099       } else {
01100          ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01101             S_OR(pu->parkinglot->mohclass, NULL),
01102             !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
01103       }
01104    }
01105    
01106    pu->start = ast_tvnow();
01107    pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime;
01108    parkingnum_copy = pu->parkingnum;
01109    if (args->extout)
01110       *(args->extout) = pu->parkingnum;
01111 
01112    if (peer) { 
01113       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
01114          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
01115          and we need the callback name to be that of transferer.  Since local,1/2 have the same
01116          name we can be tricky and just grab the bridged channel from the other side of the local
01117       */
01118       if (!strcasecmp(peer->tech->type, "Local")) {
01119          struct ast_channel *tmpchan, *base_peer;
01120          char other_side[AST_CHANNEL_NAME];
01121          char *c;
01122          ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side));
01123          if ((c = strrchr(other_side, ';'))) {
01124             *++c = '1';
01125          }
01126          if ((tmpchan = ast_channel_get_by_name(other_side))) {
01127             ast_channel_lock(tmpchan);
01128             if ((base_peer = ast_bridged_channel(tmpchan))) {
01129                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
01130             }
01131             ast_channel_unlock(tmpchan);
01132             tmpchan = ast_channel_unref(tmpchan);
01133          }
01134       } else {
01135          ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername));
01136       }
01137    }
01138 
01139    /* Remember what had been dialed, so that if the parking
01140       expires, we try to come back to the same place */
01141 
01142    pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
01143 
01144    /* If extension has options specified, they override all other possibilities
01145    such as the returntoorigin flag and transferred context. Information on
01146    extension options is lost here, so we set a flag */
01147 
01148    ast_copy_string(pu->context, 
01149       S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 
01150       sizeof(pu->context));
01151    ast_copy_string(pu->exten, 
01152       S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 
01153       sizeof(pu->exten));
01154    pu->priority = args->return_pri ? args->return_pri : 
01155       (chan->macropriority ? chan->macropriority : chan->priority);
01156 
01157    /* If parking a channel directly, don't quiet yet get parking running on it.
01158     * All parking lot entries are put into the parking lot with notquiteyet on. */
01159    if (peer != chan) 
01160       pu->notquiteyet = 0;
01161 
01162    /* Wake up the (presumably select()ing) thread */
01163    pthread_kill(parking_thread, SIGURG);
01164    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));
01165 
01166    ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
01167 
01168    if (peer) {
01169       event_from = peer->name;
01170    } else {
01171       event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
01172    }
01173 
01174    ast_manager_event(pu->chan, EVENT_FLAG_CALL, "ParkedCall",
01175       "Exten: %s\r\n"
01176       "Channel: %s\r\n"
01177       "Parkinglot: %s\r\n"
01178       "From: %s\r\n"
01179       "Timeout: %ld\r\n"
01180       "CallerIDNum: %s\r\n"
01181       "CallerIDName: %s\r\n"
01182       "Uniqueid: %s\r\n",
01183       pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "",
01184       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
01185       S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
01186       S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
01187       pu->chan->uniqueid
01188       );
01189 
01190    if (peer && adsipark && ast_adsi_available(peer)) {
01191       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
01192       ast_adsi_unload_session(peer);
01193    }
01194 
01195    con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar);
01196    if (!con)   /* Still no context? Bad */
01197       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con);
01198    if (con) {
01199       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
01200          notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE);
01201    }
01202 
01203    AST_LIST_UNLOCK(&pu->parkinglot->parkings);
01204 
01205    /* Only say number if it's a number and the channel hasn't been masqueraded away */
01206    if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
01207       /* 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. */
01208       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01209       /* Tell the peer channel the number of the parking space */
01210       ast_say_digits(peer, pu->parkingnum, "", peer->language);
01211       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
01212    }
01213    if (peer == chan) { /* pu->notquiteyet = 1 */
01214       /* Wake up parking thread if we're really done */
01215       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01216          S_OR(pu->parkinglot->mohclass, NULL),
01217          !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
01218       pu->notquiteyet = 0;
01219       pthread_kill(parking_thread, SIGURG);
01220    }
01221    return 0;
01222 }

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

Definition at line 4534 of file features.c.

References park_exec_full().

Referenced by ast_features_init().

04535 {
04536    return park_exec_full(chan, data);
04537 }

static int park_exec_full ( struct ast_channel chan,
const char *  data 
) [static]

Pickup parked call.

Todo:
XXX we would like to wait on both!

Todo:
XXX Play a message XXX

Definition at line 4363 of file features.c.

References ast_channel::_state, ao2_callback, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), AST_CEL_PARK_END, ast_cel_report_event(), 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_manager_event, ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), ast_channel::caller, parkeduser::chan, config, courtesytone, ast_datastore::data, default_parkinglot, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_caller, find_parkinglot_by_position_cb(), ast_party_caller::id, LOG_WARNING, ast_party_id::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkedplay, parkeduser::parkingexten, parkinglot, parkinglot_unref(), parkinglots, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), S_COR, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.

Referenced by park_exec().

04364 {
04365    int res = 0;
04366    struct ast_channel *peer=NULL;
04367    struct parkeduser *pu;
04368    struct ast_context *con;
04369    int park = 0;
04370    struct ast_bridge_config config;
04371    struct ast_parkinglot *parkinglot;
04372 
04373    if (data) {
04374       park = atoi((char *) data);
04375    }
04376 
04377    parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_position_cb, (void *) &park);
04378    if (!parkinglot)
04379       parkinglot = default_parkinglot;
04380 
04381    AST_LIST_LOCK(&parkinglot->parkings);
04382    AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
04383       if (!pu->notquiteyet && (!data || pu->parkingnum == park)) {
04384          if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
04385             AST_LIST_UNLOCK(&parkinglot->parkings);
04386             return -1;
04387          }
04388          AST_LIST_REMOVE_CURRENT(list);
04389          break;
04390       }
04391    }
04392    AST_LIST_TRAVERSE_SAFE_END;
04393    AST_LIST_UNLOCK(&parkinglot->parkings);
04394 
04395    if (pu) {
04396       peer = pu->chan;
04397       con = ast_context_find(parkinglot->parking_con);
04398       if (con) {
04399          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
04400             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
04401          else
04402             notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
04403       } else
04404          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
04405 
04406       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
04407       ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
04408          "Exten: %s\r\n"
04409          "Channel: %s\r\n"
04410          "From: %s\r\n"
04411          "CallerIDNum: %s\r\n"
04412          "CallerIDName: %s\r\n",
04413          pu->parkingexten, pu->chan->name, chan->name,
04414          S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
04415          S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>")
04416          );
04417 
04418       ast_free(pu);
04419    }
04420    /* JK02: it helps to answer the channel if not already up */
04421    if (chan->_state != AST_STATE_UP)
04422       ast_answer(chan);
04423 
04424    //XXX Why do we unlock here ?
04425    // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain
04426    //ASTOBJ_UNLOCK(parkinglot);
04427 
04428    if (peer) {
04429       struct ast_datastore *features_datastore;
04430       struct ast_dial_features *dialfeatures = NULL;
04431 
04432       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
04433 
04434       if (!ast_strlen_zero(courtesytone)) {
04435          int error = 0;
04436          ast_indicate(peer, AST_CONTROL_UNHOLD);
04437          if (parkedplay == 0) {
04438             error = ast_stream_and_wait(chan, courtesytone, "");
04439          } else if (parkedplay == 1) {
04440             error = ast_stream_and_wait(peer, courtesytone, "");
04441          } else if (parkedplay == 2) {
04442             if (!ast_streamfile(chan, courtesytone, chan->language) &&
04443                   !ast_streamfile(peer, courtesytone, chan->language)) {
04444                /*! \todo XXX we would like to wait on both! */
04445                res = ast_waitstream(chan, "");
04446                if (res >= 0)
04447                   res = ast_waitstream(peer, "");
04448                if (res < 0)
04449                   error = 1;
04450             }
04451          }
04452          if (error) {
04453             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
04454             ast_hangup(peer);
04455             return -1;
04456          }
04457       } else
04458          ast_indicate(peer, AST_CONTROL_UNHOLD);
04459 
04460       res = ast_channel_make_compatible(chan, peer);
04461       if (res < 0) {
04462          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
04463          ast_hangup(peer);
04464          return -1;
04465       }
04466       /* This runs sorta backwards, since we give the incoming channel control, as if it
04467          were the person called. */
04468       ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
04469 
04470       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
04471       ast_cdr_setdestchan(chan->cdr, peer->name);
04472       memset(&config, 0, sizeof(struct ast_bridge_config));
04473 
04474       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
04475       ast_channel_lock(peer);
04476       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
04477          dialfeatures = features_datastore->data;
04478       }
04479       ast_channel_unlock(peer);
04480 
04481       /* When the datastores for both caller and callee are created, both the callee and caller channels
04482        * use the features_caller flag variable to represent themselves. With that said, the config.features_callee
04483        * flags should be copied from the datastore's caller feature flags regardless if peer was a callee
04484        * or caller. */
04485       if (dialfeatures) {
04486          ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
04487       }
04488 
04489       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
04490          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
04491       }
04492       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
04493          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
04494       }
04495       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
04496          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
04497       }
04498       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
04499          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
04500       }
04501       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
04502          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
04503       }
04504       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
04505          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
04506       }
04507       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
04508          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
04509       }
04510       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
04511          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
04512       }
04513 
04514       parkinglot_unref(parkinglot);
04515       res = ast_bridge_call(chan, peer, &config);
04516 
04517       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
04518       ast_cdr_setdestchan(chan->cdr, peer->name);
04519 
04520       /* Simulate the PBX hanging up */
04521       ast_hangup(peer);
04522       return -1;
04523    } else {
04524       /*! \todo XXX Play a message XXX */
04525       if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
04526          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
04527       ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
04528       res = -1;
04529    }
04530 
04531    return -1;
04532 }

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

Definition at line 912 of file features.c.

References ao2_link, args, ast_calloc, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, ast_exists_extension(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strdupa, ast_strlen_zero(), ast_test_flag, copy_parkinglot(), default_parkinglot, find_parkinglot(), findparkinglotname(), free, parkeduser::list, LOG_ERROR, LOG_WARNING, parkeddynamic, parkinglot, parkinglot_addref(), parkinglot_unref(), parkinglots, parkeduser::parkingnum, pbx_builtin_getvar_helper(), and S_OR.

Referenced by masq_park_call(), and park_call_full().

00913 {
00914    struct parkeduser *pu;
00915    int i, parking_space = -1, parking_range;
00916    const char *parkinglotname = NULL;
00917    const char *parkingexten;
00918    struct ast_parkinglot *parkinglot = NULL;
00919 
00920    if (args->parkinglot) {
00921       parkinglot = args->parkinglot;
00922       parkinglotname = parkinglot->name;
00923    } else if (peer) {
00924       parkinglotname = findparkinglotname(peer);
00925    } else { /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */
00926       parkinglotname = findparkinglotname(chan);
00927    }
00928 
00929    if (!args->parkinglot) {
00930       if (parkinglotname) {
00931          parkinglot = find_parkinglot(parkinglotname);
00932       } else {
00933          ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
00934          parkinglot = parkinglot_addref(default_parkinglot);
00935       }
00936       ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglot->name);
00937    }
00938 
00939    /* Dynamically create parkinglot */
00940    if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
00941       const char *dyn_context, *dyn_range;
00942       const char *parkinglotname_copy = NULL;
00943       struct ast_parkinglot *parkinglot_copy = NULL;
00944       int dyn_start, dyn_end;
00945 
00946       ast_channel_lock(chan);
00947       parkinglotname_copy = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
00948       dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
00949       dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
00950       ast_channel_unlock(chan);
00951 
00952       if (!ast_strlen_zero(parkinglotname_copy)) {
00953          parkinglot_copy = find_parkinglot(parkinglotname_copy);
00954       }
00955       if (!parkinglot_copy) {
00956          parkinglot_copy = parkinglot_addref(default_parkinglot);
00957          ast_debug(1, "Using default parking lot for copy\n");
00958       }
00959       if (!(parkinglot = copy_parkinglot(parkinglotname, parkinglot_copy))) {
00960          ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
00961       } else {
00962          if (!ast_strlen_zero(dyn_context)) {
00963             ast_copy_string(parkinglot->parking_con, dyn_context, sizeof(parkinglot->parking_con));
00964          }
00965          if (!ast_strlen_zero(dyn_range)) {
00966             if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
00967                ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers\n");
00968             } else {
00969                parkinglot->parking_start = dyn_start;
00970                parkinglot->parking_stop = dyn_end;
00971             }
00972          }
00973          ao2_link(parkinglots, parkinglot);
00974       }
00975 
00976       if (parkinglot_copy) {
00977          /* unref our tempory copy */
00978          parkinglot_unref(parkinglot_copy);
00979          parkinglot_copy = NULL;
00980       }
00981    }
00982 
00983    if (!parkinglot) {
00984       parkinglot = parkinglot_addref(default_parkinglot);
00985    }
00986 
00987    ast_debug(1, "Parkinglot: %s\n", parkinglot->name);
00988 
00989    /* Allocate memory for parking data */
00990    if (!(pu = ast_calloc(1, sizeof(*pu)))) {
00991       parkinglot_unref(parkinglot);
00992       return NULL;
00993    }
00994 
00995    /* Lock parking list */
00996    AST_LIST_LOCK(&parkinglot->parkings);
00997    /* Check for channel variable PARKINGEXTEN */
00998    ast_channel_lock(chan);
00999    parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"), ""));
01000    ast_channel_unlock(chan);
01001    if (!ast_strlen_zero(parkingexten)) {
01002       /*!\note The API forces us to specify a numeric parking slot, even
01003        * though the architecture would tend to support non-numeric extensions
01004        * (as are possible with SIP, for example).  Hence, we enforce that
01005        * limitation here.  If extout was not numeric, we could permit
01006        * arbitrary non-numeric extensions.
01007        */
01008         if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) {
01009          AST_LIST_UNLOCK(&parkinglot->parkings);
01010          parkinglot_unref(parkinglot);
01011             free(pu);
01012             ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
01013             return NULL;
01014         }
01015         snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
01016 
01017       if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) {
01018          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
01019          AST_LIST_UNLOCK(&parkinglot->parkings);
01020          parkinglot_unref(parkinglot);
01021          ast_free(pu);
01022          return NULL;
01023       }
01024    } else {
01025       int start;
01026       struct parkeduser *cur = NULL;
01027 
01028       /* Select parking space within range */
01029       parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1;
01030 
01031       if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
01032          start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1);
01033       } else {
01034          start = parkinglot->parking_start;
01035       }
01036 
01037       for (i = start; 1; i++) {
01038          if (i == parkinglot->parking_stop + 1) {
01039             i = parkinglot->parking_start - 1;
01040             break;
01041          }
01042 
01043          AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
01044             if (cur->parkingnum == i) {
01045                break;
01046             }
01047          }
01048          if (!cur) {
01049             parking_space = i;
01050             break;
01051          }
01052       }
01053 
01054       if (i == start - 1 && cur) {
01055          ast_log(LOG_WARNING, "No more parking spaces\n");
01056          ast_free(pu);
01057          AST_LIST_UNLOCK(&parkinglot->parkings);
01058          parkinglot_unref(parkinglot);
01059          return NULL;
01060       }
01061       /* Set pointer for next parking */
01062       if (parkinglot->parkfindnext) 
01063          parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
01064       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
01065    }
01066 
01067    pu->notquiteyet = 1;
01068    pu->parkingnum = parking_space;
01069    pu->parkinglot = parkinglot;
01070    AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
01071 
01072    return pu;
01073 }

static int parkcall_helper ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
const char *  code,
int  sense,
struct ast_park_call_args args 
) [static]

Definition at line 1495 of file features.c.

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

Referenced by builtin_atxfer(), and builtin_parkcall().

01496 {
01497    int res = 0;
01498 
01499    if (args) {
01500       ast_debug(1, "Parkinglot specified for builtin_parkcall: %s\n", args->parkinglot->name);
01501    }
01502 
01503    /* we used to set chan's exten and priority to "s" and 1
01504       here, but this generates (in some cases) an invalid
01505       extension, and if "s" exists, could errantly
01506       cause execution of extensions you don't expect. It
01507       makes more sense to let nature take its course
01508       when chan finishes, and let the pbx do its thing
01509       and hang up when the park is over.
01510    */
01511    if (chan->_state != AST_STATE_UP)
01512       res = ast_answer(chan);
01513    if (!res)
01514       res = ast_safe_sleep(chan, 1000);
01515 
01516    if (!res) { /* one direction used to call park_call.... */
01517       struct ast_channel *parker;
01518       struct ast_channel *parkee;
01519       set_peers(&parker, &parkee, peer, chan, sense);
01520       res = masq_park_call_announce(parkee, parker, args);
01521       /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
01522    }
01523 
01524    return res;
01525 }

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

Definition at line 4547 of file features.c.

References ao2_ref, ast_debug, and parkinglot.

Referenced by park_space_reserve().

04548 {
04549    int refcount = ao2_ref(parkinglot, +1);
04550    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
04551    return parkinglot;
04552 }

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

Definition at line 682 of file features.c.

References CMP_MATCH, CMP_STOP, and parkinglot.

Referenced by ast_features_init().

00683 {
00684    struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg;
00685 
00686    return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00687 }

static void parkinglot_destroy ( void *  obj  )  [static]

Destroy a parking lot.

Definition at line 4573 of file features.c.

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

Referenced by build_parkinglot(), and create_parkinglot().

04574 {
04575    struct ast_parkinglot *ruin = obj;
04576    struct ast_context *con;
04577    con = ast_context_find(ruin->parking_con);
04578    if (con)
04579       ast_context_destroy(con, registrar);
04580 }

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

Definition at line 675 of file features.c.

References ast_str_case_hash(), and parkinglot.

Referenced by ast_features_init().

00676 {
00677    const struct ast_parkinglot *parkinglot = obj;
00678 
00679    return ast_str_case_hash(parkinglot->name);
00680 }

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

Definition at line 5173 of file features.c.

References CMP_MATCH, and parkinglot.

Referenced by ast_features_reload().

05174 {
05175    struct ast_parkinglot *parkinglot = obj;
05176    return parkinglot->the_mark ? CMP_MATCH : 0;
05177 }

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

Definition at line 5166 of file features.c.

References parkinglot.

Referenced by ast_features_reload().

05167 {
05168    struct ast_parkinglot *parkinglot = obj;
05169    parkinglot->the_mark = 1;
05170    return 0;
05171 }

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

References ao2_ref, ast_debug, and parkinglot.

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

04542 {
04543    int refcount = ao2_ref(parkinglot, -1);
04544    ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
04545 }

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

return the first unlocked cdr in a possible chain

Definition at line 3277 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

03278 {
03279    struct ast_cdr *cdr_orig = cdr;
03280    while (cdr) {
03281       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
03282          return cdr;
03283       cdr = cdr->next;
03284    }
03285    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
03286 }

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

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

Referenced by builtin_automonitor().

01548 {
01549    /* First play for caller, put other channel on auto service */
01550    if (ast_autoservice_start(callee_chan))
01551       return -1;
01552    ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
01553    if (ast_stream_and_wait(caller_chan, audiofile, "")) {
01554       ast_log(LOG_WARNING, "Failed to play automon message!\n");
01555       ast_autoservice_stop(callee_chan);
01556       return -1;
01557    }
01558    if (ast_autoservice_stop(callee_chan))
01559       return -1;
01560    /* Then play for callee, put other channel on auto service */
01561    if (ast_autoservice_start(caller_chan))
01562       return -1;
01563    ast_autoservice_ignore(caller_chan, AST_FRAME_DTMF_END);
01564    if (ast_stream_and_wait(callee_chan, audiofile, "")) {
01565       ast_log(LOG_WARNING, "Failed to play automon message !\n");
01566       ast_autoservice_stop(caller_chan);
01567       return -1;
01568    }
01569    if (ast_autoservice_stop(caller_chan))
01570       return -1;
01571    return(0);
01572 }

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

Output parking event to manager.

Definition at line 3923 of file features.c.

References ast_channel::caller, parkeduser::chan, EVENT_FLAG_CALL, ast_party_caller::id, manager_event, ast_party_id::name, ast_parkinglot::name, ast_channel::name, ast_party_id::number, parkeduser::parkingexten, parkeduser::parkinglot, S_COR, ast_party_name::str, ast_party_number::str, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.

Referenced by manage_parkinglot().

03924 {
03925    manager_event(EVENT_FLAG_CALL, s,
03926       "Exten: %s\r\n"
03927       "Channel: %s\r\n"
03928       "Parkinglot: %s\r\n"
03929       "CallerIDNum: %s\r\n"
03930       "CallerIDName: %s\r\n"
03931       "UniqueID: %s\r\n\r\n",
03932       pu->parkingexten, 
03933       pu->chan->name,
03934       pu->parkinglot->name,
03935       S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
03936       S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
03937       pu->chan->uniqueid
03938       );
03939 }

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

References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, and pbx_builtin_getvar_helper().

Referenced by builtin_atxfer(), and builtin_blindtransfer().

01818 {
01819    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
01820    if (ast_strlen_zero(s)) {
01821       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
01822    }
01823    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
01824       s = transferer->macrocontext;
01825    }
01826    if (ast_strlen_zero(s)) {
01827       s = transferer->context;
01828    }
01829    return s;  
01830 }

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

Add new feature group.

Parameters:
fgname feature group name.
Add new feature group to the feature group list insert at head of list.
Note:
This function MUST be called while feature_groups is locked.

Definition at line 2469 of file features.c.

References ast_calloc_with_stringfields, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_set, ast_verb, feature_group_exten::entry, feature_group::gname, and LOG_NOTICE.

02470 {
02471    struct feature_group *fg;
02472 
02473    if (!fgname) {
02474       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
02475       return NULL;
02476    }
02477 
02478    if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) {
02479       return NULL;
02480    }
02481 
02482    ast_string_field_set(fg, gname, fgname);
02483 
02484    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
02485 
02486    ast_verb(2, "Registered group '%s'\n", fg->gname);
02487 
02488    return fg;
02489 }

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

References ast_calloc_with_stringfields, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_set, ast_verb, feature_group_exten::entry, feature_group_exten::exten, ast_call_feature::exten, feature_group_exten::feature, feature_group::features, feature_group::gname, LOG_NOTICE, S_OR, and ast_call_feature::sname.

02501 {
02502    struct feature_group_exten *fge;
02503 
02504    if (!fg) {
02505       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
02506       return;
02507    }
02508 
02509    if (!feature) {
02510       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
02511       return;
02512    }
02513 
02514    if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) {
02515       return;
02516    }
02517 
02518    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
02519 
02520    fge->feature = feature;
02521 
02522    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
02523 
02524    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
02525                feature->sname, fg->gname, fge->exten);
02526 }

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

Definition at line 2708 of file features.c.

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

02709 {
02710    int x, res = -1;
02711 
02712    ast_rwlock_wrlock(&features_lock);
02713    for (x = 0; x < FEATURES_COUNT; x++) {
02714       if (strcasecmp(builtin_features[x].sname, name))
02715          continue;
02716 
02717       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
02718       res = 0;
02719       break;
02720    }
02721    ast_rwlock_unlock(&features_lock);
02722 
02723    return res;
02724 }

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

Definition at line 3288 of file features.c.

References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), config, feature_group_exten::feature, and LOG_WARNING.

Referenced by ast_bridge_call().

03289 {
03290    const char *feature;
03291 
03292    if (ast_strlen_zero(features)) {
03293       return;
03294    }
03295 
03296    for (feature = features; *feature; feature++) {
03297       switch (*feature) {
03298       case 'T' :
03299       case 't' :
03300          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
03301          break;
03302       case 'K' :
03303       case 'k' :
03304          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
03305          break;
03306       case 'H' :
03307       case 'h' :
03308          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
03309          break;
03310       case 'W' :
03311       case 'w' :
03312          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
03313          break;
03314       default :
03315          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
03316       }
03317    }
03318 }

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

00694 {
00695    ast_copy_string(chan->context, context, sizeof(chan->context));
00696    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00697    chan->priority = pri;
00698 }

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

Definition at line 2877 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_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, config, feature_group_exten::entry, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

02878 {
02879    int x;
02880 
02881    ast_clear_flag(config, AST_FLAGS_ALL);
02882 
02883    ast_rwlock_rdlock(&features_lock);
02884    for (x = 0; x < FEATURES_COUNT; x++) {
02885       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
02886          continue;
02887 
02888       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
02889          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02890 
02891       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
02892          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02893    }
02894    ast_rwlock_unlock(&features_lock);
02895 
02896    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
02897       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
02898 
02899       if (dynamic_features) {
02900          char *tmp = ast_strdupa(dynamic_features);
02901          char *tok;
02902          struct ast_call_feature *feature;
02903 
02904          /* while we have a feature */
02905          while ((tok = strsep(&tmp, "#"))) {
02906             struct feature_group *fg;
02907 
02908             AST_RWLIST_RDLOCK(&feature_groups);
02909             AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
02910                struct feature_group_exten *fge;
02911 
02912                AST_LIST_TRAVERSE(&fg->features, fge, entry) {
02913                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
02914                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02915                   }
02916                   if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
02917                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02918                   }
02919                }
02920             }
02921             AST_RWLIST_UNLOCK(&feature_groups);
02922 
02923             AST_RWLIST_RDLOCK(&feature_list);
02924             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
02925                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
02926                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02927                }
02928                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
02929                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02930                }
02931             }
02932             AST_RWLIST_UNLOCK(&feature_list);
02933          }
02934       }
02935    }
02936 }

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

References FEATURE_SENSE_PEER.

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

01485 {
01486    if (sense == FEATURE_SENSE_PEER) {
01487       *caller = peer;
01488       *callee = chan;
01489    } else {
01490       *callee = peer;
01491       *caller = chan;
01492    }
01493 }

static void unmap_features ( void   )  [static]

Definition at line 2698 of file features.c.

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

02699 {
02700    int x;
02701 
02702    ast_rwlock_wrlock(&features_lock);
02703    for (x = 0; x < FEATURES_COUNT; x++)
02704       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
02705    ast_rwlock_unlock(&features_lock);
02706 }


Variable Documentation

int adsipark [static]

Definition at line 433 of file features.c.

Referenced by load_config(), and park_call_full().

char* app_bridge = "Bridge" [static]

Definition at line 5641 of file features.c.

unsigned int atxfercallbackretries [static]

Definition at line 442 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferdropcall [static]

Definition at line 440 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferloopdelay [static]

Definition at line 441 of file features.c.

Referenced by builtin_atxfer(), and load_config().

int atxfernoanswertimeout [static]

Definition at line 439 of file features.c.

Referenced by builtin_atxfer(), and load_config().

struct ast_app_option bridge_exec_options[128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, } [static]

Definition at line 5678 of file features.c.

Referenced by bridge_exec().

struct ast_call_feature builtin_features[] [static]

Definition at line 2435 of file features.c.

Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().

struct ast_cli_entry cli_features[] [static]

Initial value:

 {
   { .handler =  handle_feature_show , .summary =  "Lists configured features" ,__VA_ARGS__ },
   { .handler =  handle_features_reload , .summary =  "Reloads configured features" ,__VA_ARGS__ },
   { .handler =  handle_parkedcalls , .summary =  "List currently parked calls" ,__VA_ARGS__ },
}

Definition at line 5423 of file features.c.

Referenced by ast_features_init().

int comebacktoorigin = 1 [static]

Definition at line 437 of file features.c.

Referenced by load_config(), and manage_parkinglot().

char courtesytone[256] [static]

Courtesy tone

Definition at line 425 of file features.c.

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

struct ast_parkinglot* default_parkinglot

Definition at line 422 of file features.c.

struct ast_datastore_info dial_features_info [static]

Initial value:

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

Definition at line 604 of file features.c.

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

int featuredigittimeout [static]

Definition at line 436 of file features.c.

ast_rwlock_t features_lock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RWLOCK_INITIALIZER } [static]

Definition at line 2433 of file features.c.

Referenced by ast_rdlock_call_features(), ast_unlock_call_features(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().

struct ast_app* mixmonitor_app = NULL [static]

Definition at line 452 of file features.c.

Referenced by builtin_automixmonitor().

int mixmonitor_ok = 1 [static]

Definition at line 453 of file features.c.

Referenced by builtin_automixmonitor().

struct ast_app* monitor_app = NULL [static]

Definition at line 449 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 450 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

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

Definition at line 4273 of file features.c.

Referenced by park_call_exec().

char* parkcall = PARK_APP_NAME [static]

Definition at line 447 of file features.c.

Referenced by ast_features_init(), and build_parkinglot().

char* parkedcall = "ParkedCall" [static]

Definition at line 374 of file features.c.

Referenced by ast_features_init(), and park_call_full().

int parkeddynamic = 0 [static]

Enable creation of parkinglots dynamically

Definition at line 427 of file features.c.

Referenced by load_config(), and park_space_reserve().

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 426 of file features.c.

Referenced by park_exec_full().

char parking_ext[AST_MAX_EXTENSION]

Extension you type to park the call

Definition at line 423 of file features.c.

pthread_t parking_thread [static]

Definition at line 458 of file features.c.

Referenced by ast_features_init(), and 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 420 of file features.c.

Referenced by ast_features_init(), ast_features_reload(), ast_park_call(), build_parkinglot(), builtin_atxfer(), builtin_blindtransfer(), do_parking_thread(), find_parkinglot(), handle_feature_show(), handle_parkedcalls(), manager_parking_status(), park_call_exec(), park_exec_full(), and park_space_reserve().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 376 of file features.c.

Referenced by ast_pickup_ext(), and load_config().

char pickupfailsound[256] [static]

Pickup failure sound

Definition at line 431 of file features.c.

Referenced by ast_pickup_call(), and load_config().

char pickupsound[256] [static]

Pickup sound

Definition at line 430 of file features.c.

Referenced by ast_pickup_call(), and load_config().

char* registrar = "features" [static]

Registrar for operations

Definition at line 444 of file features.c.

Referenced by build_parkinglot(), manage_parkinglot(), park_add_hints(), park_call_full(), and parkinglot_destroy().

struct ast_app* stopmixmonitor_app = NULL [static]

Definition at line 455 of file features.c.

Referenced by builtin_automixmonitor().

int stopmixmonitor_ok = 1 [static]

Definition at line 456 of file features.c.

Referenced by builtin_automixmonitor().

int transferdigittimeout [static]

Definition at line 435 of file features.c.

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

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 429 of file features.c.

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

char xfersound[256] [static]

Call transfer sound

Definition at line 428 of file features.c.

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


Generated on Wed Apr 6 11:30:04 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7