Wed Aug 18 22:34:22 2010

Asterisk developer's documentation


features.c File Reference

Routines implementing call features as call pickup, parking and transfer. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <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"

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

static 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.
static void * ast_bridge_call_thread (void *data)
 bridge the call
static void ast_bridge_call_thread_launch (void *data)
 create thread for the parked call
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature)
 detect a feature before bridging
static int ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
 Check the dynamic features.
static struct ast_channelast_feature_request_and_dial (struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language)
 Get feature and dial.
int ast_features_init (void)
int ast_features_reload (void)
 Reload call features from features.conf.
ast_call_featureast_find_call_feature (const char *name)
 look for a call feature entry by its sname
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call and read back parked location.
static int ast_park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
const char * ast_parking_ext (void)
 Determine system parking extension.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
const char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_rdlock_call_features (void)
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_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 int bridge_exec (struct ast_channel *chan, void *data)
 Bridge channels.
static struct ast_parkinglotbuild_parkinglot (char *name, struct ast_variable *var)
 Build parkinglot from configuration and chain it in.
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 Attended transfer.
static int builtin_automixmonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 Monitor a channel by DTMF.
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 Blind transfer user to another extension.
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 support routing for one touch call parking
static char * callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
static int check_compat (struct ast_channel *c, struct ast_channel *newchan)
 make channels compatible
static void check_goto_on_transfer (struct ast_channel *chan)
 Check goto on transfer.
static struct ast_parkinglotcreate_parkinglot (char *name)
 Allocate parking lot structure.
static void dial_features_destroy (void *data)
static void * dial_features_duplicate (void *data)
static void do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan)
 Actual bridge.
static void * do_parking_thread (void *ignore)
 Take care of parked calls and unpark them if needed.
static int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 exec an app by feature
static int feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, int operation, struct ast_call_feature *feature)
 Helper function for feature_interpret and ast_feature_detect.
static struct ast_call_featurefind_dynamic_feature (const char *name)
 find a call feature by name
static struct feature_groupfind_group (const char *name)
 Find a group by name.
ast_parkinglotfind_parkinglot (const char *name)
 Find parkinglot by name.
static const char * findparkinglotname (struct ast_channel *chan)
 Find parking lot name from channel.
static int finishup (struct ast_channel *chan)
static char * handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list configured features.
static char * handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list parked calls.
static int load_config (void)
int manage_parkinglot (struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
 Run management on parkinglots, called once per parkinglot.
static int manager_park (struct mansession *s, const struct message *m)
 Create manager event for parked calls.
static int manager_parking_status (struct mansession *s, const struct message *m)
 Dump parking lot status.
static int masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args)
static int masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
static int masq_park_call_announce_args (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
static enum ast_device_state metermaidstate (const char *data)
 metermaids callback from devicestate.c
static void notify_metermaids (const char *exten, char *context, enum ast_device_state state)
 Notify metermaids that we've changed an extension.
static void park_add_hints (char *context, int start, int stop)
 Add parking hints for all defined parking lots.
static int park_call_exec (struct ast_channel *chan, void *data)
 Park a call.
static int park_exec (struct ast_channel *chan, void *data)
static int park_exec_full (struct ast_channel *chan, void *data, struct ast_parkinglot *parkinglot)
 Pickup parked call.
static struct parkeduserpark_space_reserve (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
static struct ast_parkinglotparkinglot_addref (struct ast_parkinglot *parkinglot)
static int parkinglot_cmp_cb (void *obj, void *arg, int flags)
static void parkinglot_destroy (void *obj)
 Destroy a parking lot.
static int parkinglot_hash_cb (const void *obj, const int flags)
static void parkinglot_unref (struct ast_parkinglot *parkinglot)
 Unreference parkinglot object. If no more references, then go ahead and delete it.
static struct ast_cdrpick_unlocked_cdr (struct ast_cdr *cdr)
 return the first unlocked cdr in a possible chain
static int play_message_in_bridged_call (struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile)
 Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages.
static void post_manager_event (const char *s, struct parkeduser *pu)
 Output parking event to manager.
static const char * real_ctx (struct ast_channel *transferer, struct ast_channel *transferee)
 Find the context for the transfer.
static struct feature_groupregister_group (const char *fgname)
 Add new feature group.
static void register_group_feature (struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
 Add feature to group.
static int remap_feature (const char *name, const char *value)
static void set_bridge_features_on_config (struct ast_bridge_config *config, const char *features)
static void set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri)
 store context, extension and priority
static void set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
static void set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense)
 set caller and callee according to the direction
static void unmap_features (void)

Variables

static int adsipark
static char * app_bridge = "Bridge"
static unsigned int atxfercallbackretries
static unsigned int atxferdropcall
static unsigned int atxferloopdelay
static int atxfernoanswertimeout
static char * bridge_descrip
static struct ast_app_option bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE } }
static char * bridge_synopsis = "Bridge two channels"
static struct ast_call_feature builtin_features []
static struct ast_cli_entry cli_features []
static int comebacktoorigin = 1
static char courtesytone [256]
ast_parkinglotdefault_parkinglot
static char * descrip
static char * descrip2
ast_datastore_info dial_features_info
static int featuredigittimeout
static ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER
static char mandescr_bridge []
static char mandescr_park []
static struct ast_appmixmonitor_app = NULL
static int mixmonitor_ok = 1
static struct ast_appmonitor_app = NULL
static int monitor_ok = 1
static struct ast_app_option park_call_options [128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, }
static char * parkcall = PARK_APP_NAME
static char * parkedcall = "ParkedCall"
static int parkedplay = 0
char parking_ext [AST_MAX_EXTENSION]
static pthread_t parking_thread
static struct ao2_containerparkinglots
 The list of parking lots configured. Always at least one - the default parking lot.
