Wed Oct 28 13:32:37 2009

Asterisk developer's documentation


features.c File Reference

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

#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"
#include "asterisk/astobj2.h"
#include "asterisk/cel.h"

Include dependency graph for features.c:

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  ast_dial_features
struct  ast_park_call_args
struct  ast_parkinglot
 Structure for parking lots which are put in a container. More...
struct  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), OPT_CALLEE_HANGUP = (1 << 1), OPT_CALLER_HANGUP = (1 << 2), OPT_DURATION_LIMIT = (1 << 3),
  OPT_DURATION_STOP = (1 << 4), OPT_CALLEE_TRANSFER = (1 << 5), OPT_CALLER_TRANSFER = (1 << 6), OPT_CALLEE_MONITOR = (1 << 7),
  OPT_CALLER_MONITOR = (1 << 8), OPT_CALLEE_PARK = (1 << 9), OPT_CALLER_PARK = (1 << 10), OPT_CALLEE_KILL = (1 << 11)
}
enum  { OPT_ARG_DURATION_LIMIT = 0, OPT_ARG_DURATION_STOP, OPT_ARG_ARRAY_SIZE }
enum  ast_park_call_options { AST_PARK_OPT_RINGING = (1 << 0), AST_PARK_OPT_RANDOMIZE = (1 << 1), AST_PARK_OPT_SILENCE = (1 << 2) }

Functions

static void __fini_feature_groups (void)
static void __fini_feature_list (void)
static void __init_feature_groups (void)
static void __init_feature_list (void)
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 the call and set CDR
int ast_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit)
void ast_channel_log (char *title, struct ast_channel *chan)
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature)
 detect a feature before bridging
int ast_features_init (void)
int ast_features_reload (void)
 Reload call features from features.conf.
struct ast_call_featureast_find_call_feature (const char *name)
 look for a call feature entry by its sname
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call.
const char * ast_parking_ext (void)
 Determine system parking extension.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
const char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_rdlock_call_features (void)
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_list
void ast_unlock_call_features (void)
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
 Remove all features in the list.
static void ast_unregister_groups (void)
 Remove all feature groups in the list.
static void * bridge_call_thread (void *data)
 bridge the call
static void bridge_call_thread_launch (void *data)
 create thread for the parked call
static int bridge_exec (struct ast_channel *chan, const char *data)
 Bridge channels.
static struct ast_parkinglotbuild_parkinglot (char *name, struct ast_variable *var)
 Build parkinglot from configuration and chain it in.
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 Attended transfer.
static int builtin_automixmonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 Monitor a channel by DTMF.
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 Blind transfer user to another extension.
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
static int builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
 support routing for one touch call parking
static char * callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
static int check_compat (struct ast_channel *c, struct ast_channel *newchan)
 make channels compatible
static void check_goto_on_transfer (struct ast_channel *chan)
 Check goto on transfer.
static struct ast_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, const char *code, int sense, void *data)
 exec an app by feature
static int feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense)
 Check the dynamic features.
static int feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, int operation, struct ast_call_feature *feature)
 Helper function for feature_interpret and ast_feature_detect.
static struct ast_channelfeature_request_and_dial (struct ast_channel *caller, 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.
static int find_channel_by_group (void *obj, void *arg, void *data, int flags)
static struct ast_call_featurefind_dynamic_feature (const char *name)
 find a call feature by name
static struct feature_groupfind_group (const char *name)
 Find a group by name.
struct ast_parkinglotfind_parkinglot (const char *name)
 Find parkinglot by name.
static const char * findparkinglotname (struct ast_channel *chan)
 Find parking lot name from channel.
static int finishup (struct ast_channel *chan)
static char * handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list configured features.
static char * handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list parked calls.
static int load_config (void)
int manage_parkinglot (struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
 Run management on parkinglots, called once per parkinglot.
static int manager_park (struct mansession *s, const struct message *m)
 Create manager event for parked calls.
static int manager_parking_status (struct mansession *s, const struct message *m)
 Dump parking lot status.
static int masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args)
static int masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
static int masq_park_call_announce_args (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
static enum ast_device_state metermaidstate (const char *data)
 metermaids callback from devicestate.c
static void notify_metermaids (const char *exten, char *context, enum ast_device_state state)
 Notify metermaids that we've changed an extension.
static void park_add_hints (char *context, int start, int stop)
 Add parking hints for all defined parking lots.
static int park_call_exec (struct ast_channel *chan, const char *data)
 Park a call.
static int park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
static int park_exec (struct ast_channel *chan, const char *data)
static int park_exec_full (struct ast_channel *chan, const char *data, 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 struct ast_app_option bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, }
static struct ast_call_feature builtin_features []
static struct ast_cli_entry cli_features []
static int comebacktoorigin = 1
static char courtesytone [256]
struct ast_parkinglotdefault_parkinglot
static struct ast_datastore_info dial_features_info
static int featuredigittimeout
static ast_rwlock_t features_lock = { 0 }
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 pickupfailsound [256]
static char pickupsound [256]
static char * registrar = "features"
static struct ast_appstopmixmonitor_app = NULL
static int stopmixmonitor_ok = 1
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 287 of file features.c.

#define DEFAULT_ATXFER_CALLBACK_RETRIES   2

Definition at line 285 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_DROP_CALL   0

Definition at line 283 of file features.c.

Referenced by load_config().

#define DEFAULT_ATXFER_LOOP_DELAY   10000

Definition at line 284 of file features.c.

Referenced by load_config().

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

Definition at line 280 of file features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 281 of file features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 278 of file features.c.

Referenced by build_parkinglot(), and load_config().

#define DEFAULT_PARKINGLOT   "default"

Default parking lot

Definition at line 282 of file features.c.

Referenced by load_config().

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 279 of file features.c.

Referenced by load_config().

#define FEATURES_COUNT   ARRAY_LEN(builtin_features)

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

Referenced by handle_feature_show().

#define MAX_DIAL_FEATURE_OPTIONS   30

Definition at line 288 of file features.c.

Referenced by manage_parkinglot().


Enumeration Type Documentation

anonymous enum

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

Definition at line 4792 of file features.c.

04792      {
04793    BRIDGE_OPT_PLAYTONE = (1 << 0),
04794    OPT_CALLEE_HANGUP =  (1 << 1),
04795    OPT_CALLER_HANGUP =  (1 << 2),
04796    OPT_DURATION_LIMIT = (1 << 3),
04797    OPT_DURATION_STOP =  (1 << 4),
04798    OPT_CALLEE_TRANSFER = (1 << 5),
04799    OPT_CALLER_TRANSFER = (1 << 6),
04800    OPT_CALLEE_MONITOR = (1 << 7),
04801    OPT_CALLER_MONITOR = (1 << 8),
04802    OPT_CALLEE_PARK = (1 << 9),
04803    OPT_CALLER_PARK = (1 << 10),
04804    OPT_CALLEE_KILL = (1 << 11),
04805 };

anonymous enum

Enumerator:
OPT_ARG_DURATION_LIMIT 
OPT_ARG_DURATION_STOP 
OPT_ARG_ARRAY_SIZE 

Definition at line 4807 of file features.c.

04807      {
04808    OPT_ARG_DURATION_LIMIT = 0,
04809    OPT_ARG_DURATION_STOP,
04810    /* note: this entry _MUST_ be the last one in the enum */
04811    OPT_ARG_ARRAY_SIZE,
04812 };

Options to pass to park_call_full

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

Definition at line 655 of file features.c.

00655                            {
00656    /*! Provide ringing to the parked caller instead of music on hold */
00657    AST_PARK_OPT_RINGING =   (1 << 0),
00658    /*! Randomly choose a parking spot for the caller instead of choosing
00659     *  the first one that is available. */
00660    AST_PARK_OPT_RANDOMIZE = (1 << 1),
00661    /*! Do not announce the parking number */
00662    AST_PARK_OPT_SILENCE = (1 << 2),
00663 };


Function Documentation

static void __fini_feature_groups ( void   )  [static]

Definition at line 306 of file features.c.

00315 {

static void __fini_feature_list ( void   )  [static]

Definition at line 1906 of file features.c.

01910 {

static void __init_feature_groups ( void   )  [static]

Definition at line 306 of file features.c.

00315 {

static void __init_feature_list ( void   )  [static]

Definition at line 1906 of file features.c.

01910 {

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

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

Referenced by ast_features_init().

04415 {
04416    const char *channela = astman_get_header(m, "Channel1");
04417    const char *channelb = astman_get_header(m, "Channel2");
04418    const char *playtone = astman_get_header(m, "Tone");
04419    struct ast_channel *chana = NULL, *chanb = NULL;
04420    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
04421    struct ast_bridge_thread_obj *tobj = NULL;
04422 
04423    /* make sure valid channels were specified */
04424    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
04425       astman_send_error(s, m, "Missing channel parameter in request");
04426       return 0;
04427    }
04428 
04429    /* Start with chana */
04430    chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
04431 
04432    /* send errors if any of the channels could not be found/locked */
04433    if (!chana) {
04434       char buf[256];
04435       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
04436       astman_send_error(s, m, buf);
04437       return 0;
04438    }
04439 
04440    /* Answer the channels if needed */
04441    if (chana->_state != AST_STATE_UP)
04442       ast_answer(chana);
04443 
04444    /* create the placeholder channels and grab the other channels */
04445    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04446       NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
04447       astman_send_error(s, m, "Unable to create temporary channel!");
04448       chana = ast_channel_unref(chana);
04449       return 1;
04450    }
04451 
04452    do_bridge_masquerade(chana, tmpchana);
04453 
04454    chana = ast_channel_unref(chana);
04455 
04456    /* now do chanb */
04457    chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
04458    /* send errors if any of the channels could not be found/locked */
04459    if (!chanb) {
04460       char buf[256];
04461       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
04462       ast_hangup(tmpchana);
04463       astman_send_error(s, m, buf);
04464       return 0;
04465    }
04466 
04467    /* Answer the channels if needed */
04468    if (chanb->_state != AST_STATE_UP)
04469       ast_answer(chanb);
04470 
04471    /* create the placeholder channels and grab the other channels */
04472    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04473       NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) {
04474       astman_send_error(s, m, "Unable to create temporary channels!");
04475       ast_hangup(tmpchana);
04476       chanb = ast_channel_unref(chanb);
04477       return 1;
04478    }
04479 
04480    do_bridge_masquerade(chanb, tmpchanb);
04481 
04482    chanb = ast_channel_unref(chanb);
04483 
04484    /* make the channels compatible, send error if we fail doing so */
04485    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
04486       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
04487       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
04488       ast_hangup(tmpchana);
04489       ast_hangup(tmpchanb);
04490       return 1;
04491    }
04492 
04493    /* setup the bridge thread object and start the bridge */
04494    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
04495       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
04496       astman_send_error(s, m, "Unable to spawn a new bridge thread");
04497       ast_hangup(tmpchana);
04498       ast_hangup(tmpchanb);
04499       return 1;
04500    }
04501 
04502    tobj->chan = tmpchana;
04503    tobj->peer = tmpchanb;
04504    tobj->return_to_pbx = 1;
04505 
04506    if (ast_true(playtone)) {
04507       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
04508          if (ast_waitstream(tmpchanb, "") < 0)
04509             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
04510       }
04511    }
04512 
04513    bridge_call_thread_launch(tobj);
04514 
04515    astman_send_ack(s, m, "Launched bridge thread with success");
04516 
04517    return 0;
04518 }

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

Definition at line 2645 of file features.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_datastore_alloc, ast_datastore_free(), AST_FLAGS_ALL, ast_log(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, ast_dial_features::features_callee, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, ast_datastore::inheritance, ast_dial_features::is_caller, and LOG_WARNING.

Referenced by ast_bridge_call().

02646 {
02647    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
02648    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
02649 
02650    ast_channel_lock(caller);
02651    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
02652    ast_channel_unlock(caller);
02653    if (!ds_caller_features) {
02654       if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02655          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
02656          return;
02657       }
02658       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
02659          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02660          ast_datastore_free(ds_caller_features);
02661          return;
02662       }
02663       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
02664       caller_features->is_caller = 1;
02665       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
02666       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
02667       ds_caller_features->data = caller_features;
02668       ast_channel_lock(caller);
02669       ast_channel_datastore_add(caller, ds_caller_features);
02670       ast_channel_unlock(caller);
02671    } else {
02672       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
02673        * flags over from the atxfer to the caller */
02674       return;
02675    }
02676 
02677    ast_channel_lock(callee);
02678    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
02679    ast_channel_unlock(callee);
02680    if (!ds_callee_features) {
02681       if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02682          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
02683          return;
02684       }
02685       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
02686          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02687          ast_datastore_free(ds_callee_features);
02688          return;
02689       }
02690       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
02691       callee_features->is_caller = 0;
02692       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
02693       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
02694       ds_callee_features->data = callee_features;
02695       ast_channel_lock(callee);
02696       ast_channel_datastore_add(callee, ds_callee_features);
02697       ast_channel_unlock(callee);
02698    }
02699 
02700    return;
02701 }

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

References ADSI_JUST_CENT, ast_adsi_load_session, ast_adsi_print, and justify.

Referenced by park_call_full().

00594 {
00595    int res;
00596    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00597    char tmp[256];
00598    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00599 
00600    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00601    message[0] = tmp;
00602    res = ast_adsi_load_session(chan, NULL, 0, 1);
00603    if (res == -1)
00604       return res;
00605    return ast_adsi_print(chan, message, justify, 1);
00606 }

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

bridge the call and set CDR

Bridge a call, optionally allowing redirection.

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

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

Todo:
XXX how do we guarantee the latter ?

