#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"
#include "asterisk/astobj2.h"
#include "asterisk/cel.h"
#include "asterisk/test.h"
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | ast_dial_features |
struct | ast_park_call_args |
struct | ast_parkinglot |
Structure for parking lots which are put in a container. More... | |
struct | ast_parkinglot::parkinglot_parklist |
struct | feature_group |
struct | feature_group_exten |
struct | feature_groups |
struct | feature_list |
struct | parkeduser |
Description of one parked call, added to a list while active, then removed. The list belongs to a parkinglot. More... | |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
#define | DEFAULT_ATXFER_DROP_CALL 0 |
#define | DEFAULT_ATXFER_LOOP_DELAY 10000 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
#define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define | DEFAULT_PARK_EXTENSION "700" |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURES_COUNT ARRAY_LEN(builtin_features) |
#define | HFS_FORMAT "%-25s %-7s %-7s\n" |
#define | MAX_DIAL_FEATURE_OPTIONS 30 |
Enumerations | |
enum | { BRIDGE_OPT_PLAYTONE = (1 << 0), OPT_CALLEE_HANGUP = (1 << 1), OPT_CALLER_HANGUP = (1 << 2), OPT_DURATION_LIMIT = (1 << 3), OPT_DURATION_STOP = (1 << 4), OPT_CALLEE_TRANSFER = (1 << 5), OPT_CALLER_TRANSFER = (1 << 6), OPT_CALLEE_MONITOR = (1 << 7), OPT_CALLER_MONITOR = (1 << 8), OPT_CALLEE_PARK = (1 << 9), OPT_CALLER_PARK = (1 << 10), OPT_CALLEE_KILL = (1 << 11) } |
enum | { OPT_ARG_DURATION_LIMIT = 0, OPT_ARG_DURATION_STOP, OPT_ARG_ARRAY_SIZE } |
enum | ast_park_call_options { AST_PARK_OPT_RINGING = (1 << 0), AST_PARK_OPT_RANDOMIZE = (1 << 1), AST_PARK_OPT_SILENCE = (1 << 2) } |
Functions | |
static int | action_bridge (struct mansession *s, const struct message *m) |
Bridge channels together. | |
static void | add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config) |
static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
Announce call parking by ADSI. | |
int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
Bridge a call, optionally allowing redirection. | |
int | ast_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit) |
parse L option and read associated channel variables to set warning, warning frequency, and timelimit | |
void | ast_channel_log (char *title, struct ast_channel *chan) |
int | ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) |
detect a feature before bridging | |
int | ast_features_init (void) |
int | ast_features_reload (void) |
Reload call features from features.conf. | |
ast_call_feature * | ast_find_call_feature (const char *name) |
look for a call feature entry by its sname | |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
int | ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, const char *parkexten, int *extout) |
Park a call and read back parked location. | |
int | ast_parking_ext_valid (const char *exten_str, struct ast_channel *chan, const char *context) |
Determine if parking extension exists in a given context. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
const char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_rdlock_call_features (void) |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
void | ast_unlock_call_features (void) |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
static void | ast_unregister_features (void) |
Remove all features in the list. | |
static void | ast_unregister_groups (void) |
Remove all feature groups in the list. | |
static void | atxfer_fail_cleanup (struct ast_channel *transferee, struct ast_channel *transferer, struct ast_party_connected_line *connected_line) |
static void * | bridge_call_thread (void *data) |
bridge the call | |
static void | bridge_call_thread_launch (void *data) |
create thread for the parked call | |
static int | bridge_exec (struct ast_channel *chan, const char *data) |
Bridge channels. | |
static struct ast_parkinglot * | build_parkinglot (char *name, struct ast_variable *var) |
Build parkinglot from configuration and chain it in if it doesn't already exist. | |
static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
Attended transfer. | |
static int | builtin_automixmonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
Monitor a channel by DTMF. | |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
Blind transfer user to another extension. | |
static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
static int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
support routing for one touch call parking | |
static char * | callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len) |
static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
make channels compatible | |
static void | check_goto_on_transfer (struct ast_channel *chan) |
Check goto on transfer. | |
static struct ast_parkinglot * | copy_parkinglot (const char *name, const struct ast_parkinglot *parkinglot) |
Copy parkinglot and store it with new name. | |
static struct ast_parkinglot * | create_parkinglot (const char *name) |
Allocate parking lot structure. | |
static void | dial_features_destroy (void *data) |
static void * | dial_features_duplicate (void *data) |
static void | do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan) |
Actual bridge. | |
static void * | do_parking_thread (void *ignore) |
Take care of parked calls and unpark them if needed. | |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
exec an app by feature | |
static int | feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense) |
Check the dynamic features. | |
static int | feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, int operation, struct ast_call_feature *feature) |
Helper function for feature_interpret and ast_feature_detect. | |
static struct ast_channel * | feature_request_and_dial (struct ast_channel *caller, const char *caller_name, struct ast_channel *requestor, struct ast_channel *transferee, const char *type, format_t format, void *data, int timeout, int *outstate, const char *language) |
static int | find_channel_by_group (void *obj, void *arg, void *data, int flags) |
static struct ast_call_feature * | find_dynamic_feature (const char *name) |
find a call feature by name | |
static struct feature_group * | find_group (const char *name) |
Find a group by name. | |
ast_parkinglot * | find_parkinglot (const char *name) |
Find parkinglot by name. | |
static int | find_parkinglot_by_exten_cb (void *obj, void *args, int flags) |
static int | find_parkinglot_by_position_cb (void *obj, void *args, int flags) |
static const char * | findparkinglotname (struct ast_channel *chan) |
Find parking lot name from channel. | |
static int | finishup (struct ast_channel *chan) |
static char * | handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
CLI command to list configured features. | |
static char * | handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
CLI command to list parked calls. | |
static int | load_config (void) |
int | manage_parkinglot (struct ast_parkinglot *curlot, const struct pollfd *pfds, const int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms) |
Run management on parkinglots, called once per parkinglot. | |
static int | manager_park (struct mansession *s, const struct message *m) |
Create manager event for parked calls. | |
static int | manager_parking_status (struct mansession *s, const struct message *m) |
Dump parking lot status. | |
static int | masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args) |
static int | masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args) |
static enum ast_device_state | metermaidstate (const char *data) |
metermaids callback from devicestate.c | |
static void | notify_metermaids (const char *exten, char *context, enum ast_device_state state) |
Notify metermaids that we've changed an extension. | |
static void | park_add_hints (char *context, int start, int stop) |
Add parking hints for all defined parking lots. | |
static int | park_call_exec (struct ast_channel *chan, const char *data) |
Park a call. | |
static int | park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) |
static int | park_exec (struct ast_channel *chan, const char *data) |
static int | park_exec_full (struct ast_channel *chan, const char *data) |
Pickup parked call. | |
static struct parkeduser * | park_space_reserve (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) |
static int | parkcall_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, struct ast_park_call_args *args) |
static struct ast_parkinglot * | parkinglot_addref (struct ast_parkinglot *parkinglot) |
static int | parkinglot_cmp_cb (void *obj, void *arg, int flags) |
static void | parkinglot_destroy (void *obj) |
Destroy a parking lot. | |
static int | parkinglot_hash_cb (const void *obj, const int flags) |
static int | parkinglot_is_marked_cb (void *obj, void *arg, int flags) |
static int | parkinglot_markall_cb (void *obj, void *arg, int flags) |
static void | parkinglot_unref (struct ast_parkinglot *parkinglot) |
Unreference parkinglot object. If no more references, then go ahead and delete it. | |
static struct ast_cdr * | pick_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_group * | register_group (const char *fgname) |
Add new feature group. | |
static void | register_group_feature (struct feature_group *fg, const char *exten, struct ast_call_feature *feature) |
Add feature to group. | |
static int | remap_feature (const char *name, const char *value) |
static void | set_bridge_features_on_config (struct ast_bridge_config *config, const char *features) |
static void | set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri) |
store context, extension and priority | |
static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
static void | set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense) |
set caller and callee according to the direction | |
static void | unmap_features (void) |
Variables | |
static int | adsipark |
static char * | app_bridge = "Bridge" |
static unsigned int | atxfercallbackretries |
static unsigned int | atxferdropcall |
static unsigned int | atxferloopdelay |
static int | atxfernoanswertimeout |
static struct ast_app_option | bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, } |
static struct ast_call_feature | builtin_features [] |
static struct ast_cli_entry | cli_features [] |
static int | comebacktoorigin = 1 |
static char | courtesytone [256] |
ast_parkinglot * | default_parkinglot |
static struct ast_datastore_info | dial_features_info |
static int | featuredigittimeout |
static ast_rwlock_t | features_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } |
static struct ast_app * | mixmonitor_app = NULL |
static int | mixmonitor_ok = 1 |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static struct ast_app_option | park_call_options [128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } |
static char * | parkcall = PARK_APP_NAME |
static char * | parkedcall = "ParkedCall" |
static int | parkeddynamic = 0 |
static int | parkedplay = 0 |
char | parking_ext [AST_MAX_EXTENSION] |
static pthread_t | parking_thread |
static struct ao2_container * | parkinglots |
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_app * | stopmixmonitor_app = NULL |
static int | stopmixmonitor_ok = 1 |
static int | transferdigittimeout |
static char | xferfailsound [256] |
static char | xfersound [256] |
Definition in file features.c.
#define AST_MAX_WATCHERS 256 |
Definition at line 353 of file features.c.
#define DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
#define DEFAULT_ATXFER_DROP_CALL 0 |
#define DEFAULT_ATXFER_LOOP_DELAY 10000 |
#define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define DEFAULT_PARK_EXTENSION "700" |
#define DEFAULT_PARK_TIME 45000 |
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURES_COUNT ARRAY_LEN(builtin_features) |
Definition at line 2440 of file features.c.
Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
#define HFS_FORMAT "%-25s %-7s %-7s\n" |
Referenced by handle_feature_show().
#define MAX_DIAL_FEATURE_OPTIONS 30 |
anonymous enum |
Definition at line 5663 of file features.c.
05663 { 05664 BRIDGE_OPT_PLAYTONE = (1 << 0), 05665 OPT_CALLEE_HANGUP = (1 << 1), 05666 OPT_CALLER_HANGUP = (1 << 2), 05667 OPT_DURATION_LIMIT = (1 << 3), 05668 OPT_DURATION_STOP = (1 << 4), 05669 OPT_CALLEE_TRANSFER = (1 << 5), 05670 OPT_CALLER_TRANSFER = (1 << 6), 05671 OPT_CALLEE_MONITOR = (1 << 7), 05672 OPT_CALLER_MONITOR = (1 << 8), 05673 OPT_CALLEE_PARK = (1 << 9), 05674 OPT_CALLER_PARK = (1 << 10), 05675 OPT_CALLEE_KILL = (1 << 11), 05676 };
anonymous enum |
Definition at line 5678 of file features.c.
05678 { 05679 OPT_ARG_DURATION_LIMIT = 0, 05680 OPT_ARG_DURATION_STOP, 05681 /* note: this entry _MUST_ be the last one in the enum */ 05682 OPT_ARG_ARRAY_SIZE, 05683 };
Options to pass to park_call_full
Definition at line 884 of file features.c.
00884 { 00885 /*! Provide ringing to the parked caller instead of music on hold */ 00886 AST_PARK_OPT_RINGING = (1 << 0), 00887 /*! Randomly choose a parking spot for the caller instead of choosing 00888 * the first one that is available. */ 00889 AST_PARK_OPT_RANDOMIZE = (1 << 1), 00890 /*! Do not announce the parking number */ 00891 AST_PARK_OPT_SILENCE = (1 << 2), 00892 };
static int action_bridge | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Bridge channels together.
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. |
0 | on success or on incorrect use. | |
1 | on failure to bridge channels. |
Definition at line 5266 of file features.c.
References ast_channel::_state, ast_answer(), ast_calloc, ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_make_compatible(), ast_channel_unref, ast_hangup(), ast_log(), ast_manager_event_multichan, AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), bridge_call_thread_launch(), do_bridge_masquerade(), errno, EVENT_FLAG_CALL, LOG_WARNING, ast_channel::name, playtone(), and xfersound.
Referenced by ast_features_init().
05267 { 05268 const char *channela = astman_get_header(m, "Channel1"); 05269 const char *channelb = astman_get_header(m, "Channel2"); 05270 const char *playtone = astman_get_header(m, "Tone"); 05271 struct ast_channel *chana = NULL, *chanb = NULL, *chans[2]; 05272 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 05273 struct ast_bridge_thread_obj *tobj = NULL; 05274 05275 /* make sure valid channels were specified */ 05276 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 05277 astman_send_error(s, m, "Missing channel parameter in request"); 05278 return 0; 05279 } 05280 05281 /* Start with chana */ 05282 chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); 05283 05284 /* send errors if any of the channels could not be found/locked */ 05285 if (!chana) { 05286 char buf[256]; 05287 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 05288 astman_send_error(s, m, buf); 05289 return 0; 05290 } 05291 05292 /* Answer the channels if needed */ 05293 if (chana->_state != AST_STATE_UP) 05294 ast_answer(chana); 05295 05296 /* create the placeholder channels and grab the other channels */ 05297 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 05298 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) { 05299 astman_send_error(s, m, "Unable to create temporary channel!"); 05300 chana = ast_channel_unref(chana); 05301 return 1; 05302 } 05303 05304 do_bridge_masquerade(chana, tmpchana); 05305 05306 chana = ast_channel_unref(chana); 05307 05308 /* now do chanb */ 05309 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); 05310 /* send errors if any of the channels could not be found/locked */ 05311 if (!chanb) { 05312 char buf[256]; 05313 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 05314 ast_hangup(tmpchana); 05315 astman_send_error(s, m, buf); 05316 return 0; 05317 } 05318 05319 /* Answer the channels if needed */ 05320 if (chanb->_state != AST_STATE_UP) 05321 ast_answer(chanb); 05322 05323 /* create the placeholder channels and grab the other channels */ 05324 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 05325 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) { 05326 astman_send_error(s, m, "Unable to create temporary channels!"); 05327 ast_hangup(tmpchana); 05328 chanb = ast_channel_unref(chanb); 05329 return 1; 05330 } 05331 05332 do_bridge_masquerade(chanb, tmpchanb); 05333 05334 chanb = ast_channel_unref(chanb); 05335 05336 /* make the channels compatible, send error if we fail doing so */ 05337 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 05338 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 05339 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 05340 ast_hangup(tmpchana); 05341 ast_hangup(tmpchanb); 05342 return 1; 05343 } 05344 05345 /* setup the bridge thread object and start the bridge */ 05346 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 05347 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 05348 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 05349 ast_hangup(tmpchana); 05350 ast_hangup(tmpchanb); 05351 return 1; 05352 } 05353 05354 tobj->chan = tmpchana; 05355 tobj->peer = tmpchanb; 05356 tobj->return_to_pbx = 1; 05357 05358 if (ast_true(playtone)) { 05359 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 05360 if (ast_waitstream(tmpchanb, "") < 0) 05361 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 05362 } 05363 } 05364 05365 chans[0] = tmpchana; 05366 chans[1] = tmpchanb; 05367 05368 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans, 05369 "Response: Success\r\n" 05370 "Channel1: %s\r\n" 05371 "Channel2: %s\r\n", tmpchana->name, tmpchanb->name); 05372 05373 bridge_call_thread_launch(tobj); 05374 05375 astman_send_ack(s, m, "Launched bridge thread with success"); 05376 05377 return 0; 05378 }
static void add_features_datastores | ( | struct ast_channel * | caller, | |
struct ast_channel * | callee, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 3328 of file features.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_datastore_alloc, ast_datastore_free(), AST_FLAGS_ALL, ast_log(), config, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, and LOG_WARNING.
Referenced by ast_bridge_call().
03329 { 03330 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 03331 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 03332 03333 ast_channel_lock(caller); 03334 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 03335 ast_channel_unlock(caller); 03336 if (!ds_caller_features) { 03337 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) { 03338 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 03339 return; 03340 } 03341 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 03342 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 03343 ast_datastore_free(ds_caller_features); 03344 return; 03345 } 03346 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 03347 caller_features->is_caller = 1; 03348 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 03349 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 03350 ds_caller_features->data = caller_features; 03351 ast_channel_lock(caller); 03352 ast_channel_datastore_add(caller, ds_caller_features); 03353 ast_channel_unlock(caller); 03354 } else { 03355 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 03356 * flags over from the atxfer to the caller */ 03357 return; 03358 } 03359 03360 ast_channel_lock(callee); 03361 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 03362 ast_channel_unlock(callee); 03363 if (!ds_callee_features) { 03364 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) { 03365 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 03366 return; 03367 } 03368 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 03369 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 03370 ast_datastore_free(ds_callee_features); 03371 return; 03372 } 03373 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 03374 callee_features->is_caller = 0; 03375 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 03376 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 03377 ds_callee_features->data = callee_features; 03378 ast_channel_lock(callee); 03379 ast_channel_datastore_add(callee, ds_callee_features); 03380 ast_channel_unlock(callee); 03381 } 03382 03383 return; 03384 }
static int adsi_announce_park | ( | struct ast_channel * | chan, | |
char * | parkingexten | |||
) | [static] |
Announce call parking by ADSI.
chan | . | |
parkingexten | . Create message to show for ADSI, display message. |
0 | on success. | |
-1 | on failure. |
Definition at line 822 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
00823 { 00824 int res; 00825 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00826 char tmp[256]; 00827 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00828 00829 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00830 message[0] = tmp; 00831 res = ast_adsi_load_session(chan, NULL, 0, 1); 00832 if (res == -1) 00833 return res; 00834 return ast_adsi_print(chan, message, justify, 1); 00835 }
int ast_bridge_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) |
Bridge a call, optionally allowing redirection.
chan,peer,config | Set start time, check for two channels,check if monitor on check for feature activation, create new CDR |
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.
Definition at line 3395 of file features.c.
References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup_unique_swap(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_bridge(), ast_channel_connected_line_macro(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_log(), ast_channel_redirecting_macro(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_clear_flag, AST_CONTROL_AOC, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_AUDIO_MODE, AST_OPTION_DIGIT_DETECT, AST_OPTION_FAX_DETECT, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::caller, ast_channel::cdr, ast_cdr::channel, config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_party_caller::id, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_COR, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_party_number::str, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, ast_party_number::valid, and ast_channel::visible_indication.
Referenced by app_exec(), bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), and park_exec_full().
03396 { 03397 /* Copy voice back and forth between the two channels. Give the peer 03398 the ability to transfer calls with '#<extension' syntax. */ 03399 struct ast_frame *f; 03400 struct ast_channel *who; 03401 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 03402 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 03403 char orig_channame[AST_MAX_EXTENSION]; 03404 char orig_peername[AST_MAX_EXTENSION]; 03405 int res; 03406 int diff; 03407 int hasfeatures=0; 03408 int hadfeatures=0; 03409 int autoloopflag; 03410 int we_disabled_peer_cdr = 0; 03411 struct ast_option_header *aoh; 03412 struct ast_cdr *bridge_cdr = NULL; 03413 struct ast_cdr *orig_peer_cdr = NULL; 03414 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 03415 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 03416 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03417 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 03418 03419 if (chan && peer) { 03420 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 03421 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 03422 } else if (chan) { 03423 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 03424 } 03425 03426 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 03427 add_features_datastores(chan, peer, config); 03428 03429 /* This is an interesting case. One example is if a ringing channel gets redirected to 03430 * an extension that picks up a parked call. This will make sure that the call taken 03431 * out of parking gets told that the channel it just got bridged to is still ringing. */ 03432 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 03433 ast_indicate(peer, AST_CONTROL_RINGING); 03434 } 03435 03436 if (monitor_ok) { 03437 const char *monitor_exec; 03438 struct ast_channel *src = NULL; 03439 if (!monitor_app) { 03440 if (!(monitor_app = pbx_findapp("Monitor"))) 03441 monitor_ok=0; 03442 } 03443 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 03444 src = chan; 03445 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 03446 src = peer; 03447 if (monitor_app && src) { 03448 char *tmp = ast_strdupa(monitor_exec); 03449 pbx_exec(src, monitor_app, tmp); 03450 } 03451 } 03452 03453 set_config_flags(chan, peer, config); 03454 03455 /* Answer if need be */ 03456 if (chan->_state != AST_STATE_UP) { 03457 if (ast_raw_answer(chan, 1)) { 03458 return -1; 03459 } 03460 } 03461 03462 #ifdef FOR_DEBUG 03463 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 03464 ast_channel_log("Pre-bridge CHAN Channel info", chan); 03465 ast_channel_log("Pre-bridge PEER Channel info", peer); 03466 #endif 03467 /* two channels are being marked as linked here */ 03468 ast_channel_set_linkgroup(chan,peer); 03469 03470 /* copy the userfield from the B-leg to A-leg if applicable */ 03471 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 03472 char tmp[256]; 03473 if (!ast_strlen_zero(chan->cdr->userfield)) { 03474 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 03475 ast_cdr_appenduserfield(chan, tmp); 03476 } else 03477 ast_cdr_setuserfield(chan, peer->cdr->userfield); 03478 /* Don't delete the CDR; just disable it. */ 03479 ast_set_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03480 we_disabled_peer_cdr = 1; 03481 } 03482 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 03483 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 03484 orig_peer_cdr = peer_cdr; 03485 03486 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 03487 03488 if (chan_cdr) { 03489 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 03490 ast_cdr_update(chan); 03491 bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr); 03492 /* rip any forked CDR's off of the chan_cdr and attach 03493 * them to the bridge_cdr instead */ 03494 bridge_cdr->next = chan_cdr->next; 03495 chan_cdr->next = NULL; 03496 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03497 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03498 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 03499 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03500 } 03501 ast_cdr_setaccount(peer, chan->accountcode); 03502 03503 } else { 03504 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 03505 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 03506 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 03507 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 03508 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 03509 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 03510 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 03511 ast_cdr_setcid(bridge_cdr, chan); 03512 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 03513 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 03514 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 03515 /* Destination information */ 03516 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 03517 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 03518 if (peer_cdr) { 03519 bridge_cdr->start = peer_cdr->start; 03520 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 03521 } else { 03522 ast_cdr_start(bridge_cdr); 03523 } 03524 } 03525 ast_debug(4,"bridge answer set, chan answer set\n"); 03526 /* peer_cdr->answer will be set when a macro runs on the peer; 03527 in that case, the bridge answer will be delayed while the 03528 macro plays on the peer channel. The peer answered the call 03529 before the macro started playing. To the phone system, 03530 this is billable time for the call, even tho the caller 03531 hears nothing but ringing while the macro does its thing. */ 03532 03533 /* Another case where the peer cdr's time will be set, is when 03534 A self-parks by pickup up phone and dialing 700, then B 03535 picks up A by dialing its parking slot; there may be more 03536 practical paths that get the same result, tho... in which 03537 case you get the previous answer time from the Park... which 03538 is before the bridge's start time, so I added in the 03539 tvcmp check to the if below */ 03540 03541 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 03542 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 03543 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 03544 if (chan_cdr) { 03545 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 03546 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 03547 } 03548 } else { 03549 ast_cdr_answer(bridge_cdr); 03550 if (chan_cdr) { 03551 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 03552 } 03553 } 03554 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 03555 if (chan_cdr) { 03556 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 03557 } 03558 if (peer_cdr) { 03559 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 03560 } 03561 } 03562 /* the DIALED flag may be set if a dialed channel is transfered 03563 * and then bridged to another channel. In order for the 03564 * bridge CDR to be written, the DIALED flag must not be 03565 * present. */ 03566 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 03567 } 03568 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL); 03569 for (;;) { 03570 struct ast_channel *other; /* used later */ 03571 03572 res = ast_channel_bridge(chan, peer, config, &f, &who); 03573 03574 /* When frame is not set, we are probably involved in a situation 03575 where we've timed out. 03576 When frame is set, we'll come this code twice; once for DTMF_BEGIN 03577 and also for DTMF_END. If we flow into the following 'if' for both, then 03578 our wait times are cut in half, as both will subtract from the 03579 feature_timer. Not good! 03580 */ 03581 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 03582 /* Update feature timer for next pass */ 03583 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 03584 if (res == AST_BRIDGE_RETRY) { 03585 /* The feature fully timed out but has not been updated. Skip 03586 * the potential round error from the diff calculation and 03587 * explicitly set to expired. */ 03588 config->feature_timer = -1; 03589 } else { 03590 config->feature_timer -= diff; 03591 } 03592 03593 if (hasfeatures) { 03594 if (config->feature_timer <= 0) { 03595 /* Not *really* out of time, just out of time for 03596 digits to come in for features. */ 03597 ast_debug(1, "Timed out for feature!\n"); 03598 if (!ast_strlen_zero(peer_featurecode)) { 03599 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 03600 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 03601 } 03602 if (!ast_strlen_zero(chan_featurecode)) { 03603 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 03604 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 03605 } 03606 if (f) 03607 ast_frfree(f); 03608 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 03609 if (!hasfeatures) { 03610 /* No more digits expected - reset the timer */ 03611 config->feature_timer = 0; 03612 } 03613 hadfeatures = hasfeatures; 03614 /* Continue as we were */ 03615 continue; 03616 } else if (!f) { 03617 /* The bridge returned without a frame and there is a feature in progress. 03618 * However, we don't think the feature has quite yet timed out, so just 03619 * go back into the bridge. */ 03620 continue; 03621 } 03622 } else { 03623 if (config->feature_timer <=0) { 03624 /* We ran out of time */ 03625 config->feature_timer = 0; 03626 who = chan; 03627 if (f) 03628 ast_frfree(f); 03629 f = NULL; 03630 res = 0; 03631 } 03632 } 03633 } 03634 if (res < 0) { 03635 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 03636 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 03637 } 03638 goto before_you_go; 03639 } 03640 03641 if (!f || (f->frametype == AST_FRAME_CONTROL && 03642 (f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY || 03643 f->subclass.integer == AST_CONTROL_CONGESTION))) { 03644 res = -1; 03645 break; 03646 } 03647 /* many things should be sent to the 'other' channel */ 03648 other = (who == chan) ? peer : chan; 03649 if (f->frametype == AST_FRAME_CONTROL) { 03650 switch (f->subclass.integer) { 03651 case AST_CONTROL_RINGING: 03652 case AST_CONTROL_FLASH: 03653 case -1: 03654 ast_indicate(other, f->subclass.integer); 03655 break; 03656 case AST_CONTROL_CONNECTED_LINE: 03657 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 03658 break; 03659 } 03660 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 03661 break; 03662 case AST_CONTROL_REDIRECTING: 03663 if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { 03664 break; 03665 } 03666 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 03667 break; 03668 case AST_CONTROL_AOC: 03669 case AST_CONTROL_HOLD: 03670 case AST_CONTROL_UNHOLD: 03671 ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); 03672 break; 03673 case AST_CONTROL_OPTION: 03674 aoh = f->data.ptr; 03675 /* Forward option Requests, but only ones we know are safe 03676 * These are ONLY sent by chan_iax2 and I'm not convinced that 03677 * they are useful. I haven't deleted them entirely because I 03678 * just am not sure of the ramifications of removing them. */ 03679 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 03680 switch (ntohs(aoh->option)) { 03681 case AST_OPTION_TONE_VERIFY: 03682 case AST_OPTION_TDD: 03683 case AST_OPTION_RELAXDTMF: 03684 case AST_OPTION_AUDIO_MODE: 03685 case AST_OPTION_DIGIT_DETECT: 03686 case AST_OPTION_FAX_DETECT: 03687 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 03688 f->datalen - sizeof(struct ast_option_header), 0); 03689 } 03690 } 03691 break; 03692 } 03693 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 03694 /* eat it */ 03695 } else if (f->frametype == AST_FRAME_DTMF) { 03696 char *featurecode; 03697 int sense; 03698 03699 hadfeatures = hasfeatures; 03700 /* This cannot overrun because the longest feature is one shorter than our buffer */ 03701 if (who == chan) { 03702 sense = FEATURE_SENSE_CHAN; 03703 featurecode = chan_featurecode; 03704 } else { 03705 sense = FEATURE_SENSE_PEER; 03706 featurecode = peer_featurecode; 03707 } 03708 /*! append the event to featurecode. we rely on the string being zero-filled, and 03709 * not overflowing it. 03710 * \todo XXX how do we guarantee the latter ? 03711 */ 03712 featurecode[strlen(featurecode)] = f->subclass.integer; 03713 /* Get rid of the frame before we start doing "stuff" with the channels */ 03714 ast_frfree(f); 03715 f = NULL; 03716 config->feature_timer = 0; 03717 res = feature_interpret(chan, peer, config, featurecode, sense); 03718 switch(res) { 03719 case AST_FEATURE_RETURN_PASSDIGITS: 03720 ast_dtmf_stream(other, who, featurecode, 0, 0); 03721 /* Fall through */ 03722 case AST_FEATURE_RETURN_SUCCESS: 03723 memset(featurecode, 0, sizeof(chan_featurecode)); 03724 break; 03725 } 03726 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 03727 res = 0; 03728 } else { 03729 break; 03730 } 03731 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 03732 if (hadfeatures && !hasfeatures) { 03733 /* Feature completed or timed out */ 03734 config->feature_timer = 0; 03735 } else if (hasfeatures) { 03736 if (config->timelimit) { 03737 /* No warning next time - we are waiting for future */ 03738 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 03739 } 03740 config->feature_start_time = ast_tvnow(); 03741 config->feature_timer = featuredigittimeout; 03742 ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); 03743 } 03744 } 03745 if (f) 03746 ast_frfree(f); 03747 03748 } 03749 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL); 03750 before_you_go: 03751 03752 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 03753 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 03754 if (bridge_cdr) { 03755 ast_cdr_discard(bridge_cdr); 03756 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 03757 } 03758 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 03759 } 03760 03761 if (config->end_bridge_callback) { 03762 config->end_bridge_callback(config->end_bridge_callback_data); 03763 } 03764 03765 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 03766 * if it were, then chan belongs to a different thread now, and might have been hung up long 03767 * ago. 03768 */ 03769 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) 03770 && ast_exists_extension(chan, chan->context, "h", 1, 03771 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 03772 struct ast_cdr *swapper = NULL; 03773 char savelastapp[AST_MAX_EXTENSION]; 03774 char savelastdata[AST_MAX_EXTENSION]; 03775 char save_exten[AST_MAX_EXTENSION]; 03776 int save_prio; 03777 int found = 0; /* set if we find at least one match */ 03778 int spawn_error = 0; 03779 03780 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 03781 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 03782 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 03783 ast_cdr_end(bridge_cdr); 03784 } 03785 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 03786 dialplan code operate on it */ 03787 ast_channel_lock(chan); 03788 if (bridge_cdr) { 03789 swapper = chan->cdr; 03790 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 03791 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 03792 chan->cdr = bridge_cdr; 03793 } 03794 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 03795 save_prio = chan->priority; 03796 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 03797 chan->priority = 1; 03798 ast_channel_unlock(chan); 03799 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, 03800 chan->priority, 03801 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), 03802 &found, 1)) == 0) { 03803 chan->priority++; 03804 } 03805 if (spawn_error 03806 && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, 03807 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL)) 03808 || ast_check_hangup(chan))) { 03809 /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */ 03810 spawn_error = 0; 03811 } 03812 if (found && spawn_error) { 03813 /* Something bad happened, or a hangup has been requested. */ 03814 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 03815 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 03816 } 03817 /* swap it back */ 03818 ast_channel_lock(chan); 03819 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 03820 chan->priority = save_prio; 03821 if (bridge_cdr) { 03822 if (chan->cdr == bridge_cdr) { 03823 chan->cdr = swapper; 03824 } else { 03825 bridge_cdr = NULL; 03826 } 03827 } 03828 if (!spawn_error) { 03829 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 03830 } 03831 ast_channel_unlock(chan); 03832 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 03833 if (bridge_cdr) { 03834 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 03835 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 03836 } 03837 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 03838 } 03839 03840 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 03841 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 03842 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 03843 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 03844 03845 /* we can post the bridge CDR at this point */ 03846 if (bridge_cdr) { 03847 ast_cdr_end(bridge_cdr); 03848 ast_cdr_detach(bridge_cdr); 03849 } 03850 03851 /* do a specialized reset on the beginning channel 03852 CDR's, if they still exist, so as not to mess up 03853 issues in future bridges; 03854 03855 Here are the rules of the game: 03856 1. The chan and peer channel pointers will not change 03857 during the life of the bridge. 03858 2. But, in transfers, the channel names will change. 03859 between the time the bridge is started, and the 03860 time the channel ends. 03861 Usually, when a channel changes names, it will 03862 also change CDR pointers. 03863 3. Usually, only one of the two channels (chan or peer) 03864 will change names. 03865 4. Usually, if a channel changes names during a bridge, 03866 it is because of a transfer. Usually, in these situations, 03867 it is normal to see 2 bridges running simultaneously, and 03868 it is not unusual to see the two channels that change 03869 swapped between bridges. 03870 5. After a bridge occurs, we have 2 or 3 channels' CDRs 03871 to attend to; if the chan or peer changed names, 03872 we have the before and after attached CDR's. 03873 */ 03874 03875 if (new_chan_cdr) { 03876 struct ast_channel *chan_ptr = NULL; 03877 03878 if (strcasecmp(orig_channame, chan->name) != 0) { 03879 /* old channel */ 03880 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 03881 ast_channel_lock(chan_ptr); 03882 if (!ast_bridged_channel(chan_ptr)) { 03883 struct ast_cdr *cur; 03884 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 03885 if (cur == chan_cdr) { 03886 break; 03887 } 03888 } 03889 if (cur) { 03890 ast_cdr_specialized_reset(chan_cdr, 0); 03891 } 03892 } 03893 ast_channel_unlock(chan_ptr); 03894 chan_ptr = ast_channel_unref(chan_ptr); 03895 } 03896 /* new channel */ 03897 ast_cdr_specialized_reset(new_chan_cdr, 0); 03898 } else { 03899 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 03900 } 03901 } 03902 03903 { 03904 struct ast_channel *chan_ptr = NULL; 03905 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 03906 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)) 03907 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 03908 if (strcasecmp(orig_peername, peer->name) != 0) { 03909 /* old channel */ 03910 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 03911 ast_channel_lock(chan_ptr); 03912 if (!ast_bridged_channel(chan_ptr)) { 03913 struct ast_cdr *cur; 03914 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 03915 if (cur == peer_cdr) { 03916 break; 03917 } 03918 } 03919 if (cur) { 03920 ast_cdr_specialized_reset(peer_cdr, 0); 03921 } 03922 } 03923 ast_channel_unlock(chan_ptr); 03924 chan_ptr = ast_channel_unref(chan_ptr); 03925 } 03926 /* new channel */ 03927 if (new_peer_cdr) { 03928 ast_cdr_specialized_reset(new_peer_cdr, 0); 03929 } 03930 } else { 03931 if (we_disabled_peer_cdr) { 03932 ast_clear_flag(peer->cdr, AST_CDR_FLAG_POST_DISABLED); 03933 } 03934 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 03935 } 03936 } 03937 03938 return res; 03939 }
int ast_bridge_timelimit | ( | struct ast_channel * | chan, | |
struct ast_bridge_config * | config, | |||
char * | parse, | |||
struct timeval * | calldurationlimit | |||
) |
parse L option and read associated channel variables to set warning, warning frequency, and timelimit
Definition at line 5700 of file features.c.
References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, config, LOG_WARNING, pbx_builtin_getvar_helper(), S_OR, strsep(), and var.
Referenced by bridge_exec(), and dial_exec_full().
05702 { 05703 char *stringp = ast_strdupa(parse); 05704 char *limit_str, *warning_str, *warnfreq_str; 05705 const char *var; 05706 int play_to_caller = 0, play_to_callee = 0; 05707 int delta; 05708 05709 limit_str = strsep(&stringp, ":"); 05710 warning_str = strsep(&stringp, ":"); 05711 warnfreq_str = strsep(&stringp, ":"); 05712 05713 config->timelimit = atol(limit_str); 05714 if (warning_str) 05715 config->play_warning = atol(warning_str); 05716 if (warnfreq_str) 05717 config->warning_freq = atol(warnfreq_str); 05718 05719 if (!config->timelimit) { 05720 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 05721 config->timelimit = config->play_warning = config->warning_freq = 0; 05722 config->warning_sound = NULL; 05723 return -1; /* error */ 05724 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 05725 int w = config->warning_freq; 05726 05727 /* If the first warning is requested _after_ the entire call would end, 05728 and no warning frequency is requested, then turn off the warning. If 05729 a warning frequency is requested, reduce the 'first warning' time by 05730 that frequency until it falls within the call's total time limit. 05731 Graphically: 05732 timelim->| delta |<-playwarning 05733 0__________________|_________________| 05734 | w | | | | 05735 05736 so the number of intervals to cut is 1+(delta-1)/w 05737 */ 05738 05739 if (w == 0) { 05740 config->play_warning = 0; 05741 } else { 05742 config->play_warning -= w * ( 1 + (delta-1)/w ); 05743 if (config->play_warning < 1) 05744 config->play_warning = config->warning_freq = 0; 05745 } 05746 } 05747 05748 ast_channel_lock(chan); 05749 05750 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 05751 play_to_caller = var ? ast_true(var) : 1; 05752 05753 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 05754 play_to_callee = var ? ast_true(var) : 0; 05755 05756 if (!play_to_caller && !play_to_callee) 05757 play_to_caller = 1; 05758 05759 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 05760 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 05761 05762 /* The code looking at config wants a NULL, not just "", to decide 05763 * that the message should not be played, so we replace "" with NULL. 05764 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 05765 * not found. 05766 */ 05767 05768 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 05769 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 05770 05771 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 05772 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 05773 05774 ast_channel_unlock(chan); 05775 05776 /* undo effect of S(x) in case they are both used */ 05777 calldurationlimit->tv_sec = 0; 05778 calldurationlimit->tv_usec = 0; 05779 05780 /* more efficient to do it like S(x) does since no advanced opts */ 05781 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 05782 calldurationlimit->tv_sec = config->timelimit / 1000; 05783 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 05784 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 05785 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 05786 config->timelimit = play_to_caller = play_to_callee = 05787 config->play_warning = config->warning_freq = 0; 05788 } else { 05789 ast_verb(4, "Limit Data for this call:\n"); 05790 ast_verb(4, "timelimit = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0); 05791 ast_verb(4, "play_warning = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0); 05792 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 05793 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 05794 ast_verb(4, "warning_freq = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0); 05795 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 05796 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 05797 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 05798 } 05799 if (play_to_caller) 05800 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 05801 if (play_to_callee) 05802 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 05803 return 0; 05804 }
void ast_channel_log | ( | char * | title, | |
struct ast_channel * | chan | |||
) |
Definition at line 3263 of file features.c.
References ast_log(), and LOG_NOTICE.
Referenced by ast_bridge_call().
03264 { 03265 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan); 03266 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n", 03267 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority); 03268 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n", 03269 chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority); 03270 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n", 03271 chan->masq, chan->masqr, 03272 chan->_bridge, chan->uniqueid, chan->linkedid); 03273 if (chan->masqr) 03274 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n", 03275 chan->masqr->name, chan->masqr->cdr); 03276 if (chan->_bridge) 03277 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name); 03278 03279 ast_log(LOG_NOTICE, "===== done ====\n"); 03280 }
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
chan | ||
features | an ast_flags ptr | |
code | ptr of input code | |
feature |
ast_call_feature | ptr to be set if found |
Definition at line 2881 of file features.c.
References feature_group_exten::feature, and feature_interpret_helper().
Referenced by detect_disconnect().
02881 { 02882 02883 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 02884 }
int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 5975 of file features.c.
References action_bridge(), ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register_xml, ast_pthread_create, ast_register_application2(), AST_TEST_REGISTER, bridge_exec(), cli_features, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), and parkinglots.
Referenced by main().
05976 { 05977 int res; 05978 05979 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); 05980 05981 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 05982 05983 if ((res = load_config())) 05984 return res; 05985 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); 05986 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 05987 res = ast_register_application2(parkedcall, park_exec, NULL, NULL, NULL); 05988 if (!res) 05989 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); 05990 if (!res) { 05991 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status); 05992 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park); 05993 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge); 05994 } 05995 05996 res |= ast_devstate_prov_add("Park", metermaidstate); 05997 #ifdef TEST_FRAMEWORK 05998 res |= AST_TEST_REGISTER(features_test); 05999 #endif 06000 06001 return res; 06002 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 5198 of file features.c.
References ao2_t_callback, load_config(), OBJ_NODATA, OBJ_UNLINK, parkinglot_is_marked_cb(), parkinglot_markall_cb(), and parkinglots.
Referenced by handle_features_reload().
05199 { 05200 int res; 05201 05202 ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, "callback to mark all parkinglots"); 05203 res = load_config(); /* Reload configuration */ 05204 ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, "callback to remove all marked parkinglots"); 05205 05206 return res; 05207 }
struct ast_call_feature* ast_find_call_feature | ( | const char * | name | ) |
look for a call feature entry by its sname
name | a string ptr, should match "automon", "blindxfer", "atxfer", etc. |
Definition at line 2623 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
02624 { 02625 int x; 02626 for (x = 0; x < FEATURES_COUNT; x++) { 02627 if (!strcasecmp(name, builtin_features[x].sname)) 02628 return &builtin_features[x]; 02629 } 02630 return NULL; 02631 }
int ast_masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call via a masqueraded channel.
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. |
0 | on success. | |
-1 | on failure. |
Definition at line 1299 of file features.c.
References masq_park_call().
Referenced by __analog_ss_thread(), analog_ss_thread(), handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), mgcp_ss(), parkandannounce_exec(), and rpt_exec().
01300 { 01301 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 01302 }
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
const char * | parkexten, | |||
int * | extout | |||
) |
Park a call and read back parked location.
chan | the channel to actually be parked | |
host | the channel which will have the parked location read to. | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
0 | on success. | |
-1 | on failure. |
Definition at line 1225 of file features.c.
References ao2_callback, args, find_parkinglot_by_exten_cb(), park_call_full(), and parkinglots.
Referenced by iax_park_thread(), and sip_park_thread().
01226 { 01227 struct ast_parkinglot *found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, (void *) parkexten); 01228 01229 struct ast_park_call_args args = { 01230 .timeout = timeout, 01231 .extout = extout, 01232 .parkinglot = found_lot, 01233 }; 01234 01235 return park_call_full(chan, peer, &args); 01236 }
int ast_parking_ext_valid | ( | const char * | exten_str, | |
struct ast_channel * | chan, | |||
const char * | context | |||
) |
Determine if parking extension exists in a given context.
0 | if extension does not exist | |
1 | if extension does exist |
Definition at line 643 of file features.c.
References ast_get_extension_app(), E_MATCH, feature_group_exten::exten, PARK_APP_NAME, pbx_find_extension(), and pbx_find_info::stacklen.
Referenced by __analog_ss_thread(), analog_ss_thread(), dp_lookup(), handle_request_refer(), mgcp_ss(), and socket_process().
00644 { 00645 struct ast_exten *exten; 00646 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ 00647 const char *app_at_exten; 00648 00649 exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, E_MATCH); 00650 if (!exten) { 00651 return 0; 00652 } 00653 00654 app_at_exten = ast_get_extension_app(exten); 00655 if (!app_at_exten || strcmp(PARK_APP_NAME, app_at_exten)) { 00656 return 0; 00657 } 00658 00659 return 1; 00660 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
Definition at line 5598 of file features.c.
References ast_answer(), ast_channel_callback(), ast_channel_connected_line_macro(), ast_channel_lock_both, ast_channel_masquerade(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_unref, ast_channel_update_connected_line(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_manager_event_multichan, ast_party_connected_line_collect_caller(), ast_queue_control(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_channel::caller, ast_channel::connected, EVENT_FLAG_CALL, find_channel_by_group(), LOG_WARNING, ast_channel::name, pickupfailsound, pickupsound, and ast_party_connected_line::source.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), handle_request_invite(), mgcp_ss(), and pickup_exec().
05599 { 05600 struct ast_channel *cur, *chans[2] = { chan, }; 05601 struct ast_party_connected_line connected_caller; 05602 int res; 05603 const char *chan_name; 05604 const char *cur_name; 05605 05606 if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) { 05607 ast_debug(1, "No call pickup possible...\n"); 05608 if (!ast_strlen_zero(pickupfailsound)) { 05609 ast_stream_and_wait(chan, pickupfailsound, ""); 05610 } 05611 return -1; 05612 } 05613 05614 chans[1] = cur; 05615 05616 ast_channel_lock_both(cur, chan); 05617 05618 cur_name = ast_strdupa(cur->name); 05619 chan_name = ast_strdupa(chan->name); 05620 05621 ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name); 05622 05623 connected_caller = cur->connected; 05624 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05625 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 05626 ast_channel_update_connected_line(chan, &connected_caller, NULL); 05627 } 05628 05629 ast_party_connected_line_collect_caller(&connected_caller, &chan->caller); 05630 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 05631 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); 05632 05633 ast_channel_unlock(cur); 05634 ast_channel_unlock(chan); 05635 05636 if (ast_answer(chan)) { 05637 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 05638 } 05639 05640 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 05641 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 05642 } 05643 05644 if ((res = ast_channel_masquerade(cur, chan))) { 05645 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name); 05646 } 05647 05648 if (!ast_strlen_zero(pickupsound)) { 05649 ast_stream_and_wait(cur, pickupsound, ""); 05650 } 05651 05652 /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ 05653 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, 05654 "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, cur->name); 05655 05656 cur = ast_channel_unref(cur); 05657 05658 return res; 05659 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 662 of file features.c.
References pickup_ext.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), and mgcp_ss().
00663 { 00664 return pickup_ext; 00665 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 2613 of file features.c.
References ast_rwlock_rdlock, and features_lock.
Referenced by handle_request_info().
02614 { 02615 ast_rwlock_rdlock(&features_lock); 02616 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_set
feature | an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call. |
Definition at line 2457 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, feature_group_exten::feature, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
02458 { 02459 if (!feature) { 02460 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 02461 return; 02462 } 02463 02464 AST_RWLIST_WRLOCK(&feature_list); 02465 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 02466 AST_RWLIST_UNLOCK(&feature_list); 02467 02468 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 02469 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 2618 of file features.c.
References ast_rwlock_unlock, and features_lock.
Referenced by handle_request_info().
02619 { 02620 ast_rwlock_unlock(&features_lock); 02621 }
void ast_unregister_feature | ( | struct ast_call_feature * | feature | ) |
unregister feature from feature_set
feature | the ast_call_feature object which was registered before |
Definition at line 2537 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
02538 { 02539 if (!feature) { 02540 return; 02541 } 02542 02543 AST_RWLIST_WRLOCK(&feature_list); 02544 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 02545 AST_RWLIST_UNLOCK(&feature_list); 02546 02547 ast_free(feature); 02548 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 2551 of file features.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, feature_group_exten::feature, and ast_call_feature::feature_entry.
02552 { 02553 struct ast_call_feature *feature; 02554 02555 AST_RWLIST_WRLOCK(&feature_list); 02556 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 02557 ast_free(feature); 02558 } 02559 AST_RWLIST_UNLOCK(&feature_list); 02560 }
static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 2577 of file features.c.
References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, feature_group_exten::entry, and feature_group::features.
02578 { 02579 struct feature_group *fg; 02580 struct feature_group_exten *fge; 02581 02582 AST_RWLIST_WRLOCK(&feature_groups); 02583 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 02584 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 02585 ast_string_field_free_memory(fge); 02586 ast_free(fge); 02587 } 02588 02589 ast_string_field_free_memory(fg); 02590 ast_free(fg); 02591 } 02592 AST_RWLIST_UNLOCK(&feature_groups); 02593 }
static void atxfer_fail_cleanup | ( | struct ast_channel * | transferee, | |
struct ast_channel * | transferer, | |||
struct ast_party_connected_line * | connected_line | |||
) | [static] |
Definition at line 1996 of file features.c.
References ast_channel_connected_line_macro(), ast_channel_update_connected_line(), ast_party_connected_line_free(), and finishup().
Referenced by builtin_atxfer().
01997 { 01998 finishup(transferee); 01999 02000 /* 02001 * Restore party B connected line info about party A. 02002 * 02003 * Party B was the caller to party C and is the last known mode 02004 * for party B. 02005 */ 02006 if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) { 02007 ast_channel_update_connected_line(transferer, connected_line, NULL); 02008 } 02009 ast_party_connected_line_free(connected_line); 02010 }
static void* bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
data | thread bridge. |
Definition at line 757 of file features.c.
References ast_channel::appl, ast_bridge_call(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, LOG_VERBOSE, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.
Referenced by bridge_call_thread_launch().
00758 { 00759 struct ast_bridge_thread_obj *tobj = data; 00760 int res; 00761 00762 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00763 tobj->chan->data = tobj->peer->name; 00764 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00765 tobj->peer->data = tobj->chan->name; 00766 00767 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00768 00769 if (tobj->return_to_pbx) { 00770 if (!ast_check_hangup(tobj->peer)) { 00771 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 00772 res = ast_pbx_start(tobj->peer); 00773 if (res != AST_PBX_SUCCESS) 00774 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 00775 } else 00776 ast_hangup(tobj->peer); 00777 if (!ast_check_hangup(tobj->chan)) { 00778 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 00779 res = ast_pbx_start(tobj->chan); 00780 if (res != AST_PBX_SUCCESS) 00781 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 00782 } else 00783 ast_hangup(tobj->chan); 00784 } else { 00785 ast_hangup(tobj->chan); 00786 ast_hangup(tobj->peer); 00787 } 00788 00789 ast_free(tobj); 00790 00791 return NULL; 00792 }
static void bridge_call_thread_launch | ( | void * | data | ) | [static] |
create thread for the parked call
data | Create thread and attributes, call bridge_call_thread |
Definition at line 800 of file features.c.
References ast_pthread_create, bridge_call_thread(), and thread.
Referenced by action_bridge(), and builtin_atxfer().
00801 { 00802 pthread_t thread; 00803 pthread_attr_t attr; 00804 struct sched_param sched; 00805 00806 pthread_attr_init(&attr); 00807 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00808 ast_pthread_create(&thread, &attr, bridge_call_thread, data); 00809 pthread_attr_destroy(&attr); 00810 memset(&sched, 0, sizeof(sched)); 00811 pthread_setschedparam(thread, SCHED_RR, &sched); 00812 }
static int bridge_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Bridge channels.
chan | ||
data | channel to bridge with. |
Definition at line 5816 of file features.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_bridge_timelimit(), ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_make_compatible(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_free, ast_hangup(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_pbx_start(), AST_PBX_SUCCESS, ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, ast_channel::context, do_bridge_masquerade(), ast_bridge_config::end_sound, EVENT_FLAG_CALL, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_channel::name, OPT_ARG_ARRAY_SIZE, OPT_ARG_DURATION_LIMIT, OPT_CALLEE_HANGUP, OPT_CALLEE_KILL, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DURATION_LIMIT, pbx_builtin_setvar_helper(), ast_channel::priority, ast_bridge_config::start_sound, ast_bridge_config::warning_sound, and xfersound.
Referenced by ast_features_init().
05817 { 05818 struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2]; 05819 char *tmp_data = NULL; 05820 struct ast_flags opts = { 0, }; 05821 struct ast_bridge_config bconfig = { { 0, }, }; 05822 char *opt_args[OPT_ARG_ARRAY_SIZE]; 05823 struct timeval calldurationlimit = { 0, }; 05824 05825 AST_DECLARE_APP_ARGS(args, 05826 AST_APP_ARG(dest_chan); 05827 AST_APP_ARG(options); 05828 ); 05829 05830 if (ast_strlen_zero(data)) { 05831 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 05832 return -1; 05833 } 05834 05835 tmp_data = ast_strdupa(data); 05836 AST_STANDARD_APP_ARGS(args, tmp_data); 05837 if (!ast_strlen_zero(args.options)) 05838 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options); 05839 05840 /* avoid bridge with ourselves */ 05841 if (!strcmp(chan->name, args.dest_chan)) { 05842 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 05843 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 05844 "Response: Failed\r\n" 05845 "Reason: Unable to bridge channel to itself\r\n" 05846 "Channel1: %s\r\n" 05847 "Channel2: %s\r\n", 05848 chan->name, args.dest_chan); 05849 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 05850 return 0; 05851 } 05852 05853 /* make sure we have a valid end point */ 05854 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan, 05855 strlen(args.dest_chan)))) { 05856 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 05857 "cannot get its lock\n", args.dest_chan); 05858 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 05859 "Response: Failed\r\n" 05860 "Reason: Cannot grab end point\r\n" 05861 "Channel1: %s\r\n" 05862 "Channel2: %s\r\n", chan->name, args.dest_chan); 05863 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 05864 return 0; 05865 } 05866 05867 /* answer the channel if needed */ 05868 if (current_dest_chan->_state != AST_STATE_UP) { 05869 ast_answer(current_dest_chan); 05870 } 05871 05872 /* try to allocate a place holder where current_dest_chan will be placed */ 05873 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 05874 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) { 05875 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 05876 ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", 05877 "Response: Failed\r\n" 05878 "Reason: cannot create placeholder\r\n" 05879 "Channel1: %s\r\n" 05880 "Channel2: %s\r\n", chan->name, args.dest_chan); 05881 } 05882 05883 ast_channel_unlock(current_dest_chan); 05884 05885 do_bridge_masquerade(current_dest_chan, final_dest_chan); 05886 05887 chans[0] = current_dest_chan; 05888 chans[1] = final_dest_chan; 05889 05890 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 05891 /* try to make compatible, send error if we fail */ 05892 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 05893 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 05894 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 05895 "Response: Failed\r\n" 05896 "Reason: Could not make channels compatible for bridge\r\n" 05897 "Channel1: %s\r\n" 05898 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 05899 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 05900 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 05901 current_dest_chan = ast_channel_unref(current_dest_chan); 05902 return 0; 05903 } 05904 05905 /* Report that the bridge will be successfull */ 05906 ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, 05907 "Response: Success\r\n" 05908 "Channel1: %s\r\n" 05909 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 05910 05911 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 05912 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 05913 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 05914 if (ast_waitstream(final_dest_chan, "") < 0) 05915 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 05916 } 05917 } 05918 05919 current_dest_chan = ast_channel_unref(current_dest_chan); 05920 05921 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) { 05922 if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) 05923 goto done; 05924 } 05925 05926 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) 05927 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT); 05928 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) 05929 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT); 05930 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) 05931 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 05932 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) 05933 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 05934 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR)) 05935 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON); 05936 if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 05937 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON); 05938 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) 05939 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL); 05940 if (ast_test_flag(&opts, OPT_CALLER_PARK)) 05941 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL); 05942 05943 ast_bridge_call(chan, final_dest_chan, &bconfig); 05944 05945 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 05946 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 05947 if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) { 05948 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 05949 final_dest_chan->context, final_dest_chan->exten, 05950 final_dest_chan->priority, final_dest_chan->name); 05951 05952 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 05953 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 05954 ast_hangup(final_dest_chan); 05955 } else 05956 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 05957 } else { 05958 ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name); 05959 ast_hangup(final_dest_chan); 05960 } 05961 done: 05962 if (bconfig.warning_sound) { 05963 ast_free((char *)bconfig.warning_sound); 05964 } 05965 if (bconfig.end_sound) { 05966 ast_free((char *)bconfig.end_sound); 05967 } 05968 if (bconfig.start_sound) { 05969 ast_free((char *)bconfig.start_sound); 05970 } 05971 05972 return 0; 05973 }
static struct ast_parkinglot* build_parkinglot | ( | char * | name, | |
struct ast_variable * | var | |||
) | [static] |
Build parkinglot from configuration and chain it in if it doesn't already exist.
Definition at line 4621 of file features.c.
References ao2_link, ao2_lock, ao2_unlock, ast_add_extension2(), ast_context_find_or_create(), ast_copy_string(), ast_debug, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, ast_free_ptr, ast_log(), ast_strlen_zero(), create_parkinglot(), DEFAULT_PARK_EXTENSION, DEFAULT_PARK_TIME, find_parkinglot(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, park_add_hints(), parkcall, parkinglot, parkinglot_destroy(), parkinglot_unref(), parkinglots, registrar, strdup, ast_variable::value, and var.
Referenced by load_config().
04622 { 04623 struct ast_parkinglot *parkinglot; 04624 struct ast_context *con = NULL; 04625 04626 struct ast_variable *confvar = var; 04627 int error = 0; 04628 int start = 0, end = 0; 04629 int oldparkinglot = 0; 04630 04631 parkinglot = find_parkinglot(name); 04632 if (parkinglot) 04633 oldparkinglot = 1; 04634 else 04635 parkinglot = create_parkinglot(name); 04636 04637 if (!parkinglot) 04638 return NULL; 04639 04640 ao2_lock(parkinglot); 04641 04642 ast_debug(1, "Building parking lot %s\n", name); 04643 04644 /* Do some config stuff */ 04645 while(confvar) { 04646 if (!strcasecmp(confvar->name, "context")) { 04647 ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con)); 04648 } else if (!strcasecmp(confvar->name, "parkext")) { 04649 ast_copy_string(parkinglot->parkext, confvar->value, sizeof(parkinglot->parkext)); 04650 } else if (!strcasecmp(confvar->name, "parkingtime")) { 04651 if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) { 04652 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value); 04653 parkinglot->parkingtime = DEFAULT_PARK_TIME; 04654 } else 04655 parkinglot->parkingtime = parkinglot->parkingtime * 1000; 04656 } else if (!strcasecmp(confvar->name, "parkpos")) { 04657 if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) { 04658 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); 04659 error = 1; 04660 } else { 04661 parkinglot->parking_start = start; 04662 parkinglot->parking_stop = end; 04663 } 04664 } else if (!strcasecmp(confvar->name, "findslot")) { 04665 parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next")); 04666 } else if (!strcasecmp(confvar->name, "parkedcalltransfers")) { 04667 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value); 04668 if (!strcasecmp(confvar->value, "both")) 04669 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 04670 else if (!strcasecmp(confvar->value, "caller")) 04671 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 04672 else if (!strcasecmp(confvar->value, "callee")) 04673 parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 04674 } else if (!strcasecmp(confvar->name, "parkedcallreparking")) { 04675 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value); 04676 if (!strcasecmp(confvar->value, "both")) 04677 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 04678 else if (!strcasecmp(confvar->value, "caller")) 04679 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 04680 else if (!strcasecmp(confvar->value, "callee")) 04681 parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 04682 } else if (!strcasecmp(confvar->name, "parkedcallhangup")) { 04683 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value); 04684 if (!strcasecmp(confvar->value, "both")) 04685 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 04686 else if (!strcasecmp(confvar->value, "caller")) 04687 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 04688 else if (!strcasecmp(confvar->value, "callee")) 04689 parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 04690 } else if (!strcasecmp(confvar->name, "parkedcallrecording")) { 04691 ast_log(LOG_DEBUG, "Setting parking lot %s %s to %s\n", name, confvar->name, confvar->value); 04692 if (!strcasecmp(confvar->value, "both")) 04693 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 04694 else if (!strcasecmp(confvar->value, "caller")) 04695 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 04696 else if (!strcasecmp(confvar->value, "callee")) 04697 parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 04698 } 04699 confvar = confvar->next; 04700 } 04701 /* make sure parkingtime is set if not specified */ 04702 if (parkinglot->parkingtime == 0) { 04703 parkinglot->parkingtime = DEFAULT_PARK_TIME; 04704 } 04705 if (ast_strlen_zero(parkinglot->parkext)) { 04706 ast_debug(2, "no parkext specified for %s - setting it to %s\n", parkinglot->name, DEFAULT_PARK_EXTENSION); 04707 ast_copy_string(parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(parkinglot->parkext)); 04708 } 04709 04710 if (!var) { /* Default parking lot */ 04711 ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con)); 04712 ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass)); 04713 } 04714 ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial)); 04715 04716 /* Check for errors */ 04717 if (ast_strlen_zero(parkinglot->parking_con)) { 04718 ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name); 04719 error = 1; 04720 } 04721 04722 /* Create context */ 04723 if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) { 04724 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con); 04725 error = 1; 04726 } 04727 04728 /* Add a parking extension into the context */ 04729 if (!error && !oldparkinglot) { 04730 if (!ast_strlen_zero(parkinglot->parkext)) { 04731 if (ast_add_extension2(con, 1, parkinglot->parkext, 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1) 04732 error = 1; 04733 } 04734 } 04735 04736 /* Add parking hints */ 04737 if (parkinglot->parkaddhints) 04738 park_add_hints(parkinglot->parking_con, parkinglot->parking_start, parkinglot->parking_stop); 04739 04740 ao2_unlock(parkinglot); 04741 04742 if (error) { 04743 ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name); 04744 parkinglot_destroy(parkinglot); 04745 parkinglot_unref(parkinglot); 04746 return NULL; 04747 } 04748 ast_debug(1, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end); 04749 parkinglot->the_mark = 0; 04750 04751 /* Move it into the list, if it wasn't already there */ 04752 if (!oldparkinglot) { 04753 ao2_link(parkinglots, parkinglot); 04754 } 04755 parkinglot_unref(parkinglot); 04756 04757 return parkinglot; 04758 }
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.
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. |
Definition at line 2027 of file features.c.
References ast_channel::_state, ao2_callback, args, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_calloc, AST_CEL_ATTENDEDTRANSFER, ast_cel_report_event(), ast_channel_alloc, ast_channel_connected_line_macro(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_channel_update_connected_line(), ast_check_hangup(), ast_clear_flag, ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_do_masquerade(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAGS_ALL, ast_hangup(), ast_indicate(), ast_log(), ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), atxfer_fail_cleanup(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, bridge_call_thread_launch(), ast_channel::caller, check_compat(), config, ast_channel::connected, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, feature_request_and_dial(), ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, find_parkinglot_by_exten_cb(), finishup(), ast_channel::language, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, parkcall_helper(), parkinglot, parkinglots, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_party_connected_line::source, strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xferfailsound, and xfersound.
02028 { 02029 struct ast_channel *transferer;/* Party B */ 02030 struct ast_channel *transferee;/* Party A */ 02031 const char *transferer_real_context; 02032 char xferto[256] = ""; 02033 int res; 02034 int outstate=0; 02035 struct ast_channel *newchan; 02036 struct ast_channel *xferchan; 02037 struct ast_bridge_thread_obj *tobj; 02038 struct ast_bridge_config bconfig; 02039 int l; 02040 struct ast_party_connected_line connected_line; 02041 struct ast_datastore *features_datastore; 02042 struct ast_dial_features *dialfeatures = NULL; 02043 struct ast_parkinglot *parkinglot; 02044 char *transferer_tech; 02045 char *transferer_name; 02046 char *transferer_name_orig; 02047 char *dash; 02048 02049 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 02050 set_peers(&transferer, &transferee, peer, chan, sense); 02051 transferer_real_context = real_ctx(transferer, transferee); 02052 02053 /* Start autoservice on transferee while we talk to the transferer */ 02054 ast_autoservice_start(transferee); 02055 ast_indicate(transferee, AST_CONTROL_HOLD); 02056 02057 /* Transfer */ 02058 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 02059 if (res < 0) { 02060 finishup(transferee); 02061 return -1; 02062 } 02063 if (res > 0) /* If they've typed a digit already, handle it */ 02064 xferto[0] = (char) res; 02065 02066 /* this is specific of atxfer */ 02067 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 02068 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 02069 finishup(transferee); 02070 return -1; 02071 } 02072 l = strlen(xferto); 02073 if (res == 0) { 02074 if (l) { 02075 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 02076 xferto, transferer_real_context); 02077 } else { 02078 /* Does anyone care about this case? */ 02079 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n"); 02080 } 02081 ast_stream_and_wait(transferer, "pbx-invalid", ""); 02082 finishup(transferee); 02083 return AST_FEATURE_RETURN_SUCCESS; 02084 } 02085 02086 /* If we are attended transfering to parking, just use parkcall_helper instead of trying to track all of 02087 * the different variables for handling this properly with a builtin_atxfer */ 02088 parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto); 02089 if (parkinglot) { 02090 struct ast_park_call_args args = { 02091 .parkinglot = parkinglot, 02092 }; 02093 finishup(transferee); 02094 return parkcall_helper(chan, peer, config, code, sense, &args); 02095 } 02096 02097 /* Append context to dialed transfer number. */ 02098 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); 02099 02100 /* If we are performing an attended transfer and we have two channels involved then 02101 copy sound file information to play upon attended transfer completion */ 02102 if (transferee) { 02103 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02104 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 02105 02106 if (!ast_strlen_zero(chan1_attended_sound)) { 02107 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 02108 } 02109 if (!ast_strlen_zero(chan2_attended_sound)) { 02110 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 02111 } 02112 } 02113 02114 /* Extract redial transferer information from the channel name. */ 02115 transferer_name_orig = ast_strdupa(transferer->name); 02116 transferer_name = ast_strdupa(transferer_name_orig); 02117 transferer_tech = strsep(&transferer_name, "/"); 02118 dash = strrchr(transferer_name, '-'); 02119 if (dash) { 02120 /* Trim off channel name sequence/serial number. */ 02121 *dash = '\0'; 02122 } 02123 02124 /* Stop autoservice so we can monitor all parties involved in the transfer. */ 02125 if (ast_autoservice_stop(transferee) < 0) { 02126 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02127 return -1; 02128 } 02129 02130 /* Save connected line info for party B about party A in case transfer fails. */ 02131 ast_party_connected_line_init(&connected_line); 02132 ast_channel_lock(transferer); 02133 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02134 ast_channel_unlock(transferer); 02135 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02136 02137 /* Dial party C */ 02138 newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer, 02139 transferee, "Local", ast_best_codec(transferer->nativeformats), xferto, 02140 atxfernoanswertimeout, &outstate, transferer->language); 02141 ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate); 02142 02143 if (!ast_check_hangup(transferer)) { 02144 int hangup_dont = 0; 02145 02146 /* Transferer (party B) is up */ 02147 ast_debug(1, "Actually doing an attended transfer.\n"); 02148 02149 /* Start autoservice on transferee while the transferer deals with party C. */ 02150 ast_autoservice_start(transferee); 02151 02152 ast_indicate(transferer, -1); 02153 if (!newchan) { 02154 /* any reason besides user requested cancel and busy triggers the failed sound */ 02155 switch (outstate) { 02156 case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */ 02157 case AST_CONTROL_BUSY: 02158 case AST_CONTROL_CONGESTION: 02159 if (ast_stream_and_wait(transferer, xfersound, "")) { 02160 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02161 } 02162 break; 02163 default: 02164 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02165 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02166 } 02167 break; 02168 } 02169 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02170 return AST_FEATURE_RETURN_SUCCESS; 02171 } 02172 02173 if (check_compat(transferer, newchan)) { 02174 if (ast_stream_and_wait(transferer, xferfailsound, "")) { 02175 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 02176 } 02177 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02178 return AST_FEATURE_RETURN_SUCCESS; 02179 } 02180 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 02181 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 02182 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 02183 02184 /* ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we don't 02185 want that to happen here because we're also in another bridge already 02186 */ 02187 if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) { 02188 hangup_dont = 1; 02189 } 02190 /* Let party B and party C talk as long as they want. */ 02191 ast_bridge_call(transferer, newchan, &bconfig); 02192 if (hangup_dont) { 02193 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 02194 } 02195 02196 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 02197 ast_hangup(newchan); 02198 if (ast_stream_and_wait(transferer, xfersound, "")) { 02199 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02200 } 02201 atxfer_fail_cleanup(transferee, transferer, &connected_line); 02202 return AST_FEATURE_RETURN_SUCCESS; 02203 } 02204 02205 /* Transferer (party B) is confirmed hung up at this point. */ 02206 if (check_compat(transferee, newchan)) { 02207 finishup(transferee); 02208 ast_party_connected_line_free(&connected_line); 02209 return -1; 02210 } 02211 02212 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02213 if ((ast_autoservice_stop(transferee) < 0) 02214 || (ast_waitfordigit(transferee, 100) < 0) 02215 || (ast_waitfordigit(newchan, 100) < 0) 02216 || ast_check_hangup(transferee) 02217 || ast_check_hangup(newchan)) { 02218 ast_hangup(newchan); 02219 ast_party_connected_line_free(&connected_line); 02220 return -1; 02221 } 02222 } else if (!ast_check_hangup(transferee)) { 02223 /* Transferer (party B) has hung up at this point. Doing blonde transfer. */ 02224 ast_debug(1, "Actually doing a blonde transfer.\n"); 02225 02226 if (!newchan && !atxferdropcall) { 02227 /* Party C is not available, try to call party B back. */ 02228 unsigned int tries = 0; 02229 02230 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 02231 ast_log(LOG_WARNING, 02232 "Transferer channel name: '%s' cannot be used for callback.\n", 02233 transferer_name_orig); 02234 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02235 ast_party_connected_line_free(&connected_line); 02236 return -1; 02237 } 02238 02239 tries = 0; 02240 for (;;) { 02241 /* Try to get party B back. */ 02242 ast_debug(1, "We're trying to callback %s/%s\n", 02243 transferer_tech, transferer_name); 02244 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02245 transferee, transferee, transferer_tech, 02246 ast_best_codec(transferee->nativeformats), transferer_name, 02247 atxfernoanswertimeout, &outstate, transferer->language); 02248 ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n", 02249 !!newchan, outstate); 02250 if (newchan || ast_check_hangup(transferee)) { 02251 break; 02252 } 02253 02254 ++tries; 02255 if (atxfercallbackretries <= tries) { 02256 /* No more callback tries remaining. */ 02257 break; 02258 } 02259 02260 if (atxferloopdelay) { 02261 /* Transfer failed, sleeping */ 02262 ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n", 02263 atxferloopdelay); 02264 ast_safe_sleep(transferee, atxferloopdelay); 02265 if (ast_check_hangup(transferee)) { 02266 ast_party_connected_line_free(&connected_line); 02267 return -1; 02268 } 02269 } 02270 02271 /* Retry dialing party C. */ 02272 ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto); 02273 newchan = feature_request_and_dial(transferer, transferer_name_orig, 02274 transferer, transferee, "Local", 02275 ast_best_codec(transferee->nativeformats), xferto, 02276 atxfernoanswertimeout, &outstate, transferer->language); 02277 ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n", 02278 !!newchan, outstate); 02279 if (newchan || ast_check_hangup(transferee)) { 02280 break; 02281 } 02282 } 02283 } 02284 ast_indicate(transferee, AST_CONTROL_UNHOLD); 02285 if (!newchan) { 02286 /* No party C or could not callback party B. */ 02287 ast_party_connected_line_free(&connected_line); 02288 return -1; 02289 } 02290 02291 /* newchan is up, we should prepare transferee and bridge them */ 02292 if (ast_check_hangup(newchan)) { 02293 ast_hangup(newchan); 02294 ast_party_connected_line_free(&connected_line); 02295 return -1; 02296 } 02297 if (check_compat(transferee, newchan)) { 02298 ast_party_connected_line_free(&connected_line); 02299 return -1; 02300 } 02301 } else { 02302 /* 02303 * Both the transferer and transferee have hungup. If newchan 02304 * is up, hang it up as it has no one to talk to. 02305 */ 02306 ast_debug(1, "Everyone is hungup.\n"); 02307 if (newchan) { 02308 ast_hangup(newchan); 02309 } 02310 ast_party_connected_line_free(&connected_line); 02311 return -1; 02312 } 02313 02314 /* Initiate the channel transfer of party A to party C (or recalled party B). */ 02315 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan); 02316 02317 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name); 02318 if (!xferchan) { 02319 ast_hangup(newchan); 02320 ast_party_connected_line_free(&connected_line); 02321 return -1; 02322 } 02323 02324 /* Give party A a momentary ringback tone during transfer. */ 02325 xferchan->visible_indication = AST_CONTROL_RINGING; 02326 02327 /* Make formats okay */ 02328 xferchan->readformat = transferee->readformat; 02329 xferchan->writeformat = transferee->writeformat; 02330 02331 ast_channel_masquerade(xferchan, transferee); 02332 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 02333 xferchan->_state = AST_STATE_UP; 02334 ast_clear_flag(xferchan, AST_FLAGS_ALL); 02335 02336 /* Do the masquerade manually to make sure that is is completed. */ 02337 ast_do_masquerade(xferchan); 02338 02339 newchan->_state = AST_STATE_UP; 02340 ast_clear_flag(newchan, AST_FLAGS_ALL); 02341 tobj = ast_calloc(1, sizeof(*tobj)); 02342 if (!tobj) { 02343 ast_hangup(xferchan); 02344 ast_hangup(newchan); 02345 ast_party_connected_line_free(&connected_line); 02346 return -1; 02347 } 02348 02349 ast_channel_lock(newchan); 02350 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 02351 dialfeatures = features_datastore->data; 02352 } 02353 ast_channel_unlock(newchan); 02354 02355 if (dialfeatures) { 02356 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 02357 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 02358 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 02359 dialfeatures = NULL; 02360 } 02361 02362 ast_channel_lock(xferchan); 02363 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 02364 dialfeatures = features_datastore->data; 02365 } 02366 ast_channel_unlock(xferchan); 02367 02368 if (dialfeatures) { 02369 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 02370 } 02371 02372 tobj->chan = newchan; 02373 tobj->peer = xferchan; 02374 tobj->bconfig = *config; 02375 02376 if (tobj->bconfig.end_bridge_callback_data_fixup) { 02377 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 02378 } 02379 02380 /* 02381 * xferchan is transferee, and newchan is the transfer target 02382 * So...in a transfer, who is the caller and who is the callee? 02383 * 02384 * When the call is originally made, it is clear who is caller and callee. 02385 * When a transfer occurs, it is my humble opinion that the transferee becomes 02386 * the caller, and the transfer target is the callee. 02387 * 02388 * The problem is that these macros were set with the intention of the original 02389 * caller and callee taking those roles. A transfer can totally mess things up, 02390 * to be technical. What sucks even more is that you can't effectively change 02391 * the macros in the dialplan during the call from the transferer to the transfer 02392 * target because the transferee is stuck with whatever role he originally had. 02393 * 02394 * I think the answer here is just to make sure that it is well documented that 02395 * during a transfer, the transferee is the "caller" and the transfer target 02396 * is the "callee." 02397 * 02398 * This means that if party B calls party A, and party B transfers party A to 02399 * party C, then A has switched roles for the call. Now party A will have the 02400 * caller macro called on his channel instead of the callee macro. 02401 * 02402 * Luckily, the method by which the party B to party C bridge is 02403 * launched above ensures that the transferee is the "chan" on 02404 * the bridge and the transfer target is the "peer," so my idea 02405 * for the roles post-transfer does not require extensive code 02406 * changes. 02407 */ 02408 02409 /* Transfer party C connected line to party A */ 02410 ast_channel_lock(transferer); 02411 /* 02412 * Due to a limitation regarding when callerID is set on a Local channel, 02413 * we use the transferer's connected line information here. 02414 */ 02415 ast_party_connected_line_copy(&connected_line, &transferer->connected); 02416 ast_channel_unlock(transferer); 02417 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02418 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { 02419 ast_channel_update_connected_line(xferchan, &connected_line, NULL); 02420 } 02421 02422 /* Transfer party A connected line to party C */ 02423 ast_channel_lock(xferchan); 02424 ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller); 02425 ast_channel_unlock(xferchan); 02426 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 02427 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { 02428 ast_channel_update_connected_line(newchan, &connected_line, NULL); 02429 } 02430 02431 if (ast_stream_and_wait(newchan, xfersound, "")) 02432 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 02433 bridge_call_thread_launch(tobj); 02434 02435 ast_party_connected_line_free(&connected_line); 02436 return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */ 02437 }
static int builtin_automixmonitor | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 1683 of file features.c.
References args, AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_unlock, AST_FEATURE_RETURN_SUCCESS, AST_FRAME_DTMF_END, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, ast_channel::name, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_COR, S_OR, set_peers(), stopmixmonitor_app, stopmixmonitor_ok, ast_party_number::str, and ast_party_number::valid.
01684 { 01685 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 01686 int x = 0; 01687 size_t len; 01688 struct ast_channel *caller_chan, *callee_chan; 01689 const char *mixmonitor_spy_type = "MixMonitor"; 01690 int count = 0; 01691 01692 if (!mixmonitor_ok) { 01693 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01694 return -1; 01695 } 01696 01697 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 01698 mixmonitor_ok = 0; 01699 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01700 return -1; 01701 } 01702 01703 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 01704 01705 if (!ast_strlen_zero(courtesytone)) { 01706 if (ast_autoservice_start(callee_chan)) 01707 return -1; 01708 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END); 01709 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 01710 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01711 ast_autoservice_stop(callee_chan); 01712 return -1; 01713 } 01714 if (ast_autoservice_stop(callee_chan)) 01715 return -1; 01716 } 01717 01718 ast_channel_lock(callee_chan); 01719 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01720 ast_channel_unlock(callee_chan); 01721 01722 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 01723 if (count > 0) { 01724 01725 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 01726 01727 /* Make sure they are running */ 01728 ast_channel_lock(callee_chan); 01729 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01730 ast_channel_unlock(callee_chan); 01731 if (count > 0) { 01732 if (!stopmixmonitor_ok) { 01733 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01734 return -1; 01735 } 01736 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 01737 stopmixmonitor_ok = 0; 01738 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01739 return -1; 01740 } else { 01741 pbx_exec(callee_chan, stopmixmonitor_app, ""); 01742 return AST_FEATURE_RETURN_SUCCESS; 01743 } 01744 } 01745 01746 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 01747 } 01748 01749 if (caller_chan && callee_chan) { 01750 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 01751 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 01752 01753 if (!touch_format) 01754 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 01755 01756 if (!touch_monitor) 01757 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 01758 01759 if (touch_monitor) { 01760 len = strlen(touch_monitor) + 50; 01761 args = alloca(len); 01762 touch_filename = alloca(len); 01763 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 01764 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 01765 } else { 01766 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 01767 caller_chan->caller.id.number.str, caller_chan->name)); 01768 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 01769 callee_chan->caller.id.number.str, callee_chan->name)); 01770 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 01771 args = alloca(len); 01772 touch_filename = alloca(len); 01773 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 01774 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 01775 } 01776 01777 for( x = 0; x < strlen(args); x++) { 01778 if (args[x] == '/') 01779 args[x] = '-'; 01780 } 01781 01782 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 01783 01784 pbx_exec(callee_chan, mixmonitor_app, args); 01785 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01786 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01787 return AST_FEATURE_RETURN_SUCCESS; 01788 01789 } 01790 01791 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01792 return -1; 01793 01794 }
static int builtin_automonitor | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Monitor a channel by DTMF.
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. |
AST_FEATURE_RETURN_SUCCESS | on success. | |
-1 | on error. |
Definition at line 1588 of file features.c.
References args, AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, courtesytone, ast_party_caller::id, LOG_ERROR, LOG_NOTICE, ast_channel::monitor, monitor_app, monitor_ok, ast_channel::name, ast_party_id::number, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_COR, S_OR, set_peers(), ast_channel_monitor::stop, ast_party_number::str, and ast_party_number::valid.
01589 { 01590 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 01591 int x = 0; 01592 size_t len; 01593 struct ast_channel *caller_chan, *callee_chan; 01594 const char *automon_message_start = NULL; 01595 const char *automon_message_stop = NULL; 01596 01597 if (!monitor_ok) { 01598 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 01599 return -1; 01600 } 01601 01602 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 01603 monitor_ok = 0; 01604 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 01605 return -1; 01606 } 01607 01608 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 01609 if (caller_chan) { /* Find extra messages */ 01610 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 01611 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 01612 } 01613 01614 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 01615 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 01616 return -1; 01617 } 01618 } 01619 01620 if (callee_chan->monitor) { 01621 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 01622 if (!ast_strlen_zero(automon_message_stop)) { 01623 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 01624 } 01625 callee_chan->monitor->stop(callee_chan, 1); 01626 return AST_FEATURE_RETURN_SUCCESS; 01627 } 01628 01629 if (caller_chan && callee_chan) { 01630 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 01631 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 01632 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 01633 01634 if (!touch_format) 01635 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 01636 01637 if (!touch_monitor) 01638 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 01639 01640 if (!touch_monitor_prefix) 01641 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 01642 01643 if (touch_monitor) { 01644 len = strlen(touch_monitor) + 50; 01645 args = alloca(len); 01646 touch_filename = alloca(len); 01647 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 01648 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 01649 } else { 01650 caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, 01651 caller_chan->caller.id.number.str, caller_chan->name)); 01652 callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, 01653 callee_chan->caller.id.number.str, callee_chan->name)); 01654 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 01655 args = alloca(len); 01656 touch_filename = alloca(len); 01657 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 01658 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 01659 } 01660 01661 for(x = 0; x < strlen(args); x++) { 01662 if (args[x] == '/') 01663 args[x] = '-'; 01664 } 01665 01666 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 01667 01668 pbx_exec(callee_chan, monitor_app, args); 01669 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01670 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01671 01672 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 01673 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 01674 } 01675 01676 return AST_FEATURE_RETURN_SUCCESS; 01677 } 01678 01679 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01680 return -1; 01681 }
static int builtin_blindtransfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Blind transfer user to another extension.
chan | channel to be transfered | |
peer | channel initiated blind transfer | |
config | ||
code | ||
data | ||
sense | feature options |
AST_FEATURE_RETURN_SUCCESS. | ||
-1 | on failure. |
Definition at line 1846 of file features.c.
References ao2_callback, args, ast_app_dtget(), ast_async_goto(), ast_autoservice_ignore(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CEL_BLINDTRANSFER, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_update_connected_line(), AST_CONTROL_HOLD, AST_DIGIT_ANY, AST_FEATURE_RETURN_PARKFAILED, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FRAME_DTMF_END, ast_indicate(), ast_log(), ast_set_flag, ast_stopstream(), ast_stream_and_wait(), ast_verb, ast_channel::cdr, ast_cdr::channel, check_goto_on_transfer(), ast_channel::connected, ast_cdr::dstchannel, find_parkinglot_by_exten_cb(), finishup(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, masq_park_call_announce(), ast_channel::name, parkinglots, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), transferdigittimeout, and xferfailsound.
01847 { 01848 struct ast_channel *transferer; 01849 struct ast_channel *transferee; 01850 const char *transferer_real_context; 01851 struct ast_parkinglot *found_lot = NULL; 01852 char xferto[256]; 01853 int res, parkstatus = 0; 01854 01855 set_peers(&transferer, &transferee, peer, chan, sense); 01856 transferer_real_context = real_ctx(transferer, transferee); 01857 /* Start autoservice on chan while we talk to the originator */ 01858 ast_autoservice_start(transferee); 01859 ast_autoservice_ignore(transferee, AST_FRAME_DTMF_END); 01860 ast_indicate(transferee, AST_CONTROL_HOLD); 01861 01862 memset(xferto, 0, sizeof(xferto)); 01863 01864 /* Transfer */ 01865 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01866 if (res < 0) { 01867 finishup(transferee); 01868 return -1; /* error ? */ 01869 } 01870 if (res > 0) /* If they've typed a digit already, handle it */ 01871 xferto[0] = (char) res; 01872 01873 ast_stopstream(transferer); 01874 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01875 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 01876 finishup(transferee); 01877 return -1; 01878 } 01879 if (res == 0) { 01880 if (xferto[0]) { 01881 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 01882 xferto, transferer_real_context); 01883 } else { 01884 /* Does anyone care about this case? */ 01885 ast_log(LOG_WARNING, "No digits dialed.\n"); 01886 } 01887 ast_stream_and_wait(transferer, "pbx-invalid", ""); 01888 finishup(transferee); 01889 return AST_FEATURE_RETURN_SUCCESS; 01890 } 01891 01892 found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto); 01893 if (found_lot) { 01894 struct ast_park_call_args args = { 01895 .parkinglot = found_lot, 01896 }; 01897 res = finishup(transferee); 01898 if (res) { 01899 } else if (!(parkstatus = masq_park_call_announce(transferee, transferer, &args))) { /* success */ 01900 /* We return non-zero, but tell the PBX not to hang the channel when 01901 the thread dies -- We have to be careful now though. We are responsible for 01902 hanging up the channel, else it will never be hung up! */ 01903 01904 return 0; 01905 } else { 01906 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus); 01907 } 01908 ast_autoservice_start(transferee); 01909 } else { 01910 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee); 01911 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 01912 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 01913 res=finishup(transferee); 01914 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 01915 transferer->cdr=ast_cdr_alloc(); 01916 if (transferer->cdr) { 01917 ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */ 01918 ast_cdr_start(transferer->cdr); 01919 } 01920 } 01921 if (transferer->cdr) { 01922 struct ast_cdr *swap = transferer->cdr; 01923 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 01924 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 01925 transferer->cdr->channel, transferer->cdr->dstchannel); 01926 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 01927 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel); 01928 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto); 01929 /* swap cdrs-- it will save us some time & work */ 01930 transferer->cdr = transferee->cdr; 01931 transferee->cdr = swap; 01932 } 01933 if (!transferee->pbx) { 01934 /* Doh! Use our handy async_goto functions */ 01935 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n" 01936 ,transferee->name, xferto, transferer_real_context); 01937 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 01938 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 01939 } else { 01940 /* Set the channel's new extension, since it exists, using transferer context */ 01941 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 01942 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name); 01943 if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) { 01944 ast_channel_update_connected_line(transferer, &transferer->connected, NULL); 01945 } 01946 set_c_e_p(transferee, transferer_real_context, xferto, 0); 01947 } 01948 check_goto_on_transfer(transferer); 01949 return res; 01950 } 01951 if (parkstatus != AST_FEATURE_RETURN_PARKFAILED 01952 && ast_stream_and_wait(transferer, xferfailsound, "")) { 01953 finishup(transferee); 01954 return -1; 01955 } 01956 ast_stopstream(transferer); 01957 res = finishup(transferee); 01958 if (res) { 01959 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name); 01960 return res; 01961 } 01962 return AST_FEATURE_RETURN_SUCCESS; 01963 }
static int builtin_disconnect | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 1796 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
01797 { 01798 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 01799 return AST_FEATURE_RETURN_HANGUP; 01800 }
static int builtin_parkcall | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
support routing for one touch call parking
chan | channel parking call | |
peer | channel to be parked | |
config | unsed | |
code | unused | |
sense | feature options | |
data | Setup channel, set return exten,priority to 's,1' answer chan, sleep chan, park call |
Definition at line 1539 of file features.c.
References config, and parkcall_helper().
01540 { 01541 return parkcall_helper(chan, peer, config, code, sense, NULL); 01542 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 3960 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().
03961 { 03962 int i = 0; 03963 enum { 03964 OPT_CALLEE_REDIRECT = 't', 03965 OPT_CALLER_REDIRECT = 'T', 03966 OPT_CALLEE_AUTOMON = 'w', 03967 OPT_CALLER_AUTOMON = 'W', 03968 OPT_CALLEE_DISCONNECT = 'h', 03969 OPT_CALLER_DISCONNECT = 'H', 03970 OPT_CALLEE_PARKCALL = 'k', 03971 OPT_CALLER_PARKCALL = 'K', 03972 }; 03973 03974 memset(options, 0, len); 03975 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 03976 options[i++] = OPT_CALLER_REDIRECT; 03977 } 03978 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 03979 options[i++] = OPT_CALLER_AUTOMON; 03980 } 03981 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 03982 options[i++] = OPT_CALLER_DISCONNECT; 03983 } 03984 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 03985 options[i++] = OPT_CALLER_PARKCALL; 03986 } 03987 03988 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 03989 options[i++] = OPT_CALLEE_REDIRECT; 03990 } 03991 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 03992 options[i++] = OPT_CALLEE_AUTOMON; 03993 } 03994 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 03995 options[i++] = OPT_CALLEE_DISCONNECT; 03996 } 03997 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 03998 options[i++] = OPT_CALLEE_PARKCALL; 03999 } 04000 04001 return options; 04002 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
make channels compatible
c | ||
newchan |
0 | on success. | |
-1 | on failure. |
Definition at line 1972 of file features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by builtin_atxfer().
01973 { 01974 if (ast_channel_make_compatible(c, newchan) < 0) { 01975 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 01976 c->name, newchan->name); 01977 ast_hangup(newchan); 01978 return -1; 01979 } 01980 return 0; 01981 }
static void check_goto_on_transfer | ( | struct ast_channel * | chan | ) | [static] |
Check goto on transfer.
chan | Check if channel has 'GOTO_ON_BLINDXFR' set, if not exit. When found make sure the types are compatible. Check if channel is valid if so start the new channel else hangup the call. |
Definition at line 708 of file features.c.
References ast_channel::_state, ast_channel_alloc, ast_channel_clear_softhangup(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_SOFTHANGUP_ALL, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), f, ast_channel::linkedid, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.
Referenced by builtin_blindtransfer().
00709 { 00710 struct ast_channel *xferchan; 00711 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00712 char *x, *goto_on_transfer; 00713 struct ast_frame *f; 00714 00715 if (ast_strlen_zero(val)) 00716 return; 00717 00718 goto_on_transfer = ast_strdupa(val); 00719 00720 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, "%s", chan->name))) 00721 return; 00722 00723 for (x = goto_on_transfer; x && *x; x++) { 00724 if (*x == '^') 00725 *x = ','; 00726 } 00727 /* Make formats okay */ 00728 xferchan->readformat = chan->readformat; 00729 xferchan->writeformat = chan->writeformat; 00730 ast_channel_masquerade(xferchan, chan); 00731 ast_parseable_goto(xferchan, goto_on_transfer); 00732 xferchan->_state = AST_STATE_UP; 00733 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00734 ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL); 00735 if ((f = ast_read(xferchan))) { 00736 ast_frfree(f); 00737 f = NULL; 00738 ast_pbx_start(xferchan); 00739 } else { 00740 ast_hangup(xferchan); 00741 } 00742 }
struct ast_parkinglot * copy_parkinglot | ( | const char * | name, | |
const struct ast_parkinglot * | parkinglot | |||
) | [static] |
Copy parkinglot and store it with new name.
Definition at line 4265 of file features.c.
References ao2_ref, ast_copy_string(), ast_debug, AST_LIST_HEAD_INIT, ast_strlen_zero(), create_parkinglot(), find_parkinglot(), ast_parkinglot::name, parkinglot, and ast_parkinglot::parkings.
Referenced by park_space_reserve().
04265 { 04266 struct ast_parkinglot *copylot; 04267 04268 if (ast_strlen_zero(name)) { /* No name specified */ 04269 return NULL; 04270 } 04271 if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */ 04272 if (copylot) { 04273 ao2_ref(copylot, -1); 04274 } 04275 return NULL; 04276 } 04277 04278 copylot = create_parkinglot(name); 04279 ast_debug(1, "Building parking lot %s\n", name); 04280 04281 memcpy(copylot, parkinglot, sizeof(struct ast_parkinglot)); 04282 ast_copy_string(copylot->name, name, sizeof(copylot->name)); 04283 AST_LIST_HEAD_INIT(©lot->parkings); 04284 04285 return copylot; 04286 }
static struct ast_parkinglot * create_parkinglot | ( | const char * | name | ) | [static] |
Allocate parking lot structure.
Definition at line 4574 of file features.c.
References ao2_alloc, ast_copy_string(), AST_LIST_HEAD_INIT, and parkinglot_destroy().
Referenced by build_parkinglot(), and copy_parkinglot().
04575 { 04576 struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL; 04577 04578 if (!name) 04579 return NULL; 04580 04581 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 04582 if (!newlot) 04583 return NULL; 04584 04585 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 04586 AST_LIST_HEAD_INIT(&newlot->parkings); 04587 04588 return newlot; 04589 }
static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 596 of file features.c.
References ast_free.
00597 { 00598 struct ast_dial_features *df = data; 00599 if (df) { 00600 ast_free(df); 00601 } 00602 }
static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 583 of file features.c.
References ast_calloc.
00584 { 00585 struct ast_dial_features *df = data, *df_copy; 00586 00587 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00588 return NULL; 00589 } 00590 00591 memcpy(df_copy, df, sizeof(*df)); 00592 00593 return df_copy; 00594 }
static void do_bridge_masquerade | ( | struct ast_channel * | chan, | |
struct ast_channel * | tmpchan | |||
) | [static] |
Actual bridge.
chan | ||
tmpchan | Stop hold music, lock both channels, masq channels, after bridge return channel to next priority. |
Definition at line 5234 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().
05235 { 05236 ast_moh_stop(chan); 05237 ast_channel_lock_both(chan, tmpchan); 05238 ast_setstate(tmpchan, chan->_state); 05239 tmpchan->readformat = chan->readformat; 05240 tmpchan->writeformat = chan->writeformat; 05241 ast_channel_masquerade(tmpchan, chan); 05242 ast_channel_unlock(chan); 05243 ast_channel_unlock(tmpchan); 05244 05245 /* must be done without any channel locks held */ 05246 ast_do_masquerade(tmpchan); 05247 05248 /* when returning from bridge, the channel will continue at the next priority */ 05249 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 05250 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
ignore | unused var. |
Definition at line 4215 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_free, ast_poll, manage_parkinglot(), and parkinglots.
Referenced by ast_features_init().
04216 { 04217 struct pollfd *pfds = NULL, *new_pfds = NULL; 04218 int nfds = 0, new_nfds = 0; 04219 04220 for (;;) { 04221 struct ao2_iterator iter; 04222 struct ast_parkinglot *curlot; 04223 int ms = -1; /* poll2 timeout, uninitialized */ 04224 iter = ao2_iterator_init(parkinglots, 0); 04225 04226 while ((curlot = ao2_iterator_next(&iter))) { 04227 manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms); 04228 ao2_ref(curlot, -1); 04229 } 04230 ao2_iterator_destroy(&iter); 04231 04232 /* Recycle */ 04233 ast_free(pfds); 04234 pfds = new_pfds; 04235 nfds = new_nfds; 04236 new_pfds = NULL; 04237 new_nfds = 0; 04238 04239 /* Wait for something to happen */ 04240 ast_poll(pfds, nfds, ms); 04241 pthread_testcancel(); 04242 } 04243 /* If this WERE reached, we'd need to free(pfds) */ 04244 return NULL; /* Never reached */ 04245 }
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
chan,peer,config,code,sense,data | Find a feature, determine which channel activated |
AST_FEATURE_RETURN_NO_HANGUP_PEER | ||
-1 | error. | |
-2 | when an application cannot be found. |
Definition at line 2642 of file features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, AST_FRAME_DTMF_END, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, feature_group_exten::feature, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_channel::name, pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), and ast_call_feature::sname.
02643 { 02644 struct ast_app *app; 02645 struct ast_call_feature *feature = data; 02646 struct ast_channel *work, *idle; 02647 int res; 02648 02649 if (!feature) { /* shouldn't ever happen! */ 02650 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 02651 return -1; 02652 } 02653 02654 if (sense == FEATURE_SENSE_CHAN) { 02655 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 02656 return AST_FEATURE_RETURN_KEEPTRYING; 02657 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 02658 work = chan; 02659 idle = peer; 02660 } else { 02661 work = peer; 02662 idle = chan; 02663 } 02664 } else { 02665 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 02666 return AST_FEATURE_RETURN_KEEPTRYING; 02667 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 02668 work = peer; 02669 idle = chan; 02670 } else { 02671 work = chan; 02672 idle = peer; 02673 } 02674 } 02675 02676 if (!(app = pbx_findapp(feature->app))) { 02677 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 02678 return -2; 02679 } 02680 02681 ast_autoservice_start(idle); 02682 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END); 02683 02684 if(work && idle) { 02685 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name); 02686 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name); 02687 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname); 02688 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname); 02689 } 02690 02691 if (!ast_strlen_zero(feature->moh_class)) 02692 ast_moh_start(idle, feature->moh_class, NULL); 02693 02694 res = pbx_exec(work, app, feature->app_args); 02695 02696 if (!ast_strlen_zero(feature->moh_class)) 02697 ast_moh_stop(idle); 02698 02699 ast_autoservice_stop(idle); 02700 02701 if (res) { 02702 return AST_FEATURE_RETURN_SUCCESSBREAK; 02703 } 02704 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 02705 }
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.
chan,peer,config,code,sense |
res | on success. | |
-1 | on failure. |
Definition at line 2852 of file features.c.
References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, config, feature_group_exten::feature, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
02852 { 02853 02854 char dynamic_features_buf[128]; 02855 const char *peer_dynamic_features, *chan_dynamic_features; 02856 struct ast_flags features; 02857 struct ast_call_feature feature; 02858 if (sense == FEATURE_SENSE_CHAN) { 02859 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 02860 } 02861 else { 02862 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 02863 } 02864 02865 ast_channel_lock(peer); 02866 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 02867 ast_channel_unlock(peer); 02868 02869 ast_channel_lock(chan); 02870 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 02871 ast_channel_unlock(chan); 02872 02873 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,"")); 02874 02875 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); 02876 02877 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature); 02878 }
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.
chan,peer,config,code,sense,dynamic_features_buf,features,operation,feature | Lock features list, browse for code, unlock list If a feature is found and the operation variable is set, that feature's operation is executed. The first feature found is copied to the feature parameter. |
res | on success. | |
-1 | on failure. |
Definition at line 2745 of file features.c.
References ast_debug, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_STOREDIGITS, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_strlen_zero(), ast_test_flag, ast_verb, builtin_features, config, feature_group_exten::entry, ast_call_feature::exten, feature_group_exten::exten, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), find_group(), ast_call_feature::fname, ast_call_feature::operation, ast_call_feature::sname, and strsep().
Referenced by ast_feature_detect(), and feature_interpret().
02748 { 02749 int x; 02750 struct feature_group *fg = NULL; 02751 struct feature_group_exten *fge; 02752 struct ast_call_feature *tmpfeature; 02753 char *tmp, *tok; 02754 int res = AST_FEATURE_RETURN_PASSDIGITS; 02755 int feature_detected = 0; 02756 02757 if (!(peer && chan && config) && operation) { 02758 return -1; /* can not run feature operation */ 02759 } 02760 02761 ast_rwlock_rdlock(&features_lock); 02762 for (x = 0; x < FEATURES_COUNT; x++) { 02763 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 02764 !ast_strlen_zero(builtin_features[x].exten)) { 02765 /* Feature is up for consideration */ 02766 if (!strcmp(builtin_features[x].exten, code)) { 02767 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 02768 if (operation) { 02769 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 02770 } 02771 memcpy(feature, &builtin_features[x], sizeof(feature)); 02772 feature_detected = 1; 02773 break; 02774 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 02775 if (res == AST_FEATURE_RETURN_PASSDIGITS) 02776 res = AST_FEATURE_RETURN_STOREDIGITS; 02777 } 02778 } 02779 } 02780 ast_rwlock_unlock(&features_lock); 02781 02782 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 02783 return res; 02784 } 02785 02786 tmp = dynamic_features_buf; 02787 02788 while ((tok = strsep(&tmp, "#"))) { 02789 AST_RWLIST_RDLOCK(&feature_groups); 02790 02791 fg = find_group(tok); 02792 02793 if (fg) { 02794 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 02795 if (!strcmp(fge->exten, code)) { 02796 if (operation) { 02797 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 02798 } 02799 memcpy(feature, fge->feature, sizeof(feature)); 02800 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 02801 AST_RWLIST_UNLOCK(&feature_groups); 02802 break; 02803 } 02804 res = AST_FEATURE_RETURN_PASSDIGITS; 02805 } else if (!strncmp(fge->exten, code, strlen(code))) { 02806 res = AST_FEATURE_RETURN_STOREDIGITS; 02807 } 02808 } 02809 if (fge) { 02810 break; 02811 } 02812 } 02813 02814 AST_RWLIST_UNLOCK(&feature_groups); 02815 02816 AST_RWLIST_RDLOCK(&feature_list); 02817 02818 if (!(tmpfeature = find_dynamic_feature(tok))) { 02819 AST_RWLIST_UNLOCK(&feature_list); 02820 continue; 02821 } 02822 02823 /* Feature is up for consideration */ 02824 if (!strcmp(tmpfeature->exten, code)) { 02825 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 02826 if (operation) { 02827 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 02828 } 02829 memcpy(feature, tmpfeature, sizeof(feature)); 02830 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 02831 AST_RWLIST_UNLOCK(&feature_list); 02832 break; 02833 } 02834 res = AST_FEATURE_RETURN_PASSDIGITS; 02835 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 02836 res = AST_FEATURE_RETURN_STOREDIGITS; 02837 02838 AST_RWLIST_UNLOCK(&feature_list); 02839 } 02840 02841 return res; 02842 }
static struct ast_channel * feature_request_and_dial | ( | struct ast_channel * | caller, | |
const char * | caller_name, | |||
struct ast_channel * | requestor, | |||
struct ast_channel * | transferee, | |||
const char * | type, | |||
format_t | format, | |||
void * | data, | |||
int | timeout, | |||
int * | outstate, | |||
const char * | language | |||
) | [static] |
Definition at line 2981 of file features.c.
References ast_channel::_state, ast_autoservice_start(), ast_autoservice_stop(), ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_connected_line_macro(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_redirecting_macro(), ast_channel_set_connected_line(), ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), ast_connected_line_parse_data(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_PROGRESS, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_frisolate(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_is_deferrable_frame(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_party_connected_line_free(), ast_party_connected_line_set_init(), ast_poll_channel_add(), ast_poll_channel_del(), ast_queue_frame_head(), ast_read(), ast_request(), ast_rwlock_rdlock, ast_rwlock_unlock, AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), builtin_features, ast_channel::call_forward, ast_channel::caller, cause, connected, ast_channel::connected, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_channel::hangupcause, LOG_NOTICE, ast_channel::name, and pbx_builtin_setvar_helper().
Referenced by builtin_atxfer().
02985 { 02986 int state = 0; 02987 int cause = 0; 02988 int to; 02989 int caller_hungup; 02990 int transferee_hungup; 02991 struct ast_channel *chan; 02992 struct ast_channel *monitor_chans[3]; 02993 struct ast_channel *active_channel; 02994 int res; 02995 int ready = 0; 02996 struct timeval started; 02997 int x, len = 0; 02998 char *disconnect_code = NULL, *dialed_code = NULL; 02999 struct ast_frame *f; 03000 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; 03001 03002 caller_hungup = ast_check_hangup(caller); 03003 03004 if (!(chan = ast_request(type, format, requestor, data, &cause))) { 03005 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 03006 switch (cause) { 03007 case AST_CAUSE_BUSY: 03008 state = AST_CONTROL_BUSY; 03009 break; 03010 case AST_CAUSE_CONGESTION: 03011 state = AST_CONTROL_CONGESTION; 03012 break; 03013 default: 03014 state = 0; 03015 break; 03016 } 03017 goto done; 03018 } 03019 03020 ast_string_field_set(chan, language, language); 03021 ast_channel_inherit_variables(caller, chan); 03022 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name); 03023 03024 ast_channel_lock(chan); 03025 ast_connected_line_copy_from_caller(&chan->connected, &requestor->caller); 03026 ast_channel_unlock(chan); 03027 03028 if (ast_call(chan, data, timeout)) { 03029 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 03030 switch (chan->hangupcause) { 03031 case AST_CAUSE_BUSY: 03032 state = AST_CONTROL_BUSY; 03033 break; 03034 case AST_CAUSE_CONGESTION: 03035 state = AST_CONTROL_CONGESTION; 03036 break; 03037 default: 03038 state = 0; 03039 break; 03040 } 03041 goto done; 03042 } 03043 03044 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 03045 ast_rwlock_rdlock(&features_lock); 03046 for (x = 0; x < FEATURES_COUNT; x++) { 03047 if (strcasecmp(builtin_features[x].sname, "disconnect")) 03048 continue; 03049 03050 disconnect_code = builtin_features[x].exten; 03051 len = strlen(disconnect_code) + 1; 03052 dialed_code = alloca(len); 03053 memset(dialed_code, 0, len); 03054 break; 03055 } 03056 ast_rwlock_unlock(&features_lock); 03057 x = 0; 03058 started = ast_tvnow(); 03059 to = timeout; 03060 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); 03061 03062 ast_poll_channel_add(caller, chan); 03063 03064 transferee_hungup = 0; 03065 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) { 03066 int num_chans = 0; 03067 03068 monitor_chans[num_chans++] = transferee; 03069 monitor_chans[num_chans++] = chan; 03070 if (!caller_hungup) { 03071 if (ast_check_hangup(caller)) { 03072 caller_hungup = 1; 03073 03074 #if defined(ATXFER_NULL_TECH) 03075 /* Change caller's name to ensure that it will remain unique. */ 03076 set_new_chan_name(caller); 03077 03078 /* 03079 * Get rid of caller's physical technology so it is free for 03080 * other calls. 03081 */ 03082 set_null_chan_tech(caller); 03083 #endif /* defined(ATXFER_NULL_TECH) */ 03084 } else { 03085 /* caller is not hungup so monitor it. */ 03086 monitor_chans[num_chans++] = caller; 03087 } 03088 } 03089 03090 /* see if the timeout has been violated */ 03091 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 03092 state = AST_CONTROL_UNHOLD; 03093 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name); 03094 break; /*doh! timeout*/ 03095 } 03096 03097 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to); 03098 if (!active_channel) 03099 continue; 03100 03101 f = NULL; 03102 if (transferee == active_channel) { 03103 struct ast_frame *dup_f; 03104 03105 f = ast_read(transferee); 03106 if (f == NULL) { /*doh! where'd he go?*/ 03107 transferee_hungup = 1; 03108 state = 0; 03109 break; 03110 } 03111 if (ast_is_deferrable_frame(f)) { 03112 dup_f = ast_frisolate(f); 03113 if (dup_f) { 03114 if (dup_f == f) { 03115 f = NULL; 03116 } 03117 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); 03118 } 03119 } 03120 } else if (chan == active_channel) { 03121 if (!ast_strlen_zero(chan->call_forward)) { 03122 state = 0; 03123 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state); 03124 if (!chan) { 03125 break; 03126 } 03127 continue; 03128 } 03129 f = ast_read(chan); 03130 if (f == NULL) { /*doh! where'd he go?*/ 03131 switch (chan->hangupcause) { 03132 case AST_CAUSE_BUSY: 03133 state = AST_CONTROL_BUSY; 03134 break; 03135 case AST_CAUSE_CONGESTION: 03136 state = AST_CONTROL_CONGESTION; 03137 break; 03138 default: 03139 state = 0; 03140 break; 03141 } 03142 break; 03143 } 03144 03145 if (f->frametype == AST_FRAME_CONTROL) { 03146 if (f->subclass.integer == AST_CONTROL_RINGING) { 03147 ast_verb(3, "%s is ringing\n", chan->name); 03148 ast_indicate(caller, AST_CONTROL_RINGING); 03149 } else if (f->subclass.integer == AST_CONTROL_BUSY) { 03150 state = f->subclass.integer; 03151 ast_verb(3, "%s is busy\n", chan->name); 03152 ast_indicate(caller, AST_CONTROL_BUSY); 03153 ast_frfree(f); 03154 break; 03155 } else if (f->subclass.integer == AST_CONTROL_CONGESTION) { 03156 state = f->subclass.integer; 03157 ast_verb(3, "%s is congested\n", chan->name); 03158 ast_indicate(caller, AST_CONTROL_CONGESTION); 03159 ast_frfree(f); 03160 break; 03161 } else if (f->subclass.integer == AST_CONTROL_ANSWER) { 03162 /* This is what we are hoping for */ 03163 state = f->subclass.integer; 03164 ast_frfree(f); 03165 ready=1; 03166 break; 03167 } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) { 03168 if (caller_hungup) { 03169 struct ast_party_connected_line connected; 03170 03171 /* Just save it for the transfer. */ 03172 ast_party_connected_line_set_init(&connected, &caller->connected); 03173 res = ast_connected_line_parse_data(f->data.ptr, f->datalen, 03174 &connected); 03175 if (!res) { 03176 ast_channel_set_connected_line(caller, &connected, NULL); 03177 } 03178 ast_party_connected_line_free(&connected); 03179 } else { 03180 ast_autoservice_start(transferee); 03181 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { 03182 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, 03183 f->data.ptr, f->datalen); 03184 } 03185 ast_autoservice_stop(transferee); 03186 } 03187 } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) { 03188 if (!caller_hungup) { 03189 ast_autoservice_start(transferee); 03190 if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { 03191 ast_indicate_data(caller, AST_CONTROL_REDIRECTING, 03192 f->data.ptr, f->datalen); 03193 } 03194 ast_autoservice_stop(transferee); 03195 } 03196 } else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) { 03197 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer); 03198 } 03199 /* else who cares */ 03200 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03201 ast_write(caller, f); 03202 } 03203 } else if (caller == active_channel) { 03204 f = ast_read(caller); 03205 if (f) { 03206 if (f->frametype == AST_FRAME_DTMF) { 03207 dialed_code[x++] = f->subclass.integer; 03208 dialed_code[x] = '\0'; 03209 if (strlen(dialed_code) == len) { 03210 x = 0; 03211 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 03212 x = 0; 03213 dialed_code[x] = '\0'; 03214 } 03215 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 03216 /* Caller Canceled the call */ 03217 state = AST_CONTROL_UNHOLD; 03218 ast_frfree(f); 03219 break; 03220 } 03221 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 03222 ast_write(chan, f); 03223 } 03224 } 03225 } 03226 if (f) 03227 ast_frfree(f); 03228 } /* end while */ 03229 03230 ast_poll_channel_del(caller, chan); 03231 03232 /* 03233 * We need to free all the deferred frames, but we only need to 03234 * queue the deferred frames if no hangup was received. 03235 */ 03236 ast_channel_lock(transferee); 03237 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee)); 03238 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { 03239 if (!transferee_hungup) { 03240 ast_queue_frame_head(transferee, f); 03241 } 03242 ast_frfree(f); 03243 } 03244 ast_channel_unlock(transferee); 03245 03246 done: 03247 ast_indicate(caller, -1); 03248 if (chan && (ready || chan->_state == AST_STATE_UP)) { 03249 state = AST_CONTROL_ANSWER; 03250 } else if (chan) { 03251 ast_hangup(chan); 03252 chan = NULL; 03253 } 03254 03255 if (outstate) 03256 *outstate = state; 03257 03258 return chan; 03259 }
static int find_channel_by_group | ( | void * | obj, | |
void * | arg, | |||
void * | data, | |||
int | flags | |||
) | [static] |
Definition at line 5573 of file features.c.
References ast_channel::_state, AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, CMP_MATCH, CMP_STOP, ast_channel::masq, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by ast_pickup_call().
05574 { 05575 struct ast_channel *c = data; 05576 struct ast_channel *chan = obj; 05577 05578 int i = !chan->pbx && 05579 /* Accessing 'chan' here is safe without locking, because there is no way for 05580 the channel do disappear from under us at this point. pickupgroup *could* 05581 change while we're here, but that isn't a problem. */ 05582 (c != chan) && 05583 (chan->pickupgroup & c->callgroup) && 05584 ((chan->_state == AST_STATE_RINGING) || (chan->_state == AST_STATE_RING)) && 05585 !c->masq; 05586 05587 return i ? CMP_MATCH | CMP_STOP : 0; 05588 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a call feature by name
Definition at line 2563 of file features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by feature_interpret_helper(), and set_config_flags().
02564 { 02565 struct ast_call_feature *tmp; 02566 02567 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 02568 if (!strcasecmp(tmp->sname, name)) { 02569 break; 02570 } 02571 } 02572 02573 return tmp; 02574 }
static struct feature_group* find_group | ( | const char * | name | ) | [static] |
Find a group by name.
name | feature name |
feature | group on success. | |
NULL | on failure. |
Definition at line 2601 of file features.c.
References AST_LIST_TRAVERSE, feature_group_exten::entry, and feature_group::gname.
Referenced by feature_interpret_helper().
02602 { 02603 struct feature_group *fg = NULL; 02604 02605 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 02606 if (!strcasecmp(fg->gname, name)) 02607 break; 02608 } 02609 02610 return fg; 02611 }
struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) |
Find parkinglot by name.
Definition at line 4248 of file features.c.
References ao2_find, ast_debug, ast_strlen_zero(), parkinglot, and parkinglots.
Referenced by build_parkinglot(), copy_parkinglot(), manager_park(), and park_space_reserve().
04249 { 04250 struct ast_parkinglot *parkinglot; 04251 04252 if (ast_strlen_zero(name)) { 04253 return NULL; 04254 } 04255 04256 parkinglot = ao2_find(parkinglots, (void *) name, 0); 04257 if (parkinglot) { 04258 ast_debug(1, "Found Parkinglot: %s\n", parkinglot->name); 04259 } 04260 04261 return parkinglot; 04262 }
static int find_parkinglot_by_exten_cb | ( | void * | obj, | |
void * | args, | |||
int | flags | |||
) | [static] |
Definition at line 631 of file features.c.
References CMP_MATCH, CMP_STOP, and parkinglot.
Referenced by ast_park_call(), builtin_atxfer(), builtin_blindtransfer(), and park_call_exec().
00632 { 00633 struct ast_parkinglot *parkinglot = obj; 00634 const char *parkext = args; 00635 00636 if (!strcmp(parkinglot->parkext, parkext)) { 00637 return CMP_MATCH | CMP_STOP; 00638 } 00639 00640 return 0; 00641 }
static int find_parkinglot_by_position_cb | ( | void * | obj, | |
void * | args, | |||
int | flags | |||
) | [static] |
Definition at line 619 of file features.c.
References CMP_MATCH, CMP_STOP, and parkinglot.
Referenced by park_exec_full().
00620 { 00621 struct ast_parkinglot *parkinglot = obj; 00622 int *parkpos = args; 00623 00624 if (*parkpos >= parkinglot->parking_start && *parkpos <= parkinglot->parking_stop) { 00625 return CMP_MATCH | CMP_STOP; 00626 } 00627 00628 return 0; 00629 }
static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 838 of file features.c.
References ast_strlen_zero(), ast_channel::parkinglot, parkinglot, and pbx_builtin_getvar_helper().
Referenced by park_space_reserve().
00839 { 00840 const char *temp, *parkinglot = NULL; 00841 00842 /* Check if the channel has a parking lot */ 00843 if (!ast_strlen_zero(chan->parkinglot)) 00844 parkinglot = chan->parkinglot; 00845 00846 /* Channel variables override everything */ 00847 00848 if ((temp = pbx_builtin_getvar_helper(chan, "PARKINGLOT"))) 00849 return temp; 00850 00851 return parkinglot; 00852 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1802 of file features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by atxfer_fail_cleanup(), builtin_atxfer(), and builtin_blindtransfer().
01803 { 01804 ast_indicate(chan, AST_CONTROL_UNHOLD); 01805 01806 return ast_autoservice_stop(chan); 01807 }
static char* handle_feature_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
CLI command to list configured features.
e | ||
cmd | ||
a |
CLI_SUCCESS | on success. | |
NULL | when tab completion is used. |
Definition at line 5107 of file features.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), AST_LIST_TRAVERSE, ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, builtin_features, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, feature_group_exten::entry, feature_group_exten::exten, ast_call_feature::exten, ast_cli_args::fd, feature_group_exten::feature, feature_group::features, FEATURES_COUNT, features_lock, ast_call_feature::fname, feature_group::gname, HFS_FORMAT, ast_parkinglot::mohclass, ast_parkinglot::name, ast_parkinglot::parkext, ast_parkinglot::parking_con, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglots, ast_parkinglot::parkingtime, ast_call_feature::sname, and ast_cli_entry::usage.
05108 { 05109 int i; 05110 struct ast_call_feature *feature; 05111 struct ao2_iterator iter; 05112 struct ast_parkinglot *curlot; 05113 #define HFS_FORMAT "%-25s %-7s %-7s\n" 05114 05115 switch (cmd) { 05116 05117 case CLI_INIT: 05118 e->command = "features show"; 05119 e->usage = 05120 "Usage: features show\n" 05121 " Lists configured features\n"; 05122 return NULL; 05123 case CLI_GENERATE: 05124 return NULL; 05125 } 05126 05127 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 05128 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 05129 05130 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 05131 05132 ast_rwlock_rdlock(&features_lock); 05133 for (i = 0; i < FEATURES_COUNT; i++) 05134 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 05135 ast_rwlock_unlock(&features_lock); 05136 05137 ast_cli(a->fd, "\n"); 05138 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 05139 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 05140 if (AST_RWLIST_EMPTY(&feature_list)) { 05141 ast_cli(a->fd, "(none)\n"); 05142 } else { 05143 AST_RWLIST_RDLOCK(&feature_list); 05144 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 05145 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 05146 } 05147 AST_RWLIST_UNLOCK(&feature_list); 05148 } 05149 05150 ast_cli(a->fd, "\nFeature Groups:\n"); 05151 ast_cli(a->fd, "---------------\n"); 05152 if (AST_RWLIST_EMPTY(&feature_groups)) { 05153 ast_cli(a->fd, "(none)\n"); 05154 } else { 05155 struct feature_group *fg; 05156 struct feature_group_exten *fge; 05157 05158 AST_RWLIST_RDLOCK(&feature_groups); 05159 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 05160 ast_cli(a->fd, "===> Group: %s\n", fg->gname); 05161 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 05162 ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten); 05163 } 05164 } 05165 AST_RWLIST_UNLOCK(&feature_groups); 05166 } 05167 05168 iter = ao2_iterator_init(parkinglots, 0); 05169 while ((curlot = ao2_iterator_next(&iter))) { 05170 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 05171 ast_cli(a->fd, "------------\n"); 05172 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->parkext); 05173 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->parking_con); 05174 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop); 05175 ast_cli(a->fd,"%-22s: %d\n", "Parkingtime", curlot->parkingtime); 05176 ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->mohclass); 05177 ast_cli(a->fd,"\n"); 05178 ao2_ref(curlot, -1); 05179 } 05180 ao2_iterator_destroy(&iter); 05181 05182 return CLI_SUCCESS; 05183 }
static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 5209 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
05210 { 05211 switch (cmd) { 05212 case CLI_INIT: 05213 e->command = "features reload"; 05214 e->usage = 05215 "Usage: features reload\n" 05216 " Reloads configured call features from features.conf\n"; 05217 return NULL; 05218 case CLI_GENERATE: 05219 return NULL; 05220 } 05221 ast_features_reload(); 05222 05223 return CLI_SUCCESS; 05224 }
static char* handle_parkedcalls | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
CLI command to list parked calls.
e | ||
cmd | ||
a | Check right usage, lock parking lot, display parked calls, unlock parking lot list. |
CLI_SUCCESS | on success. | |
CLI_SHOWUSAGE | on incorrect number of arguments. | |
NULL | when tab completion is used. |
Definition at line 5391 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.
05392 { 05393 struct parkeduser *cur; 05394 int numparked = 0; 05395 struct ao2_iterator iter; 05396 struct ast_parkinglot *curlot; 05397 05398 switch (cmd) { 05399 case CLI_INIT: 05400 e->command = "parkedcalls show"; 05401 e->usage = 05402 "Usage: parkedcalls show\n" 05403 " List currently parked calls\n"; 05404 return NULL; 05405 case CLI_GENERATE: 05406 return NULL; 05407 } 05408 05409 if (a->argc > e->args) 05410 return CLI_SHOWUSAGE; 05411 05412 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 05413 , "Context", "Extension", "Pri", "Timeout"); 05414 05415 iter = ao2_iterator_init(parkinglots, 0); 05416 while ((curlot = ao2_iterator_next(&iter))) { 05417 int lotparked = 0; 05418 /* subtract ref for iterator and for configured parking lot */ 05419 ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, ao2_ref(curlot, 0) - 2); 05420 05421 AST_LIST_LOCK(&curlot->parkings); 05422 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 05423 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 05424 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 05425 ,cur->priority, 05426 (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) ); 05427 numparked++; 05428 numparked += lotparked; 05429 } 05430 AST_LIST_UNLOCK(&curlot->parkings); 05431 if (lotparked) 05432 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name); 05433 05434 ao2_ref(curlot, -1); 05435 } 05436 05437 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 05438 05439 return CLI_SUCCESS; 05440 }
static int load_config | ( | void | ) | [static] |
Definition at line 4760 of file features.c.
References adsipark, ao2_lock, ao2_unlock, ast_config_load2(), ast_copy_string(), ast_debug, ast_log(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_EXTENSION, DEFAULT_PARK_TIME, DEFAULT_PARKINGLOT, default_parkinglot, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_ERROR, LOG_WARNING, parkeddynamic, pickup_ext, pickupfailsound, pickupsound, transferdigittimeout, var, xferfailsound, and xfersound.
04761 { 04762 int start = 0, end = 0; 04763 int res; 04764 int i; 04765 struct ast_context *con = NULL; 04766 struct ast_config *cfg = NULL; 04767 struct ast_variable *var = NULL; 04768 struct feature_group *fg = NULL; 04769 struct ast_flags config_flags = { 0 }; 04770 char *ctg; 04771 static const char * const categories[] = { 04772 /* Categories in features.conf that are not 04773 * to be parsed as group categories 04774 */ 04775 "general", 04776 "featuremap", 04777 "applicationmap" 04778 }; 04779 04780 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 04781 if (default_parkinglot) { 04782 ao2_lock(default_parkinglot); 04783 ast_copy_string(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(default_parkinglot->parkext)); 04784 default_parkinglot->parking_start = 701; 04785 default_parkinglot->parking_stop = 750; 04786 default_parkinglot->parking_offset = 0; 04787 default_parkinglot->parkfindnext = 0; 04788 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 04789 ao2_unlock(default_parkinglot); 04790 } 04791 04792 if (default_parkinglot) { 04793 ast_debug(1, "Configuration of default parkinglot done.\n"); 04794 } else { 04795 ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n"); 04796 return -1; 04797 } 04798 04799 /* Reset to defaults */ 04800 strcpy(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION); 04801 strcpy(pickup_ext, "*8"); 04802 courtesytone[0] = '\0'; 04803 strcpy(xfersound, "beep"); 04804 strcpy(xferfailsound, "beeperr"); 04805 pickupsound[0] = '\0'; 04806 pickupfailsound[0] = '\0'; 04807 adsipark = 0; 04808 comebacktoorigin = 1; 04809 parkeddynamic = 0; 04810 04811 default_parkinglot->parkaddhints = 0; 04812 default_parkinglot->parkedcalltransfers = 0; 04813 default_parkinglot->parkedcallreparking = 0; 04814 default_parkinglot->parkedcallrecording = 0; 04815 default_parkinglot->parkedcallhangup = 0; 04816 04817 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 04818 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 04819 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 04820 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 04821 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 04822 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 04823 04824 cfg = ast_config_load2("features.conf", "features", config_flags); 04825 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { 04826 ast_log(LOG_WARNING,"Could not load features.conf\n"); 04827 return 0; 04828 } 04829 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 04830 if (!strcasecmp(var->name, "parkext")) { 04831 ast_copy_string(default_parkinglot->parkext, var->value, sizeof(default_parkinglot->parkext)); 04832 } else if (!strcasecmp(var->name, "context")) { 04833 ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con)); 04834 } else if (!strcasecmp(var->name, "parkingtime")) { 04835 if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) { 04836 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 04837 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 04838 } else 04839 default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000; 04840 } else if (!strcasecmp(var->name, "parkpos")) { 04841 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 04842 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); 04843 } else if (default_parkinglot) { 04844 default_parkinglot->parking_start = start; 04845 default_parkinglot->parking_stop = end; 04846 } else { 04847 ast_log(LOG_WARNING, "No default parking lot!\n"); 04848 } 04849 } else if (!strcasecmp(var->name, "findslot")) { 04850 default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next")); 04851 } else if (!strcasecmp(var->name, "parkinghints")) { 04852 default_parkinglot->parkaddhints = ast_true(var->value); 04853 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 04854 if (!strcasecmp(var->value, "both")) 04855 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 04856 else if (!strcasecmp(var->value, "caller")) 04857 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 04858 else if (!strcasecmp(var->value, "callee")) 04859 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 04860 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 04861 if (!strcasecmp(var->value, "both")) 04862 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 04863 else if (!strcasecmp(var->value, "caller")) 04864 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 04865 else if (!strcasecmp(var->value, "callee")) 04866 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 04867 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 04868 if (!strcasecmp(var->value, "both")) 04869 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 04870 else if (!strcasecmp(var->value, "caller")) 04871 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 04872 else if (!strcasecmp(var->value, "callee")) 04873 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 04874 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 04875 if (!strcasecmp(var->value, "both")) 04876 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 04877 else if (!strcasecmp(var->value, "caller")) 04878 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 04879 else if (!strcasecmp(var->value, "callee")) 04880 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 04881 } else if (!strcasecmp(var->name, "parkeddynamic")) { 04882 parkeddynamic = ast_true(var->value); 04883 } else if (!strcasecmp(var->name, "adsipark")) { 04884 adsipark = ast_true(var->value); 04885 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 04886 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 04887 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 04888 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 04889 } else 04890 transferdigittimeout = transferdigittimeout * 1000; 04891 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 04892 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 04893 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 04894 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 04895 } 04896 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 04897 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 04898 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 04899 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 04900 } else 04901 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 04902 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 04903 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 04904 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 04905 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 04906 } else 04907 atxferloopdelay *= 1000; 04908 } else if (!strcasecmp(var->name, "atxferdropcall")) { 04909 atxferdropcall = ast_true(var->value); 04910 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 04911 if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) { 04912 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 04913 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 04914 } 04915 } else if (!strcasecmp(var->name, "courtesytone")) { 04916 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 04917 } else if (!strcasecmp(var->name, "parkedplay")) { 04918 if (!strcasecmp(var->value, "both")) 04919 parkedplay = 2; 04920 else if (!strcasecmp(var->value, "parked")) 04921 parkedplay = 1; 04922 else 04923 parkedplay = 0; 04924 } else if (!strcasecmp(var->name, "xfersound")) { 04925 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 04926 } else if (!strcasecmp(var->name, "xferfailsound")) { 04927 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 04928 } else if (!strcasecmp(var->name, "pickupexten")) { 04929 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 04930 } else if (!strcasecmp(var->name, "pickupsound")) { 04931 ast_copy_string(pickupsound, var->value, sizeof(pickupsound)); 04932 } else if (!strcasecmp(var->name, "pickupfailsound")) { 04933 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound)); 04934 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 04935 comebacktoorigin = ast_true(var->value); 04936 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 04937 ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass)); 04938 } 04939 } 04940 04941 unmap_features(); 04942 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 04943 if (remap_feature(var->name, var->value)) 04944 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 04945 } 04946 04947 /* Map a key combination to an application*/ 04948 ast_unregister_features(); 04949 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 04950 char *tmp_val = ast_strdupa(var->value); 04951 char *activateon; 04952 struct ast_call_feature *feature; 04953 AST_DECLARE_APP_ARGS(args, 04954 AST_APP_ARG(exten); 04955 AST_APP_ARG(activatedby); 04956 AST_APP_ARG(app); 04957 AST_APP_ARG(app_args); 04958 AST_APP_ARG(moh_class); 04959 ); 04960 04961 AST_STANDARD_APP_ARGS(args, tmp_val); 04962 if (strchr(args.app, '(')) { 04963 /* New syntax */ 04964 args.moh_class = args.app_args; 04965 args.app_args = strchr(args.app, '('); 04966 *args.app_args++ = '\0'; 04967 if (args.app_args[strlen(args.app_args) - 1] == ')') { 04968 args.app_args[strlen(args.app_args) - 1] = '\0'; 04969 } 04970 } 04971 04972 activateon = strsep(&args.activatedby, "/"); 04973 04974 /*! \todo XXX var_name or app_args ? */ 04975 if (ast_strlen_zero(args.app) || ast_strlen_zero(args.exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 04976 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 04977 args.app, args.exten, activateon, var->name); 04978 continue; 04979 } 04980 04981 AST_RWLIST_RDLOCK(&feature_list); 04982 if ((feature = find_dynamic_feature(var->name))) { 04983 AST_RWLIST_UNLOCK(&feature_list); 04984 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 04985 continue; 04986 } 04987 AST_RWLIST_UNLOCK(&feature_list); 04988 04989 if (!(feature = ast_calloc(1, sizeof(*feature)))) { 04990 continue; 04991 } 04992 04993 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 04994 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN); 04995 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN); 04996 04997 if (args.app_args) { 04998 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN); 04999 } 05000 05001 if (args.moh_class) { 05002 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN); 05003 } 05004 05005 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten)); 05006 feature->operation = feature_exec_app; 05007 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 05008 05009 /* Allow caller and calle to be specified for backwards compatability */ 05010 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 05011 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 05012 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 05013 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 05014 else { 05015 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 05016 " must be 'self', or 'peer'\n", var->name); 05017 continue; 05018 } 05019 05020 if (ast_strlen_zero(args.activatedby)) 05021 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05022 else if (!strcasecmp(args.activatedby, "caller")) 05023 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 05024 else if (!strcasecmp(args.activatedby, "callee")) 05025 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 05026 else if (!strcasecmp(args.activatedby, "both")) 05027 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 05028 else { 05029 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 05030 " must be 'caller', or 'callee', or 'both'\n", var->name); 05031 continue; 05032 } 05033 05034 ast_register_feature(feature); 05035 05036 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, args.app, args.app_args, args.exten); 05037 } 05038 05039 ast_unregister_groups(); 05040 AST_RWLIST_WRLOCK(&feature_groups); 05041 05042 ctg = NULL; 05043 while ((ctg = ast_category_browse(cfg, ctg))) { 05044 /* Is this a parkinglot definition ? */ 05045 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 05046 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 05047 if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) 05048 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 05049 else 05050 ast_debug(1, "Configured parking context %s\n", ctg); 05051 continue; 05052 } 05053 /* No, check if it's a group */ 05054 for (i = 0; i < ARRAY_LEN(categories); i++) { 05055 if (!strcasecmp(categories[i], ctg)) 05056 break; 05057 } 05058 05059 if (i < ARRAY_LEN(categories)) 05060 continue; 05061 05062 if (!(fg = register_group(ctg))) 05063 continue; 05064 05065 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 05066 struct ast_call_feature *feature; 05067 05068 AST_RWLIST_RDLOCK(&feature_list); 05069 if (!(feature = find_dynamic_feature(var->name)) && 05070 !(feature = ast_find_call_feature(var->name))) { 05071 AST_RWLIST_UNLOCK(&feature_list); 05072 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 05073 continue; 05074 } 05075 AST_RWLIST_UNLOCK(&feature_list); 05076 05077 register_group_feature(fg, var->value, feature); 05078 } 05079 } 05080 05081 AST_RWLIST_UNLOCK(&feature_groups); 05082 05083 ast_config_destroy(cfg); 05084 05085 if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) { 05086 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con); 05087 return -1; 05088 } 05089 res = ast_add_extension2(con, 1, default_parkinglot->parkext, 1, NULL, NULL, parkcall, NULL, NULL, registrar); 05090 if (default_parkinglot->parkaddhints) 05091 park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop); 05092 if (!res) 05093 notify_metermaids(default_parkinglot->parkext, default_parkinglot->parking_con, AST_DEVICE_INUSE); 05094 return res; 05095 05096 }
int manage_parkinglot | ( | struct ast_parkinglot * | curlot, | |
const struct pollfd * | pfds, | |||
const int | nfds, | |||
struct pollfd ** | new_pfds, | |||
int * | new_nfds, | |||
int * | fs | |||
) |
Run management on parkinglots, called once per parkinglot.
Definition at line 4005 of file features.c.
References ast_add_extension2(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_debug, AST_DEVICE_NOT_INUSE, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, ast_log(), ast_pbx_start(), ast_read(), ast_realloc, ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, callback_dialoptions(), parkeduser::chan, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, free, ast_channel::generatordata, parkeduser::list, LOG_ERROR, LOG_NOTICE, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_unref(), parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), and parkeduser::start.
Referenced by do_parking_thread().
04006 { 04007 struct parkeduser *pu; 04008 int res = 0; 04009 char parkingslot[AST_MAX_EXTENSION]; 04010 04011 /* Lock parking list */ 04012 AST_LIST_LOCK(&curlot->parkings); 04013 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 04014 struct ast_channel *chan = pu->chan; /* shorthand */ 04015 int tms; /* timeout for this item */ 04016 int x; /* fd index in channel */ 04017 struct ast_context *con; 04018 04019 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 04020 continue; 04021 } 04022 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 04023 if (tms > pu->parkingtime) { 04024 /* Stop music on hold */ 04025 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 04026 /* Get chan, exten from derived kludge */ 04027 if (pu->peername[0]) { 04028 char *peername = ast_strdupa(pu->peername); 04029 char *dash = strrchr(peername, '-'); 04030 char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 04031 int i; 04032 04033 if (dash) { 04034 *dash = '\0'; 04035 } 04036 04037 peername_flat = ast_strdupa(peername); 04038 for (i = 0; peername_flat[i]; i++) { 04039 if (peername_flat[i] == '/') { 04040 peername_flat[i]= '_'; 04041 } 04042 } 04043 04044 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar); 04045 if (!con) { 04046 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial); 04047 } else { 04048 char returnexten[AST_MAX_EXTENSION]; 04049 struct ast_datastore *features_datastore; 04050 struct ast_dial_features *dialfeatures = NULL; 04051 04052 ast_channel_lock(chan); 04053 04054 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 04055 dialfeatures = features_datastore->data; 04056 04057 ast_channel_unlock(chan); 04058 04059 if (!strncmp(peername, "Parked/", 7)) { 04060 peername += 7; 04061 } 04062 04063 if (dialfeatures) { 04064 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 04065 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 04066 } else { /* Existing default */ 04067 ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n", chan->name); 04068 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername); 04069 } 04070 04071 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar); 04072 } 04073 if (pu->options_specified == 1) { 04074 /* Park() was called with overriding return arguments, respect those arguments */ 04075 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04076 } else { 04077 if (comebacktoorigin) { 04078 set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1); 04079 } else { 04080 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 04081 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 04082 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 04083 } 04084 } 04085 } else { 04086 /* They've been waiting too long, send them back to where they came. Theoretically they 04087 should have their original extensions and such, but we copy to be on the safe side */ 04088 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 04089 } 04090 post_manager_event("ParkedCallTimeOut", pu); 04091 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL); 04092 04093 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); 04094 /* Start up the PBX, or hang them up */ 04095 if (ast_pbx_start(chan)) { 04096 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name); 04097 ast_hangup(chan); 04098 } 04099 /* And take them out of the parking lot */ 04100 con = ast_context_find(pu->parkinglot->parking_con); 04101 if (con) { 04102 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 04103 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n"); 04104 else 04105 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 04106 } else 04107 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 04108 AST_LIST_REMOVE_CURRENT(list); 04109 free(pu); 04110 } else { /* still within parking time, process descriptors */ 04111 for (x = 0; x < AST_MAX_FDS; x++) { 04112 struct ast_frame *f; 04113 int y; 04114 04115 if (chan->fds[x] == -1) { 04116 continue; /* nothing on this descriptor */ 04117 } 04118 04119 for (y = 0; y < nfds; y++) { 04120 if (pfds[y].fd == chan->fds[x]) { 04121 /* Found poll record! */ 04122 break; 04123 } 04124 } 04125 if (y == nfds) { 04126 /* Not found */ 04127 continue; 04128 } 04129 04130 if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) { 04131 /* Next x */ 04132 continue; 04133 } 04134 04135 if (pfds[y].revents & POLLPRI) { 04136 ast_set_flag(chan, AST_FLAG_EXCEPTION); 04137 } else { 04138 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 04139 } 04140 chan->fdno = x; 04141 04142 /* See if they need servicing */ 04143 f = ast_read(pu->chan); 04144 /* Hangup? */ 04145 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) { 04146 if (f) 04147 ast_frfree(f); 04148 post_manager_event("ParkedCallGiveUp", pu); 04149 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", NULL); 04150 04151 /* There's a problem, hang them up*/ 04152 ast_verb(2, "%s got tired of being parked\n", chan->name); 04153 ast_hangup(chan); 04154 /* And take them out of the parking lot */ 04155 con = ast_context_find(curlot->parking_con); 04156 if (con) { 04157 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 04158 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 04159 else 04160 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 04161 } else 04162 ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name); 04163 AST_LIST_REMOVE_CURRENT(list); 04164 parkinglot_unref(pu->parkinglot); 04165 free(pu); 04166 break; 04167 } else { 04168 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 04169 ast_frfree(f); 04170 if (pu->moh_trys < 3 && !chan->generatordata) { 04171 ast_debug(1, "MOH on parked call stopped by outside source. Restarting on channel %s.\n", chan->name); 04172 ast_indicate_data(chan, AST_CONTROL_HOLD, 04173 S_OR(curlot->mohclass, NULL), 04174 (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0)); 04175 pu->moh_trys++; 04176 } 04177 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 04178 } 04179 } /* End for */ 04180 if (x >= AST_MAX_FDS) { 04181 std: for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */ 04182 if (chan->fds[x] > -1) { 04183 void *tmp = ast_realloc(*new_pfds, (*new_nfds + 1) * sizeof(struct pollfd)); 04184 if (!tmp) { 04185 continue; 04186 } 04187 *new_pfds = tmp; 04188 (*new_pfds)[*new_nfds].fd = chan->fds[x]; 04189 (*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI; 04190 (*new_pfds)[*new_nfds].revents = 0; 04191 (*new_nfds)++; 04192 } 04193 } 04194 /* Keep track of our shortest wait */ 04195 if (tms < *ms || *ms < 0) { 04196 *ms = tms; 04197 } 04198 } 04199 } 04200 } 04201 AST_LIST_TRAVERSE_SAFE_END; 04202 AST_LIST_UNLOCK(&curlot->parkings); 04203 04204 return res; 04205 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Create manager event for parked calls.
s | ||
m | Get channels involved in park, create event. |
Definition at line 5510 of file features.c.
References args, ast_channel_get_by_name(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), CHANNEL_DEADLOCK_AVOIDANCE, find_parkinglot(), and masq_park_call().
Referenced by ast_features_init().
05511 { 05512 const char *channel = astman_get_header(m, "Channel"); 05513 const char *channel2 = astman_get_header(m, "Channel2"); 05514 const char *timeout = astman_get_header(m, "Timeout"); 05515 const char *parkinglotname = astman_get_header(m, "Parkinglot"); 05516 char buf[BUFSIZ]; 05517 int res = 0; 05518 struct ast_channel *ch1, *ch2; 05519 struct ast_park_call_args args = {0,}; 05520 05521 if (ast_strlen_zero(channel)) { 05522 astman_send_error(s, m, "Channel not specified"); 05523 return 0; 05524 } 05525 05526 if (ast_strlen_zero(channel2)) { 05527 astman_send_error(s, m, "Channel2 not specified"); 05528 return 0; 05529 } 05530 05531 if (!(ch1 = ast_channel_get_by_name(channel))) { 05532 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 05533 astman_send_error(s, m, buf); 05534 return 0; 05535 } 05536 05537 if (!(ch2 = ast_channel_get_by_name(channel2))) { 05538 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 05539 astman_send_error(s, m, buf); 05540 ast_channel_unref(ch1); 05541 return 0; 05542 } 05543 05544 if (!ast_strlen_zero(timeout)) { 05545 sscanf(timeout, "%30d", &args.timeout); 05546 } 05547 if (!ast_strlen_zero(parkinglotname)) { 05548 args.parkinglot = find_parkinglot(parkinglotname); 05549 } 05550 05551 ast_channel_lock(ch1); 05552 while (ast_channel_trylock(ch2)) { 05553 CHANNEL_DEADLOCK_AVOIDANCE(ch1); 05554 } 05555 05556 res = masq_park_call(ch1, ch2, 0, NULL, 0, &args); 05557 if (!res) { 05558 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 05559 astman_send_ack(s, m, "Park successful"); 05560 } else { 05561 astman_send_error(s, m, "Park failure"); 05562 } 05563 05564 ast_channel_unlock(ch1); 05565 ast_channel_unlock(ch2); 05566 05567 ch1 = ast_channel_unref(ch1); 05568 ch2 = ast_channel_unref(ch2); 05569 05570 return 0; 05571 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump parking lot status.
s | ||
m | Lock parking lot, iterate list and append parked calls status, unlock parking lot. |
Definition at line 5456 of file features.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::caller, parkeduser::chan, ast_party_caller::id, ast_party_id::name, ast_channel::name, ast_party_id::number, parkinglots, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, S_COR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.
Referenced by ast_features_init().
05457 { 05458 struct parkeduser *cur; 05459 const char *id = astman_get_header(m, "ActionID"); 05460 char idText[256] = ""; 05461 struct ao2_iterator iter; 05462 struct ast_parkinglot *curlot; 05463 05464 if (!ast_strlen_zero(id)) 05465 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 05466 05467 astman_send_ack(s, m, "Parked calls will follow"); 05468 05469 iter = ao2_iterator_init(parkinglots, 0); 05470 while ((curlot = ao2_iterator_next(&iter))) { 05471 05472 AST_LIST_LOCK(&curlot->parkings); 05473 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 05474 astman_append(s, "Event: ParkedCall\r\n" 05475 "Exten: %d\r\n" 05476 "Channel: %s\r\n" 05477 "From: %s\r\n" 05478 "Timeout: %ld\r\n" 05479 "CallerIDNum: %s\r\n" 05480 "CallerIDName: %s\r\n" 05481 "%s" 05482 "\r\n", 05483 cur->parkingnum, cur->chan->name, cur->peername, 05484 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 05485 S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""), /* XXX in other places it is <unknown> */ 05486 S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""), 05487 idText); 05488 } 05489 AST_LIST_UNLOCK(&curlot->parkings); 05490 ao2_ref(curlot, -1); 05491 } 05492 05493 astman_append(s, 05494 "Event: ParkedCallsComplete\r\n" 05495 "%s" 05496 "\r\n",idText); 05497 05498 05499 return RESULT_SUCCESS; 05500 }
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] |
rchan | is the transferee | |
peer | is the transferer |
Definition at line 1242 of file features.c.
References ast_channel::accountcode, ast_channel::amaflags, args, ast_channel_alloc, ast_channel_masquerade(), ast_copy_string(), AST_FEATURE_RETURN_PARKFAILED, ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), ast_channel::context, ast_channel::exten, f, ast_channel::linkedid, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, ast_channel::name, park_call_full(), park_space_reserve(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.
Referenced by ast_masq_park_call(), manager_park(), and masq_park_call_announce().
01243 { 01244 struct ast_channel *chan; 01245 struct ast_frame *f; 01246 struct ast_park_call_args park_args = {0,}; 01247 01248 if (!args) { 01249 args = &park_args; 01250 args->timeout = timeout; 01251 args->extout = extout; 01252 } 01253 01254 if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) { 01255 if (peer) { 01256 ast_stream_and_wait(peer, "pbx-parkingfailed", ""); 01257 } 01258 return AST_FEATURE_RETURN_PARKFAILED; 01259 } 01260 01261 /* Make a new, fake channel that we'll use to masquerade in the real one */ 01262 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s",rchan->name))) { 01263 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 01264 return -1; 01265 } 01266 01267 /* Make formats okay */ 01268 chan->readformat = rchan->readformat; 01269 chan->writeformat = rchan->writeformat; 01270 ast_channel_masquerade(chan, rchan); 01271 01272 /* Setup the extensions and such */ 01273 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 01274 01275 /* Setup the macro extension and such */ 01276 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext)); 01277 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten)); 01278 chan->macropriority = rchan->macropriority; 01279 01280 /* Make the masq execute */ 01281 if ((f = ast_read(chan))) 01282 ast_frfree(f); 01283 01284 if (peer == rchan) { 01285 peer = chan; 01286 } 01287 01288 if (peer && (!play_announcement && args == &park_args)) { 01289 args->orig_chan_name = ast_strdupa(peer->name); 01290 } 01291 01292 /* parking space reserved, return code check unnecessary */ 01293 park_call_full(chan, peer, args); 01294 01295 return 0; 01296 }
static int masq_park_call_announce | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 1304 of file features.c.
References args, and masq_park_call().
Referenced by builtin_blindtransfer(), park_call_exec(), and parkcall_helper().
01305 { 01306 return masq_park_call(rchan, peer, 0, NULL, 1, args); 01307 }
static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 864 of file features.c.
References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_strdupa, and strsep().
Referenced by ast_features_init().
00865 { 00866 char *context; 00867 char *exten; 00868 00869 context = ast_strdupa(data); 00870 00871 exten = strsep(&context, "@"); 00872 if (!context) 00873 return AST_DEVICE_INVALID; 00874 00875 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 00876 00877 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 00878 return AST_DEVICE_NOT_INUSE; 00879 00880 return AST_DEVICE_INUSE; 00881 }
static void notify_metermaids | ( | const char * | exten, | |
char * | context, | |||
enum ast_device_state | state | |||
) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 855 of file features.c.
References ast_debug, ast_devstate2str(), and ast_devstate_changed().
Referenced by manage_parkinglot(), park_call_full(), and park_exec_full().
00856 { 00857 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 00858 exten, context, ast_devstate2str(state)); 00859 00860 ast_devstate_changed(state, "park:%s@%s", exten, context); 00861 }
static void park_add_hints | ( | char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Add parking hints for all defined parking lots.
context | ||
start | starting parkinglot number | |
stop | ending parkinglot number |
Definition at line 4607 of file features.c.
References ast_add_extension(), PRIORITY_HINT, and registrar.
Referenced by build_parkinglot().
04608 { 04609 int numext; 04610 char device[AST_MAX_EXTENSION]; 04611 char exten[10]; 04612 04613 for (numext = start; numext <= stop; numext++) { 04614 snprintf(exten, sizeof(exten), "%d", numext); 04615 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 04616 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 04617 } 04618 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Park a call.
Definition at line 4295 of file features.c.
References ast_channel::_state, ao2_callback, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_channel::exten, find_parkinglot_by_exten_cb(), ast_flags::flags, LOG_WARNING, masq_park_call_announce(), ast_channel::name, orig_exten(), park_call_options, parkinglots, parse(), and ast_channel::priority.
Referenced by ast_features_init().
04296 { 04297 /* Cache the original channel name in case we get masqueraded in the middle 04298 * of a park--it is still theoretically possible for a transfer to happen before 04299 * we get here, but it is _really_ unlikely */ 04300 char *orig_chan_name = ast_strdupa(chan->name); 04301 char orig_exten[AST_MAX_EXTENSION]; 04302 int orig_priority = chan->priority; 04303 04304 /* Data is unused at the moment but could contain a parking 04305 lot context eventually */ 04306 int res = 0; 04307 04308 char *parse = NULL; 04309 AST_DECLARE_APP_ARGS(app_args, 04310 AST_APP_ARG(timeout); 04311 AST_APP_ARG(return_con); 04312 AST_APP_ARG(return_ext); 04313 AST_APP_ARG(return_pri); 04314 AST_APP_ARG(options); 04315 ); 04316 04317 parse = ast_strdupa(data); 04318 AST_STANDARD_APP_ARGS(app_args, parse); 04319 04320 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 04321 04322 /* Setup the exten/priority to be s/1 since we don't know 04323 where this call should return */ 04324 strcpy(chan->exten, "s"); 04325 chan->priority = 1; 04326 04327 /* Answer if call is not up */ 04328 if (chan->_state != AST_STATE_UP) 04329 res = ast_answer(chan); 04330 04331 /* Sleep to allow VoIP streams to settle down */ 04332 if (!res) 04333 res = ast_safe_sleep(chan, 1000); 04334 04335 /* Park the call */ 04336 if (!res) { 04337 struct ast_park_call_args args = { 04338 .orig_chan_name = orig_chan_name, 04339 }; 04340 struct ast_flags flags = { 0 }; 04341 04342 if (parse) { 04343 if (!ast_strlen_zero(app_args.timeout)) { 04344 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) { 04345 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 04346 args.timeout = 0; 04347 } 04348 } 04349 if (!ast_strlen_zero(app_args.return_con)) { 04350 args.return_con = app_args.return_con; 04351 } 04352 if (!ast_strlen_zero(app_args.return_ext)) { 04353 args.return_ext = app_args.return_ext; 04354 } 04355 if (!ast_strlen_zero(app_args.return_pri)) { 04356 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) { 04357 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 04358 args.return_pri = 0; 04359 } 04360 } 04361 } 04362 04363 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 04364 args.flags = flags.flags; 04365 04366 args.parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &orig_exten); 04367 res = masq_park_call_announce(chan, chan, &args); 04368 /* Continue on in the dialplan */ 04369 if (res == 1) { 04370 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 04371 chan->priority = orig_priority; 04372 res = 0; 04373 } else if (!res) { 04374 res = 1; 04375 } 04376 } 04377 04378 return res; 04379 }
static int park_call_full | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 1076 of file features.c.
References adsi_announce_park(), adsipark, ast_channel::appl, args, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_bridged_channel(), AST_CEL_PARK_START, ast_cel_report_event(), ast_channel_get_by_name(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_unlock, ast_channel_unref, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HOLD, AST_CONTROL_RINGING, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), ast_manager_event, AST_PARK_OPT_RINGING, AST_PARK_OPT_SILENCE, ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, ast_channel::caller, parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, ast_party_caller::id, ast_channel::language, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, ast_parkinglot::mohclass, ast_party_id::name, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkeduser::options_specified, park_space_reserve(), parkedcall, ast_parkinglot::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, ast_parkinglot::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, registrar, S_COR, S_OR, parkeduser::start, ast_party_name::str, ast_party_number::str, ast_channel::tech, ast_channel_tech::type, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.
Referenced by ast_park_call(), and masq_park_call().
01077 { 01078 struct ast_context *con; 01079 int parkingnum_copy; 01080 struct parkeduser *pu = args->pu; 01081 const char *event_from; 01082 01083 if (pu == NULL) 01084 args->pu = pu = park_space_reserve(chan, peer, args); 01085 if (pu == NULL) 01086 return 1; /* Continue execution if possible */ 01087 01088 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum); 01089 01090 chan->appl = "Parked Call"; 01091 chan->data = NULL; 01092 01093 pu->chan = chan; 01094 01095 /* Put the parked channel on hold if we have two different channels */ 01096 if (chan != peer) { 01097 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 01098 ast_indicate(pu->chan, AST_CONTROL_RINGING); 01099 } else { 01100 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01101 S_OR(pu->parkinglot->mohclass, NULL), 01102 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 01103 } 01104 } 01105 01106 pu->start = ast_tvnow(); 01107 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime; 01108 parkingnum_copy = pu->parkingnum; 01109 if (args->extout) 01110 *(args->extout) = pu->parkingnum; 01111 01112 if (peer) { 01113 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels 01114 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking 01115 and we need the callback name to be that of transferer. Since local,1/2 have the same 01116 name we can be tricky and just grab the bridged channel from the other side of the local 01117 */ 01118 if (!strcasecmp(peer->tech->type, "Local")) { 01119 struct ast_channel *tmpchan, *base_peer; 01120 char other_side[AST_CHANNEL_NAME]; 01121 char *c; 01122 ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side)); 01123 if ((c = strrchr(other_side, ';'))) { 01124 *++c = '1'; 01125 } 01126 if ((tmpchan = ast_channel_get_by_name(other_side))) { 01127 ast_channel_lock(tmpchan); 01128 if ((base_peer = ast_bridged_channel(tmpchan))) { 01129 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 01130 } 01131 ast_channel_unlock(tmpchan); 01132 tmpchan = ast_channel_unref(tmpchan); 01133 } 01134 } else { 01135 ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername)); 01136 } 01137 } 01138 01139 /* Remember what had been dialed, so that if the parking 01140 expires, we try to come back to the same place */ 01141 01142 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri); 01143 01144 /* If extension has options specified, they override all other possibilities 01145 such as the returntoorigin flag and transferred context. Information on 01146 extension options is lost here, so we set a flag */ 01147 01148 ast_copy_string(pu->context, 01149 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 01150 sizeof(pu->context)); 01151 ast_copy_string(pu->exten, 01152 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 01153 sizeof(pu->exten)); 01154 pu->priority = args->return_pri ? args->return_pri : 01155 (chan->macropriority ? chan->macropriority : chan->priority); 01156 01157 /* If parking a channel directly, don't quiet yet get parking running on it. 01158 * All parking lot entries are put into the parking lot with notquiteyet on. */ 01159 if (peer != chan) 01160 pu->notquiteyet = 0; 01161 01162 /* Wake up the (presumably select()ing) thread */ 01163 pthread_kill(parking_thread, SIGURG); 01164 ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); 01165 01166 ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer); 01167 01168 if (peer) { 01169 event_from = peer->name; 01170 } else { 01171 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 01172 } 01173 01174 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "ParkedCall", 01175 "Exten: %s\r\n" 01176 "Channel: %s\r\n" 01177 "Parkinglot: %s\r\n" 01178 "From: %s\r\n" 01179 "Timeout: %ld\r\n" 01180 "CallerIDNum: %s\r\n" 01181 "CallerIDName: %s\r\n" 01182 "Uniqueid: %s\r\n", 01183 pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "", 01184 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 01185 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 01186 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 01187 pu->chan->uniqueid 01188 ); 01189 01190 if (peer && adsipark && ast_adsi_available(peer)) { 01191 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 01192 ast_adsi_unload_session(peer); 01193 } 01194 01195 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar); 01196 if (!con) /* Still no context? Bad */ 01197 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con); 01198 if (con) { 01199 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar)) 01200 notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE); 01201 } 01202 01203 AST_LIST_UNLOCK(&pu->parkinglot->parkings); 01204 01205 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 01206 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) { 01207 /* If a channel is masqueraded into peer while playing back the parking slot number do not continue playing it back. This is the case if an attended transfer occurs. */ 01208 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01209 /* Tell the peer channel the number of the parking space */ 01210 ast_say_digits(peer, pu->parkingnum, "", peer->language); 01211 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 01212 } 01213 if (peer == chan) { /* pu->notquiteyet = 1 */ 01214 /* Wake up parking thread if we're really done */ 01215 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01216 S_OR(pu->parkinglot->mohclass, NULL), 01217 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 01218 pu->notquiteyet = 0; 01219 pthread_kill(parking_thread, SIGURG); 01220 } 01221 return 0; 01222 }
static int park_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 4553 of file features.c.
References park_exec_full().
Referenced by ast_features_init().
04554 { 04555 return park_exec_full(chan, data); 04556 }
static int park_exec_full | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Pickup parked call.
Definition at line 4382 of file features.c.
References ast_channel::_state, ao2_callback, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, ast_copy_flags, AST_DEVICE_NOT_INUSE, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_free, ast_hangup(), ast_indicate(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_manager_event, ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), ast_channel::caller, parkeduser::chan, config, courtesytone, ast_datastore::data, default_parkinglot, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_caller, find_parkinglot_by_position_cb(), ast_party_caller::id, LOG_WARNING, ast_party_id::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_party_id::number, parkedplay, parkeduser::parkingexten, parkinglot, parkinglot_unref(), parkinglots, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), S_COR, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.
Referenced by park_exec().
04383 { 04384 int res = 0; 04385 struct ast_channel *peer=NULL; 04386 struct parkeduser *pu; 04387 struct ast_context *con; 04388 int park = 0; 04389 struct ast_bridge_config config; 04390 struct ast_parkinglot *parkinglot; 04391 04392 if (data) { 04393 park = atoi((char *) data); 04394 } 04395 04396 parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_position_cb, (void *) &park); 04397 if (!parkinglot) 04398 parkinglot = default_parkinglot; 04399 04400 AST_LIST_LOCK(&parkinglot->parkings); 04401 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 04402 if (!pu->notquiteyet && (!data || pu->parkingnum == park)) { 04403 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 04404 AST_LIST_UNLOCK(&parkinglot->parkings); 04405 return -1; 04406 } 04407 AST_LIST_REMOVE_CURRENT(list); 04408 break; 04409 } 04410 } 04411 AST_LIST_TRAVERSE_SAFE_END; 04412 AST_LIST_UNLOCK(&parkinglot->parkings); 04413 04414 if (pu) { 04415 peer = pu->chan; 04416 con = ast_context_find(parkinglot->parking_con); 04417 if (con) { 04418 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 04419 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 04420 else 04421 notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE); 04422 } else 04423 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 04424 04425 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan); 04426 ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall", 04427 "Exten: %s\r\n" 04428 "Channel: %s\r\n" 04429 "From: %s\r\n" 04430 "CallerIDNum: %s\r\n" 04431 "CallerIDName: %s\r\n", 04432 pu->parkingexten, pu->chan->name, chan->name, 04433 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 04434 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>") 04435 ); 04436 04437 ast_free(pu); 04438 } 04439 /* JK02: it helps to answer the channel if not already up */ 04440 if (chan->_state != AST_STATE_UP) 04441 ast_answer(chan); 04442 04443 //XXX Why do we unlock here ? 04444 // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain 04445 //ASTOBJ_UNLOCK(parkinglot); 04446 04447 if (peer) { 04448 struct ast_datastore *features_datastore; 04449 struct ast_dial_features *dialfeatures = NULL; 04450 04451 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 04452 04453 if (!ast_strlen_zero(courtesytone)) { 04454 int error = 0; 04455 ast_indicate(peer, AST_CONTROL_UNHOLD); 04456 if (parkedplay == 0) { 04457 error = ast_stream_and_wait(chan, courtesytone, ""); 04458 } else if (parkedplay == 1) { 04459 error = ast_stream_and_wait(peer, courtesytone, ""); 04460 } else if (parkedplay == 2) { 04461 if (!ast_streamfile(chan, courtesytone, chan->language) && 04462 !ast_streamfile(peer, courtesytone, chan->language)) { 04463 /*! \todo XXX we would like to wait on both! */ 04464 res = ast_waitstream(chan, ""); 04465 if (res >= 0) 04466 res = ast_waitstream(peer, ""); 04467 if (res < 0) 04468 error = 1; 04469 } 04470 } 04471 if (error) { 04472 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 04473 ast_hangup(peer); 04474 return -1; 04475 } 04476 } else 04477 ast_indicate(peer, AST_CONTROL_UNHOLD); 04478 04479 res = ast_channel_make_compatible(chan, peer); 04480 if (res < 0) { 04481 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 04482 ast_hangup(peer); 04483 return -1; 04484 } 04485 /* This runs sorta backwards, since we give the incoming channel control, as if it 04486 were the person called. */ 04487 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park); 04488 04489 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 04490 ast_cdr_setdestchan(chan->cdr, peer->name); 04491 memset(&config, 0, sizeof(struct ast_bridge_config)); 04492 04493 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 04494 ast_channel_lock(peer); 04495 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 04496 dialfeatures = features_datastore->data; 04497 } 04498 ast_channel_unlock(peer); 04499 04500 /* When the datastores for both caller and callee are created, both the callee and caller channels 04501 * use the features_caller flag variable to represent themselves. With that said, the config.features_callee 04502 * flags should be copied from the datastore's caller feature flags regardless if peer was a callee 04503 * or caller. */ 04504 if (dialfeatures) { 04505 ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 04506 } 04507 04508 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 04509 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 04510 } 04511 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 04512 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 04513 } 04514 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 04515 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 04516 } 04517 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 04518 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 04519 } 04520 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 04521 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 04522 } 04523 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 04524 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 04525 } 04526 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 04527 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 04528 } 04529 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 04530 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 04531 } 04532 04533 parkinglot_unref(parkinglot); 04534 res = ast_bridge_call(chan, peer, &config); 04535 04536 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 04537 ast_cdr_setdestchan(chan->cdr, peer->name); 04538 04539 /* Simulate the PBX hanging up */ 04540 ast_hangup(peer); 04541 return -1; 04542 } else { 04543 /*! \todo XXX Play a message XXX */ 04544 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) 04545 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 04546 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 04547 res = -1; 04548 } 04549 04550 return -1; 04551 }
static struct parkeduser* park_space_reserve | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 912 of file features.c.
References ao2_link, args, ast_calloc, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, ast_exists_extension(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strdupa, ast_strlen_zero(), ast_test_flag, copy_parkinglot(), default_parkinglot, find_parkinglot(), findparkinglotname(), free, parkeduser::list, LOG_ERROR, LOG_WARNING, parkeddynamic, parkinglot, parkinglot_addref(), parkinglot_unref(), parkinglots, parkeduser::parkingnum, pbx_builtin_getvar_helper(), and S_OR.
Referenced by masq_park_call(), and park_call_full().
00913 { 00914 struct parkeduser *pu; 00915 int i, parking_space = -1, parking_range; 00916 const char *parkinglotname = NULL; 00917 const char *parkingexten; 00918 struct ast_parkinglot *parkinglot = NULL; 00919 00920 if (args->parkinglot) { 00921 parkinglot = args->parkinglot; 00922 parkinglotname = parkinglot->name; 00923 } else if (peer) { 00924 parkinglotname = findparkinglotname(peer); 00925 } else { /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */ 00926 parkinglotname = findparkinglotname(chan); 00927 } 00928 00929 if (!args->parkinglot) { 00930 if (parkinglotname) { 00931 parkinglot = find_parkinglot(parkinglotname); 00932 } else { 00933 ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n"); 00934 parkinglot = parkinglot_addref(default_parkinglot); 00935 } 00936 ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglot->name); 00937 } 00938 00939 /* Dynamically create parkinglot */ 00940 if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) { 00941 const char *dyn_context, *dyn_range; 00942 const char *parkinglotname_copy = NULL; 00943 struct ast_parkinglot *parkinglot_copy = NULL; 00944 int dyn_start, dyn_end; 00945 00946 ast_channel_lock(chan); 00947 parkinglotname_copy = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), "")); 00948 dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), "")); 00949 dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), "")); 00950 ast_channel_unlock(chan); 00951 00952 if (!ast_strlen_zero(parkinglotname_copy)) { 00953 parkinglot_copy = find_parkinglot(parkinglotname_copy); 00954 } 00955 if (!parkinglot_copy) { 00956 parkinglot_copy = parkinglot_addref(default_parkinglot); 00957 ast_debug(1, "Using default parking lot for copy\n"); 00958 } 00959 if (!(parkinglot = copy_parkinglot(parkinglotname, parkinglot_copy))) { 00960 ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n"); 00961 } else { 00962 if (!ast_strlen_zero(dyn_context)) { 00963 ast_copy_string(parkinglot->parking_con, dyn_context, sizeof(parkinglot->parking_con)); 00964 } 00965 if (!ast_strlen_zero(dyn_range)) { 00966 if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) { 00967 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers\n"); 00968 } else { 00969 parkinglot->parking_start = dyn_start; 00970 parkinglot->parking_stop = dyn_end; 00971 } 00972 } 00973 ao2_link(parkinglots, parkinglot); 00974 } 00975 00976 if (parkinglot_copy) { 00977 /* unref our tempory copy */ 00978 parkinglot_unref(parkinglot_copy); 00979 parkinglot_copy = NULL; 00980 } 00981 } 00982 00983 if (!parkinglot) { 00984 parkinglot = parkinglot_addref(default_parkinglot); 00985 } 00986 00987 ast_debug(1, "Parkinglot: %s\n", parkinglot->name); 00988 00989 /* Allocate memory for parking data */ 00990 if (!(pu = ast_calloc(1, sizeof(*pu)))) { 00991 parkinglot_unref(parkinglot); 00992 return NULL; 00993 } 00994 00995 /* Lock parking list */ 00996 AST_LIST_LOCK(&parkinglot->parkings); 00997 /* Check for channel variable PARKINGEXTEN */ 00998 ast_channel_lock(chan); 00999 parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"), "")); 01000 ast_channel_unlock(chan); 01001 if (!ast_strlen_zero(parkingexten)) { 01002 /*!\note The API forces us to specify a numeric parking slot, even 01003 * though the architecture would tend to support non-numeric extensions 01004 * (as are possible with SIP, for example). Hence, we enforce that 01005 * limitation here. If extout was not numeric, we could permit 01006 * arbitrary non-numeric extensions. 01007 */ 01008 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) { 01009 AST_LIST_UNLOCK(&parkinglot->parkings); 01010 parkinglot_unref(parkinglot); 01011 free(pu); 01012 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); 01013 return NULL; 01014 } 01015 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 01016 01017 if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) { 01018 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con); 01019 AST_LIST_UNLOCK(&parkinglot->parkings); 01020 parkinglot_unref(parkinglot); 01021 ast_free(pu); 01022 return NULL; 01023 } 01024 } else { 01025 int start; 01026 struct parkeduser *cur = NULL; 01027 01028 /* Select parking space within range */ 01029 parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1; 01030 01031 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) { 01032 start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1); 01033 } else { 01034 start = parkinglot->parking_start; 01035 } 01036 01037 for (i = start; 1; i++) { 01038 if (i == parkinglot->parking_stop + 1) { 01039 i = parkinglot->parking_start - 1; 01040 break; 01041 } 01042 01043 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 01044 if (cur->parkingnum == i) { 01045 break; 01046 } 01047 } 01048 if (!cur) { 01049 parking_space = i; 01050 break; 01051 } 01052 } 01053 01054 if (i == start - 1 && cur) { 01055 ast_log(LOG_WARNING, "No more parking spaces\n"); 01056 ast_free(pu); 01057 AST_LIST_UNLOCK(&parkinglot->parkings); 01058 parkinglot_unref(parkinglot); 01059 return NULL; 01060 } 01061 /* Set pointer for next parking */ 01062 if (parkinglot->parkfindnext) 01063 parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1; 01064 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 01065 } 01066 01067 pu->notquiteyet = 1; 01068 pu->parkingnum = parking_space; 01069 pu->parkinglot = parkinglot; 01070 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list); 01071 01072 return pu; 01073 }
static int parkcall_helper | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
const char * | code, | |||
int | sense, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 1495 of file features.c.
References ast_channel::_state, args, ast_answer(), ast_debug, ast_safe_sleep(), AST_STATE_UP, masq_park_call_announce(), and set_peers().
Referenced by builtin_atxfer(), and builtin_parkcall().
01496 { 01497 int res = 0; 01498 01499 if (args) { 01500 ast_debug(1, "Parkinglot specified for builtin_parkcall: %s\n", args->parkinglot->name); 01501 } 01502 01503 /* we used to set chan's exten and priority to "s" and 1 01504 here, but this generates (in some cases) an invalid 01505 extension, and if "s" exists, could errantly 01506 cause execution of extensions you don't expect. It 01507 makes more sense to let nature take its course 01508 when chan finishes, and let the pbx do its thing 01509 and hang up when the park is over. 01510 */ 01511 if (chan->_state != AST_STATE_UP) 01512 res = ast_answer(chan); 01513 if (!res) 01514 res = ast_safe_sleep(chan, 1000); 01515 01516 if (!res) { /* one direction used to call park_call.... */ 01517 struct ast_channel *parker; 01518 struct ast_channel *parkee; 01519 set_peers(&parker, &parkee, peer, chan, sense); 01520 res = masq_park_call_announce(parkee, parker, args); 01521 /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ 01522 } 01523 01524 return res; 01525 }
static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 4566 of file features.c.
References ao2_ref, ast_debug, and parkinglot.
Referenced by park_space_reserve().
04567 { 04568 int refcount = ao2_ref(parkinglot, +1); 04569 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1); 04570 return parkinglot; 04571 }
static int parkinglot_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 682 of file features.c.
References CMP_MATCH, CMP_STOP, and parkinglot.
Referenced by ast_features_init().
00683 { 00684 struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg; 00685 00686 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0; 00687 }
static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 4592 of file features.c.
References ast_context_destroy(), ast_context_find(), ast_parkinglot::parking_con, and registrar.
Referenced by build_parkinglot(), and create_parkinglot().
04593 { 04594 struct ast_parkinglot *ruin = obj; 04595 struct ast_context *con; 04596 con = ast_context_find(ruin->parking_con); 04597 if (con) 04598 ast_context_destroy(con, registrar); 04599 }
static int parkinglot_hash_cb | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 675 of file features.c.
References ast_str_case_hash(), and parkinglot.
Referenced by ast_features_init().
00676 { 00677 const struct ast_parkinglot *parkinglot = obj; 00678 00679 return ast_str_case_hash(parkinglot->name); 00680 }
static int parkinglot_is_marked_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 5192 of file features.c.
References CMP_MATCH, and parkinglot.
Referenced by ast_features_reload().
05193 { 05194 struct ast_parkinglot *parkinglot = obj; 05195 return parkinglot->the_mark ? CMP_MATCH : 0; 05196 }
static int parkinglot_markall_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 5185 of file features.c.
References parkinglot.
Referenced by ast_features_reload().
05186 { 05187 struct ast_parkinglot *parkinglot = obj; 05188 parkinglot->the_mark = 1; 05189 return 0; 05190 }
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 4560 of file features.c.
References ao2_ref, ast_debug, and parkinglot.
Referenced by build_parkinglot(), manage_parkinglot(), park_exec_full(), and park_space_reserve().
04561 { 04562 int refcount = ao2_ref(parkinglot, -1); 04563 ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1); 04564 }
return the first unlocked cdr in a possible chain
Definition at line 3285 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
03286 { 03287 struct ast_cdr *cdr_orig = cdr; 03288 while (cdr) { 03289 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 03290 return cdr; 03291 cdr = cdr->next; 03292 } 03293 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 03294 }
static int play_message_in_bridged_call | ( | struct ast_channel * | caller_chan, | |
struct ast_channel * | callee_chan, | |||
const char * | audiofile | |||
) | [static] |
Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages.
Definition at line 1547 of file features.c.
References ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FRAME_DTMF_END, ast_log(), ast_stream_and_wait(), and LOG_WARNING.
Referenced by builtin_automonitor().
01548 { 01549 /* First play for caller, put other channel on auto service */ 01550 if (ast_autoservice_start(callee_chan)) 01551 return -1; 01552 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END); 01553 if (ast_stream_and_wait(caller_chan, audiofile, "")) { 01554 ast_log(LOG_WARNING, "Failed to play automon message!\n"); 01555 ast_autoservice_stop(callee_chan); 01556 return -1; 01557 } 01558 if (ast_autoservice_stop(callee_chan)) 01559 return -1; 01560 /* Then play for callee, put other channel on auto service */ 01561 if (ast_autoservice_start(caller_chan)) 01562 return -1; 01563 ast_autoservice_ignore(caller_chan, AST_FRAME_DTMF_END); 01564 if (ast_stream_and_wait(callee_chan, audiofile, "")) { 01565 ast_log(LOG_WARNING, "Failed to play automon message !\n"); 01566 ast_autoservice_stop(caller_chan); 01567 return -1; 01568 } 01569 if (ast_autoservice_stop(caller_chan)) 01570 return -1; 01571 return(0); 01572 }
static void post_manager_event | ( | const char * | s, | |
struct parkeduser * | pu | |||
) | [static] |
Output parking event to manager.
Definition at line 3942 of file features.c.
References ast_channel::caller, parkeduser::chan, EVENT_FLAG_CALL, ast_party_caller::id, manager_event, ast_party_id::name, ast_parkinglot::name, ast_channel::name, ast_party_id::number, parkeduser::parkingexten, parkeduser::parkinglot, S_COR, ast_party_name::str, ast_party_number::str, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.
Referenced by manage_parkinglot().
03943 { 03944 manager_event(EVENT_FLAG_CALL, s, 03945 "Exten: %s\r\n" 03946 "Channel: %s\r\n" 03947 "Parkinglot: %s\r\n" 03948 "CallerIDNum: %s\r\n" 03949 "CallerIDName: %s\r\n" 03950 "UniqueID: %s\r\n", 03951 pu->parkingexten, 03952 pu->chan->name, 03953 pu->parkinglot->name, 03954 S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"), 03955 S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"), 03956 pu->chan->uniqueid 03957 ); 03958 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
transferer | ||
transferee | Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext. |
Definition at line 1817 of file features.c.
References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, and pbx_builtin_getvar_helper().
Referenced by builtin_atxfer(), and builtin_blindtransfer().
01818 { 01819 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 01820 if (ast_strlen_zero(s)) { 01821 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 01822 } 01823 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 01824 s = transferer->macrocontext; 01825 } 01826 if (ast_strlen_zero(s)) { 01827 s = transferer->context; 01828 } 01829 return s; 01830 }
static struct feature_group* register_group | ( | const char * | fgname | ) | [static] |
Add new feature group.
fgname | feature group name. |
Definition at line 2478 of file features.c.
References ast_calloc_with_stringfields, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_set, ast_verb, feature_group_exten::entry, feature_group::gname, and LOG_NOTICE.
02479 { 02480 struct feature_group *fg; 02481 02482 if (!fgname) { 02483 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 02484 return NULL; 02485 } 02486 02487 if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) { 02488 return NULL; 02489 } 02490 02491 ast_string_field_set(fg, gname, fgname); 02492 02493 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 02494 02495 ast_verb(2, "Registered group '%s'\n", fg->gname); 02496 02497 return fg; 02498 }
static void register_group_feature | ( | struct feature_group * | fg, | |
const char * | exten, | |||
struct ast_call_feature * | feature | |||
) | [static] |
Add feature to group.
fg | feature group | |
exten | ||
feature | feature to add. |
Definition at line 2509 of file features.c.
References ast_calloc_with_stringfields, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_set, ast_verb, feature_group_exten::entry, feature_group_exten::exten, ast_call_feature::exten, feature_group_exten::feature, feature_group::features, feature_group::gname, LOG_NOTICE, S_OR, and ast_call_feature::sname.
02510 { 02511 struct feature_group_exten *fge; 02512 02513 if (!fg) { 02514 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 02515 return; 02516 } 02517 02518 if (!feature) { 02519 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 02520 return; 02521 } 02522 02523 if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) { 02524 return; 02525 } 02526 02527 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 02528 02529 fge->feature = feature; 02530 02531 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 02532 02533 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 02534 feature->sname, fg->gname, fge->exten); 02535 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 2717 of file features.c.
References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, FEATURES_COUNT, and features_lock.
02718 { 02719 int x, res = -1; 02720 02721 ast_rwlock_wrlock(&features_lock); 02722 for (x = 0; x < FEATURES_COUNT; x++) { 02723 if (strcasecmp(builtin_features[x].sname, name)) 02724 continue; 02725 02726 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 02727 res = 0; 02728 break; 02729 } 02730 ast_rwlock_unlock(&features_lock); 02731 02732 return res; 02733 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 3296 of file features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), config, feature_group_exten::feature, and LOG_WARNING.
Referenced by ast_bridge_call().
03297 { 03298 const char *feature; 03299 03300 if (ast_strlen_zero(features)) { 03301 return; 03302 } 03303 03304 for (feature = features; *feature; feature++) { 03305 switch (*feature) { 03306 case 'T' : 03307 case 't' : 03308 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 03309 break; 03310 case 'K' : 03311 case 'k' : 03312 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 03313 break; 03314 case 'H' : 03315 case 'h' : 03316 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 03317 break; 03318 case 'W' : 03319 case 'w' : 03320 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 03321 break; 03322 default : 03323 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 03324 } 03325 } 03326 }
static void set_c_e_p | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | ext, | |||
int | pri | |||
) | [static] |
store context, extension and priority
chan,context,ext,pri |
Definition at line 693 of file features.c.
References ast_copy_string(), ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by builtin_blindtransfer(), manage_parkinglot(), and masq_park_call().
00694 { 00695 ast_copy_string(chan->context, context, sizeof(chan->context)); 00696 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00697 chan->priority = pri; 00698 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 2886 of file features.c.
References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, config, feature_group_exten::entry, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().
Referenced by ast_bridge_call().
02887 { 02888 int x; 02889 02890 ast_clear_flag(config, AST_FLAGS_ALL); 02891 02892 ast_rwlock_rdlock(&features_lock); 02893 for (x = 0; x < FEATURES_COUNT; x++) { 02894 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 02895 continue; 02896 02897 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 02898 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 02899 02900 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 02901 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 02902 } 02903 ast_rwlock_unlock(&features_lock); 02904 02905 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 02906 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 02907 02908 if (dynamic_features) { 02909 char *tmp = ast_strdupa(dynamic_features); 02910 char *tok; 02911 struct ast_call_feature *feature; 02912 02913 /* while we have a feature */ 02914 while ((tok = strsep(&tmp, "#"))) { 02915 struct feature_group *fg; 02916 02917 AST_RWLIST_RDLOCK(&feature_groups); 02918 AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) { 02919 struct feature_group_exten *fge; 02920 02921 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 02922 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) { 02923 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 02924 } 02925 if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) { 02926 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 02927 } 02928 } 02929 } 02930 AST_RWLIST_UNLOCK(&feature_groups); 02931 02932 AST_RWLIST_RDLOCK(&feature_list); 02933 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 02934 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) { 02935 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 02936 } 02937 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) { 02938 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 02939 } 02940 } 02941 AST_RWLIST_UNLOCK(&feature_list); 02942 } 02943 } 02944 } 02945 }
static void set_peers | ( | struct ast_channel ** | caller, | |
struct ast_channel ** | callee, | |||
struct ast_channel * | peer, | |||
struct ast_channel * | chan, | |||
int | sense | |||
) | [static] |
set caller and callee according to the direction
caller,callee,peer,chan,sense | Detect who triggered feature and set callee/caller variables accordingly |
Definition at line 1483 of file features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and parkcall_helper().
01485 { 01486 if (sense == FEATURE_SENSE_PEER) { 01487 *caller = peer; 01488 *callee = chan; 01489 } else { 01490 *callee = peer; 01491 *caller = chan; 01492 } 01493 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 2707 of file features.c.
References ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, FEATURES_COUNT, and features_lock.
02708 { 02709 int x; 02710 02711 ast_rwlock_wrlock(&features_lock); 02712 for (x = 0; x < FEATURES_COUNT; x++) 02713 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 02714 ast_rwlock_unlock(&features_lock); 02715 }
int adsipark [static] |
char* app_bridge = "Bridge" [static] |
Definition at line 5661 of file features.c.
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] |
Definition at line 2444 of file features.c.
Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
struct ast_cli_entry cli_features[] [static] |
Initial value:
{ { .handler = handle_feature_show , .summary = "Lists configured features" ,__VA_ARGS__ }, { .handler = handle_features_reload , .summary = "Reloads configured features" ,__VA_ARGS__ }, { .handler = handle_parkedcalls , .summary = "List currently parked calls" ,__VA_ARGS__ }, }
Definition at line 5442 of file features.c.
Referenced by ast_features_init().
int comebacktoorigin = 1 [static] |
char courtesytone[256] [static] |
Courtesy tone
Definition at line 425 of file features.c.
Referenced by builtin_automixmonitor(), builtin_automonitor(), load_config(), and park_exec_full().
struct ast_parkinglot* default_parkinglot |
Definition at line 422 of file features.c.
struct ast_datastore_info dial_features_info [static] |
Initial value:
{ .type = "dial-features", .destroy = dial_features_destroy, .duplicate = dial_features_duplicate, }
Definition at line 604 of file features.c.
Referenced by add_features_datastores(), builtin_atxfer(), manage_parkinglot(), and park_exec_full().
int featuredigittimeout [static] |
Definition at line 436 of file features.c.
ast_rwlock_t features_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } [static] |
Definition at line 2442 of file features.c.
Referenced by ast_rdlock_call_features(), ast_unlock_call_features(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
struct ast_app* mixmonitor_app = NULL [static] |
int mixmonitor_ok = 1 [static] |
struct ast_app* monitor_app = NULL [static] |
Definition at line 449 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 450 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
struct ast_app_option park_call_options[128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } [static] |
char* parkcall = PARK_APP_NAME [static] |
Definition at line 447 of file features.c.
Referenced by ast_features_init(), and build_parkinglot().
char* parkedcall = "ParkedCall" [static] |
int parkeddynamic = 0 [static] |
Enable creation of parkinglots dynamically
Definition at line 427 of file features.c.
Referenced by load_config(), and park_space_reserve().
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 426 of file features.c.
Referenced by park_exec_full().
char parking_ext[AST_MAX_EXTENSION] |
Extension you type to park the call
Definition at line 423 of file features.c.
pthread_t parking_thread [static] |
struct ao2_container* parkinglots [static] |
The list of parking lots configured. Always at least one - the default parking lot.
Definition at line 420 of file features.c.
Referenced by ast_features_init(), ast_features_reload(), ast_park_call(), build_parkinglot(), builtin_atxfer(), builtin_blindtransfer(), do_parking_thread(), find_parkinglot(), handle_feature_show(), handle_parkedcalls(), manager_parking_status(), park_call_exec(), park_exec_full(), and park_space_reserve().
char pickup_ext[AST_MAX_EXTENSION] [static] |
Call pickup extension
Definition at line 376 of file features.c.
Referenced by ast_pickup_ext(), and load_config().
char pickupfailsound[256] [static] |
Pickup failure sound
Definition at line 431 of file features.c.
Referenced by ast_pickup_call(), and load_config().
char pickupsound[256] [static] |
Pickup sound
Definition at line 430 of file features.c.
Referenced by ast_pickup_call(), and load_config().
char* registrar = "features" [static] |
Registrar for operations
Definition at line 444 of file features.c.
Referenced by build_parkinglot(), manage_parkinglot(), park_add_hints(), park_call_full(), and parkinglot_destroy().
struct ast_app* stopmixmonitor_app = NULL [static] |
int stopmixmonitor_ok = 1 [static] |
int transferdigittimeout [static] |
Definition at line 435 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 429 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().
char xfersound[256] [static] |
Call transfer sound
Definition at line 428 of file features.c.
Referenced by action_bridge(), bridge_exec(), builtin_atxfer(), load_config(), and local_attended_transfer().