static char pickup_ext [AST_MAX_EXTENSION]
static char * registrar = "features"
static struct ast_appstopmixmonitor_app = NULL
static int stopmixmonitor_ok = 1
static char * synopsis = "Answer a parked call"
static char * synopsis2 = "Park yourself"
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Detailed Description

Routines implementing call features as call pickup, parking and transfer.

Author:
Mark Spencer <markster@digium.com>

Definition in file features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 69 of file features.c.

#define DEFAULT_ATXFER_CALLBACK_RETRIES   2

Definition at line 67 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_DROP_CALL   0

Definition at line 65 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_LOOP_DELAY   10000

Definition at line 66 of file features.c.

Referenced by load_config().

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

Definition at line 62 of file features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 63 of file features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 60 of file features.c.

Referenced by build_parkinglot(), and load_config().

#define DEFAULT_PARKINGLOT   "default"

Default parking lot

Definition at line 64 of file features.c.

Referenced by load_config().

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 61 of file features.c.

Referenced by load_config().

#define FEATURES_COUNT   ARRAY_LEN(builtin_features)

Definition at line 1621 of file features.c.

Referenced by ast_feature_request_and_dial(), ast_find_call_feature(), feature_interpret_helper(), 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 70 of file features.c.

Referenced by manage_parkinglot().


Enumeration Type Documentation

anonymous enum

Enumerator:
BRIDGE_OPT_PLAYTONE 

Definition at line 4481 of file features.c.

04481      {
04482    BRIDGE_OPT_PLAYTONE = (1 << 0),
04483 };

enum ast_park_call_options

Options to pass to ast_park_call_full

Enumerator:
AST_PARK_OPT_RINGING  Provide ringing to the parked caller instead of music on hold
AST_PARK_OPT_RANDOMIZE  Randomly choose a parking spot for the caller instead of choosing the first one that is available.
AST_PARK_OPT_SILENCE  Do not announce the parking number

Definition at line 468 of file features.c.

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


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

References ast_channel::_state, ast_answer(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc, ast_channel_make_compatible(), ast_channel_unlock, ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), buf, do_bridge_masquerade(), errno, LOG_WARNING, ast_channel::name, playtone(), s, and xfersound.

Referenced by ast_features_init().

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

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

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

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

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

References ADSI_JUST_CENT, ast_adsi_load_session, ast_adsi_print, chan, and justify.

Referenced by ast_park_call_full().

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

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

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_channel::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_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_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, config, ast_channel::context, ast_channel::data, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_cdr::uniqueid, ast_channel::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.

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

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

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

bridge the call

Parameters:
data thread bridge.
Set Last Data for respective channels, reset cdr for channels bridge call, check if we're going back to dialplan if not hangup both legs of the call

Definition at line 341 of file features.c.

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

Referenced by ast_bridge_call_thread_launch().

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

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

create thread for the parked call

Parameters:
data Create thread and attributes, call ast_bridge_call_thread

Definition at line 384 of file features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by action_bridge(), and builtin_atxfer().

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

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

detect a feature before bridging

Parameters:
chan 
ast_flags ptr
char ptr of input code
Return values:
ast_call_feature ptr to be set if found
Returns:
result, was feature found or not

Definition at line 2059 of file features.c.

References chan, feature_group_exten::feature, and feature_interpret_helper().

Referenced by detect_disconnect().

02059                                                                                                                            {
02060 
02061    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02062 }

static int ast_feature_interpret ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense 
) [static]

Check the dynamic features.

Parameters:
chan,peer,config,code,sense 
Return values:
res on success.
-1 on failure.

Definition at line 2030 of file features.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, chan, 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().

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

static struct ast_channel * ast_feature_request_and_dial ( struct ast_channel caller,
struct ast_channel transferee,
const char *  type,
int  format,
void *  data,
int  timeout,
int *  outstate,
const char *  cid_num,
const char *  cid_name,
int  igncallerstate,
const char *  language 
) [static]

Get feature and dial.

Parameters:
caller,transferee,type,format,data,timeout,outstate,cid_num,cid_name,igncallerstate Request channel, set channel variables, initiate call,check if they want to disconnect go into loop, check if timeout has elapsed, check if person to be transfered hung up, check for answer break loop, set cdr return channel.
Todo:
XXX Check - this is very similar to the code in channel.c
Returns:
always a channel