Definition at line 2712 of file features.c.

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_bridge(), ast_channel_connected_line_macro(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_log(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, 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_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_free, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_channel::exten, f, feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_start_time, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_caller, ast_frame::frametype, 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, ast_frame::ptr, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_frame::subclass, ast_bridge_config::timelimit, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.

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

02713 {
02714    /* Copy voice back and forth between the two channels.  Give the peer
02715       the ability to transfer calls with '#<extension' syntax. */
02716    struct ast_frame *f;
02717    struct ast_channel *who;
02718    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
02719    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
02720    char orig_channame[AST_MAX_EXTENSION];
02721    char orig_peername[AST_MAX_EXTENSION];
02722    int res;
02723    int diff;
02724    int hasfeatures=0;
02725    int hadfeatures=0;
02726    int autoloopflag;
02727    struct ast_option_header *aoh;
02728    struct ast_cdr *bridge_cdr = NULL;
02729    struct ast_cdr *orig_peer_cdr = NULL;
02730    struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02731    struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02732    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02733    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02734 
02735    if (chan && peer) {
02736       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
02737       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
02738    } else if (chan) {
02739       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
02740    }
02741 
02742    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
02743    add_features_datastores(chan, peer, config);
02744 
02745    /* This is an interesting case.  One example is if a ringing channel gets redirected to
02746     * an extension that picks up a parked call.  This will make sure that the call taken
02747     * out of parking gets told that the channel it just got bridged to is still ringing. */
02748    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
02749       ast_indicate(peer, AST_CONTROL_RINGING);
02750    }
02751 
02752    if (monitor_ok) {
02753       const char *monitor_exec;
02754       struct ast_channel *src = NULL;
02755       if (!monitor_app) {
02756          if (!(monitor_app = pbx_findapp("Monitor")))
02757             monitor_ok=0;
02758       }
02759       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
02760          src = chan;
02761       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
02762          src = peer;
02763       if (monitor_app && src) {
02764          char *tmp = ast_strdupa(monitor_exec);
02765          pbx_exec(src, monitor_app, tmp);
02766       }
02767    }
02768 
02769    set_config_flags(chan, peer, config);
02770 
02771    /* Answer if need be */
02772    if (chan->_state != AST_STATE_UP) {
02773       if (ast_raw_answer(chan, 1)) {
02774          return -1;
02775       }
02776    }
02777 
02778 #ifdef FOR_DEBUG
02779    /* show the two channels and cdrs involved in the bridge for debug & devel purposes */
02780    ast_channel_log("Pre-bridge CHAN Channel info", chan);
02781    ast_channel_log("Pre-bridge PEER Channel info", peer);
02782 #endif
02783    /* two channels are being marked as linked here */
02784    ast_channel_set_linkgroup(chan,peer);
02785 
02786    /* copy the userfield from the B-leg to A-leg if applicable */
02787    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
02788       char tmp[256];
02789       if (!ast_strlen_zero(chan->cdr->userfield)) {
02790          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
02791          ast_cdr_appenduserfield(chan, tmp);
02792       } else
02793          ast_cdr_setuserfield(chan, peer->cdr->userfield);
02794       /* free the peer's cdr without ast_cdr_free complaining */
02795       ast_free(peer->cdr);
02796       peer->cdr = NULL;
02797    }
02798    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
02799    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
02800    orig_peer_cdr = peer_cdr;
02801    
02802    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
02803       
02804       if (chan_cdr) {
02805          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
02806          ast_cdr_update(chan);
02807          bridge_cdr = ast_cdr_dup(chan_cdr);
02808          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02809          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02810       } else {
02811          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
02812          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
02813          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
02814          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
02815          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
02816          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02817          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02818          ast_cdr_setcid(bridge_cdr, chan);
02819          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
02820          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
02821          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
02822          /* Destination information */
02823          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
02824          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
02825          if (peer_cdr) {
02826             bridge_cdr->start = peer_cdr->start;
02827             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02828          } else {
02829             ast_cdr_start(bridge_cdr);
02830          }
02831       }
02832       ast_debug(4,"bridge answer set, chan answer set\n");
02833       /* peer_cdr->answer will be set when a macro runs on the peer;
02834          in that case, the bridge answer will be delayed while the
02835          macro plays on the peer channel. The peer answered the call
02836          before the macro started playing. To the phone system,
02837          this is billable time for the call, even tho the caller
02838          hears nothing but ringing while the macro does its thing. */
02839 
02840       /* Another case where the peer cdr's time will be set, is when
02841          A self-parks by pickup up phone and dialing 700, then B
02842          picks up A by dialing its parking slot; there may be more 
02843          practical paths that get the same result, tho... in which
02844          case you get the previous answer time from the Park... which
02845          is before the bridge's start time, so I added in the 
02846          tvcmp check to the if below */
02847 
02848       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
02849          bridge_cdr->answer = peer_cdr->answer;
02850          bridge_cdr->disposition = peer_cdr->disposition;
02851          if (chan_cdr) {
02852             chan_cdr->answer = peer_cdr->answer;
02853             chan_cdr->disposition = peer_cdr->disposition;
02854          }
02855       } else {
02856          ast_cdr_answer(bridge_cdr);
02857          if (chan_cdr) {
02858             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
02859          }
02860       }
02861       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
02862          if (chan_cdr) {
02863             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
02864          }
02865          if (peer_cdr) {
02866             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
02867          }
02868       }
02869    }
02870    ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL);
02871    for (;;) {
02872       struct ast_channel *other; /* used later */
02873    
02874       res = ast_channel_bridge(chan, peer, config, &f, &who);
02875       
02876       /* When frame is not set, we are probably involved in a situation
02877          where we've timed out.
02878          When frame is set, we'll come this code twice; once for DTMF_BEGIN
02879          and also for DTMF_END. If we flow into the following 'if' for both, then 
02880          our wait times are cut in half, as both will subtract from the
02881          feature_timer. Not good!
02882       */
02883       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
02884          /* Update feature timer for next pass */
02885          diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
02886          if (res == AST_BRIDGE_RETRY) {
02887             /* The feature fully timed out but has not been updated. Skip
02888              * the potential round error from the diff calculation and
02889              * explicitly set to expired. */
02890             config->feature_timer = -1;
02891          } else {
02892             config->feature_timer -= diff;
02893          }
02894 
02895          if (hasfeatures) {
02896             if (config->feature_timer <= 0) {
02897                /* Not *really* out of time, just out of time for
02898                   digits to come in for features. */
02899                ast_debug(1, "Timed out for feature!\n");
02900                if (!ast_strlen_zero(peer_featurecode)) {
02901                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
02902                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
02903                }
02904                if (!ast_strlen_zero(chan_featurecode)) {
02905                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
02906                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
02907                }
02908                if (f)
02909                   ast_frfree(f);
02910                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02911                if (!hasfeatures) {
02912                   /* No more digits expected - reset the timer */
02913                   config->feature_timer = 0;
02914                }
02915                hadfeatures = hasfeatures;
02916                /* Continue as we were */
02917                continue;
02918             } else if (!f) {
02919                /* The bridge returned without a frame and there is a feature in progress.
02920                 * However, we don't think the feature has quite yet timed out, so just
02921                 * go back into the bridge. */
02922                continue;
02923             }
02924          } else {
02925             if (config->feature_timer <=0) {
02926                /* We ran out of time */
02927                config->feature_timer = 0;
02928                who = chan;
02929                if (f)
02930                   ast_frfree(f);
02931                f = NULL;
02932                res = 0;
02933             }
02934          }
02935       }
02936       if (res < 0) {
02937          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
02938             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
02939          }
02940          goto before_you_go;
02941       }
02942       
02943       if (!f || (f->frametype == AST_FRAME_CONTROL &&
02944             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
02945                f->subclass == AST_CONTROL_CONGESTION))) {
02946          res = -1;
02947          break;
02948       }
02949       /* many things should be sent to the 'other' channel */
02950       other = (who == chan) ? peer : chan;
02951       if (f->frametype == AST_FRAME_CONTROL) {
02952          switch (f->subclass) {
02953          case AST_CONTROL_RINGING:
02954          case AST_CONTROL_FLASH:
02955          case -1:
02956             ast_indicate(other, f->subclass);
02957             break;
02958          case AST_CONTROL_CONNECTED_LINE:
02959             if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
02960                break;
02961             }
02962             /* The implied "else" falls through purposely */
02963          case AST_CONTROL_HOLD:
02964          case AST_CONTROL_UNHOLD:
02965             ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
02966             break;
02967          case AST_CONTROL_OPTION:
02968             aoh = f->data.ptr;
02969             /* Forward option Requests */
02970             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02971                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
02972                   f->datalen - sizeof(struct ast_option_header), 0);
02973             }
02974             break;
02975          }
02976       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02977          /* eat it */
02978       } else if (f->frametype == AST_FRAME_DTMF) {
02979          char *featurecode;
02980          int sense;
02981 
02982          hadfeatures = hasfeatures;
02983          /* This cannot overrun because the longest feature is one shorter than our buffer */
02984          if (who == chan) {
02985             sense = FEATURE_SENSE_CHAN;
02986             featurecode = chan_featurecode;
02987          } else  {
02988             sense = FEATURE_SENSE_PEER;
02989             featurecode = peer_featurecode;
02990          }
02991          /*! append the event to featurecode. we rely on the string being zero-filled, and
02992           * not overflowing it. 
02993           * \todo XXX how do we guarantee the latter ?
02994           */
02995          featurecode[strlen(featurecode)] = f->subclass;
02996          /* Get rid of the frame before we start doing "stuff" with the channels */
02997          ast_frfree(f);
02998          f = NULL;
02999          config->feature_timer = 0;
03000          res = feature_interpret(chan, peer, config, featurecode, sense);
03001          switch(res) {
03002          case AST_FEATURE_RETURN_PASSDIGITS:
03003             ast_dtmf_stream(other, who, featurecode, 0, 0);
03004             /* Fall through */
03005          case AST_FEATURE_RETURN_SUCCESS:
03006             memset(featurecode, 0, sizeof(chan_featurecode));
03007             break;
03008          }
03009          if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
03010             res = 0;
03011          } else {
03012             break;
03013          }
03014          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
03015          if (hadfeatures && !hasfeatures) {
03016             /* Feature completed or timed out */
03017             config->feature_timer = 0;
03018          } else if (hasfeatures) {
03019             if (config->timelimit) {
03020                /* No warning next time - we are waiting for future */
03021                ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
03022             }
03023             config->feature_start_time = ast_tvnow();
03024             config->feature_timer = featuredigittimeout;
03025             ast_debug(1, "Set feature timer to %ld\n", config->feature_timer);
03026          }
03027       }
03028       if (f)
03029          ast_frfree(f);
03030 
03031    }
03032    ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL);
03033    before_you_go:
03034 
03035    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
03036       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
03037       if (bridge_cdr) {
03038          ast_cdr_discard(bridge_cdr);
03039          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
03040       }
03041       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
03042    }
03043 
03044    if (config->end_bridge_callback) {
03045       config->end_bridge_callback(config->end_bridge_callback_data);
03046    }
03047 
03048    /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 
03049     * if it were, then chan belongs to a different thread now, and might have been hung up long
03050      * ago.
03051     */
03052    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) &&
03053       ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
03054       struct ast_cdr *swapper = NULL;
03055       char savelastapp[AST_MAX_EXTENSION];
03056       char savelastdata[AST_MAX_EXTENSION];
03057       char save_exten[AST_MAX_EXTENSION];
03058       int  save_prio;
03059       int  found = 0;   /* set if we find at least one match */
03060       int  spawn_error = 0;
03061       
03062       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
03063       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
03064       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
03065          ast_cdr_end(bridge_cdr);
03066       }
03067       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
03068          dialplan code operate on it */
03069       ast_channel_lock(chan);
03070       if (bridge_cdr) {
03071          swapper = chan->cdr;
03072          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
03073          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
03074          chan->cdr = bridge_cdr;
03075       }
03076       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
03077       save_prio = chan->priority;
03078       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
03079       chan->priority = 1;
03080       ast_channel_unlock(chan);
03081       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) {
03082          chan->priority++;
03083       }
03084       if (found && spawn_error) {
03085          /* Something bad happened, or a hangup has been requested. */
03086          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03087          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
03088       }
03089       /* swap it back */
03090       ast_channel_lock(chan);
03091       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
03092       chan->priority = save_prio;
03093       if (bridge_cdr) {
03094          if (chan->cdr == bridge_cdr) {
03095             chan->cdr = swapper;
03096          } else {
03097             bridge_cdr = NULL;
03098          }
03099       }
03100       if (chan->priority != 1 || !spawn_error) {
03101          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
03102       }
03103       ast_channel_unlock(chan);
03104       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
03105       if (bridge_cdr) {
03106          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
03107          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
03108       }
03109       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03110    }
03111    
03112    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
03113    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
03114    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
03115       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
03116 
03117    /* we can post the bridge CDR at this point */
03118    if (bridge_cdr) {
03119       ast_cdr_end(bridge_cdr);
03120       ast_cdr_detach(bridge_cdr);
03121    }
03122    
03123    /* do a specialized reset on the beginning channel
03124       CDR's, if they still exist, so as not to mess up
03125       issues in future bridges;
03126       
03127       Here are the rules of the game:
03128       1. The chan and peer channel pointers will not change
03129          during the life of the bridge.
03130       2. But, in transfers, the channel names will change.
03131          between the time the bridge is started, and the
03132          time the channel ends. 
03133          Usually, when a channel changes names, it will
03134          also change CDR pointers.
03135       3. Usually, only one of the two channels (chan or peer)
03136          will change names.
03137       4. Usually, if a channel changes names during a bridge,
03138          it is because of a transfer. Usually, in these situations,
03139          it is normal to see 2 bridges running simultaneously, and
03140          it is not unusual to see the two channels that change
03141          swapped between bridges.
03142       5. After a bridge occurs, we have 2 or 3 channels' CDRs
03143          to attend to; if the chan or peer changed names,
03144          we have the before and after attached CDR's.
03145    */
03146 
03147    if (new_chan_cdr) {
03148       struct ast_channel *chan_ptr = NULL;
03149 
03150       if (strcasecmp(orig_channame, chan->name) != 0) { 
03151          /* old channel */
03152          if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
03153             ast_channel_lock(chan_ptr);
03154             if (!ast_bridged_channel(chan_ptr)) {
03155                struct ast_cdr *cur;
03156                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03157                   if (cur == chan_cdr) {
03158                      break;
03159                   }
03160                }
03161                if (cur) {
03162                   ast_cdr_specialized_reset(chan_cdr, 0);
03163                }
03164             }
03165             ast_channel_unlock(chan_ptr);
03166             chan_ptr = ast_channel_unref(chan_ptr);
03167          }
03168          /* new channel */
03169          ast_cdr_specialized_reset(new_chan_cdr, 0);
03170       } else {
03171          ast_cdr_specialized_reset(chan_cdr, 0); /* nothing changed, reset the chan_cdr  */
03172       }
03173    }
03174 
03175    {
03176       struct ast_channel *chan_ptr = NULL;
03177       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
03178       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))
03179          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
03180       if (strcasecmp(orig_peername, peer->name) != 0) { 
03181          /* old channel */
03182          if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
03183             ast_channel_lock(chan_ptr);
03184             if (!ast_bridged_channel(chan_ptr)) {
03185                struct ast_cdr *cur;
03186                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
03187                   if (cur == peer_cdr) {
03188                      break;
03189                   }
03190                }
03191                if (cur) {
03192                   ast_cdr_specialized_reset(peer_cdr, 0);
03193                }
03194             }
03195             ast_channel_unlock(chan_ptr);
03196             chan_ptr = ast_channel_unref(chan_ptr);
03197          }
03198          /* new channel */
03199          if (new_peer_cdr) {
03200             ast_cdr_specialized_reset(new_peer_cdr, 0);
03201          }
03202       } else {
03203          ast_cdr_specialized_reset(peer_cdr, 0); /* nothing changed, reset the peer_cdr  */
03204       }
03205    }
03206    
03207    return res;
03208 }

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

Definition at line 4829 of file features.c.

References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, ast_bridge_config::end_sound, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, pbx_builtin_getvar_helper(), ast_bridge_config::play_warning, S_OR, ast_bridge_config::start_sound, strsep(), ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by bridge_exec(), and dial_exec_full().

04831 {
04832    char *stringp = ast_strdupa(parse);
04833    char *limit_str, *warning_str, *warnfreq_str;
04834    const char *var;
04835    int play_to_caller = 0, play_to_callee = 0;
04836    int delta;
04837 
04838    limit_str = strsep(&stringp, ":");
04839    warning_str = strsep(&stringp, ":");
04840    warnfreq_str = strsep(&stringp, ":");
04841 
04842    config->timelimit = atol(limit_str);
04843    if (warning_str)
04844       config->play_warning = atol(warning_str);
04845    if (warnfreq_str)
04846       config->warning_freq = atol(warnfreq_str);
04847 
04848    if (!config->timelimit) {
04849       ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
04850       config->timelimit = config->play_warning = config->warning_freq = 0;
04851       config->warning_sound = NULL;
04852       return -1; /* error */
04853    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
04854       int w = config->warning_freq;
04855 
04856       /* If the first warning is requested _after_ the entire call would end,
04857          and no warning frequency is requested, then turn off the warning. If
04858          a warning frequency is requested, reduce the 'first warning' time by
04859          that frequency until it falls within the call's total time limit.
04860          Graphically:
04861               timelim->|    delta        |<-playwarning
04862          0__________________|_________________|
04863                 | w  |    |    |    |
04864 
04865          so the number of intervals to cut is 1+(delta-1)/w
04866       */
04867 
04868       if (w == 0) {
04869          config->play_warning = 0;
04870       } else {
04871          config->play_warning -= w * ( 1 + (delta-1)/w );
04872          if (config->play_warning < 1)
04873             config->play_warning = config->warning_freq = 0;
04874       }
04875    }
04876    
04877    ast_channel_lock(chan);
04878 
04879    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
04880    play_to_caller = var ? ast_true(var) : 1;
04881 
04882    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
04883    play_to_callee = var ? ast_true(var) : 0;
04884 
04885    if (!play_to_caller && !play_to_callee)
04886       play_to_caller = 1;
04887 
04888    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
04889    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
04890 
04891    /* The code looking at config wants a NULL, not just "", to decide
04892     * that the message should not be played, so we replace "" with NULL.
04893     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
04894     * not found.
04895     */
04896 
04897    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
04898    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
04899 
04900    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
04901    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
04902 
04903    ast_channel_unlock(chan);
04904 
04905    /* undo effect of S(x) in case they are both used */
04906    calldurationlimit->tv_sec = 0;
04907    calldurationlimit->tv_usec = 0;
04908 
04909    /* more efficient to do it like S(x) does since no advanced opts */
04910    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
04911       calldurationlimit->tv_sec = config->timelimit / 1000;
04912       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
04913       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
04914          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
04915       config->timelimit = play_to_caller = play_to_callee =
04916       config->play_warning = config->warning_freq = 0;
04917    } else {
04918       ast_verb(3, "Limit Data for this call:\n");
04919       ast_verb(4, "timelimit      = %ld\n", config->timelimit);
04920       ast_verb(4, "play_warning   = %ld\n", config->play_warning);
04921       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
04922       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
04923       ast_verb(4, "warning_freq   = %ld\n", config->warning_freq);
04924       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
04925       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
04926       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
04927    }
04928    if (play_to_caller)
04929       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
04930    if (play_to_callee)
04931       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
04932    return 0;
04933 }

void ast_channel_log ( char *  title,
struct ast_channel chan 
)

Definition at line 2580 of file features.c.

References ast_log(), and LOG_NOTICE.

Referenced by ast_bridge_call().

02581 {
02582        ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan);
02583        ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
02584                        chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority);
02585        ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
02586                        chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority);
02587        ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
02588                        chan->masq, chan->masqr,
02589                        chan->_bridge, chan->uniqueid, chan->linkedid);
02590        if (chan->masqr)
02591                ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
02592                                chan->masqr->name, chan->masqr->cdr);
02593        if (chan->_bridge)
02594                ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name);
02595 
02596    ast_log(LOG_NOTICE, "===== done ====\n");
02597 }

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

detect a feature before bridging

Parameters:
chan 
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 2336 of file features.c.

References feature_interpret_helper().

Referenced by detect_disconnect().

02336                                                                                                                                  {
02337 
02338    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02339 }

int ast_features_init ( void   ) 

int ast_features_reload ( void   ) 

Reload call features from features.conf.

Definition at line 4343 of file features.c.

References load_config().

Referenced by handle_features_reload().

04344 {
04345    int res;
04346    /* Release parking lot list */
04347    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04348    // TODO: I don't think any marking is necessary
04349 
04350    /* Reload configuration */
04351    res = load_config();
04352    
04353    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04354    return res;
04355 }

struct ast_call_feature* ast_find_call_feature ( const char *  name  )  [read]

look for a call feature entry by its sname

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

Definition at line 2082 of file features.c.

References FEATURES_COUNT, and ast_call_feature::sname.

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

02083 {
02084    int x;
02085    for (x = 0; x < FEATURES_COUNT; x++) {
02086       if (!strcasecmp(name, builtin_features[x].sname))
02087          return &builtin_features[x];
02088    }
02089    return NULL;
02090 }

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

References masq_park_call().

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

01011 {
01012    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
01013 }

int ast_park_call ( struct ast_channel chan,
struct ast_channel peer,
int  timeout,
int *  extout 
)

Park a call.

Park a call and read back parked location.

Definition at line 944 of file features.c.

References park_call_full(), and ast_park_call_args::timeout.

Referenced by iax_park_thread(), and sip_park_thread().

00945 {
00946    struct ast_park_call_args args = {
00947       .timeout = timeout,
00948       .extout = extout,
00949    };
00950 
00951    return park_call_full(chan, peer, &args);
00952 }

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

References parking_ext.

Referenced by __analog_ss_thread(), analog_ss_thread(), build_parkinglot(), builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), load_config(), mgcp_ss(), and socket_process().

00432 {
00433    return parking_ext;
00434 }

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

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

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

