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