Definition at line 2117 of file features.c.

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

Referenced by builtin_atxfer().

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

int ast_features_init ( void   ) 

Provided by features.c

Definition at line 4616 of file features.c.

References action_bridge(), ao2_container_alloc, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application2(), bridge_exec(), cli_features, descrip, descrip2, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), parkinglots, synopsis, and synopsis2.

Referenced by main().

04617 {
04618    int res;
04619 
04620    ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
04621 
04622    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
04623 
04624    if ((res = load_config()))
04625       return res;
04626    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
04627    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
04628    res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
04629    if (!res)
04630       res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
04631    if (!res) {
04632       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
04633       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park); 
04634       ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
04635    }
04636 
04637    res |= ast_devstate_prov_add("Park", metermaidstate);
04638 
04639    return res;
04640 }

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4052 of file features.c.

References load_config().

Referenced by handle_features_reload().

04053 {
04054    int res;
04055    /* Release parking lot list */
04056    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04057    // TODO: I don't think any marking is necessary
04058 
04059    /* Reload configuration */
04060    res = load_config();
04061    
04062    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04063    return res;
04064 }

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

References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.

Referenced by action_atxfer(), and handle_request_info().

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

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

References masq_park_call().

Referenced by handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().

00826 {
00827    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00828 }

int ast_park_call ( struct ast_channel chan,
struct ast_channel host,
int  timeout,
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 754 of file features.c.

References ast_park_call_full(), chan, and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

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

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

Definition at line 609 of file features.c.

References adsi_announce_park(), adsipark, ast_channel::appl, ast_add_extension2(), ast_adsi_available, ast_adsi_unload_session, ast_bridged_channel(), AST_CHANNEL_NAME, ast_channel_unlock, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HOLD, AST_CONTROL_RINGING, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RINGING, AST_PARK_OPT_SILENCE, ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, parkeduser::chan, chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, ast_park_call_args::extout, ast_channel::language, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, ast_park_call_args::orig_chan_name, park_space_reserve(), parkedcall, ast_parkinglot::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, ast_parkinglot::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, ast_park_call_args::pu, registrar, ast_park_call_args::return_con, ast_park_call_args::return_ext, ast_park_call_args::return_pri, S_OR, parkeduser::start, ast_channel::tech, ast_park_call_args::timeout, ast_channel_tech::type, and ast_channel::uniqueid.

Referenced by ast_park_call(), and masq_park_call().

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

const char* ast_parking_ext ( void   ) 

Determine system parking extension.

Returns:
the call parking extension for drivers that provide special call parking help

Definition at line 244 of file features.c.

References parking_ext.

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

00245 {
00246    return parking_ext;
00247 }

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

References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, chan, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup.

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

04437 {
04438    struct ast_channel *cur = NULL;
04439    int res = -1;
04440 
04441    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04442       if (!cur->pbx && 
04443          (cur != chan) &&
04444          (chan->pickupgroup & cur->callgroup) &&
04445          ((cur->_state == AST_STATE_RINGING) ||
04446           (cur->_state == AST_STATE_RING))) {
04447             break;
04448       }
04449       ast_channel_unlock(cur);
04450    }
04451    if (cur) {
04452       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04453       res = ast_answer(chan);
04454       if (res)
04455          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04456       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04457       if (res)
04458          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04459       res = ast_channel_masquerade(cur, chan);
04460       if (res)
04461          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04462       ast_channel_unlock(cur);
04463    } else   {
04464       ast_debug(1, "No call pickup possible...\n");
04465    }
04466    return res;
04467 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 249 of file features.c.

References pickup_ext.

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

00250 {
00251    return pickup_ext;
00252 }

void ast_rdlock_call_features ( void   ) 

Definition at line 1802 of file features.c.

References ast_rwlock_rdlock(), and features_lock.

Referenced by handle_request_info().

01803 {
01804    ast_rwlock_rdlock(&features_lock);
01805 }

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

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

void ast_unlock_call_features ( void   ) 

Definition at line 1807 of file features.c.

References ast_rwlock_unlock(), and features_lock.

Referenced by handle_request_info().

01808 {
01809    ast_rwlock_unlock(&features_lock);
01810 }

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

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

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

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1741 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.

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

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

Definition at line 1767 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.

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

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

Bridge channels.

Parameters:
chan 
data channel to bridge with.
Split data, check we aren't bridging with ourself, check valid channel, answer call if not already, check compatible channels, setup bridge config now bridge call, if transfered party hangs up return to PBX extension.

Definition at line 4498 of file features.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_channel_alloc, ast_channel_make_compatible(), ast_channel_unlock, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, chan, ast_channel::context, do_bridge_masquerade(), EVENT_FLAG_CALL, ast_channel::exten, ast_channel::language, LOG_WARNING, manager_event, ast_channel::name, pbx_builtin_setvar_helper(), ast_channel::priority, and xfersound.

Referenced by ast_features_init().

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

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

Build parkinglot from configuration and chain it in.

Definition at line 3522 of file features.c.

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

Referenced by load_config().

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

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

Attended transfer.

Parameters:
chan transfered user
peer person transfering call
config 
code 
sense feature options
data Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel.
Returns:
-1 on failure

Definition at line 1324 of file features.c.

References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc, ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FEATURE_RETURN_SUCCESS, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_parking_ext(), ast_read(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, builtin_parkcall(), chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, f, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xferfailsound, and xfersound.

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

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

Definition at line 1033 of file features.c.

References AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_unlock, AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, courtesytone, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), stopmixmonitor_app, and stopmixmonitor_ok.

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

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

Monitor a channel by DTMF.

Parameters:
chan channel requesting monitor
peer channel to be monitored
config 
code 
sense feature options
data Check monitor app enabled, setup channels, both caller/callee chans not null get TOUCH_MONITOR variable for filename if exists, exec monitor app.
Return values:
AST_FEATURE_RETURN_SUCCESS on success.
-1 on error.

Definition at line 940 of file features.c.

References AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, courtesytone, len(), LOG_ERROR, LOG_NOTICE, ast_channel::monitor, monitor_app, monitor_ok, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_OR, set_peers(), and ast_channel_monitor::stop.

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

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

Blind transfer user to another extension.

Parameters:
chan channel to be transfered
peer channel initiated blind transfer
config 
code 
data 
sense feature options
Place chan on hold, check if transferred to parkinglot extension, otherwise check extension exists and transfer caller.
Return values:
AST_FEATURE_RETURN_SUCCESS. 
-1 on failure.

Todo:
XXX Maybe we should have another message here instead of invalid extension XXX

Definition at line 1193 of file features.c.

References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), AST_FEATURE_RETURN_PARKFAILED, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, ast_stopstream(), ast_stream_and_wait(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_cdr::dstchannel, finishup(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, masq_park_call_announce(), ast_channel::name, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), transferdigittimeout, and xferfailsound.

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

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

Definition at line 1143 of file features.c.

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

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

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

support routing for one touch call parking

Parameters:
chan channel parking call
peer channel to be parked
config unsed
code unused
sense feature options
data Setup channel, set return exten,priority to 's,1' answer chan, sleep chan, park call

Definition at line 870 of file features.c.

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

Referenced by builtin_atxfer().

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

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

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

02933 {
02934    int i = 0;
02935    enum {
02936       OPT_CALLEE_REDIRECT   = 't',
02937       OPT_CALLER_REDIRECT   = 'T',
02938       OPT_CALLEE_AUTOMON    = 'w',
02939       OPT_CALLER_AUTOMON    = 'W',
02940       OPT_CALLEE_DISCONNECT = 'h',
02941       OPT_CALLER_DISCONNECT = 'H',
02942       OPT_CALLEE_PARKCALL   = 'k',
02943       OPT_CALLER_PARKCALL   = 'K',
02944    };
02945 
02946    memset(options, 0, len);
02947    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02948       options[i++] = OPT_CALLER_REDIRECT;
02949    }
02950    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02951       options[i++] = OPT_CALLER_AUTOMON;
02952    }
02953    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02954       options[i++] = OPT_CALLER_DISCONNECT;
02955    }
02956    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02957       options[i++] = OPT_CALLER_PARKCALL;
02958    }
02959 
02960    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02961       options[i++] = OPT_CALLEE_REDIRECT;
02962    }
02963    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02964       options[i++] = OPT_CALLEE_AUTOMON;
02965    }
02966    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02967       options[i++] = OPT_CALLEE_DISCONNECT;
02968    }
02969    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02970       options[i++] = OPT_CALLEE_PARKCALL;
02971    }
02972 
02973    return options;
02974 }

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

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