04734 {
04735    struct ast_channel *cur;
04736    struct ast_party_connected_line connected_caller;
04737    int res;
04738    const char *chan_name;
04739    const char *cur_name;
04740 
04741    if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
04742       ast_debug(1, "No call pickup possible...\n");
04743       if (!ast_strlen_zero(pickupfailsound)) {
04744          ast_stream_and_wait(chan, pickupfailsound, "");
04745       }
04746       return -1;
04747    }
04748 
04749    ast_channel_lock_both(cur, chan);
04750 
04751    cur_name = ast_strdupa(cur->name);
04752    chan_name = ast_strdupa(chan->name);
04753 
04754    ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name);
04755 
04756    connected_caller = cur->connected;
04757    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
04758    if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
04759       ast_channel_update_connected_line(chan, &connected_caller);
04760    }
04761 
04762    ast_party_connected_line_collect_caller(&connected_caller, &chan->cid);
04763    connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
04764    ast_channel_queue_connected_line_update(chan, &connected_caller);
04765 
04766    ast_channel_unlock(cur);
04767    ast_channel_unlock(chan);
04768 
04769    if (ast_answer(chan)) {
04770       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
04771    }
04772 
04773    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
04774       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
04775    }
04776 
04777    if ((res = ast_channel_masquerade(cur, chan))) {
04778       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name);
04779    }
04780 
04781    if (!ast_strlen_zero(pickupsound)) {
04782       ast_stream_and_wait(cur, pickupsound, "");
04783    }
04784 
04785    cur = ast_channel_unref(cur);
04786 
04787    return res;
04788 }

const char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 436 of file features.c.

References pickup_ext.

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

00437 {
00438    return pickup_ext;
00439 }

void ast_rdlock_call_features ( void   ) 

Definition at line 2072 of file features.c.

References ast_rwlock_rdlock(), and features_lock.

Referenced by handle_request_info().

02073 {
02074    ast_rwlock_rdlock(&features_lock);
02075 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_list

register new feature into feature_set

Definition at line 1909 of file features.c.

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

Referenced by load_config().

01910 {
01911    if (!feature) {
01912       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01913       return;
01914    }
01915   
01916    AST_RWLIST_WRLOCK(&feature_list);
01917    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01918    AST_RWLIST_UNLOCK(&feature_list);
01919 
01920    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01921 }

void ast_unlock_call_features ( void   ) 

Definition at line 2077 of file features.c.

References ast_rwlock_unlock(), and features_lock.

Referenced by handle_request_info().

02078 {
02079    ast_rwlock_unlock(&features_lock);
02080 }

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

References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

01998 {
01999    if (!feature) {
02000       return;
02001    }
02002 
02003    AST_RWLIST_WRLOCK(&feature_list);
02004    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
02005    AST_RWLIST_UNLOCK(&feature_list);
02006 
02007    ast_free(feature);
02008 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 2011 of file features.c.

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

Referenced by load_config().

02012 {
02013    struct ast_call_feature *feature;
02014 
02015    AST_RWLIST_WRLOCK(&feature_list);
02016    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
02017       ast_free(feature);
02018    }
02019    AST_RWLIST_UNLOCK(&feature_list);
02020 }

static void ast_unregister_groups ( void   )  [static]

Remove all feature groups in the list.

Definition at line 2037 of file features.c.

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

Referenced by load_config().

02038 {
02039    struct feature_group *fg;
02040    struct feature_group_exten *fge;
02041 
02042    AST_RWLIST_WRLOCK(&feature_groups);
02043    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
02044       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
02045          ast_string_field_free_memory(fge);
02046          ast_free(fge);
02047       }
02048 
02049       ast_string_field_free_memory(fg);
02050       ast_free(fg);
02051    }
02052    AST_RWLIST_UNLOCK(&feature_groups);
02053 }

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

bridge the call

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

Definition at line 528 of file features.c.

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

Referenced by bridge_call_thread_launch().

00529 {
00530    struct ast_bridge_thread_obj *tobj = data;
00531    int res;
00532 
00533    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00534    tobj->chan->data = tobj->peer->name;
00535    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00536    tobj->peer->data = tobj->chan->name;
00537 
00538    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00539 
00540    if (tobj->return_to_pbx) {
00541       if (!ast_check_hangup(tobj->peer)) {
00542          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00543          res = ast_pbx_start(tobj->peer);
00544          if (res != AST_PBX_SUCCESS)
00545             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00546       } else
00547          ast_hangup(tobj->peer);
00548       if (!ast_check_hangup(tobj->chan)) {
00549          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00550          res = ast_pbx_start(tobj->chan);
00551          if (res != AST_PBX_SUCCESS)
00552             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00553       } else
00554          ast_hangup(tobj->chan);
00555    } else {
00556       ast_hangup(tobj->chan);
00557       ast_hangup(tobj->peer);
00558    }
00559 
00560    ast_free(tobj);
00561 
00562    return NULL;
00563 }

static void bridge_call_thread_launch ( void *  data  )  [static]

create thread for the parked call

Parameters:
data Create thread and attributes, call bridge_call_thread

Definition at line 571 of file features.c.

References ast_pthread_create, bridge_call_thread(), and thread.

Referenced by action_bridge(), and builtin_atxfer().

00572 {
00573    pthread_t thread;
00574    pthread_attr_t attr;
00575    struct sched_param sched;
00576 
00577    pthread_attr_init(&attr);
00578    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00579    ast_pthread_create(&thread, &attr, bridge_call_thread, data);
00580    pthread_attr_destroy(&attr);
00581    memset(&sched, 0, sizeof(sched));
00582    pthread_setschedparam(thread, SCHED_RR, &sched);
00583 }

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

Bridge channels.

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

Definition at line 4945 of file features.c.

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

Referenced by ast_features_init().

04946 {
04947    struct ast_channel *current_dest_chan, *final_dest_chan;
04948    char *tmp_data  = NULL;
04949    struct ast_flags opts = { 0, };
04950    struct ast_bridge_config bconfig = { { 0, }, };
04951    char *opt_args[OPT_ARG_ARRAY_SIZE];
04952    struct timeval calldurationlimit = { 0, };
04953 
04954    AST_DECLARE_APP_ARGS(args,
04955       AST_APP_ARG(dest_chan);
04956       AST_APP_ARG(options);
04957    );
04958    
04959    if (ast_strlen_zero(data)) {
04960       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
04961       return -1;
04962    }
04963 
04964    tmp_data = ast_strdupa(data);
04965    AST_STANDARD_APP_ARGS(args, tmp_data);
04966    if (!ast_strlen_zero(args.options))
04967       ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
04968 
04969    /* avoid bridge with ourselves */
04970    if (!strncmp(chan->name, args.dest_chan, 
04971       strlen(chan->name) < strlen(args.dest_chan) ? 
04972       strlen(chan->name) : strlen(args.dest_chan))) {
04973       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
04974       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04975                "Response: Failed\r\n"
04976                "Reason: Unable to bridge channel to itself\r\n"
04977                "Channel1: %s\r\n"
04978                "Channel2: %s\r\n",
04979                chan->name, args.dest_chan);
04980       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
04981       return 0;
04982    }
04983 
04984    /* make sure we have a valid end point */
04985    if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
04986          strlen(args.dest_chan)))) {
04987       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
04988          "cannot get its lock\n", args.dest_chan);
04989       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04990                "Response: Failed\r\n"
04991                "Reason: Cannot grab end point\r\n"
04992                "Channel1: %s\r\n"
04993                "Channel2: %s\r\n", chan->name, args.dest_chan);
04994       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
04995       return 0;
04996    }
04997 
04998    /* answer the channel if needed */
04999    if (current_dest_chan->_state != AST_STATE_UP) {
05000       ast_answer(current_dest_chan);
05001    }
05002 
05003    /* try to allocate a place holder where current_dest_chan will be placed */
05004    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
05005       NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
05006       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
05007       manager_event(EVENT_FLAG_CALL, "BridgeExec",
05008                "Response: Failed\r\n"
05009                "Reason: cannot create placeholder\r\n"
05010                "Channel1: %s\r\n"
05011                "Channel2: %s\r\n", chan->name, args.dest_chan);
05012    }
05013 
05014    ast_channel_unlock(current_dest_chan);
05015 
05016    do_bridge_masquerade(current_dest_chan, final_dest_chan);
05017 
05018    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
05019    /* try to make compatible, send error if we fail */
05020    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
05021       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
05022       manager_event(EVENT_FLAG_CALL, "BridgeExec",
05023                "Response: Failed\r\n"
05024                "Reason: Could not make channels compatible for bridge\r\n"
05025                "Channel1: %s\r\n"
05026                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05027       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
05028       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
05029       current_dest_chan = ast_channel_unref(current_dest_chan);
05030       return 0;
05031    }
05032 
05033    /* Report that the bridge will be successfull */
05034    manager_event(EVENT_FLAG_CALL, "BridgeExec",
05035             "Response: Success\r\n"
05036             "Channel1: %s\r\n"
05037             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
05038 
05039    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
05040    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
05041       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
05042          if (ast_waitstream(final_dest_chan, "") < 0)
05043             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
05044       }
05045    }
05046    
05047    current_dest_chan = ast_channel_unref(current_dest_chan);
05048    
05049    if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
05050       if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
05051          goto done;
05052    }
05053 
05054    if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
05055       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
05056    if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
05057       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
05058    if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
05059       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
05060    if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
05061       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
05062    if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
05063       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
05064    if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 
05065       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
05066    if (ast_test_flag(&opts, OPT_CALLEE_PARK))
05067       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
05068    if (ast_test_flag(&opts, OPT_CALLER_PARK))
05069       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
05070 
05071    ast_bridge_call(chan, final_dest_chan, &bconfig);
05072 
05073    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
05074    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
05075    if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) {
05076       ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 
05077          final_dest_chan->context, final_dest_chan->exten, 
05078          final_dest_chan->priority, final_dest_chan->name);
05079 
05080       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
05081          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
05082          ast_hangup(final_dest_chan);
05083       } else
05084          ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
05085    } else {
05086       ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name);
05087       ast_hangup(final_dest_chan);
05088    }
05089 done:
05090    if (bconfig.warning_sound) {
05091       ast_free((char *)bconfig.warning_sound);
05092    }
05093    if (bconfig.end_sound) {
05094       ast_free((char *)bconfig.end_sound);
05095    }
05096    if (bconfig.start_sound) {
05097       ast_free((char *)bconfig.start_sound);
05098    }
05099 
05100    return 0;
05101 }

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

Build parkinglot from configuration and chain it in.

Definition at line 3818 of file features.c.

References ao2_link, ao2_lock(), ao2_unlock(), ast_add_extension2(), ast_context_find_or_create(), ast_copy_string(), ast_free_ptr, ast_log(), ast_parking_ext(), ast_strlen_zero(), create_parkinglot(), DEFAULT_PARK_TIME, find_parkinglot(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_parkinglot::mohclass, ast_variable::name, ast_variable::next, option_debug, parkcall, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglot_destroy(), parkinglot_unref(), parkinglots, ast_parkinglot::parkingtime, registrar, strdup, and ast_variable::value.

Referenced by load_config().

03819 {
03820    struct ast_parkinglot *parkinglot;
03821    struct ast_context *con = NULL;
03822 
03823    struct ast_variable *confvar = var;
03824    int error = 0;
03825    int start = 0, end = 0;
03826    int oldparkinglot = 0;
03827 
03828    parkinglot = find_parkinglot(name);
03829    if (parkinglot)
03830       oldparkinglot = 1;
03831    else
03832       parkinglot = create_parkinglot(name);
03833 
03834    if (!parkinglot)
03835       return NULL;
03836 
03837    ao2_lock(parkinglot);
03838 
03839    if (option_debug)
03840       ast_log(LOG_DEBUG, "Building parking lot %s\n", name);
03841    
03842    /* Do some config stuff */
03843    while(confvar) {
03844       if (!strcasecmp(confvar->name, "context")) {
03845          ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
03846       } else if (!strcasecmp(confvar->name, "parkingtime")) {
03847          if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
03848             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
03849             parkinglot->parkingtime = DEFAULT_PARK_TIME;
03850          } else
03851             parkinglot->parkingtime = parkinglot->parkingtime * 1000;
03852       } else if (!strcasecmp(confvar->name, "parkpos")) {
03853          if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) {
03854             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);
03855             error = 1;
03856          } else {
03857             parkinglot->parking_start = start;
03858             parkinglot->parking_stop = end;
03859          }
03860       } else if (!strcasecmp(confvar->name, "findslot")) {
03861          parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next"));
03862       }
03863       confvar = confvar->next;
03864    }
03865    /* make sure parkingtime is set if not specified */
03866    if (parkinglot->parkingtime == 0) {
03867       parkinglot->parkingtime = DEFAULT_PARK_TIME;
03868    }
03869 
03870    if (!var) { /* Default parking lot */
03871       ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
03872       ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial));
03873       ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass));
03874    }
03875 
03876    /* Check for errors */
03877    if (ast_strlen_zero(parkinglot->parking_con)) {
03878       ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name);
03879       error = 1;
03880    }
03881 
03882    /* Create context */
03883    if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) {
03884       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
03885       error = 1;
03886    }
03887 
03888    /* Add a parking extension into the context */
03889    if (!error && !oldparkinglot) {
03890       if (!ast_strlen_zero(ast_parking_ext())) {
03891          if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
03892             error = 1;
03893       }
03894    }
03895 
03896    ao2_unlock(parkinglot);
03897 
03898    if (error) {
03899       ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
03900       parkinglot_destroy(parkinglot);
03901       return NULL;
03902    }
03903    if (option_debug)
03904       ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
03905 
03906 
03907    /* Move it into the list, if it wasn't already there */
03908    if (!oldparkinglot) {
03909       ao2_link(parkinglots, parkinglot);
03910    }
03911    parkinglot_unref(parkinglot);
03912 
03913    return parkinglot;
03914 }

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

Attended transfer.

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

Definition at line 1513 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_calloc, AST_CEL_ATTENDEDTRANSFER, ast_cel_report_event(), ast_channel_alloc, ast_channel_connected_line_macro(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_channel_update_connected_line(), ast_check_hangup(), ast_clear_flag, ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_SUCCESS, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_parking_ext(), ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_read(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, ast_bridge_thread_obj::bconfig, bridge_call_thread_launch(), builtin_parkcall(), ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::connected, ast_channel::context, ast_datastore::data, ast_bridge_config::end_bridge_callback_data_fixup, ast_channel::exten, f, feature_request_and_dial(), ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), ast_channel::language, ast_channel::linkedid, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_party_connected_line::source, strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xferfailsound, and xfersound.

01514 {
01515    struct ast_channel *transferer;
01516    struct ast_channel *transferee;
01517    const char *transferer_real_context;
01518    char xferto[256] = "";
01519    int res;
01520    int outstate=0;
01521    struct ast_channel *newchan;
01522    struct ast_channel *xferchan;
01523    struct ast_bridge_thread_obj *tobj;
01524    struct ast_bridge_config bconfig;
01525    struct ast_frame *f;
01526    int l;
01527    struct ast_party_connected_line connected_line;
01528    struct ast_datastore *features_datastore;
01529    struct ast_dial_features *dialfeatures = NULL;
01530 
01531    ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
01532    set_peers(&transferer, &transferee, peer, chan, sense);
01533    transferer_real_context = real_ctx(transferer, transferee);
01534    /* Start autoservice on chan while we talk to the originator */
01535    ast_autoservice_start(transferee);
01536    ast_indicate(transferee, AST_CONTROL_HOLD);
01537    
01538    /* Transfer */
01539    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01540    if (res < 0) {
01541       finishup(transferee);
01542       return res;
01543    }
01544    if (res > 0) /* If they've typed a digit already, handle it */
01545       xferto[0] = (char) res;
01546 
01547    /* this is specific of atxfer */
01548    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01549    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
01550       finishup(transferee);
01551       return res;
01552    }
01553    if (res == 0) {
01554       ast_log(LOG_WARNING, "Did not read data.\n");
01555       finishup(transferee);
01556       if (ast_stream_and_wait(transferer, "beeperr", ""))
01557          return -1;
01558       return AST_FEATURE_RETURN_SUCCESS;
01559    }
01560 
01561    /* valid extension, res == 1 */
01562    if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01563       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
01564       finishup(transferee);
01565       if (ast_stream_and_wait(transferer, "beeperr", ""))
01566          return -1;
01567       return AST_FEATURE_RETURN_SUCCESS;
01568    }
01569 
01570    /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of
01571     * the different variables for handling this properly with a builtin_atxfer */
01572    if (!strcmp(xferto, ast_parking_ext())) {
01573       finishup(transferee);
01574       return builtin_parkcall(chan, peer, config, code, sense, data);
01575    }
01576 
01577    l = strlen(xferto);
01578    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);   /* append context */
01579 
01580    /* If we are performing an attended transfer and we have two channels involved then
01581       copy sound file information to play upon attended transfer completion */
01582    if (transferee) {
01583       const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
01584       const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
01585 
01586       if (!ast_strlen_zero(chan1_attended_sound)) {
01587          pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
01588       }
01589       if (!ast_strlen_zero(chan2_attended_sound)) {
01590          pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
01591       }
01592    }
01593 
01594    newchan = feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01595       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01596 
01597    ast_party_connected_line_init(&connected_line);
01598    if (!ast_check_hangup(transferer)) {
01599       /* Transferer is up - old behaviour */
01600       ast_indicate(transferer, -1);
01601       if (!newchan) {
01602          finishup(transferee);
01603          /* any reason besides user requested cancel and busy triggers the failed sound */
01604          if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
01605             ast_stream_and_wait(transferer, xferfailsound, ""))
01606             return -1;
01607          if (ast_stream_and_wait(transferer, xfersound, ""))
01608             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01609          return AST_FEATURE_RETURN_SUCCESS;
01610       }
01611 
01612       if (check_compat(transferer, newchan)) {
01613          /* we do mean transferee here, NOT transferer */
01614          finishup(transferee);
01615          return -1;
01616       }
01617       memset(&bconfig,0,sizeof(struct ast_bridge_config));
01618       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
01619       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
01620       /* We need to get the transferer's connected line information copied
01621        * at this point because he is likely to hang up during the bridge with
01622        * newchan. This info will be used down below before bridging the 
01623        * transferee and newchan
01624        *
01625        * As a result, we need to be sure to free this data before returning
01626        * or overwriting it.
01627        */
01628       ast_channel_lock(transferer);
01629       ast_party_connected_line_copy(&connected_line, &transferer->connected);
01630       ast_channel_unlock(transferer);
01631       res = ast_bridge_call(transferer, newchan, &bconfig);
01632       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
01633          ast_hangup(newchan);
01634          if (ast_stream_and_wait(transferer, xfersound, ""))
01635             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01636          finishup(transferee);
01637          transferer->_softhangup = 0;
01638          ast_party_connected_line_free(&connected_line);
01639          return AST_FEATURE_RETURN_SUCCESS;
01640       }
01641 
01642       ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
01643 
01644       if (check_compat(transferee, newchan)) {
01645          finishup(transferee);
01646          ast_party_connected_line_free(&connected_line);
01647          return -1;
01648       }
01649       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01650 
01651       if ((ast_autoservice_stop(transferee) < 0)
01652        || (ast_waitfordigit(transferee, 100) < 0)
01653        || (ast_waitfordigit(newchan, 100) < 0)
01654        || ast_check_hangup(transferee)
01655        || ast_check_hangup(newchan)) {
01656          ast_hangup(newchan);
01657          ast_party_connected_line_free(&connected_line);
01658          return -1;
01659       }
01660       xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name);
01661       if (!xferchan) {
01662          ast_hangup(newchan);
01663          ast_party_connected_line_free(&connected_line);
01664          return -1;
01665       }
01666       /* Make formats okay */
01667       xferchan->visible_indication = transferer->visible_indication;
01668       xferchan->readformat = transferee->readformat;
01669       xferchan->writeformat = transferee->writeformat;
01670       ast_channel_masquerade(xferchan, transferee);
01671       ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01672       xferchan->_state = AST_STATE_UP;
01673       ast_clear_flag(xferchan, AST_FLAGS_ALL);
01674       xferchan->_softhangup = 0;
01675       if ((f = ast_read(xferchan)))
01676          ast_frfree(f);
01677       newchan->_state = AST_STATE_UP;
01678       ast_clear_flag(newchan, AST_FLAGS_ALL);
01679       newchan->_softhangup = 0;
01680       if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01681          ast_hangup(xferchan);
01682          ast_hangup(newchan);
01683          ast_party_connected_line_free(&connected_line);
01684          return -1;
01685       }
01686 
01687       ast_channel_lock(newchan);
01688       if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
01689             dialfeatures = features_datastore->data;
01690       }
01691       ast_channel_unlock(newchan);
01692 
01693       if (dialfeatures) {
01694          /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
01695             I don't currently understand, the abilities of newchan seem to be stored on the caller side */
01696          ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01697          dialfeatures = NULL;
01698       }
01699 
01700       ast_channel_lock(xferchan);
01701       if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
01702          dialfeatures = features_datastore->data;
01703       }
01704       ast_channel_unlock(xferchan);
01705     
01706       if (dialfeatures) {
01707          ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01708       }
01709     
01710       tobj->chan = newchan;
01711       tobj->peer = xferchan;
01712       tobj->bconfig = *config;
01713 
01714       if (tobj->bconfig.end_bridge_callback_data_fixup) {
01715          tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01716       }
01717 
01718       /* Due to a limitation regarding when callerID is set on a Local channel,
01719        * we use the transferer's connected line information here.
01720        */
01721 
01722       /* xferchan is transferee, and newchan is the transfer target
01723        * So...in a transfer, who is the caller and who is the callee?
01724        *
01725        * When the call is originally made, it is clear who is caller and callee.
01726        * When a transfer occurs, it is my humble opinion that the transferee becomes
01727        * the caller, and the transfer target is the callee.
01728        *
01729        * The problem is that these macros were set with the intention of the original
01730        * caller and callee taking those roles. A transfer can totally mess things up,
01731        * to be technical. What sucks even more is that you can't effectively change
01732        * the macros in the dialplan during the call from the transferer to the transfer
01733        * target because the transferee is stuck with whatever role he originally had.
01734        *
01735        * I think the answer here is just to make sure that it is well documented that
01736        * during a transfer, the transferee is the "caller" and the transfer target
01737        * is the "callee."
01738        *
01739        * This means that if party A calls party B, and party A transfers party B to
01740        * party C, then B has switched roles for the call. Now party B will have the
01741        * caller macro called on his channel instead of the callee macro.
01742        *
01743        * Luckily, the method by which the bridge is launched here ensures that the 
01744        * transferee is the "chan" on the bridge and the transfer target is the "peer,"
01745        * so my idea for the roles post-transfer does not require extensive code changes.
01746        */
01747       connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
01748       if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
01749          ast_channel_update_connected_line(xferchan, &connected_line);
01750       }
01751       ast_channel_lock(xferchan);
01752       ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid);
01753       ast_channel_unlock(xferchan);
01754       connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
01755       if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
01756          ast_channel_update_connected_line(newchan, &connected_line);
01757       }
01758       ast_party_connected_line_free(&connected_line);
01759 
01760       if (ast_stream_and_wait(newchan, xfersound, ""))
01761          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01762       bridge_call_thread_launch(tobj);
01763       return -1;      /* XXX meaning the channel is bridged ? */
01764    } else if (!ast_check_hangup(transferee)) {
01765       /* act as blind transfer */
01766       if (ast_autoservice_stop(transferee) < 0) {
01767          ast_hangup(newchan);
01768          return -1;
01769       }
01770 
01771       if (!newchan) {
01772          unsigned int tries = 0;
01773          char *transferer_tech, *transferer_name = ast_strdupa(transferer->name);
01774 
01775          transferer_tech = strsep(&transferer_name, "/");
01776          transferer_name = strsep(&transferer_name, "-");
01777 
01778          if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
01779             ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name);
01780             if (ast_stream_and_wait(transferee, "beeperr", ""))
01781                return -1;
01782             return AST_FEATURE_RETURN_SUCCESS;
01783          }
01784 
01785          ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name);
01786          newchan = feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01787             transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01788          while (!newchan && !atxferdropcall && tries < atxfercallbackretries) {
01789             /* Trying to transfer again */
01790             ast_autoservice_start(transferee);
01791             ast_indicate(transferee, AST_CONTROL_HOLD);
01792 
01793             newchan = feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01794                xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01795             if (ast_autoservice_stop(transferee) < 0) {
01796                if (newchan)
01797                   ast_hangup(newchan);
01798                return -1;
01799             }
01800             if (!newchan) {
01801                /* Transfer failed, sleeping */
01802                ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay);
01803                ast_safe_sleep(transferee, atxferloopdelay);
01804                ast_debug(1, "Trying to callback...\n");
01805                newchan = feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01806                   transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01807             }
01808             tries++;
01809          }
01810       }
01811       if (!newchan)
01812          return -1;
01813 
01814       ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
01815 
01816       /* newchan is up, we should prepare transferee and bridge them */
01817       if (check_compat(transferee, newchan)) {
01818          finishup(transferee);
01819          return -1;
01820       }
01821       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01822 
01823       if ((ast_waitfordigit(transferee, 100) < 0)
01824          || (ast_waitfordigit(newchan, 100) < 0)
01825          || ast_check_hangup(transferee)
01826          || ast_check_hangup(newchan)) {
01827          ast_hangup(newchan);
01828          return -1;
01829       }
01830 
01831       xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name);
01832       if (!xferchan) {
01833          ast_hangup(newchan);
01834          return -1;
01835       }
01836       /* Make formats okay */
01837       xferchan->visible_indication = transferer->visible_indication;
01838       xferchan->readformat = transferee->readformat;
01839       xferchan->writeformat = transferee->writeformat;
01840       ast_channel_masquerade(xferchan, transferee);
01841       ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01842       xferchan->_state = AST_STATE_UP;
01843       ast_clear_flag(xferchan, AST_FLAGS_ALL);
01844       xferchan->_softhangup = 0;
01845       if ((f = ast_read(xferchan)))
01846          ast_frfree(f);
01847       newchan->_state = AST_STATE_UP;
01848       ast_clear_flag(newchan, AST_FLAGS_ALL);
01849       newchan->_softhangup = 0;
01850       if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01851          ast_hangup(xferchan);
01852          ast_hangup(newchan);
01853          return -1;
01854       }
01855       tobj->chan = newchan;
01856       tobj->peer = xferchan;
01857       tobj->bconfig = *config;
01858       
01859       if (tobj->bconfig.end_bridge_callback_data_fixup) {
01860          tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01861       }
01862 
01863       ast_channel_lock(newchan);
01864       ast_connected_line_copy_from_caller(&connected_line, &newchan->cid);
01865       ast_channel_unlock(newchan);
01866       connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
01867       if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
01868          ast_channel_update_connected_line(xferchan, &connected_line);
01869       }
01870       ast_channel_lock(xferchan);
01871       ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid);
01872       ast_channel_unlock(xferchan);
01873       connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
01874       if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
01875          ast_channel_update_connected_line(newchan, &connected_line);
01876       }
01877 
01878       ast_party_connected_line_free(&connected_line);
01879       
01880       if (ast_stream_and_wait(newchan, xfersound, ""))
01881          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01882       bridge_call_thread_launch(tobj);
01883       return -1;      /* XXX meaning the channel is bridged ? */
01884    } else {
01885       /* Transferee hung up */
01886       finishup(transferee);
01887       return -1;
01888    }
01889 }

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

Definition at line 1218 of file features.c.

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

01219 {
01220    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01221    int x = 0;
01222    size_t len;
01223    struct ast_channel *caller_chan, *callee_chan;
01224    const char *mixmonitor_spy_type = "MixMonitor";
01225    int count = 0;
01226 
01227    if (!mixmonitor_ok) {
01228       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01229       return -1;
01230    }
01231 
01232    if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
01233       mixmonitor_ok = 0;
01234       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01235       return -1;
01236    }
01237 
01238    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01239 
01240    if (!ast_strlen_zero(courtesytone)) {
01241       if (ast_autoservice_start(callee_chan))
01242          return -1;
01243       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
01244          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01245          ast_autoservice_stop(callee_chan);
01246          return -1;
01247       }
01248       if (ast_autoservice_stop(callee_chan))
01249          return -1;
01250    }
01251 
01252    ast_channel_lock(callee_chan);
01253    count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01254    ast_channel_unlock(callee_chan);
01255 
01256    /* This means a mixmonitor is attached to the channel, running or not is unknown. */
01257    if (count > 0) {
01258       
01259       ast_verb(3, "User hit '%s' to stop recording call.\n", code);
01260 
01261       /* Make sure they are running */
01262       ast_channel_lock(callee_chan);
01263       count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01264       ast_channel_unlock(callee_chan);
01265       if (count > 0) {
01266          if (!stopmixmonitor_ok) {
01267             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01268             return -1;
01269          }
01270          if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
01271             stopmixmonitor_ok = 0;
01272             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01273             return -1;
01274          } else {
01275             pbx_exec(callee_chan, stopmixmonitor_app, "");
01276             return AST_FEATURE_RETURN_SUCCESS;
01277          }
01278       }
01279       
01280       ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 
01281    }        
01282 
01283    if (caller_chan && callee_chan) {
01284       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
01285       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
01286 
01287       if (!touch_format)
01288          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
01289 
01290       if (!touch_monitor)
01291          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
01292 
01293       if (touch_monitor) {
01294          len = strlen(touch_monitor) + 50;
01295          args = alloca(len);
01296          touch_filename = alloca(len);
01297          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
01298          snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
01299       } else {
01300          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
01301          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
01302          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01303          args = alloca(len);
01304          touch_filename = alloca(len);
01305          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
01306          snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
01307       }
01308 
01309       for( x = 0; x < strlen(args); x++) {
01310          if (args[x] == '/')
01311             args[x] = '-';
01312       }
01313 
01314       ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
01315 
01316       pbx_exec(callee_chan, mixmonitor_app, args);
01317       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01318       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01319       return AST_FEATURE_RETURN_SUCCESS;
01320    
01321    }
01322 
01323    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
01324    return -1;
01325 
01326 }

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

Monitor a channel by DTMF.

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

Definition at line 1125 of file features.c.

References AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::cid, ast_callerid::cid_num, courtesytone, len(), LOG_ERROR, LOG_NOTICE, ast_channel::monitor, monitor_app, monitor_ok, 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.

01126 {
01127    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01128    int x = 0;
01129    size_t len;
01130    struct ast_channel *caller_chan, *callee_chan;
01131    const char *automon_message_start = NULL;
01132    const char *automon_message_stop = NULL;
01133 
01134    if (!monitor_ok) {
01135       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
01136       return -1;
01137    }
01138 
01139    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
01140       monitor_ok = 0;
01141       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
01142       return -1;
01143    }
01144 
01145    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01146    if (caller_chan) {   /* Find extra messages */
01147       automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
01148       automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
01149    }
01150 
01151    if (!ast_strlen_zero(courtesytone)) {  /* Play courtesy tone if configured */
01152       if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
01153          return -1;
01154       }
01155    }
01156    
01157    if (callee_chan->monitor) {
01158       ast_verb(4, "User hit '%s' to stop recording call.\n", code);
01159       if (!ast_strlen_zero(automon_message_stop)) {
01160          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
01161       }
01162       callee_chan->monitor->stop(callee_chan, 1);
01163       return AST_FEATURE_RETURN_SUCCESS;
01164    }
01165 
01166    if (caller_chan && callee_chan) {
01167       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
01168       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
01169       const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
01170 
01171       if (!touch_format)
01172          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
01173 
01174       if (!touch_monitor)
01175          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
01176    
01177       if (!touch_monitor_prefix)
01178          touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
01179    
01180       if (touch_monitor) {
01181          len = strlen(touch_monitor) + 50;
01182          args = alloca(len);
01183          touch_filename = alloca(len);
01184          snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
01185          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
01186       } else {
01187          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
01188          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
01189          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01190          args = alloca(len);
01191          touch_filename = alloca(len);
01192          snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
01193          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
01194       }
01195 
01196       for(x = 0; x < strlen(args); x++) {
01197          if (args[x] == '/')
01198             args[x] = '-';
01199       }
01200       
01201       ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
01202 
01203       pbx_exec(callee_chan, monitor_app, args);
01204       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01205       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01206 
01207       if (!ast_strlen_zero(automon_message_start)) {  /* Play start message for both channels */
01208          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
01209       }
01210    
01211       return AST_FEATURE_RETURN_SUCCESS;
01212    }
01213    
01214    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
01215    return -1;
01216 }

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

Blind transfer user to another extension.

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

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

Definition at line 1378 of file features.c.

References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CEL_BLINDTRANSFER, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_update_connected_line(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), AST_FEATURE_RETURN_PARKFAILED, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, ast_stopstream(), ast_stream_and_wait(), ast_verb, ast_channel::cdr, ast_cdr::channel, check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_channel::connected, 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.

01379 {
01380    struct ast_channel *transferer;
01381    struct ast_channel *transferee;
01382    const char *transferer_real_context;
01383    char xferto[256];
01384    int res, parkstatus = 0;
01385 
01386    set_peers(&transferer, &transferee, peer, chan, sense);
01387    transferer_real_context = real_ctx(transferer, transferee);
01388    /* Start autoservice on chan while we talk to the originator */
01389    ast_autoservice_start(transferee);
01390    ast_indicate(transferee, AST_CONTROL_HOLD);
01391 
01392    memset(xferto, 0, sizeof(xferto));
01393 
01394    /* Transfer */
01395    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01396    if (res < 0) {
01397       finishup(transferee);
01398       return -1; /* error ? */
01399    }
01400    if (res > 0)   /* If they've typed a digit already, handle it */
01401       xferto[0] = (char) res;
01402 
01403    ast_stopstream(transferer);
01404    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01405    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
01406       finishup(transferee);
01407       return res;
01408    }
01409    if (!strcmp(xferto, ast_parking_ext())) {
01410       res = finishup(transferee);
01411       if (res)
01412          res = -1;
01413       else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) {   /* success */
01414          /* We return non-zero, but tell the PBX not to hang the channel when
01415             the thread dies -- We have to be careful now though.  We are responsible for 
01416             hanging up the channel, else it will never be hung up! */
01417 
01418          return 0;
01419       } else {
01420          ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01421       }
01422       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
01423    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01424       ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
01425       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01426       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01427       res=finishup(transferee);
01428       if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
01429          transferer->cdr=ast_cdr_alloc();
01430          if (transferer->cdr) {
01431             ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */
01432             ast_cdr_start(transferer->cdr);
01433          }
01434       }
01435       if (transferer->cdr) {
01436          struct ast_cdr *swap = transferer->cdr;
01437          ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01438                transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 
01439                transferer->cdr->channel, transferer->cdr->dstchannel);
01440          ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01441                transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01442          ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01443          /* swap cdrs-- it will save us some time & work */
01444          transferer->cdr = transferee->cdr;
01445          transferee->cdr = swap;
01446       }
01447       if (!transferee->pbx) {
01448          /* Doh!  Use our handy async_goto functions */
01449          ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01450                         ,transferee->name, xferto, transferer_real_context);
01451          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01452             ast_log(LOG_WARNING, "Async goto failed :-(\n");
01453       } else {
01454          /* Set the channel's new extension, since it exists, using transferer context */
01455          ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
01456          ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01457          if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) {
01458             ast_channel_update_connected_line(transferee, &transferer->connected);
01459          }
01460          set_c_e_p(transferee, transferer_real_context, xferto, 0);
01461       }
01462       check_goto_on_transfer(transferer);
01463       return res;
01464    } else {
01465       ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
01466    }
01467    if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
01468       finishup(transferee);
01469       return -1;
01470    }
01471    ast_stopstream(transferer);
01472    res = finishup(transferee);
01473    if (res) {
01474       ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01475       return res;
01476    }
01477    return AST_FEATURE_RETURN_SUCCESS;
01478 }

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