Referenced by builtin_atxfer().

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

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

Referenced by builtin_blindtransfer().

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

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

Allocate parking lot structure.

Definition at line 3493 of file features.c.

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

Referenced by build_parkinglot().

03494 {
03495    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
03496 
03497    if (!name)
03498       return NULL;
03499 
03500    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
03501    if (!newlot)
03502       return NULL;
03503    
03504    ast_copy_string(newlot->name, name, sizeof(newlot->name));
03505    AST_LIST_HEAD_INIT(&newlot->parkings);
03506 
03507    return newlot;
03508 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 222 of file features.c.

References ast_free.

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

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

Definition at line 209 of file features.c.

References ast_calloc.

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

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

References ast_channel::_state, ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_explicit_goto(), ast_moh_stop(), ast_setstate(), chan, ast_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

Referenced by action_bridge(), and bridge_exec().

04100 {
04101    ast_moh_stop(chan);
04102    ast_channel_lock(chan);
04103    ast_setstate(tmpchan, chan->_state);
04104    tmpchan->readformat = chan->readformat;
04105    tmpchan->writeformat = chan->writeformat;
04106    ast_channel_masquerade(tmpchan, chan);
04107    ast_channel_lock(tmpchan);
04108    ast_do_masquerade(tmpchan);
04109    /* when returning from bridge, the channel will continue at the next priority */
04110    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
04111    ast_channel_unlock(tmpchan);
04112    ast_channel_unlock(chan);
04113 }

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

References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_samp2tv(), ast_select(), manage_parkinglot(), and parkinglots.

Referenced by ast_features_init().

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

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

exec an app by feature

Parameters:
chan,peer,config,code,sense,data Find a feature, determine which channel activated
Return values:
AST_FEATURE_RETURN_NO_HANGUP_PEER 
-1 error.
-2 when an application cannot be found.

Todo:
XXX should probably return res

Definition at line 1831 of file features.c.

References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, chan, feature_group_exten::feature, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().

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

static int feature_interpret_helper ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense,
char *  dynamic_features_buf,
struct ast_flags features,
int  operation,
struct ast_call_feature feature 
) [static]