Definition at line 1328 of file features.c.

References AST_FEATURE_RETURN_HANGUP, and ast_verb.

01329 {
01330    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
01331    return AST_FEATURE_RETURN_HANGUP;
01332 }

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

support routing for one touch call parking

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

Definition at line 1055 of file features.c.

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

Referenced by builtin_atxfer().

01056 {
01057    struct ast_channel *parker;
01058    struct ast_channel *parkee;
01059    int res = 0;
01060 
01061    set_peers(&parker, &parkee, peer, chan, sense);
01062    /* we used to set chan's exten and priority to "s" and 1
01063       here, but this generates (in some cases) an invalid
01064       extension, and if "s" exists, could errantly
01065       cause execution of extensions you don't expect. It
01066       makes more sense to let nature take its course
01067       when chan finishes, and let the pbx do its thing
01068       and hang up when the park is over.
01069    */
01070    if (chan->_state != AST_STATE_UP)
01071       res = ast_answer(chan);
01072    if (!res)
01073       res = ast_safe_sleep(chan, 1000);
01074 
01075    if (!res) { /* one direction used to call park_call.... */
01076       res = masq_park_call_announce(parkee, parker, 0, NULL);
01077       /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
01078    }
01079 
01080    return res;
01081 }

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

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

03230 {
03231    int i = 0;
03232    enum {
03233       OPT_CALLEE_REDIRECT   = 't',
03234       OPT_CALLER_REDIRECT   = 'T',
03235       OPT_CALLEE_AUTOMON    = 'w',
03236       OPT_CALLER_AUTOMON    = 'W',
03237       OPT_CALLEE_DISCONNECT = 'h',
03238       OPT_CALLER_DISCONNECT = 'H',
03239       OPT_CALLEE_PARKCALL   = 'k',
03240       OPT_CALLER_PARKCALL   = 'K',
03241    };
03242 
03243    memset(options, 0, len);
03244    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
03245       options[i++] = OPT_CALLER_REDIRECT;
03246    }
03247    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
03248       options[i++] = OPT_CALLER_AUTOMON;
03249    }
03250    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
03251       options[i++] = OPT_CALLER_DISCONNECT;
03252    }
03253    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
03254       options[i++] = OPT_CALLER_PARKCALL;
03255    }
03256 
03257    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
03258       options[i++] = OPT_CALLEE_REDIRECT;
03259    }
03260    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
03261       options[i++] = OPT_CALLEE_AUTOMON;
03262    }
03263    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
03264       options[i++] = OPT_CALLEE_DISCONNECT;
03265    }
03266    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
03267       options[i++] = OPT_CALLEE_PARKCALL;
03268    }
03269 
03270    return options;
03271 }

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

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

Referenced by builtin_atxfer().

01488 {
01489    if (ast_channel_make_compatible(c, newchan) < 0) {
01490       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01491          c->name, newchan->name);
01492       ast_hangup(newchan);
01493       return -1;
01494    }
01495    return 0;
01496 }

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

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

Referenced by builtin_blindtransfer().

00483 {
00484    struct ast_channel *xferchan;
00485    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00486    char *x, *goto_on_transfer;
00487    struct ast_frame *f;
00488 
00489    if (ast_strlen_zero(val))
00490       return;
00491 
00492    goto_on_transfer = ast_strdupa(val);
00493 
00494    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, "%s", chan->name)))
00495       return;
00496 
00497    for (x = goto_on_transfer; x && *x; x++) {
00498       if (*x == '^')
00499          *x = '|';
00500    }
00501    /* Make formats okay */
00502    xferchan->readformat = chan->readformat;
00503    xferchan->writeformat = chan->writeformat;
00504    ast_channel_masquerade(xferchan, chan);
00505    ast_parseable_goto(xferchan, goto_on_transfer);
00506    xferchan->_state = AST_STATE_UP;
00507    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00508    xferchan->_softhangup = 0;
00509    if ((f = ast_read(xferchan))) {
00510       ast_frfree(f);
00511       f = NULL;
00512       ast_pbx_start(xferchan);
00513    } else {
00514       ast_hangup(xferchan);
00515    }
00516 }

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

Allocate parking lot structure.

Definition at line 3789 of file features.c.

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

Referenced by build_parkinglot().

03790 {
03791    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
03792 
03793    if (!name)
03794       return NULL;
03795 
03796    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
03797    if (!newlot)
03798       return NULL;
03799    
03800    ast_copy_string(newlot->name, name, sizeof(newlot->name));
03801    AST_LIST_HEAD_INIT(&newlot->parkings);
03802 
03803    return newlot;
03804 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 409 of file features.c.

References ast_free.

00410 {
00411    struct ast_dial_features *df = data;
00412    if (df) {
00413       ast_free(df);
00414    }
00415 }

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

Definition at line 396 of file features.c.

References ast_calloc.

00397 {
00398    struct ast_dial_features *df = data, *df_copy;
00399  
00400    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00401       return NULL;
00402    }
00403  
00404    memcpy(df_copy, df, sizeof(*df));
00405  
00406    return df_copy;
00407 }

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

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

Referenced by action_bridge(), and bridge_exec().

04383 {
04384    ast_moh_stop(chan);
04385    ast_channel_lock_both(chan, tmpchan);
04386    ast_setstate(tmpchan, chan->_state);
04387    tmpchan->readformat = chan->readformat;
04388    tmpchan->writeformat = chan->writeformat;
04389    ast_channel_masquerade(tmpchan, chan);
04390    ast_channel_unlock(chan);
04391    ast_channel_unlock(tmpchan);
04392 
04393    /* must be done without any channel locks held */
04394    ast_do_masquerade(tmpchan);
04395 
04396    /* when returning from bridge, the channel will continue at the next priority */
04397    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
04398 }

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

03457 {
03458    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
03459    fd_set nrfds, nefds; /* args for the next select */
03460    FD_ZERO(&rfds);
03461    FD_ZERO(&efds);
03462 
03463    for (;;) {
03464       int res = 0;
03465       int ms = -1;   /* select timeout, uninitialized */
03466       int max = -1;  /* max fd, none there yet */
03467       struct ao2_iterator iter;
03468       struct ast_parkinglot *curlot;
03469       FD_ZERO(&nrfds);
03470       FD_ZERO(&nefds);
03471       iter = ao2_iterator_init(parkinglots, 0);
03472 
03473       while ((curlot = ao2_iterator_next(&iter))) {
03474          res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max);
03475          ao2_ref(curlot, -1);
03476       }
03477 
03478       rfds = nrfds;
03479       efds = nefds;
03480       {
03481          struct timeval wait = ast_samp2tv(ms, 1000);
03482          /* Wait for something to happen */
03483          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
03484       }
03485       pthread_testcancel();
03486    }
03487    return NULL;   /* Never reached */
03488 }

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

exec an app by feature

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

Todo:
XXX should probably return res

Definition at line 2101 of file features.c.

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

Referenced by load_config().

02102 {
02103    struct ast_app *app;
02104    struct ast_call_feature *feature = data;
02105    struct ast_channel *work, *idle;
02106    int res;
02107 
02108    if (!feature) { /* shouldn't ever happen! */
02109       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
02110       return -1; 
02111    }
02112 
02113    if (sense == FEATURE_SENSE_CHAN) {
02114       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
02115          return AST_FEATURE_RETURN_KEEPTRYING;
02116       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02117          work = chan;
02118          idle = peer;
02119       } else {
02120          work = peer;
02121          idle = chan;
02122       }
02123    } else {
02124       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
02125          return AST_FEATURE_RETURN_KEEPTRYING;
02126       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
02127          work = peer;
02128          idle = chan;
02129       } else {
02130          work = chan;
02131          idle = peer;
02132       }
02133    }
02134 
02135    if (!(app = pbx_findapp(feature->app))) {
02136       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
02137       return -2;
02138    }
02139 
02140    ast_autoservice_start(idle);
02141    
02142    if(work && idle) {
02143       pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name);
02144       pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name);
02145       pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
02146       pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
02147    }
02148 
02149    if (!ast_strlen_zero(feature->moh_class))
02150       ast_moh_start(idle, feature->moh_class, NULL);
02151 
02152    res = pbx_exec(work, app, feature->app_args);
02153 
02154    if (!ast_strlen_zero(feature->moh_class))
02155       ast_moh_stop(idle);
02156 
02157    ast_autoservice_stop(idle);
02158 
02159    if (res) {
02160       return AST_FEATURE_RETURN_SUCCESSBREAK;
02161    }
02162    return AST_FEATURE_RETURN_SUCCESS;  /*! \todo XXX should probably return res */
02163 }

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

Check the dynamic features.

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

Definition at line 2307 of file features.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

02307                                                                                                                                                 {
02308 
02309    char dynamic_features_buf[128];
02310    const char *peer_dynamic_features, *chan_dynamic_features;
02311    struct ast_flags features;
02312    struct ast_call_feature feature;
02313    if (sense == FEATURE_SENSE_CHAN) {
02314       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
02315    }
02316    else {
02317       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
02318    }
02319 
02320    ast_channel_lock(peer);
02321    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
02322    ast_channel_unlock(peer);
02323 
02324    ast_channel_lock(chan);
02325    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
02326    ast_channel_unlock(chan);
02327 
02328    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,""));
02329 
02330    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);
02331 
02332    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
02333 }

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

Helper function for feature_interpret and ast_feature_detect.

Parameters:
chan,peer,config,code,sense,dynamic_features 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 2203 of file features.c.

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

Referenced by ast_feature_detect(), and feature_interpret().

02206 {
02207    int x;
02208    struct feature_group *fg = NULL;
02209    struct feature_group_exten *fge;
02210    struct ast_call_feature *tmpfeature;
02211    char *tmp, *tok;
02212    int res = AST_FEATURE_RETURN_PASSDIGITS;
02213    int feature_detected = 0;
02214 
02215    if (!(peer && chan && config) && operation) {
02216       return -1; /* can not run feature operation */
02217    }
02218 
02219    ast_rwlock_rdlock(&features_lock);
02220    for (x = 0; x < FEATURES_COUNT; x++) {
02221       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
02222           !ast_strlen_zero(builtin_features[x].exten)) {
02223          /* Feature is up for consideration */
02224          if (!strcmp(builtin_features[x].exten, code)) {
02225             ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
02226             if (operation) {
02227                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
02228             }
02229             memcpy(feature, &builtin_features[x], sizeof(feature));
02230             feature_detected = 1;
02231             break;
02232          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
02233             if (res == AST_FEATURE_RETURN_PASSDIGITS)
02234                res = AST_FEATURE_RETURN_STOREDIGITS;
02235          }
02236       }
02237    }
02238    ast_rwlock_unlock(&features_lock);
02239 
02240    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
02241       return res;
02242    }
02243 
02244    tmp = dynamic_features_buf;
02245 
02246    while ((tok = strsep(&tmp, "#"))) {
02247       AST_RWLIST_RDLOCK(&feature_groups);
02248 
02249       fg = find_group(tok);
02250 
02251       if (fg) {
02252          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
02253             if (strcasecmp(fge->exten, code))
02254                continue;
02255             if (operation) {
02256                res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
02257             }
02258             memcpy(feature, fge->feature, sizeof(feature));
02259             if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02260                AST_RWLIST_UNLOCK(&feature_groups);
02261                break;
02262             }
02263             res = AST_FEATURE_RETURN_PASSDIGITS;
02264          }
02265          if (fge)
02266             break;
02267       }
02268 
02269       AST_RWLIST_UNLOCK(&feature_groups);
02270 
02271       AST_RWLIST_RDLOCK(&feature_list);
02272 
02273       if (!(tmpfeature = find_dynamic_feature(tok))) {
02274          AST_RWLIST_UNLOCK(&feature_list);
02275          continue;
02276       }
02277 
02278       /* Feature is up for consideration */
02279       if (!strcmp(tmpfeature->exten, code)) {
02280          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
02281          if (operation) {
02282             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
02283          }
02284          memcpy(feature, tmpfeature, sizeof(feature));
02285          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02286             AST_RWLIST_UNLOCK(&feature_list);
02287             break;
02288          }
02289          res = AST_FEATURE_RETURN_PASSDIGITS;
02290       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
02291          res = AST_FEATURE_RETURN_STOREDIGITS;
02292 
02293       AST_RWLIST_UNLOCK(&feature_list);
02294    }
02295 
02296    return res;
02297 }

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

Get feature and dial.

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

Definition at line 2394 of file features.c.

References ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_connected_line_macro(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, 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_indicate_data(), 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(), ast_channel::call_forward, cause, ast_channel::cid, ast_channel::connected, ast_frame::data, ast_frame::datalen, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_frame::frametype, len(), LOG_NOTICE, ast_channel::name, pbx_builtin_setvar_helper(), ast_frame::ptr, and ast_frame::subclass.

Referenced by builtin_atxfer().

02395 {
02396    int state = 0;
02397    int cause = 0;
02398    int to;
02399    struct ast_channel *chan;
02400    struct ast_channel *monitor_chans[2];
02401    struct ast_channel *active_channel;
02402    int res = 0, ready = 0;
02403    struct timeval started;
02404    int x, len = 0;
02405    char *disconnect_code = NULL, *dialed_code = NULL;
02406 
02407    if (!(chan = ast_request(type, format, caller, data, &cause))) {
02408       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
02409       switch(cause) {
02410       case AST_CAUSE_BUSY:
02411          state = AST_CONTROL_BUSY;
02412          break;
02413       case AST_CAUSE_CONGESTION:
02414          state = AST_CONTROL_CONGESTION;
02415          break;
02416       }
02417       goto done;
02418    }
02419 
02420    ast_set_callerid(chan, cid_num, cid_name, cid_num);
02421    ast_string_field_set(chan, language, language);
02422    ast_channel_inherit_variables(caller, chan); 
02423    pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
02424       
02425    ast_channel_lock(chan);
02426    ast_connected_line_copy_from_caller(&chan->connected, &caller->cid);
02427    ast_channel_unlock(chan);
02428    
02429    if (ast_call(chan, data, timeout)) {
02430       ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
02431       goto done;
02432    }
02433    
02434    ast_indicate(caller, AST_CONTROL_RINGING);
02435    /* support dialing of the featuremap disconnect code while performing an attended tranfer */
02436    ast_rwlock_rdlock(&features_lock);
02437    for (x = 0; x < FEATURES_COUNT; x++) {
02438       if (strcasecmp(builtin_features[x].sname, "disconnect"))
02439          continue;
02440 
02441       disconnect_code = builtin_features[x].exten;
02442       len = strlen(disconnect_code) + 1;
02443       dialed_code = alloca(len);
02444       memset(dialed_code, 0, len);
02445       break;
02446    }
02447    ast_rwlock_unlock(&features_lock);
02448    x = 0;
02449    started = ast_tvnow();
02450    to = timeout;
02451 
02452    ast_poll_channel_add(caller, chan);
02453 
02454    while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
02455       struct ast_frame *f = NULL;
02456 
02457       monitor_chans[0] = caller;
02458       monitor_chans[1] = chan;
02459       active_channel = ast_waitfor_n(monitor_chans, 2, &to);
02460 
02461       /* see if the timeout has been violated */
02462       if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
02463          state = AST_CONTROL_UNHOLD;
02464          ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
02465          break; /*doh! timeout*/
02466       }
02467 
02468       if (!active_channel)
02469          continue;
02470 
02471       if (chan && (chan == active_channel)){
02472          if (!ast_strlen_zero(chan->call_forward)) {
02473             if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) {
02474                return NULL;
02475             }
02476             continue;
02477          }
02478          f = ast_read(chan);
02479          if (f == NULL) { /*doh! where'd he go?*/
02480             state = AST_CONTROL_HANGUP;
02481             res = 0;
02482             break;
02483          }
02484          
02485          if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
02486             if (f->subclass == AST_CONTROL_RINGING) {
02487                state = f->subclass;
02488                ast_verb(3, "%s is ringing\n", chan->name);
02489                ast_indicate(caller, AST_CONTROL_RINGING);
02490             } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
02491                state = f->subclass;
02492                ast_verb(3, "%s is busy\n", chan->name);
02493                ast_indicate(caller, AST_CONTROL_BUSY);
02494                ast_frfree(f);
02495                f = NULL;
02496                break;
02497             } else if (f->subclass == AST_CONTROL_ANSWER) {
02498                /* This is what we are hoping for */
02499                state = f->subclass;
02500                ast_frfree(f);
02501                f = NULL;
02502                ready=1;
02503                break;
02504             } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) {
02505                if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
02506                   ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
02507                }
02508             } else if (f->subclass != -1 && f->subclass != AST_CONTROL_PROGRESS) {
02509                ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
02510             }
02511             /* else who cares */
02512          } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
02513             ast_write(caller, f);
02514          }
02515 
02516       } else if (caller && (active_channel == caller)) {
02517          f = ast_read(caller);
02518          if (f == NULL) { /*doh! where'd he go?*/
02519             if (!igncallerstate) {
02520                if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
02521                   /* make this a blind transfer */
02522                   ready = 1;
02523                   break;
02524                }
02525                state = AST_CONTROL_HANGUP;
02526                res = 0;
02527                break;
02528             }
02529          } else {
02530          
02531             if (f->frametype == AST_FRAME_DTMF) {
02532                dialed_code[x++] = f->subclass;
02533                dialed_code[x] = '\0';
02534                if (strlen(dialed_code) == len) {
02535                   x = 0;
02536                } else if (x && strncmp(dialed_code, disconnect_code, x)) {
02537                   x = 0;
02538                   dialed_code[x] = '\0';
02539                }
02540                if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
02541                   /* Caller Canceled the call */
02542                   state = AST_CONTROL_UNHOLD;
02543                   ast_frfree(f);
02544                   f = NULL;
02545                   break;
02546                }
02547             } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
02548                ast_write(chan, f);
02549             }
02550          }
02551       }
02552       if (f)
02553          ast_frfree(f);
02554    } /* end while */
02555 
02556    ast_poll_channel_del(caller, chan);
02557       
02558 done:
02559    ast_indicate(caller, -1);
02560    if (chan && ready) {
02561       if (chan->_state == AST_STATE_UP) 
02562          state = AST_CONTROL_ANSWER;
02563       res = 0;
02564    } else if (chan) {
02565       res = -1;
02566       ast_hangup(chan);
02567       chan = NULL;
02568    } else {
02569       res = -1;
02570    }
02571    
02572    if (outstate)
02573       *outstate = state;
02574 
02575    return chan;
02576 }

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