Helper function for feature_interpret and ast_feature_detect.

Parameters:
chan,peer,config,code,sense,dynamic_features char buf,feature flags,operation,feature
Lock features list, browse for code, unlock list If a feature is found and the operation variable is set, that feature's operation is executed. The first feature found is copied to the feature parameter.
Return values:
res on success.
-1 on failure.

Definition at line 1926 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, chan, 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 ast_feature_interpret().

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

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

find a call feature by name

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

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

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

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

Referenced by feature_interpret_helper().

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

struct ast_parkinglot * find_parkinglot ( const char *  name  ) 

Find parkinglot by name.

Definition at line 3192 of file features.c.

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

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

03193 {
03194    struct ast_parkinglot *parkinglot = NULL;
03195    struct ast_parkinglot tmp_parkinglot;
03196    
03197    if (ast_strlen_zero(name))
03198       return NULL;
03199 
03200    ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
03201 
03202    parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
03203 
03204    if (parkinglot && option_debug)
03205       ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
03206 
03207    return parkinglot;
03208 }

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

Find parking lot name from channel.

Definition at line 422 of file features.c.

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

Referenced by park_exec_full(), and park_space_reserve().

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

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 1149 of file features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

01150 {
01151    ast_indicate(chan, AST_CONTROL_UNHOLD);
01152 
01153    return ast_autoservice_stop(chan);
01154 }

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

References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), builtin_features, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, ast_call_feature::exten, ast_cli_args::fd, FEATURES_COUNT, features_lock, ast_call_feature::fname, HFS_FORMAT, ast_parkinglot::name, ast_parkinglot::parking_con, parking_ext, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglots, ast_call_feature::sname, and ast_cli_entry::usage.

03993 {
03994    int i;
03995    struct ast_call_feature *feature;
03996    struct ao2_iterator iter;
03997    struct ast_parkinglot *curlot;
03998 #define HFS_FORMAT "%-25s %-7s %-7s\n"
03999 
04000    switch (cmd) {
04001    
04002    case CLI_INIT:
04003       e->command = "features show";
04004       e->usage =
04005          "Usage: features show\n"
04006          "       Lists configured features\n";
04007       return NULL;
04008    case CLI_GENERATE:
04009       return NULL;
04010    }
04011 
04012    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
04013    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
04014 
04015    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
04016 
04017    ast_rwlock_rdlock(&features_lock);
04018    for (i = 0; i < FEATURES_COUNT; i++)
04019       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
04020    ast_rwlock_unlock(&features_lock);
04021 
04022    ast_cli(a->fd, "\n");
04023    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
04024    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
04025    if (AST_RWLIST_EMPTY(&feature_list)) {
04026       ast_cli(a->fd, "(none)\n");
04027    } else {
04028       AST_RWLIST_RDLOCK(&feature_list);
04029       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
04030          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
04031       }
04032       AST_RWLIST_UNLOCK(&feature_list);
04033    }
04034 
04035    // loop through all the parking lots
04036    iter = ao2_iterator_init(parkinglots, 0);
04037 
04038    while ((curlot = ao2_iterator_next(&iter))) {
04039       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
04040       ast_cli(a->fd, "------------\n");
04041       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", parking_ext);
04042       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->parking_con);
04043       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
04044       ast_cli(a->fd,"\n");
04045       ao2_ref(curlot, -1);
04046    }
04047 
04048 
04049    return CLI_SUCCESS;
04050 }

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

Definition at line 4066 of file features.c.

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

04067 {
04068    switch (cmd) { 
04069    case CLI_INIT:
04070       e->command = "features reload";
04071       e->usage =
04072          "Usage: features reload\n"
04073          "       Reloads configured call features from features.conf\n";
04074       return NULL;
04075    case CLI_GENERATE:
04076       return NULL;
04077    }
04078    ast_features_reload();
04079 
04080    return CLI_SUCCESS;
04081 }

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

04250 {
04251    struct parkeduser *cur;
04252    int numparked = 0;
04253    struct ao2_iterator iter;
04254    struct ast_parkinglot *curlot;
04255 
04256    switch (cmd) {
04257    case CLI_INIT:
04258       e->command = "parkedcalls show";
04259       e->usage =
04260          "Usage: parkedcalls show\n"
04261          "       List currently parked calls\n";
04262       return NULL;
04263    case CLI_GENERATE:
04264       return NULL;
04265    }
04266 
04267    if (a->argc > e->args)
04268       return CLI_SHOWUSAGE;
04269 
04270    ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
04271       , "Context", "Extension", "Pri", "Timeout");
04272 
04273    iter = ao2_iterator_init(parkinglots, 0);
04274    while ((curlot = ao2_iterator_next(&iter))) {
04275       int lotparked = 0;
04276       ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name);
04277 
04278       AST_LIST_LOCK(&curlot->parkings);
04279       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04280          ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
04281             ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
04282             ,cur->priority,
04283             (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
04284          numparked++;
04285          numparked += lotparked;
04286       }
04287       AST_LIST_UNLOCK(&curlot->parkings);
04288       if (lotparked)
04289          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
04290 
04291       ao2_ref(curlot, -1);
04292    }
04293 
04294    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
04295 
04296    return CLI_SUCCESS;
04297 }

static int load_config ( void   )  [static]

Definition at line 3640 of file features.c.

References adsipark, ao2_lock(), ao2_unlock(), ast_config_load2(), ast_copy_string(), ast_log(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, config_flags, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_TIME, DEFAULT_PARKINGLOT, default_parkinglot, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_DEBUG, LOG_ERROR, LOG_WARNING, option_debug, ast_parkinglot::parkaddhints, ast_parkinglot::parkedcallhangup, ast_parkinglot::parkedcallrecording, ast_parkinglot::parkedcallreparking, ast_parkinglot::parkedcalltransfers, ast_parkinglot::parking_con, parking_ext, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.

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

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

int manage_parkinglot ( struct ast_parkinglot curlot,
fd_set *  rfds,
fd_set *  efds,
fd_set *  nrfds,
fd_set *  nefds,
int *  fs,
int *  max 
)

Run management on parkinglots, called once per parkinglot.

Definition at line 2977 of file features.c.

References ast_add_extension2(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, ast_log(), AST_MAX_FDS, ast_pbx_start(), ast_read(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, buf, callback_dialoptions(), parkeduser::chan, chan, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, free, parkeduser::list, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), and parkeduser::start.

Referenced by do_parking_thread().

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

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

References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), buf, and s.

Referenced by ast_features_init().

04375 {
04376    const char *channel = astman_get_header(m, "Channel");
04377    const char *channel2 = astman_get_header(m, "Channel2");
04378    const char *timeout = astman_get_header(m, "Timeout");
04379    char buf[BUFSIZ];
04380    int to = 0;
04381    int res = 0;
04382    int parkExt = 0;
04383    struct ast_channel *ch1, *ch2;
04384 
04385    if (ast_strlen_zero(channel)) {
04386       astman_send_error(s, m, "Channel not specified");
04387       return 0;
04388    }
04389 
04390    if (ast_strlen_zero(channel2)) {
04391       astman_send_error(s, m, "Channel2 not specified");
04392       return 0;
04393    }
04394 
04395    ch1 = ast_get_channel_by_name_locked(channel);
04396    if (!ch1) {
04397       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
04398       astman_send_error(s, m, buf);
04399       return 0;
04400    }
04401 
04402    ch2 = ast_get_channel_by_name_locked(channel2);
04403    if (!ch2) {
04404       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
04405       astman_send_error(s, m, buf);
04406       ast_channel_unlock(ch1);
04407       return 0;
04408    }
04409 
04410    if (!ast_strlen_zero(timeout)) {
04411       sscanf(timeout, "%30d", &to);
04412    }
04413 
04414    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
04415    if (!res) {
04416       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
04417       astman_send_ack(s, m, "Park successful");
04418    } else {
04419       astman_send_error(s, m, "Park failure");
04420    }
04421 
04422    ast_channel_unlock(ch1);
04423    ast_channel_unlock(ch2);
04424 
04425    return 0;
04426 }

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

References ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::name, parkinglots, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.

Referenced by ast_features_init().

04314 {
04315    struct parkeduser *cur;
04316    const char *id = astman_get_header(m, "ActionID");
04317    char idText[256] = "";
04318    struct ao2_iterator iter;
04319    struct ast_parkinglot *curlot;
04320 
04321    if (!ast_strlen_zero(id))
04322       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04323 
04324    astman_send_ack(s, m, "Parked calls will follow");
04325 
04326    iter = ao2_iterator_init(parkinglots, 0);
04327    while ((curlot = ao2_iterator_next(&iter))) {
04328 
04329       AST_LIST_LOCK(&curlot->parkings);
04330       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04331          astman_append(s, "Event: ParkedCall\r\n"
04332             "Exten: %d\r\n"
04333             "Channel: %s\r\n"
04334             "From: %s\r\n"
04335             "Timeout: %ld\r\n"
04336             "CallerIDNum: %s\r\n"
04337             "CallerIDName: %s\r\n"
04338             "%s"
04339             "\r\n",
04340             cur->parkingnum, cur->chan->name, cur->peername,
04341             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
04342             S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
04343             S_OR(cur->chan->cid.cid_name, ""),
04344             idText);
04345       }
04346       AST_LIST_UNLOCK(&curlot->parkings);
04347       ao2_ref(curlot, -1);
04348    }
04349 
04350    astman_append(s,
04351       "Event: ParkedCallsComplete\r\n"
04352       "%s"
04353       "\r\n",idText);
04354 
04355 
04356    return RESULT_SUCCESS;
04357 }