Definition at line 4709 of file features.c.

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

Referenced by ast_pickup_call().

04710 {
04711    struct ast_channel *c = data;
04712    struct ast_channel *chan = obj;
04713 
04714    int i = !chan->pbx &&
04715       /* Accessing 'chan' here is safe without locking, because there is no way for
04716          the channel do disappear from under us at this point.  pickupgroup *could*
04717          change while we're here, but that isn't a problem. */
04718       (c != chan) &&
04719       (chan->pickupgroup & c->callgroup) &&
04720       ((chan->_state == AST_STATE_RINGING) || (chan->_state == AST_STATE_RING));
04721 
04722    return i ? CMP_MATCH | CMP_STOP : 0;
04723 }

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

find a call feature by name

Definition at line 2023 of file features.c.

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

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

02024 {
02025    struct ast_call_feature *tmp;
02026 
02027    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
02028       if (!strcasecmp(tmp->sname, name)) {
02029          break;
02030       }
02031    }
02032 
02033    return tmp;
02034 }

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

Find a group by name.

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

Definition at line 2061 of file features.c.

References AST_LIST_TRAVERSE, and feature_group::gname.

Referenced by feature_interpret_helper().

02061                                                           {
02062    struct feature_group *fg = NULL;
02063 
02064    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
02065       if (!strcasecmp(fg->gname, name))
02066          break;
02067    }
02068 
02069    return fg;
02070 }

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

Find parkinglot by name.

Definition at line 3491 of file features.c.

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

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

03492 {
03493    struct ast_parkinglot *parkinglot = NULL;
03494    struct ast_parkinglot tmp_parkinglot;
03495    
03496    if (ast_strlen_zero(name))
03497       return NULL;
03498 
03499    ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
03500 
03501    parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
03502 
03503    if (parkinglot && option_debug)
03504       ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
03505 
03506    return parkinglot;
03507 }

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

Find parking lot name from channel.

Definition at line 609 of file features.c.

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

Referenced by park_exec_full(), and park_space_reserve().

00610 {
00611    const char *temp, *parkinglot = NULL;
00612 
00613    /* Check if the channel has a parking lot */
00614    if (!ast_strlen_zero(chan->parkinglot))
00615       parkinglot = chan->parkinglot;
00616 
00617    /* Channel variables override everything */
00618 
00619    if ((temp  = pbx_builtin_getvar_helper(chan, "PARKINGLOT")))
00620       return temp;
00621 
00622    return parkinglot;
00623 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 1334 of file features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

01335 {
01336    ast_indicate(chan, AST_CONTROL_UNHOLD);
01337 
01338    return ast_autoservice_stop(chan);
01339 }

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

References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, ast_call_feature::exten, ast_cli_args::fd, FEATURES_COUNT, 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.

04284 {
04285    int i;
04286    struct ast_call_feature *feature;
04287    struct ao2_iterator iter;
04288    struct ast_parkinglot *curlot;
04289 #define HFS_FORMAT "%-25s %-7s %-7s\n"
04290 
04291    switch (cmd) {
04292    
04293    case CLI_INIT:
04294       e->command = "features show";
04295       e->usage =
04296          "Usage: features show\n"
04297          "       Lists configured features\n";
04298       return NULL;
04299    case CLI_GENERATE:
04300       return NULL;
04301    }
04302 
04303    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
04304    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
04305 
04306    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
04307 
04308    ast_rwlock_rdlock(&features_lock);
04309    for (i = 0; i < FEATURES_COUNT; i++)
04310       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
04311    ast_rwlock_unlock(&features_lock);
04312 
04313    ast_cli(a->fd, "\n");
04314    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
04315    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
04316    if (AST_RWLIST_EMPTY(&feature_list)) {
04317       ast_cli(a->fd, "(none)\n");
04318    } else {
04319       AST_RWLIST_RDLOCK(&feature_list);
04320       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
04321          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
04322       }
04323       AST_RWLIST_UNLOCK(&feature_list);
04324    }
04325 
04326    // loop through all the parking lots
04327    iter = ao2_iterator_init(parkinglots, 0);
04328 
04329    while ((curlot = ao2_iterator_next(&iter))) {
04330       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
04331       ast_cli(a->fd, "------------\n");
04332       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", parking_ext);
04333       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->parking_con);
04334       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
04335       ast_cli(a->fd,"\n");
04336       ao2_ref(curlot, -1);
04337    }
04338 
04339 
04340    return CLI_SUCCESS;
04341 }

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

Definition at line 4357 of file features.c.

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

04358 {
04359    switch (cmd) { 
04360    case CLI_INIT:
04361       e->command = "features reload";
04362       e->usage =
04363          "Usage: features reload\n"
04364          "       Reloads configured call features from features.conf\n";
04365       return NULL;
04366    case CLI_GENERATE:
04367       return NULL;
04368    }
04369    ast_features_reload();
04370 
04371    return CLI_SUCCESS;
04372 }

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

04532 {
04533    struct parkeduser *cur;
04534    int numparked = 0;
04535    struct ao2_iterator iter;
04536    struct ast_parkinglot *curlot;
04537 
04538    switch (cmd) {
04539    case CLI_INIT:
04540       e->command = "parkedcalls show";
04541       e->usage =
04542          "Usage: parkedcalls show\n"
04543          "       List currently parked calls\n";
04544       return NULL;
04545    case CLI_GENERATE:
04546       return NULL;
04547    }
04548 
04549    if (a->argc > e->args)
04550       return CLI_SHOWUSAGE;
04551 
04552    ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
04553       , "Context", "Extension", "Pri", "Timeout");
04554 
04555    iter = ao2_iterator_init(parkinglots, 0);
04556    while ((curlot = ao2_iterator_next(&iter))) {
04557       int lotparked = 0;
04558       ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name);
04559 
04560       AST_LIST_LOCK(&curlot->parkings);
04561       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04562          ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
04563             ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
04564             ,cur->priority,
04565             (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
04566          numparked++;
04567          numparked += lotparked;
04568       }
04569       AST_LIST_UNLOCK(&curlot->parkings);
04570       if (lotparked)
04571          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
04572 
04573       ao2_ref(curlot, -1);
04574    }
04575 
04576    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
04577 
04578    return CLI_SUCCESS;
04579 }

static int load_config ( void   )  [static]

Todo:
XXX var_name or app_args ?

Definition at line 3936 of file features.c.

References adsipark, ao2_lock(), ao2_unlock(), ast_call_feature::app, app, ast_call_feature::app_args, ARRAY_LEN, ast_add_extension2(), ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load2(), ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FEATURE_FLAG_ONPEER, AST_FEATURE_FLAG_ONSELF, ast_find_call_feature(), ast_log(), ast_parking_ext(), ast_register_feature(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_unregister_groups(), ast_variable_browse(), ast_verb, atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_TIME, DEFAULT_PARKINGLOT, default_parkinglot, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_MOH_LEN, FEATURE_SNAME_LEN, featuredigittimeout, find_dynamic_feature(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_variable::name, ast_variable::next, notify_metermaids(), ast_call_feature::operation, option_debug, park_add_hints(), parkcall, parkedplay, parking_ext, pickup_ext, pickupfailsound, pickupsound, register_group(), register_group_feature(), registrar, remap_feature(), ast_call_feature::sname, strsep(), transferdigittimeout, unmap_features(), ast_variable::value, var, xferfailsound, and xfersound.

03937 {
03938    int start = 0, end = 0;
03939    int res;
03940    int i;
03941    struct ast_context *con = NULL;
03942    struct ast_config *cfg = NULL;
03943    struct ast_variable *var = NULL;
03944    struct feature_group *fg = NULL;
03945    struct ast_flags config_flags = { 0 };
03946    char old_parking_ext[AST_MAX_EXTENSION];
03947    char old_parking_con[AST_MAX_EXTENSION] = "";
03948    char *ctg; 
03949    static const char * const categories[] = { 
03950       /* Categories in features.conf that are not
03951        * to be parsed as group categories
03952        */
03953       "general",
03954       "featuremap",
03955       "applicationmap"
03956    };
03957 
03958    if (default_parkinglot) {
03959       strcpy(old_parking_con, default_parkinglot->parking_con);
03960       strcpy(old_parking_ext, parking_ext);
03961    } else {
03962       default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
03963       if (default_parkinglot) {
03964          ao2_lock(default_parkinglot);
03965          default_parkinglot->parking_start = 701;
03966          default_parkinglot->parking_stop = 750;
03967          default_parkinglot->parking_offset = 0;
03968          default_parkinglot->parkfindnext = 0;
03969          default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
03970          ao2_unlock(default_parkinglot);
03971       }
03972    }
03973    if (default_parkinglot) {
03974       if (option_debug)
03975          ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n");
03976    } else {
03977       ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n");
03978       return -1;
03979    }
03980    
03981 
03982    /* Reset to defaults */
03983    strcpy(parking_ext, "700");
03984    strcpy(pickup_ext, "*8");
03985    courtesytone[0] = '\0';
03986    strcpy(xfersound, "beep");
03987    strcpy(xferfailsound, "pbx-invalid");
03988    pickupsound[0] = '\0';
03989    pickupfailsound[0] = '\0';
03990    adsipark = 0;
03991    comebacktoorigin = 1;
03992 
03993    default_parkinglot->parkaddhints = 0;
03994    default_parkinglot->parkedcalltransfers = 0;
03995    default_parkinglot->parkedcallreparking = 0;
03996    default_parkinglot->parkedcallrecording = 0;
03997    default_parkinglot->parkedcallhangup = 0;
03998 
03999    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04000    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04001    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04002    atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04003    atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
04004    atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04005 
04006    cfg = ast_config_load2("features.conf", "features", config_flags);
04007    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
04008       ast_log(LOG_WARNING,"Could not load features.conf\n");
04009       return 0;
04010    }
04011    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04012       if (!strcasecmp(var->name, "parkext")) {
04013          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
04014       } else if (!strcasecmp(var->name, "context")) {
04015          ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con));
04016       } else if (!strcasecmp(var->name, "parkingtime")) {
04017          if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) {
04018             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
04019             default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
04020          } else
04021             default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000;
04022       } else if (!strcasecmp(var->name, "parkpos")) {
04023          if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
04024             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);
04025          } else if (default_parkinglot) {
04026             default_parkinglot->parking_start = start;
04027             default_parkinglot->parking_stop = end;
04028          } else {
04029             ast_log(LOG_WARNING, "No default parking lot!\n");
04030          }
04031       } else if (!strcasecmp(var->name, "findslot")) {
04032          default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next"));
04033       } else if (!strcasecmp(var->name, "parkinghints")) {
04034          default_parkinglot->parkaddhints = ast_true(var->value);
04035       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
04036          if (!strcasecmp(var->value, "both"))
04037             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
04038          else if (!strcasecmp(var->value, "caller"))
04039             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
04040          else if (!strcasecmp(var->value, "callee"))
04041             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
04042       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
04043          if (!strcasecmp(var->value, "both"))
04044             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
04045          else if (!strcasecmp(var->value, "caller"))
04046             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
04047          else if (!strcasecmp(var->value, "callee"))
04048             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
04049       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
04050          if (!strcasecmp(var->value, "both"))
04051             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
04052          else if (!strcasecmp(var->value, "caller"))
04053             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
04054          else if (!strcasecmp(var->value, "callee"))
04055             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
04056       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
04057          if (!strcasecmp(var->value, "both"))
04058             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
04059          else if (!strcasecmp(var->value, "caller"))
04060             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
04061          else if (!strcasecmp(var->value, "callee"))
04062             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
04063       } else if (!strcasecmp(var->name, "adsipark")) {
04064          adsipark = ast_true(var->value);
04065       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
04066          if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
04067             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
04068             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
04069          } else
04070             transferdigittimeout = transferdigittimeout * 1000;
04071       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
04072          if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
04073             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
04074             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
04075          }
04076       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
04077          if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
04078             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
04079             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
04080          } else
04081             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
04082       } else if (!strcasecmp(var->name, "atxferloopdelay")) {
04083          if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
04084             ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
04085             atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
04086          } else 
04087             atxferloopdelay *= 1000;
04088       } else if (!strcasecmp(var->name, "atxferdropcall")) {
04089          atxferdropcall = ast_true(var->value);
04090       } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
04091          if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
04092             ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
04093             atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
04094          }
04095       } else if (!strcasecmp(var->name, "courtesytone")) {
04096          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
04097       }  else if (!strcasecmp(var->name, "parkedplay")) {
04098          if (!strcasecmp(var->value, "both"))
04099             parkedplay = 2;
04100          else if (!strcasecmp(var->value, "parked"))
04101             parkedplay = 1;
04102          else
04103             parkedplay = 0;
04104       } else if (!strcasecmp(var->name, "xfersound")) {
04105          ast_copy_string(xfersound, var->value, sizeof(xfersound));
04106       } else if (!strcasecmp(var->name, "xferfailsound")) {
04107          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
04108       } else if (!strcasecmp(var->name, "pickupexten")) {
04109          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
04110       } else if (!strcasecmp(var->name, "pickupsound")) {
04111          ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
04112       } else if (!strcasecmp(var->name, "pickupfailsound")) {
04113          ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
04114       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
04115          comebacktoorigin = ast_true(var->value);
04116       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
04117          ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass));
04118       }
04119    }
04120 
04121    unmap_features();
04122    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
04123       if (remap_feature(var->name, var->value))
04124          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
04125    }
04126 
04127    /* Map a key combination to an application*/
04128    ast_unregister_features();
04129    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
04130       char *tmp_val = ast_strdupa(var->value);
04131       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
04132       struct ast_call_feature *feature;
04133 
04134       /* strsep() sets the argument to NULL if match not found, and it
04135        * is safe to use it with a NULL argument, so we don't check
04136        * between calls.
04137        */
04138       exten = strsep(&tmp_val,",");
04139       activatedby = strsep(&tmp_val,",");
04140       app = strsep(&tmp_val,",");
04141       app_args = strsep(&tmp_val,",");
04142       moh_class = strsep(&tmp_val,",");
04143 
04144       activateon = strsep(&activatedby, "/");   
04145 
04146       /*! \todo XXX var_name or app_args ? */
04147       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
04148          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
04149             app, exten, activateon, var->name);
04150          continue;
04151       }
04152 
04153       AST_RWLIST_RDLOCK(&feature_list);
04154       if ((feature = find_dynamic_feature(var->name))) {
04155          AST_RWLIST_UNLOCK(&feature_list);
04156          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
04157          continue;
04158       }
04159       AST_RWLIST_UNLOCK(&feature_list);
04160             
04161       if (!(feature = ast_calloc(1, sizeof(*feature))))
04162          continue;               
04163 
04164       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
04165       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
04166       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
04167       
04168       if (app_args) 
04169          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
04170 
04171       if (moh_class)
04172          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
04173          
04174       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
04175       feature->operation = feature_exec_app;
04176       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
04177 
04178       /* Allow caller and calle to be specified for backwards compatability */
04179       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
04180          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
04181       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
04182          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
04183       else {
04184          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
04185             " must be 'self', or 'peer'\n", var->name);
04186          continue;
04187       }
04188 
04189       if (ast_strlen_zero(activatedby))
04190          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
04191       else if (!strcasecmp(activatedby, "caller"))
04192          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
04193       else if (!strcasecmp(activatedby, "callee"))
04194          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
04195       else if (!strcasecmp(activatedby, "both"))
04196          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
04197       else {
04198          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
04199             " must be 'caller', or 'callee', or 'both'\n", var->name);
04200          continue;
04201       }
04202 
04203       ast_register_feature(feature);
04204          
04205       ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
04206    }
04207 
04208    ast_unregister_groups();
04209    AST_RWLIST_WRLOCK(&feature_groups);
04210 
04211    ctg = NULL;
04212    while ((ctg = ast_category_browse(cfg, ctg))) {
04213       /* Is this a parkinglot definition ? */
04214       if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
04215          ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
04216          if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg)))
04217             ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
04218          else
04219             ast_debug(1, "Configured parking context %s\n", ctg);
04220          continue;   
04221       }
04222       /* No, check if it's a group */
04223       for (i = 0; i < ARRAY_LEN(categories); i++) {
04224          if (!strcasecmp(categories[i], ctg))
04225             break;
04226       }
04227 
04228       if (i < ARRAY_LEN(categories)) 
04229          continue;
04230 
04231       if (!(fg = register_group(ctg)))
04232          continue;
04233 
04234       for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
04235          struct ast_call_feature *feature;
04236 
04237          AST_RWLIST_RDLOCK(&feature_list);
04238          if (!(feature = find_dynamic_feature(var->name)) && 
04239              !(feature = ast_find_call_feature(var->name))) {
04240             AST_RWLIST_UNLOCK(&feature_list);
04241             ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
04242             continue;
04243          }
04244          AST_RWLIST_UNLOCK(&feature_list);
04245 
04246          register_group_feature(fg, var->value, feature);
04247       }
04248    }
04249 
04250    AST_RWLIST_UNLOCK(&feature_groups);
04251 
04252    ast_config_destroy(cfg);
04253 
04254    /* Remove the old parking extension */
04255    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
04256       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0))
04257             notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE);
04258       ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
04259    }
04260    
04261    if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) {
04262       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con);
04263       return -1;
04264    }
04265    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
04266    if (default_parkinglot->parkaddhints)
04267       park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop);
04268    if (!res)
04269       notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE);
04270    return res;
04271 
04272 }

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