static int masq_park_call ( struct ast_channel rchan,
struct ast_channel peer,
int  timeout,
int *  extout,
int  play_announcement,
struct ast_park_call_args args 
) [static]

Definition at line 764 of file features.c.

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

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

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

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

Definition at line 835 of file features.c.

References masq_park_call().

Referenced by builtin_blindtransfer(), and builtin_parkcall().

00836 {
00837    return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
00838 }

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

Definition at line 830 of file features.c.

References masq_park_call().

Referenced by park_call_exec().

00831 {
00832    return masq_park_call(rchan, peer, 0, NULL, 1, args);
00833 }

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

metermaids callback from devicestate.c

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

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

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

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

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

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

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

References ast_add_extension(), PRIORITY_HINT, and registrar.

03628 {
03629    int numext;
03630    char device[AST_MAX_EXTENSION];
03631    char exten[10];
03632 
03633    for (numext = start; numext <= stop; numext++) {
03634       snprintf(exten, sizeof(exten), "%d", numext);
03635       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03636       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03637    }
03638 }

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

Park a call.

Definition at line 3217 of file features.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), chan, ast_channel::exten, ast_park_call_args::flags, ast_flags::flags, LOG_WARNING, masq_park_call_announce_args(), ast_channel::name, ast_park_call_args::orig_chan_name, orig_exten(), park_call_options, parse(), ast_channel::priority, ast_park_call_args::return_con, ast_park_call_args::return_ext, ast_park_call_args::return_pri, and ast_park_call_args::timeout.

Referenced by ast_features_init().

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

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

Definition at line 3470 of file features.c.

References chan, default_parkinglot, and park_exec_full().

Referenced by ast_features_init().

03471 {
03472    return park_exec_full(chan, data, default_parkinglot);
03473 }

static int park_exec_full ( struct ast_channel chan,
void *  data,
struct ast_parkinglot parkinglot 
) [static]

Pickup parked call.

Todo:
XXX we would like to wait on both!

Todo:
XXX Play a message XXX

Definition at line 3303 of file features.c.

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

Referenced by park_exec().

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

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

Definition at line 495 of file features.c.

References ast_calloc, ast_channel_lock, ast_channel_unlock, 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, chan, default_parkinglot, find_parkinglot(), findparkinglotname(), free, parkeduser::list, LOG_DEBUG, LOG_WARNING, option_debug, parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_park_call_full(), and masq_park_call().

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

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

Definition at line 3484 of file features.c.

References ao2_ref, ast_log(), LOG_DEBUG, option_debug, and parkinglot.

Referenced by park_space_reserve().

03485 {
03486    int refcount = ao2_ref(parkinglot, +1);
03487    if (option_debug > 2)
03488       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
03489    return parkinglot;
03490 }

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

Definition at line 269 of file features.c.

References CMP_MATCH, CMP_STOP, and parkinglot.

Referenced by ast_features_init().

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

static void parkinglot_destroy ( void *  obj  )  [static]

Destroy a parking lot.

Definition at line 3511 of file features.c.

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

Referenced by build_parkinglot(), and create_parkinglot().

03512 {
03513    struct ast_parkinglot *ruin = obj;
03514    struct ast_context *con;
03515    con = ast_context_find(ruin->parking_con);
03516    if (con)
03517       ast_context_destroy(con, registrar);
03518    ao2_unlink(parkinglots, ruin);
03519 }

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

Definition at line 262 of file features.c.

References ast_str_case_hash(), and parkinglot.

Referenced by ast_features_init().

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

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

References ao2_ref, ast_log(), LOG_DEBUG, option_debug, and parkinglot.

Referenced by build_parkinglot(), and park_space_reserve().

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

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

return the first unlocked cdr in a possible chain

Definition at line 2294 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

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

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

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

Referenced by builtin_automonitor().

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

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

Output parking event to manager.

Definition at line 2914 of file features.c.

References parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event, ast_parkinglot::name, ast_channel::name, parkeduser::parkingexten, parkeduser::parkinglot, S_OR, and ast_channel::uniqueid.

Referenced by manage_parkinglot().

02915 {
02916    manager_event(EVENT_FLAG_CALL, s,
02917       "Exten: %s\r\n"
02918       "Channel: %s\r\n"
02919       "Parkinglot: %s\r\n"
02920       "CallerIDNum: %s\r\n"
02921       "CallerIDName: %s\r\n"
02922       "UniqueID: %s\r\n\r\n",
02923       pu->parkingexten, 
02924       pu->chan->name,
02925       pu->parkinglot->name,
02926       S_OR(pu->chan->cid.cid_num, "<unknown>"),
02927       S_OR(pu->chan->cid.cid_name, "<unknown>"),
02928       pu->chan->uniqueid
02929       );
02930 }

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

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

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

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