References ast_add_extension2(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), AST_MAX_FDS, ast_pbx_start(), ast_read(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, buf, callback_dialoptions(), parkeduser::chan, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, ast_frame::frametype, free, ast_channel::generatordata, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_parkinglot::mohclass, ast_parkinglot::name, 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(), parkeduser::start, and ast_frame::subclass.

Referenced by do_parking_thread().

03275 {
03276 
03277    struct parkeduser *pu;
03278    int res = 0;
03279    char parkingslot[AST_MAX_EXTENSION];
03280 
03281    /* Lock parking list */
03282    AST_LIST_LOCK(&curlot->parkings);
03283    AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
03284       struct ast_channel *chan = pu->chan;   /* shorthand */
03285       int tms;        /* timeout for this item */
03286       int x;          /* fd index in channel */
03287       struct ast_context *con;
03288 
03289       if (pu->notquiteyet) { /* Pretend this one isn't here yet */
03290          continue;
03291       }
03292       tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
03293       if (tms > pu->parkingtime) {
03294          /* Stop music on hold */
03295          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
03296          /* Get chan, exten from derived kludge */
03297          if (pu->peername[0]) {
03298             char *peername = ast_strdupa(pu->peername);
03299             char *cp = strrchr(peername, '-');
03300             char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */
03301             int i;
03302 
03303             if (cp) 
03304                *cp = 0;
03305             ast_copy_string(peername_flat,peername,sizeof(peername_flat));
03306             for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
03307                if (peername_flat[i] == '/') 
03308                   peername_flat[i]= '0';
03309             }
03310             con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
03311             if (!con) {
03312                ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
03313             }
03314             if (con) {
03315                char returnexten[AST_MAX_EXTENSION];
03316                struct ast_datastore *features_datastore;
03317                struct ast_dial_features *dialfeatures = NULL;
03318 
03319                ast_channel_lock(chan);
03320 
03321                if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
03322                   dialfeatures = features_datastore->data;
03323 
03324                ast_channel_unlock(chan);
03325 
03326                if (!strncmp(peername, "Parked/", 7)) {
03327                   peername += 7;
03328                }
03329 
03330                if (dialfeatures) {
03331                   char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
03332                   snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
03333                } else { /* Existing default */
03334                   ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name);
03335                   snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
03336                }
03337 
03338                ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
03339             }
03340             if (pu->options_specified == 1) {
03341                /* Park() was called with overriding return arguments, respect those arguments */
03342                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
03343             } else {
03344                if (comebacktoorigin) {
03345                   set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1);
03346                } else {
03347                   ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
03348                   snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
03349                   pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
03350                   set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
03351                }
03352             }
03353          } else {
03354             /* They've been waiting too long, send them back to where they came.  Theoretically they
03355                should have their original extensions and such, but we copy to be on the safe side */
03356             set_c_e_p(chan, pu->context, pu->exten, pu->priority);
03357          }
03358          post_manager_event("ParkedCallTimeOut", pu);
03359          ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
03360 
03361          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);
03362          /* Start up the PBX, or hang them up */
03363          if (ast_pbx_start(chan))  {
03364             ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
03365             ast_hangup(chan);
03366          }
03367          /* And take them out of the parking lot */
03368          con = ast_context_find(pu->parkinglot->parking_con);
03369          if (con) {
03370             if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03371                ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
03372             else
03373                notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
03374          } else
03375             ast_log(LOG_WARNING, "Whoa, no parking context?\n");
03376          AST_LIST_REMOVE_CURRENT(list);
03377          free(pu);
03378       } else { /* still within parking time, process descriptors */
03379          for (x = 0; x < AST_MAX_FDS; x++) {
03380             struct ast_frame *f;
03381 
03382             if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds))) 
03383                continue;
03384             
03385             if (FD_ISSET(chan->fds[x], efds))
03386                ast_set_flag(chan, AST_FLAG_EXCEPTION);
03387             else
03388                ast_clear_flag(chan, AST_FLAG_EXCEPTION);
03389             chan->fdno = x;
03390 
03391             /* See if they need servicing */
03392             f = ast_read(pu->chan);
03393             /* Hangup? */
03394             if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
03395                if (f)
03396                   ast_frfree(f);
03397                post_manager_event("ParkedCallGiveUp", pu);
03398                ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", NULL);
03399 
03400                /* There's a problem, hang them up*/
03401                ast_verb(2, "%s got tired of being parked\n", chan->name);
03402                ast_hangup(chan);
03403                /* And take them out of the parking lot */
03404                con = ast_context_find(curlot->parking_con);
03405                if (con) {
03406                   if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03407                      ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
03408                   else
03409                      notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
03410                } else
03411                   ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
03412                AST_LIST_REMOVE_CURRENT(list);
03413                free(pu);
03414                break;
03415             } else {
03416                /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
03417                ast_frfree(f);
03418                if (pu->moh_trys < 3 && !chan->generatordata) {
03419                   ast_debug(1, "MOH on parked call stopped by outside source.  Restarting on channel %s.\n", chan->name);
03420                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
03421                      S_OR(curlot->mohclass, NULL),
03422                      (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0));
03423                   pu->moh_trys++;
03424                }
03425                goto std;   /* XXX Ick: jumping into an else statement??? XXX */
03426             }
03427          } /* End for */
03428          if (x >= AST_MAX_FDS) {
03429 std:           for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
03430                if (chan->fds[x] > -1) {
03431                   FD_SET(chan->fds[x], nrfds);
03432                   FD_SET(chan->fds[x], nefds);
03433                   if (chan->fds[x] > *max)
03434                      *max = chan->fds[x];
03435                }
03436             }
03437             /* Keep track of our shortest wait */
03438             if (tms < *ms || *ms < 0)
03439                *ms = tms;
03440          }
03441       }
03442    }
03443    AST_LIST_TRAVERSE_SAFE_END;
03444    AST_LIST_UNLOCK(&curlot->parkings);
03445    return res;
03446 }

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

References ast_channel_get_by_name(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), buf, and CHANNEL_DEADLOCK_AVOIDANCE.

Referenced by ast_features_init().

04650 {
04651    const char *channel = astman_get_header(m, "Channel");
04652    const char *channel2 = astman_get_header(m, "Channel2");
04653    const char *timeout = astman_get_header(m, "Timeout");
04654    char buf[BUFSIZ];
04655    int to = 0;
04656    int res = 0;
04657    int parkExt = 0;
04658    struct ast_channel *ch1, *ch2;
04659 
04660    if (ast_strlen_zero(channel)) {
04661       astman_send_error(s, m, "Channel not specified");
04662       return 0;
04663    }
04664 
04665    if (ast_strlen_zero(channel2)) {
04666       astman_send_error(s, m, "Channel2 not specified");
04667       return 0;
04668    }
04669 
04670    if (!(ch1 = ast_channel_get_by_name(channel))) {
04671       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
04672       astman_send_error(s, m, buf);
04673       return 0;
04674    }
04675 
04676    if (!(ch2 = ast_channel_get_by_name(channel2))) {
04677       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
04678       astman_send_error(s, m, buf);
04679       ast_channel_unref(ch1);
04680       return 0;
04681    }
04682 
04683    ast_channel_lock(ch1);
04684    while (ast_channel_trylock(ch2)) {
04685       CHANNEL_DEADLOCK_AVOIDANCE(ch1);
04686    }
04687 
04688    if (!ast_strlen_zero(timeout)) {
04689       sscanf(timeout, "%30d", &to);
04690    }
04691 
04692    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
04693    if (!res) {
04694       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
04695       astman_send_ack(s, m, "Park successful");
04696    } else {
04697       astman_send_error(s, m, "Park failure");
04698    }
04699 
04700    ast_channel_unlock(ch1);
04701    ast_channel_unlock(ch2);
04702 
04703    ch1 = ast_channel_unref(ch1);
04704    ch2 = ast_channel_unref(ch2);
04705 
04706    return 0;
04707 }

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 4595 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_OR, and parkeduser::start.

Referenced by ast_features_init().

04596 {
04597    struct parkeduser *cur;
04598    const char *id = astman_get_header(m, "ActionID");
04599    char idText[256] = "";
04600    struct ao2_iterator iter;
04601    struct ast_parkinglot *curlot;
04602 
04603    if (!ast_strlen_zero(id))
04604       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04605 
04606    astman_send_ack(s, m, "Parked calls will follow");
04607 
04608    iter = ao2_iterator_init(parkinglots, 0);
04609    while ((curlot = ao2_iterator_next(&iter))) {
04610 
04611       AST_LIST_LOCK(&curlot->parkings);
04612       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04613          astman_append(s, "Event: ParkedCall\r\n"
04614             "Exten: %d\r\n"
04615             "Channel: %s\r\n"
04616             "From: %s\r\n"
04617             "Timeout: %ld\r\n"
04618             "CallerIDNum: %s\r\n"
04619             "CallerIDName: %s\r\n"
04620             "%s"
04621             "\r\n",
04622             cur->parkingnum, cur->chan->name, cur->peername,
04623             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
04624             S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
04625             S_OR(cur->chan->cid.cid_name, ""),
04626             idText);
04627       }
04628       AST_LIST_UNLOCK(&curlot->parkings);
04629       ao2_ref(curlot, -1);
04630    }
04631 
04632    astman_append(s,
04633       "Event: ParkedCallsComplete\r\n"
04634       "%s"
04635       "\r\n",idText);
04636 
04637 
04638    return RESULT_SUCCESS;
04639 }

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

References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc, ast_channel_masquerade(), AST_FEATURE_RETURN_PARKFAILED, ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), ast_channel::context, ast_channel::exten, ast_park_call_args::extout, f, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_park_call_args::orig_chan_name, park_call_full(), 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().

00955 {
00956    struct ast_channel *chan;
00957    struct ast_frame *f;
00958    int park_status;
00959    struct ast_park_call_args park_args = {0,};
00960 
00961    if (!args) {
00962       args = &park_args;
00963       args->timeout = timeout;
00964       args->extout = extout;
00965    }
00966 
00967    if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
00968       if (peer)
00969          ast_stream_and_wait(peer, "beeperr", "");
00970       return AST_FEATURE_RETURN_PARKFAILED;
00971    }
00972 
00973    /* Make a new, fake channel that we'll use to masquerade in the real one */
00974    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s",rchan->name))) {
00975       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00976       return -1;
00977    }
00978 
00979    /* Make formats okay */
00980    chan->readformat = rchan->readformat;
00981    chan->writeformat = rchan->writeformat;
00982    ast_channel_masquerade(chan, rchan);
00983 
00984    /* Setup the extensions and such */
00985    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00986 
00987    /* Make the masq execute */
00988    if ((f = ast_read(chan)))
00989       ast_frfree(f);
00990 
00991    if (peer == rchan) {
00992       peer = chan;
00993    }
00994 
00995    if (!play_announcement && args == &park_args) {
00996       args->orig_chan_name = ast_strdupa(chan->name);
00997    }
00998 
00999    park_status = park_call_full(chan, peer, args);
01000    if (park_status == 1) {
01001    /* would be nice to play "invalid parking extension" */
01002       ast_hangup(chan);
01003       return -1;
01004    }
01005 
01006    return 0;
01007 }

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

Definition at line 1020 of file features.c.

References masq_park_call().

Referenced by builtin_blindtransfer(), and builtin_parkcall().

01021 {
01022    return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
01023 }

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

References masq_park_call().

Referenced by park_call_exec().

01016 {
01017    return masq_park_call(rchan, peer, 0, NULL, 1, args);
01018 }

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

metermaids callback from devicestate.c

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

00636 {
00637    char *context;
00638    char *exten;
00639 
00640    context = ast_strdupa(data);
00641 
00642    exten = strsep(&context, "@");
00643    if (!context)
00644       return AST_DEVICE_INVALID;
00645    
00646    ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
00647 
00648    if (!ast_exists_extension(NULL, context, exten, 1, NULL))
00649       return AST_DEVICE_NOT_INUSE;
00650 
00651    return AST_DEVICE_INUSE;
00652 }

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

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

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

00627 {
00628    ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
00629       exten, context, ast_devstate2str(state));
00630 
00631    ast_devstate_changed(state, "park:%s@%s", exten, context);
00632 }

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

References ast_add_extension(), PRIORITY_HINT, and registrar.

Referenced by load_config().

03924 {
03925    int numext;
03926    char device[AST_MAX_EXTENSION];
03927    char exten[10];
03928 
03929    for (numext = start; numext <= stop; numext++) {
03930       snprintf(exten, sizeof(exten), "%d", numext);
03931       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03932       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03933    }
03934 }

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

Park a call.

Definition at line 3516 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(), ast_channel::exten, ast_flags::flags, ast_park_call_args::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().

03517 {
03518    /* Cache the original channel name in case we get masqueraded in the middle
03519     * of a park--it is still theoretically possible for a transfer to happen before
03520     * we get here, but it is _really_ unlikely */
03521    char *orig_chan_name = ast_strdupa(chan->name);
03522    char orig_exten[AST_MAX_EXTENSION];
03523    int orig_priority = chan->priority;
03524 
03525    /* Data is unused at the moment but could contain a parking
03526       lot context eventually */
03527    int res = 0;
03528 
03529    char *parse = NULL;
03530    AST_DECLARE_APP_ARGS(app_args,
03531       AST_APP_ARG(timeout);
03532       AST_APP_ARG(return_con);
03533       AST_APP_ARG(return_ext);
03534       AST_APP_ARG(return_pri);
03535       AST_APP_ARG(options);
03536    );
03537 
03538    parse = ast_strdupa(data);
03539    AST_STANDARD_APP_ARGS(app_args, parse);
03540 
03541    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
03542 
03543    /* Setup the exten/priority to be s/1 since we don't know
03544       where this call should return */
03545    strcpy(chan->exten, "s");
03546    chan->priority = 1;
03547 
03548    /* Answer if call is not up */
03549    if (chan->_state != AST_STATE_UP)
03550       res = ast_answer(chan);
03551 
03552    /* Sleep to allow VoIP streams to settle down */
03553    if (!res)
03554       res = ast_safe_sleep(chan, 1000);
03555 
03556    /* Park the call */
03557    if (!res) {
03558       struct ast_park_call_args args = {
03559          .orig_chan_name = orig_chan_name,
03560       };
03561       struct ast_flags flags = { 0 };
03562 
03563       if (parse) {
03564          if (!ast_strlen_zero(app_args.timeout)) {
03565             if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
03566                ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
03567                args.timeout = 0;
03568             }
03569          }
03570          if (!ast_strlen_zero(app_args.return_con)) {
03571             args.return_con = app_args.return_con;
03572          }
03573          if (!ast_strlen_zero(app_args.return_ext)) {
03574             args.return_ext = app_args.return_ext;
03575          }
03576          if (!ast_strlen_zero(app_args.return_pri)) {
03577             if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
03578                ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
03579                args.return_pri = 0;
03580             }
03581          }
03582       }
03583 
03584       ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
03585       args.flags = flags.flags;
03586 
03587       res = masq_park_call_announce_args(chan, chan, &args);
03588       /* Continue on in the dialplan */
03589       if (res == 1) {
03590          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
03591          chan->priority = orig_priority;
03592          res = 0;
03593       } else if (!res) {
03594          res = 1;
03595       }
03596    }
03597 
03598    return res;
03599 }

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