References ast_calloc, ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_init, ast_string_field_set, ast_verb, feature_group_exten::entry, and LOG_NOTICE.

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

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

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

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

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

Definition at line 1898 of file features.c.

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

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

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

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

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

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

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

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

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

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

Definition at line 2064 of file features.c.

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, chan, config, feature_group_exten::feature, ast_call_feature::feature_mask, FEATURES_COUNT, features_lock, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

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

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

References chan, and FEATURE_SENSE_PEER.

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

00848 {
00849    if (sense == FEATURE_SENSE_PEER) {
00850       *caller = peer;
00851       *callee = chan;
00852    } else {
00853       *callee = peer;
00854       *caller = chan;
00855    }
00856 }

static void unmap_features ( void   )  [static]

Definition at line 1888 of file features.c.

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

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


Variable Documentation

int adsipark [static]

Definition at line 144 of file features.c.

Referenced by ast_park_call_full(), and load_config().

char* app_bridge = "Bridge" [static]

Definition at line 4469 of file features.c.

unsigned int atxfercallbackretries [static]

Definition at line 153 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferdropcall [static]

Definition at line 151 of file features.c.

Referenced by builtin_atxfer(), and load_config().

unsigned int atxferloopdelay [static]

Definition at line 152 of file features.c.

Referenced by builtin_atxfer(), and load_config().

int atxfernoanswertimeout [static]

Definition at line 150 of file features.c.

Referenced by builtin_atxfer(), and load_config().

char* bridge_descrip [static]

Definition at line 4471 of file features.c.

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

Definition at line 4487 of file features.c.

Referenced by bridge_exec().

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

Definition at line 4470 of file features.c.

struct ast_call_feature builtin_features[] [static]

Definition at line 1625 of file features.c.

Referenced by ast_feature_request_and_dial(), ast_find_call_feature(), feature_interpret_helper(), 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 4299 of file features.c.

Referenced by ast_features_init().

int comebacktoorigin = 1 [static]

Definition at line 148 of file features.c.

Referenced by load_config(), and manage_parkinglot().

char courtesytone[256] [static]

Courtesy tone

Definition at line 139 of file features.c.

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

struct ast_parkinglot* default_parkinglot

Definition at line 136 of file features.c.

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

char* descrip [static]

Definition at line 160 of file features.c.

Referenced by aji_handle_presence(), ast_features_init(), and load_module().

char* descrip2 [static]

Definition at line 171 of file features.c.

Referenced by ast_features_init().

struct ast_datastore_info dial_features_info

Initial value:

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

Definition at line 230 of file features.c.

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

int featuredigittimeout [static]

Definition at line 147 of file features.c.

Referenced by ast_bridge_call(), and load_config().

ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static]

Definition at line 1623 of file features.c.

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

char mandescr_bridge[] [static]

Definition at line 4083 of file features.c.

char mandescr_park[] [static]

Definition at line 4359 of file features.c.

struct ast_app* mixmonitor_app = NULL [static]

Definition at line 196 of file features.c.

Referenced by builtin_automixmonitor().

int mixmonitor_ok = 1 [static]

Definition at line 197 of file features.c.

Referenced by builtin_automixmonitor().

struct ast_app* monitor_app = NULL [static]

Definition at line 193 of file features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

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

Referenced by park_call_exec().

char* parkcall = PARK_APP_NAME [static]

Definition at line 167 of file features.c.

Referenced by ast_features_init(), and build_parkinglot().

char* parkedcall = "ParkedCall" [static]

Definition at line 90 of file features.c.

Referenced by ast_features_init(), and ast_park_call_full().

int parkedplay = 0 [static]

Who to play the courtesy tone to

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

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

pthread_t parking_thread [static]

Definition at line 202 of file features.c.

Referenced by ast_features_init(), and ast_park_call_full().

struct ao2_container* parkinglots [static]

The list of parking lots configured. Always at least one - the default parking lot.

Definition at line 134 of file features.c.

Referenced by ast_features_init(), build_parkinglot(), do_parking_thread(), find_parkinglot(), handle_feature_show(), handle_parkedcalls(), manager_parking_status(), and parkinglot_destroy().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 92 of file features.c.

Referenced by ast_pickup_ext(), and load_config().

char* registrar = "features" [static]

Registrar for operations

Definition at line 155 of file features.c.

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

struct ast_app* stopmixmonitor_app = NULL [static]

Definition at line 199 of file features.c.

Referenced by builtin_automixmonitor().

int stopmixmonitor_ok = 1 [static]

Definition at line 200 of file features.c.

Referenced by builtin_automixmonitor().

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

Definition at line 158 of file features.c.

Referenced by ast_features_init(), and load_module().

char* synopsis2 = "Park yourself" [static]

Definition at line 169 of file features.c.

Referenced by ast_features_init().

int transferdigittimeout [static]

Definition at line 146 of file features.c.

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

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 142 of file features.c.

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

char xfersound[256] [static]

Call transfer sound

Definition at line 141 of file features.c.

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


Generated on Wed Aug 18 22:34:23 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7