Definition at line 795 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_CEL_PARK_START, ast_cel_report_event(), ast_channel_get_by_name(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_unlock, ast_channel_unref, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HOLD, AST_CONTROL_RINGING, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RINGING, AST_PARK_OPT_SILENCE, ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, ast_park_call_args::extout, 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().

00796 {
00797    struct ast_context *con;
00798    int parkingnum_copy;
00799    struct parkeduser *pu = args->pu;
00800    const char *event_from;
00801 
00802    if (pu == NULL)
00803       pu = park_space_reserve(chan, peer, args);
00804    if (pu == NULL)
00805       return 1; /* Continue execution if possible */
00806 
00807    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
00808    
00809    chan->appl = "Parked Call";
00810    chan->data = NULL; 
00811 
00812    pu->chan = chan;
00813    
00814    /* Put the parked channel on hold if we have two different channels */
00815    if (chan != peer) {
00816       if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
00817          ast_indicate(pu->chan, AST_CONTROL_RINGING);
00818       } else {
00819          ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00820             S_OR(pu->parkinglot->mohclass, NULL),
00821             !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
00822       }
00823    }
00824    
00825    pu->start = ast_tvnow();
00826    pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime;
00827    parkingnum_copy = pu->parkingnum;
00828    if (args->extout)
00829       *(args->extout) = pu->parkingnum;
00830 
00831    if (peer) { 
00832       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
00833          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
00834          and we need the callback name to be that of transferer.  Since local,1/2 have the same
00835          name we can be tricky and just grab the bridged channel from the other side of the local
00836       */
00837       if (!strcasecmp(peer->tech->type, "Local")) {
00838          struct ast_channel *tmpchan, *base_peer;
00839          char other_side[AST_CHANNEL_NAME];
00840          char *c;
00841          ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side));
00842          if ((c = strrchr(other_side, ';'))) {
00843             *++c = '1';
00844          }
00845          if ((tmpchan = ast_channel_get_by_name(other_side))) {
00846             ast_channel_lock(tmpchan);
00847             if ((base_peer = ast_bridged_channel(tmpchan))) {
00848                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00849             }
00850             ast_channel_unlock(tmpchan);
00851             tmpchan = ast_channel_unref(tmpchan);
00852          }
00853       } else {
00854          ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername));
00855       }
00856    }
00857 
00858    /* Remember what had been dialed, so that if the parking
00859       expires, we try to come back to the same place */
00860 
00861    pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
00862 
00863    /* If extension has options specified, they override all other possibilities
00864    such as the returntoorigin flag and transferred context. Information on
00865    extension options is lost here, so we set a flag */
00866 
00867    ast_copy_string(pu->context, 
00868       S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 
00869       sizeof(pu->context));
00870    ast_copy_string(pu->exten, 
00871       S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 
00872       sizeof(pu->exten));
00873    pu->priority = args->return_pri ? args->return_pri : 
00874       (chan->macropriority ? chan->macropriority : chan->priority);
00875 
00876    /* If parking a channel directly, don't quiet yet get parking running on it.
00877     * All parking lot entries are put into the parking lot with notquiteyet on. */
00878    if (peer != chan) 
00879       pu->notquiteyet = 0;
00880 
00881    /* Wake up the (presumably select()ing) thread */
00882    pthread_kill(parking_thread, SIGURG);
00883    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));
00884 
00885    ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
00886 
00887    if (peer) {
00888       event_from = peer->name;
00889    } else {
00890       event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
00891    }
00892 
00893    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00894       "Exten: %s\r\n"
00895       "Channel: %s\r\n"
00896       "Parkinglot: %s\r\n"
00897       "From: %s\r\n"
00898       "Timeout: %ld\r\n"
00899       "CallerIDNum: %s\r\n"
00900       "CallerIDName: %s\r\n"
00901       "Uniqueid: %s\r\n",
00902       pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "",
00903       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00904       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00905       S_OR(pu->chan->cid.cid_name, "<unknown>"),
00906       pu->chan->uniqueid
00907       );
00908 
00909    if (peer && adsipark && ast_adsi_available(peer)) {
00910       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00911       ast_adsi_unload_session(peer);
00912    }
00913 
00914    con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar);
00915    if (!con)   /* Still no context? Bad */
00916       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con);
00917    if (con) {
00918       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
00919          notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE);
00920    }
00921 
00922    AST_LIST_UNLOCK(&pu->parkinglot->parkings);
00923 
00924    /* Only say number if it's a number and the channel hasn't been masqueraded away */
00925    if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
00926       /* 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. */
00927       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00928       /* Tell the peer channel the number of the parking space */
00929       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00930       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00931    }
00932    if (peer == chan) { /* pu->notquiteyet = 1 */
00933       /* Wake up parking thread if we're really done */
00934       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00935          S_OR(pu->parkinglot->mohclass, NULL),
00936          !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
00937       pu->notquiteyet = 0;
00938       pthread_kill(parking_thread, SIGURG);
00939    }
00940    return 0;
00941 }

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

Definition at line 3766 of file features.c.

References default_parkinglot, and park_exec_full().

Referenced by ast_features_init().

03767 {
03768    return park_exec_full(chan, data, default_parkinglot);
03769 }

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

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

Referenced by park_exec().

03603 {
03604    int res = 0;
03605    struct ast_channel *peer=NULL;
03606    struct parkeduser *pu;
03607    struct ast_context *con;
03608    int park = 0;
03609    struct ast_bridge_config config;
03610 
03611    if (data)
03612       park = atoi((char *) data);
03613 
03614    parkinglot = find_parkinglot(findparkinglotname(chan));  
03615    if (!parkinglot)
03616       parkinglot = default_parkinglot;
03617 
03618    AST_LIST_LOCK(&parkinglot->parkings);
03619    AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
03620       if (!data || pu->parkingnum == park) {
03621          if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
03622             AST_LIST_UNLOCK(&parkinglot->parkings);
03623             return -1;
03624          }
03625          AST_LIST_REMOVE_CURRENT(list);
03626          break;
03627       }
03628    }
03629    AST_LIST_TRAVERSE_SAFE_END;
03630    AST_LIST_UNLOCK(&parkinglot->parkings);
03631 
03632    if (pu) {
03633       peer = pu->chan;
03634       con = ast_context_find(parkinglot->parking_con);
03635       if (con) {
03636          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03637             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
03638          else
03639             notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
03640       } else
03641          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
03642 
03643       ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
03644       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
03645          "Exten: %s\r\n"
03646          "Channel: %s\r\n"
03647          "From: %s\r\n"
03648          "CallerIDNum: %s\r\n"
03649          "CallerIDName: %s\r\n",
03650          pu->parkingexten, pu->chan->name, chan->name,
03651          S_OR(pu->chan->cid.cid_num, "<unknown>"),
03652          S_OR(pu->chan->cid.cid_name, "<unknown>")
03653          );
03654 
03655       ast_free(pu);
03656    }
03657    /* JK02: it helps to answer the channel if not already up */
03658    if (chan->_state != AST_STATE_UP)
03659       ast_answer(chan);
03660 
03661    //XXX Why do we unlock here ?
03662    // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain
03663    //ASTOBJ_UNLOCK(parkinglot);
03664 
03665    if (peer) {
03666       struct ast_datastore *features_datastore;
03667       struct ast_dial_features *dialfeatures = NULL;
03668 
03669       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
03670 
03671       if (!ast_strlen_zero(courtesytone)) {
03672          int error = 0;
03673          ast_indicate(peer, AST_CONTROL_UNHOLD);
03674          if (parkedplay == 0) {
03675             error = ast_stream_and_wait(chan, courtesytone, "");
03676          } else if (parkedplay == 1) {
03677             error = ast_stream_and_wait(peer, courtesytone, "");
03678          } else if (parkedplay == 2) {
03679             if (!ast_streamfile(chan, courtesytone, chan->language) &&
03680                   !ast_streamfile(peer, courtesytone, chan->language)) {
03681                /*! \todo XXX we would like to wait on both! */
03682                res = ast_waitstream(chan, "");
03683                if (res >= 0)
03684                   res = ast_waitstream(peer, "");
03685                if (res < 0)
03686                   error = 1;
03687             }
03688          }
03689          if (error) {
03690             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
03691             ast_hangup(peer);
03692             return -1;
03693          }
03694       } else
03695          ast_indicate(peer, AST_CONTROL_UNHOLD);
03696 
03697       res = ast_channel_make_compatible(chan, peer);
03698       if (res < 0) {
03699          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
03700          ast_hangup(peer);
03701          return -1;
03702       }
03703       /* This runs sorta backwards, since we give the incoming channel control, as if it
03704          were the person called. */
03705       ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
03706 
03707       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03708       ast_cdr_setdestchan(chan->cdr, peer->name);
03709       memset(&config, 0, sizeof(struct ast_bridge_config));
03710 
03711       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
03712       ast_channel_lock(peer);
03713       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
03714          dialfeatures = features_datastore->data;
03715       }
03716       ast_channel_unlock(peer);
03717 
03718       if (dialfeatures) {
03719          ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL);
03720       }
03721 
03722       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03723          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
03724       }
03725       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03726          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
03727       }
03728       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03729          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
03730       }
03731       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03732          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
03733       }
03734       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03735          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
03736       }
03737       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03738          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
03739       }
03740       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03741          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
03742       }
03743       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03744          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
03745       }
03746 
03747       res = ast_bridge_call(chan, peer, &config);
03748 
03749       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03750       ast_cdr_setdestchan(chan->cdr, peer->name);
03751 
03752       /* Simulate the PBX hanging up */
03753       ast_hangup(peer);
03754       return -1;
03755    } else {
03756       /*! \todo XXX Play a message XXX */
03757       if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
03758          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
03759       ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
03760       res = -1;
03761    }
03762 
03763    return -1;
03764 }

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

Note:
The API forces us to specify a numeric parking slot, even though the architecture would tend to support non-numeric extensions (as are possible with SIP, for example). Hence, we enforce that limitation here. If extout was not numeric, we could permit arbitrary non-numeric extensions.

Definition at line 682 of file features.c.

References ast_calloc, ast_channel_lock, ast_channel_unlock, ast_exists_extension(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strlen_zero(), ast_test_flag, default_parkinglot, find_parkinglot(), findparkinglotname(), free, LOG_DEBUG, LOG_WARNING, ast_parkinglot::name, parkeduser::notquiteyet, option_debug, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, ast_parkinglot::parking_offset, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, ast_parkinglot::parkings, and pbx_builtin_getvar_helper().

Referenced by masq_park_call(), and park_call_full().

00684 {
00685    struct parkeduser *pu;
00686    int i, parking_space = -1, parking_range;
00687    const char *parkinglotname = NULL;
00688    const char *parkingexten;
00689    struct ast_parkinglot *parkinglot = NULL;
00690    
00691    if (peer)
00692       parkinglotname = findparkinglotname(peer);
00693 
00694    if (parkinglotname) {
00695       if (option_debug)
00696          ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname);
00697       parkinglot = find_parkinglot(parkinglotname);   
00698    }
00699    if (!parkinglot)
00700       parkinglot = default_parkinglot;
00701 
00702    parkinglot_addref(parkinglot);
00703    if (option_debug)
00704       ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name);
00705 
00706    /* Allocate memory for parking data */
00707    if (!(pu = ast_calloc(1, sizeof(*pu)))) {
00708       parkinglot_unref(parkinglot);
00709       return NULL;
00710    }
00711 
00712    /* Lock parking list */
00713    AST_LIST_LOCK(&parkinglot->parkings);
00714    /* Check for channel variable PARKINGEXTEN */
00715    ast_channel_lock(chan);
00716    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00717    ast_channel_unlock(chan);
00718    if (!ast_strlen_zero(parkingexten)) {
00719       /*!\note The API forces us to specify a numeric parking slot, even
00720        * though the architecture would tend to support non-numeric extensions
00721        * (as are possible with SIP, for example).  Hence, we enforce that
00722        * limitation here.  If extout was not numeric, we could permit
00723        * arbitrary non-numeric extensions.
00724        */
00725         if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) {
00726          AST_LIST_UNLOCK(&parkinglot->parkings);
00727          parkinglot_unref(parkinglot);
00728             free(pu);
00729             ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00730             return NULL;
00731         }
00732         snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00733 
00734       if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) {
00735          AST_LIST_UNLOCK(&parkinglot->parkings);
00736          parkinglot_unref(parkinglot);
00737          ast_free(pu);
00738          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
00739          return NULL;
00740       }
00741    } else {
00742       int start;
00743       struct parkeduser *cur = NULL;
00744 
00745       /* Select parking space within range */
00746       parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1;
00747 
00748       if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
00749          start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1);
00750       } else {
00751          start = parkinglot->parking_start;
00752       }
00753 
00754       for (i = start; 1; i++) {
00755          if (i == parkinglot->parking_stop + 1) {
00756             i = parkinglot->parking_start - 1;
00757             continue;
00758          }
00759 
00760          AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
00761             if (cur->parkingnum == i) {
00762                break;
00763             }
00764          }
00765 
00766          if (!cur || i == start - 1) {
00767             parking_space = i;
00768             break;
00769          }
00770       }
00771 
00772       if (i == start - 1 && cur) {
00773          ast_log(LOG_WARNING, "No more parking spaces\n");
00774          ast_free(pu);
00775          AST_LIST_UNLOCK(&parkinglot->parkings);
00776          parkinglot_unref(parkinglot);
00777          return NULL;
00778       }
00779       /* Set pointer for next parking */
00780       if (parkinglot->parkfindnext) 
00781          parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
00782       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00783    }
00784 
00785    pu->notquiteyet = 1;
00786    pu->parkingnum = parking_space;
00787    pu->parkinglot = parkinglot;
00788    AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
00789    parkinglot_unref(parkinglot);
00790 
00791    return pu;
00792 }

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

Definition at line 3780 of file features.c.

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

Referenced by park_space_reserve().

03781 {
03782    int refcount = ao2_ref(parkinglot, +1);
03783    if (option_debug > 2)
03784       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
03785    return parkinglot;
03786 }

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

Definition at line 456 of file features.c.

References CMP_MATCH, CMP_STOP, and ast_parkinglot::name.

Referenced by ast_features_init().

00457 {
00458    struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg;
00459 
00460    return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00461 }

static void parkinglot_destroy ( void *  obj  )  [static]

Destroy a parking lot.

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

03808 {
03809    struct ast_parkinglot *ruin = obj;
03810    struct ast_context *con;
03811    con = ast_context_find(ruin->parking_con);
03812    if (con)
03813       ast_context_destroy(con, registrar);
03814    ao2_unlink(parkinglots, ruin);
03815 }

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

Definition at line 449 of file features.c.

References ast_str_case_hash(), and ast_parkinglot::name.

Referenced by ast_features_init().

00450 {
00451    const struct ast_parkinglot *parkinglot = obj;
00452 
00453    return ast_str_case_hash(parkinglot->name);
00454 }

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

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

Referenced by build_parkinglot(), and park_space_reserve().

03774 {
03775    int refcount = ao2_ref(parkinglot, -1);
03776    if (option_debug > 2)
03777       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
03778 }

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

return the first unlocked cdr in a possible chain

Definition at line 2602 of file features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

02603 {
02604    struct ast_cdr *cdr_orig = cdr;
02605    while (cdr) {
02606       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02607          return cdr;
02608       cdr = cdr->next;
02609    }
02610    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
02611 }

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

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

Referenced by builtin_automonitor().

01087 {
01088    /* First play for caller, put other channel on auto service */
01089    if (ast_autoservice_start(callee_chan))
01090       return -1;
01091    if (ast_stream_and_wait(caller_chan, audiofile, "")) {
01092       ast_log(LOG_WARNING, "Failed to play automon message!\n");
01093       ast_autoservice_stop(callee_chan);
01094       return -1;
01095    }
01096    if (ast_autoservice_stop(callee_chan))
01097       return -1;
01098    /* Then play for callee, put other channel on auto service */
01099    if (ast_autoservice_start(caller_chan))
01100       return -1;
01101    if (ast_stream_and_wait(callee_chan, audiofile, "")) {
01102       ast_log(LOG_WARNING, "Failed to play automon message !\n");
01103       ast_autoservice_stop(caller_chan);
01104       return -1;
01105    }
01106    if (ast_autoservice_stop(caller_chan))
01107       return -1;
01108    return(0);
01109 }

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

Output parking event to manager.

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

03212 {
03213    manager_event(EVENT_FLAG_CALL, s,
03214       "Exten: %s\r\n"
03215       "Channel: %s\r\n"
03216       "Parkinglot: %s\r\n"
03217       "CallerIDNum: %s\r\n"
03218       "CallerIDName: %s\r\n"
03219       "UniqueID: %s\r\n\r\n",
03220       pu->parkingexten, 
03221       pu->chan->name,
03222       pu->parkinglot->name,
03223       S_OR(pu->chan->cid.cid_num, "<unknown>"),
03224       S_OR(pu->chan->cid.cid_name, "<unknown>"),
03225       pu->chan->uniqueid
03226       );
03227 }

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

01350 {
01351    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
01352    if (ast_strlen_zero(s)) {
01353       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
01354    }
01355    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
01356       s = transferer->macrocontext;
01357    }
01358    if (ast_strlen_zero(s)) {
01359       s = transferer->context;
01360    }
01361    return s;  
01362 }

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

Add new feature group.

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

Definition at line 1930 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::gname, and LOG_NOTICE.

Referenced by load_config().

01931 {
01932    struct feature_group *fg;
01933 
01934    if (!fgname) {
01935       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
01936       return NULL;
01937    }
01938 
01939    if (!(fg = ast_calloc(1, sizeof(*fg))))
01940       return NULL;
01941 
01942    if (ast_string_field_init(fg, 128)) {
01943       ast_free(fg);
01944       return NULL;
01945    }
01946 
01947    ast_string_field_set(fg, gname, fgname);
01948 
01949    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
01950 
01951    ast_verb(2, "Registered group '%s'\n", fg->gname);
01952 
01953    return fg;
01954 }

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

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

Referenced by load_config().

01966 {
01967    struct feature_group_exten *fge;
01968 
01969    if (!fg) {
01970       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
01971       return;
01972    }
01973 
01974    if (!feature) {
01975       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
01976       return;
01977    }
01978 
01979    if (!(fge = ast_calloc(1, sizeof(*fge))))
01980       return;
01981 
01982    if (ast_string_field_init(fge, 128)) {
01983       ast_free(fge);
01984       return;
01985    }
01986 
01987    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
01988 
01989    fge->feature = feature;
01990 
01991    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);      
01992 
01993    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
01994                feature->sname, fg->gname, exten);
01995 }

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

Definition at line 2175 of file features.c.

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

Referenced by load_config().

02176 {
02177    int x, res = -1;
02178 
02179    ast_rwlock_wrlock(&features_lock);
02180    for (x = 0; x < FEATURES_COUNT; x++) {
02181       if (strcasecmp(builtin_features[x].sname, name))
02182          continue;
02183 
02184       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
02185       res = 0;
02186       break;
02187    }
02188    ast_rwlock_unlock(&features_lock);
02189 
02190    return res;
02191 }

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

Definition at line 2613 of file features.c.

References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), ast_bridge_config::features_caller, and LOG_WARNING.

Referenced by ast_bridge_call().

02614 {
02615    const char *feature;
02616 
02617    if (ast_strlen_zero(features)) {
02618       return;
02619    }
02620 
02621    for (feature = features; *feature; feature++) {
02622       switch (*feature) {
02623       case 'T' :
02624       case 't' :
02625          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
02626          break;
02627       case 'K' :
02628       case 'k' :
02629          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
02630          break;
02631       case 'H' :
02632       case 'h' :
02633          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
02634          break;
02635       case 'W' :
02636       case 'w' :
02637          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
02638          break;
02639       default :
02640          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
02641       }
02642    }
02643 }

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

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

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

00468 {
00469    ast_copy_string(chan->context, context, sizeof(chan->context));
00470    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00471    chan->priority = pri;
00472 }

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