#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | ast_dial_features |
struct | feature_group |
struct | feature_group_exten |
struct | feature_groups |
struct | feature_list |
struct | parkeduser |
struct | parkinglot |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
#define | DEFAULT_ATXFER_DROP_CALL 0 |
#define | DEFAULT_ATXFER_LOOP_DELAY 10000 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
#define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURE_RETURN_HANGUP -1 |
#define | FEATURE_RETURN_KEEPTRYING 24 |
#define | FEATURE_RETURN_PARKFAILED 25 |
#define | FEATURE_RETURN_PASSDIGITS 21 |
#define | FEATURE_RETURN_STOREDIGITS 22 |
#define | FEATURE_RETURN_SUCCESS 23 |
#define | FEATURE_RETURN_SUCCESSBREAK 0 |
#define | FEATURES_COUNT ARRAY_LEN(builtin_features) |
#define | HFS_FORMAT "%-25s %-7s %-7s\n" |
#define | MAX_DIAL_FEATURE_OPTIONS 30 |
Enumerations | |
enum | { AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3), AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3) } |
enum | { BRIDGE_OPT_PLAYTONE = (1 << 0) } |
Functions | |
static int | action_bridge (struct mansession *s, const struct message *m) |
Bridge channels together. | |
static void | add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config) |
static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
Announce call parking by ADSI. | |
int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
Bridge a call, optionally allowing redirection. | |
static void * | ast_bridge_call_thread (void *data) |
bridge the call | |
static void | ast_bridge_call_thread_launch (void *data) |
create thread for the parked call | |
int | ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature) |
detect a feature before bridging | |
static int | ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
Check the dynamic features. | |
static struct ast_channel * | ast_feature_request_and_dial (struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language) |
Get feature and dial. | |
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, int *extout) |
Park a call and read back parked location. | |
const char * | ast_parking_ext (void) |
Determine system parking extension. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
const char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_rdlock_call_features (void) |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
void | ast_unlock_call_features (void) |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
static void | ast_unregister_features (void) |
Remove all features in the list. | |
static void | ast_unregister_groups (void) |
Remove all feature groups in the list. | |
static int | bridge_exec (struct ast_channel *chan, void *data) |
Bridge channels. | |
static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Attended transfer. | |
static int | builtin_automixmonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Monitor a channel by DTMF. | |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Blind transfer user to another extension. | |
static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
support routing for one touch call parking | |
static char * | callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len) |
static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
make channels compatible | |
static void | check_goto_on_transfer (struct ast_channel *chan) |
Check goto on transfer. | |
static void | dial_features_destroy (void *data) |
static void * | dial_features_duplicate (void *data) |
static void | do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan) |
Actual bridge. | |
static void * | do_parking_thread (void *ignore) |
Take care of parked calls and unpark them if needed. | |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
exec an app by feature | |
static int | feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, int operation, struct ast_call_feature *feature) |
Helper function for feature_interpret and ast_feature_detect. | |
static struct ast_call_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. | |
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 char * | handle_parkedcalls_deprecated (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static int | load_config (void) |
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, const char *orig_chan_name) |
static int | masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name) |
static enum ast_device_state | metermaidstate (const char *data) |
metermaids callback from devicestate.c | |
static void | notify_metermaids (const char *exten, char *context, enum ast_device_state state) |
Notify metermaids that we've changed an extension. | |
static void | park_add_hints (char *context, int start, int stop) |
Add parking hints for all defined parking lots. | |
static int | park_call_exec (struct ast_channel *chan, void *data) |
Park a call. | |
static int | park_call_full (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name, struct parkeduser *pu) |
static int | park_exec (struct ast_channel *chan, void *data) |
Pickup parked call. | |
static struct parkeduser * | park_space_reserve (struct ast_channel *chan) |
static struct ast_cdr * | pick_unlocked_cdr (struct ast_cdr *cdr) |
return the first unlocked cdr in a possible chain | |
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 char * | bridge_descrip |
static struct ast_app_option | bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE } } |
static char * | bridge_synopsis = "Bridge two channels" |
static struct ast_call_feature | builtin_features [] |
static struct ast_cli_entry | cli_features [] |
static struct ast_cli_entry | cli_show_parkedcalls_deprecated = { .handler = handle_parkedcalls_deprecated , .summary = "List currently parked calls." ,__VA_ARGS__ } |
static int | comebacktoorigin = 1 |
static char | courtesytone [256] |
static char * | descrip |
static char * | descrip2 |
ast_datastore_info | dial_features_info |
static int | featuredigittimeout |
static ast_rwlock_t | features_lock = PTHREAD_RWLOCK_INITIALIZER |
static char | mandescr_bridge [] |
static char | mandescr_park [] |
static struct ast_app * | mixmonitor_app = NULL |
static int | mixmonitor_ok = 1 |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static int | parkaddhints = 0 |
static char * | parkcall = "Park" |
static char * | parkedcall = "ParkedCall" |
static int | parkedcallhangup = 0 |
static int | parkedcallrecording = 0 |
static int | parkedcallreparking = 0 |
static int | parkedcalltransfers = 0 |
static int | parkedplay = 0 |
static int | parkfindnext |
static char | parking_con [AST_MAX_EXTENSION] |
static char | parking_con_dial [AST_MAX_EXTENSION] |
static char | parking_ext [AST_MAX_EXTENSION] |
static int | parking_offset |
static int | parking_start |
static int | parking_stop |
static pthread_t | parking_thread |
static int | parkingtime = DEFAULT_PARK_TIME |
static char | parkmohclass [MAX_MUSICCLASS] |
static char | pickup_ext [AST_MAX_EXTENSION] |
static char * | registrar = "features" |
static struct ast_app * | stopmixmonitor_app = NULL |
static int | stopmixmonitor_ok = 1 |
static char * | synopsis = "Answer a parked call" |
static char * | synopsis2 = "Park yourself" |
static int | transferdigittimeout |
static char | xferfailsound [256] |
static char | xfersound [256] |
Definition in file features.c.
#define AST_MAX_WATCHERS 256 |
Definition at line 66 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_TIME 45000 |
Definition at line 58 of file features.c.
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURE_RETURN_HANGUP -1 |
#define FEATURE_RETURN_KEEPTRYING 24 |
#define FEATURE_RETURN_PARKFAILED 25 |
Definition at line 75 of file features.c.
Referenced by builtin_blindtransfer(), and masq_park_call().
#define FEATURE_RETURN_PASSDIGITS 21 |
#define FEATURE_RETURN_STOREDIGITS 22 |
Definition at line 72 of file features.c.
#define FEATURE_RETURN_SUCCESS 23 |
Definition at line 73 of file features.c.
Referenced by ast_bridge_call(), builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app().
#define FEATURE_RETURN_SUCCESSBREAK 0 |
#define FEATURES_COUNT ARRAY_LEN(builtin_features) |
Definition at line 1406 of file features.c.
Referenced by ast_feature_request_and_dial(), ast_find_call_feature(), feature_interpret_helper(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
#define HFS_FORMAT "%-25s %-7s %-7s\n" |
Referenced by handle_feature_show().
#define MAX_DIAL_FEATURE_OPTIONS 30 |
anonymous enum |
AST_FEATURE_FLAG_NEEDSDTMF | |
AST_FEATURE_FLAG_ONPEER | |
AST_FEATURE_FLAG_ONSELF | |
AST_FEATURE_FLAG_BYCALLEE | |
AST_FEATURE_FLAG_BYCALLER | |
AST_FEATURE_FLAG_BYBOTH |
Definition at line 77 of file features.c.
00077 { 00078 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00079 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00080 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00081 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00082 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00083 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00084 };
anonymous enum |
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 3553 of file features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc, ast_channel_make_compatible(), ast_channel_unlock, ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), buf, do_bridge_masquerade(), errno, LOG_WARNING, ast_channel::name, playtone(), s, and xfersound.
Referenced by ast_features_init().
03554 { 03555 const char *channela = astman_get_header(m, "Channel1"); 03556 const char *channelb = astman_get_header(m, "Channel2"); 03557 const char *playtone = astman_get_header(m, "Tone"); 03558 struct ast_channel *chana = NULL, *chanb = NULL; 03559 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 03560 struct ast_bridge_thread_obj *tobj = NULL; 03561 03562 /* make sure valid channels were specified */ 03563 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 03564 astman_send_error(s, m, "Missing channel parameter in request"); 03565 return 0; 03566 } 03567 03568 /* The same code must be executed for chana and chanb. To avoid a 03569 * theoretical deadlock, this code is separated so both chana and chanb will 03570 * not hold locks at the same time. */ 03571 03572 /* Start with chana */ 03573 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela)); 03574 03575 /* send errors if any of the channels could not be found/locked */ 03576 if (!chana) { 03577 char buf[256]; 03578 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 03579 astman_send_error(s, m, buf); 03580 return 0; 03581 } 03582 03583 /* Answer the channels if needed */ 03584 if (chana->_state != AST_STATE_UP) 03585 ast_answer(chana); 03586 03587 /* create the placeholder channels and grab the other channels */ 03588 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 03589 NULL, NULL, 0, "Bridge/%s", chana->name))) { 03590 astman_send_error(s, m, "Unable to create temporary channel!"); 03591 ast_channel_unlock(chana); 03592 return 1; 03593 } 03594 03595 do_bridge_masquerade(chana, tmpchana); 03596 ast_channel_unlock(chana); 03597 chana = NULL; 03598 03599 /* now do chanb */ 03600 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb)); 03601 /* send errors if any of the channels could not be found/locked */ 03602 if (!chanb) { 03603 char buf[256]; 03604 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 03605 ast_hangup(tmpchana); 03606 astman_send_error(s, m, buf); 03607 return 0; 03608 } 03609 03610 /* Answer the channels if needed */ 03611 if (chanb->_state != AST_STATE_UP) 03612 ast_answer(chanb); 03613 03614 /* create the placeholder channels and grab the other channels */ 03615 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 03616 NULL, NULL, 0, "Bridge/%s", chanb->name))) { 03617 astman_send_error(s, m, "Unable to create temporary channels!"); 03618 ast_hangup(tmpchana); 03619 ast_channel_unlock(chanb); 03620 return 1; 03621 } 03622 do_bridge_masquerade(chanb, tmpchanb); 03623 ast_channel_unlock(chanb); 03624 chanb = NULL; 03625 03626 /* make the channels compatible, send error if we fail doing so */ 03627 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 03628 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 03629 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 03630 ast_hangup(tmpchana); 03631 ast_hangup(tmpchanb); 03632 return 1; 03633 } 03634 03635 /* setup the bridge thread object and start the bridge */ 03636 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 03637 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 03638 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 03639 ast_hangup(tmpchana); 03640 ast_hangup(tmpchanb); 03641 return 1; 03642 } 03643 03644 tobj->chan = tmpchana; 03645 tobj->peer = tmpchanb; 03646 tobj->return_to_pbx = 1; 03647 03648 if (ast_true(playtone)) { 03649 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 03650 if (ast_waitstream(tmpchanb, "") < 0) 03651 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 03652 } 03653 } 03654 03655 ast_bridge_call_thread_launch(tobj); 03656 03657 astman_send_ack(s, m, "Launched bridge thread with success"); 03658 03659 return 0; 03660 }
static void add_features_datastores | ( | struct ast_channel * | caller, | |
struct ast_channel * | callee, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 2116 of file features.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, 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().
02117 { 02118 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 02119 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 02120 02121 ast_channel_lock(caller); 02122 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 02123 ast_channel_unlock(caller); 02124 if (!ds_caller_features) { 02125 if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 02126 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 02127 return; 02128 } 02129 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 02130 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02131 ast_channel_datastore_free(ds_caller_features); 02132 return; 02133 } 02134 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 02135 caller_features->is_caller = 1; 02136 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 02137 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 02138 ds_caller_features->data = caller_features; 02139 ast_channel_lock(caller); 02140 ast_channel_datastore_add(caller, ds_caller_features); 02141 ast_channel_unlock(caller); 02142 } else { 02143 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 02144 * flags over from the atxfer to the caller */ 02145 return; 02146 } 02147 02148 ast_channel_lock(callee); 02149 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 02150 ast_channel_unlock(callee); 02151 if (!ds_callee_features) { 02152 if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 02153 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 02154 return; 02155 } 02156 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 02157 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02158 ast_channel_datastore_free(ds_callee_features); 02159 return; 02160 } 02161 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 02162 callee_features->is_caller = 0; 02163 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 02164 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 02165 ds_callee_features->data = callee_features; 02166 ast_channel_lock(callee); 02167 ast_channel_datastore_add(callee, ds_callee_features); 02168 ast_channel_unlock(callee); 02169 } 02170 02171 return; 02172 }
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 376 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session, ast_adsi_print, chan, and justify.
Referenced by park_call_full().
00377 { 00378 int res; 00379 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00380 char tmp[256]; 00381 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00382 00383 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00384 message[0] = tmp; 00385 res = ast_adsi_load_session(chan, NULL, 0, 1); 00386 if (res == -1) 00387 return res; 00388 return ast_adsi_print(chan, message, justify, 1); 00389 }
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 2183 of file features.c.
References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_cdr::amaflags, ast_channel::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, config, ast_channel::context, ast_channel::data, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_cdr::uniqueid, ast_channel::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.
Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), and park_exec().
02184 { 02185 /* Copy voice back and forth between the two channels. Give the peer 02186 the ability to transfer calls with '#<extension' syntax. */ 02187 struct ast_frame *f; 02188 struct ast_channel *who; 02189 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02190 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02191 char orig_channame[AST_MAX_EXTENSION]; 02192 char orig_peername[AST_MAX_EXTENSION]; 02193 int res; 02194 int diff; 02195 int hasfeatures=0; 02196 int hadfeatures=0; 02197 int autoloopflag; 02198 struct ast_option_header *aoh; 02199 struct ast_bridge_config backup_config; 02200 struct ast_cdr *bridge_cdr = NULL; 02201 struct ast_cdr *orig_peer_cdr = NULL; 02202 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02203 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02204 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02205 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02206 02207 memset(&backup_config, 0, sizeof(backup_config)); 02208 02209 config->start_time = ast_tvnow(); 02210 02211 if (chan && peer) { 02212 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02213 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02214 } else if (chan) { 02215 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02216 } 02217 02218 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02219 add_features_datastores(chan, peer, config); 02220 02221 /* This is an interesting case. One example is if a ringing channel gets redirected to 02222 * an extension that picks up a parked call. This will make sure that the call taken 02223 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02224 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02225 ast_indicate(peer, AST_CONTROL_RINGING); 02226 } 02227 02228 if (monitor_ok) { 02229 const char *monitor_exec; 02230 struct ast_channel *src = NULL; 02231 if (!monitor_app) { 02232 if (!(monitor_app = pbx_findapp("Monitor"))) 02233 monitor_ok=0; 02234 } 02235 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02236 src = chan; 02237 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02238 src = peer; 02239 if (monitor_app && src) { 02240 char *tmp = ast_strdupa(monitor_exec); 02241 pbx_exec(src, monitor_app, tmp); 02242 } 02243 } 02244 02245 set_config_flags(chan, peer, config); 02246 config->firstpass = 1; 02247 02248 /* Answer if need be */ 02249 if (chan->_state != AST_STATE_UP) { 02250 if (ast_raw_answer(chan, 1)) { 02251 return -1; 02252 } 02253 } 02254 02255 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02256 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02257 orig_peer_cdr = peer_cdr; 02258 02259 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02260 02261 if (chan_cdr) { 02262 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02263 ast_cdr_update(chan); 02264 bridge_cdr = ast_cdr_dup(chan_cdr); 02265 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02266 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02267 } else { 02268 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02269 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02270 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02271 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02272 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02273 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02274 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02275 ast_cdr_setcid(bridge_cdr, chan); 02276 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02277 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02278 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02279 /* Destination information */ 02280 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02281 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02282 if (peer_cdr) { 02283 bridge_cdr->start = peer_cdr->start; 02284 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02285 } else { 02286 ast_cdr_start(bridge_cdr); 02287 } 02288 } 02289 ast_debug(4,"bridge answer set, chan answer set\n"); 02290 /* peer_cdr->answer will be set when a macro runs on the peer; 02291 in that case, the bridge answer will be delayed while the 02292 macro plays on the peer channel. The peer answered the call 02293 before the macro started playing. To the phone system, 02294 this is billable time for the call, even tho the caller 02295 hears nothing but ringing while the macro does its thing. */ 02296 if (peer_cdr && !ast_tvzero(peer_cdr->answer)) { 02297 bridge_cdr->answer = peer_cdr->answer; 02298 bridge_cdr->disposition = peer_cdr->disposition; 02299 if (chan_cdr) { 02300 chan_cdr->answer = peer_cdr->answer; 02301 chan_cdr->disposition = peer_cdr->disposition; 02302 } 02303 } else { 02304 ast_cdr_answer(bridge_cdr); 02305 if (chan_cdr) { 02306 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02307 } 02308 } 02309 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 02310 if (chan_cdr) { 02311 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02312 } 02313 if (peer_cdr) { 02314 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02315 } 02316 } 02317 } 02318 for (;;) { 02319 struct ast_channel *other; /* used later */ 02320 02321 res = ast_channel_bridge(chan, peer, config, &f, &who); 02322 02323 /* When frame is not set, we are probably involved in a situation 02324 where we've timed out. 02325 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02326 and also for DTMF_END. If we flow into the following 'if' for both, then 02327 our wait times are cut in half, as both will subtract from the 02328 feature_timer. Not good! 02329 */ 02330 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02331 /* Update time limit for next pass */ 02332 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02333 if (res == AST_BRIDGE_RETRY) { 02334 /* The feature fully timed out but has not been updated. Skip 02335 * the potential round error from the diff calculation and 02336 * explicitly set to expired. */ 02337 config->feature_timer = -1; 02338 } else { 02339 config->feature_timer -= diff; 02340 } 02341 02342 if (hasfeatures) { 02343 /* Running on backup config, meaning a feature might be being 02344 activated, but that's no excuse to keep things going 02345 indefinitely! */ 02346 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02347 ast_debug(1, "Timed out, realtime this time!\n"); 02348 config->feature_timer = 0; 02349 who = chan; 02350 if (f) 02351 ast_frfree(f); 02352 f = NULL; 02353 res = 0; 02354 } else if (config->feature_timer <= 0) { 02355 /* Not *really* out of time, just out of time for 02356 digits to come in for features. */ 02357 ast_debug(1, "Timed out for feature!\n"); 02358 if (!ast_strlen_zero(peer_featurecode)) { 02359 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02360 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02361 } 02362 if (!ast_strlen_zero(chan_featurecode)) { 02363 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02364 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02365 } 02366 if (f) 02367 ast_frfree(f); 02368 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02369 if (!hasfeatures) { 02370 /* Restore original (possibly time modified) bridge config */ 02371 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02372 memset(&backup_config, 0, sizeof(backup_config)); 02373 } 02374 hadfeatures = hasfeatures; 02375 /* Continue as we were */ 02376 continue; 02377 } else if (!f) { 02378 /* The bridge returned without a frame and there is a feature in progress. 02379 * However, we don't think the feature has quite yet timed out, so just 02380 * go back into the bridge. */ 02381 continue; 02382 } 02383 } else { 02384 if (config->feature_timer <=0) { 02385 /* We ran out of time */ 02386 config->feature_timer = 0; 02387 who = chan; 02388 if (f) 02389 ast_frfree(f); 02390 f = NULL; 02391 res = 0; 02392 } 02393 } 02394 } 02395 if (res < 0) { 02396 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02397 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02398 goto before_you_go; 02399 } 02400 02401 if (!f || (f->frametype == AST_FRAME_CONTROL && 02402 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02403 f->subclass == AST_CONTROL_CONGESTION))) { 02404 res = -1; 02405 break; 02406 } 02407 /* many things should be sent to the 'other' channel */ 02408 other = (who == chan) ? peer : chan; 02409 if (f->frametype == AST_FRAME_CONTROL) { 02410 switch (f->subclass) { 02411 case AST_CONTROL_RINGING: 02412 case AST_CONTROL_FLASH: 02413 case -1: 02414 ast_indicate(other, f->subclass); 02415 break; 02416 case AST_CONTROL_HOLD: 02417 case AST_CONTROL_UNHOLD: 02418 ast_indicate_data(other, f->subclass, f->data, f->datalen); 02419 break; 02420 case AST_CONTROL_OPTION: 02421 aoh = f->data; 02422 /* Forward option Requests */ 02423 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02424 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02425 f->datalen - sizeof(struct ast_option_header), 0); 02426 } 02427 break; 02428 } 02429 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02430 /* eat it */ 02431 } else if (f->frametype == AST_FRAME_DTMF) { 02432 char *featurecode; 02433 int sense; 02434 02435 hadfeatures = hasfeatures; 02436 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02437 if (who == chan) { 02438 sense = FEATURE_SENSE_CHAN; 02439 featurecode = chan_featurecode; 02440 } else { 02441 sense = FEATURE_SENSE_PEER; 02442 featurecode = peer_featurecode; 02443 } 02444 /*! append the event to featurecode. we rely on the string being zero-filled, and 02445 * not overflowing it. 02446 * \todo XXX how do we guarantee the latter ? 02447 */ 02448 featurecode[strlen(featurecode)] = f->subclass; 02449 /* Get rid of the frame before we start doing "stuff" with the channels */ 02450 ast_frfree(f); 02451 f = NULL; 02452 config->feature_timer = backup_config.feature_timer; 02453 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 02454 switch(res) { 02455 case FEATURE_RETURN_PASSDIGITS: 02456 ast_dtmf_stream(other, who, featurecode, 0, 0); 02457 /* Fall through */ 02458 case FEATURE_RETURN_SUCCESS: 02459 memset(featurecode, 0, sizeof(chan_featurecode)); 02460 break; 02461 } 02462 if (res >= FEATURE_RETURN_PASSDIGITS) { 02463 res = 0; 02464 } else 02465 break; 02466 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02467 if (hadfeatures && !hasfeatures) { 02468 /* Restore backup */ 02469 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02470 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02471 } else if (hasfeatures) { 02472 if (!hadfeatures) { 02473 /* Backup configuration */ 02474 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02475 /* Setup temporary config options */ 02476 config->play_warning = 0; 02477 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02478 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02479 config->warning_freq = 0; 02480 config->warning_sound = NULL; 02481 config->end_sound = NULL; 02482 config->start_sound = NULL; 02483 config->firstpass = 0; 02484 } 02485 config->start_time = ast_tvnow(); 02486 config->feature_timer = featuredigittimeout; 02487 ast_debug(1, "Set time limit to %ld\n", config->feature_timer); 02488 } 02489 } 02490 if (f) 02491 ast_frfree(f); 02492 02493 } 02494 before_you_go: 02495 02496 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02497 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02498 if (bridge_cdr) { 02499 ast_cdr_discard(bridge_cdr); 02500 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02501 } 02502 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02503 } 02504 02505 if (config->end_bridge_callback) { 02506 config->end_bridge_callback(config->end_bridge_callback_data); 02507 } 02508 02509 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02510 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02511 struct ast_cdr *swapper = NULL; 02512 char savelastapp[AST_MAX_EXTENSION]; 02513 char savelastdata[AST_MAX_EXTENSION]; 02514 char save_exten[AST_MAX_EXTENSION]; 02515 int save_prio; 02516 int found = 0; /* set if we find at least one match */ 02517 int spawn_error = 0; 02518 02519 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02520 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02521 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02522 ast_cdr_end(bridge_cdr); 02523 } 02524 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02525 dialplan code operate on it */ 02526 ast_channel_lock(chan); 02527 if (bridge_cdr) { 02528 swapper = chan->cdr; 02529 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02530 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02531 chan->cdr = bridge_cdr; 02532 } 02533 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02534 save_prio = chan->priority; 02535 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02536 chan->priority = 1; 02537 ast_channel_unlock(chan); 02538 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 02539 chan->priority++; 02540 } 02541 if (found && spawn_error) { 02542 /* Something bad happened, or a hangup has been requested. */ 02543 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02544 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02545 } 02546 /* swap it back */ 02547 ast_channel_lock(chan); 02548 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02549 chan->priority = save_prio; 02550 if (bridge_cdr) { 02551 if (chan->cdr == bridge_cdr) { 02552 chan->cdr = swapper; 02553 } else { 02554 bridge_cdr = NULL; 02555 } 02556 } 02557 if (chan->priority != 1 || !spawn_error) { 02558 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02559 } 02560 ast_channel_unlock(chan); 02561 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02562 if (bridge_cdr) { 02563 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02564 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02565 } 02566 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02567 } 02568 02569 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02570 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02571 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 02572 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02573 02574 /* we can post the bridge CDR at this point */ 02575 if (bridge_cdr) { 02576 ast_cdr_end(bridge_cdr); 02577 ast_cdr_detach(bridge_cdr); 02578 } 02579 02580 /* do a specialized reset on the beginning channel 02581 CDR's, if they still exist, so as not to mess up 02582 issues in future bridges; 02583 02584 Here are the rules of the game: 02585 1. The chan and peer channel pointers will not change 02586 during the life of the bridge. 02587 2. But, in transfers, the channel names will change. 02588 between the time the bridge is started, and the 02589 time the channel ends. 02590 Usually, when a channel changes names, it will 02591 also change CDR pointers. 02592 3. Usually, only one of the two channels (chan or peer) 02593 will change names. 02594 4. Usually, if a channel changes names during a bridge, 02595 it is because of a transfer. Usually, in these situations, 02596 it is normal to see 2 bridges running simultaneously, and 02597 it is not unusual to see the two channels that change 02598 swapped between bridges. 02599 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02600 to attend to; if the chan or peer changed names, 02601 we have the before and after attached CDR's. 02602 */ 02603 02604 if (new_chan_cdr) { 02605 struct ast_channel *chan_ptr = NULL; 02606 02607 if (strcasecmp(orig_channame, chan->name) != 0) { 02608 /* old channel */ 02609 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02610 if (chan_ptr) { 02611 if (!ast_bridged_channel(chan_ptr)) { 02612 struct ast_cdr *cur; 02613 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02614 if (cur == chan_cdr) { 02615 break; 02616 } 02617 } 02618 if (cur) 02619 ast_cdr_specialized_reset(chan_cdr,0); 02620 } 02621 ast_channel_unlock(chan_ptr); 02622 } 02623 /* new channel */ 02624 ast_cdr_specialized_reset(new_chan_cdr,0); 02625 } else { 02626 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02627 } 02628 } 02629 02630 { 02631 struct ast_channel *chan_ptr = NULL; 02632 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02633 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)) 02634 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02635 if (strcasecmp(orig_peername, peer->name) != 0) { 02636 /* old channel */ 02637 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02638 if (chan_ptr) { 02639 if (!ast_bridged_channel(chan_ptr)) { 02640 struct ast_cdr *cur; 02641 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02642 if (cur == peer_cdr) { 02643 break; 02644 } 02645 } 02646 if (cur) 02647 ast_cdr_specialized_reset(peer_cdr,0); 02648 } 02649 ast_channel_unlock(chan_ptr); 02650 } 02651 /* new channel */ 02652 ast_cdr_specialized_reset(new_peer_cdr,0); 02653 } else { 02654 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02655 } 02656 } 02657 02658 return res; 02659 }
static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
data | thread bridge. |
Definition at line 311 of file features.c.
References ast_channel::appl, ast_bridge_call(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, LOG_VERBOSE, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.
Referenced by ast_bridge_call_thread_launch().
00312 { 00313 struct ast_bridge_thread_obj *tobj = data; 00314 int res; 00315 00316 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00317 tobj->chan->data = tobj->peer->name; 00318 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00319 tobj->peer->data = tobj->chan->name; 00320 00321 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00322 00323 if (tobj->return_to_pbx) { 00324 if (!ast_check_hangup(tobj->peer)) { 00325 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 00326 res = ast_pbx_start(tobj->peer); 00327 if (res != AST_PBX_SUCCESS) 00328 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 00329 } else 00330 ast_hangup(tobj->peer); 00331 if (!ast_check_hangup(tobj->chan)) { 00332 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 00333 res = ast_pbx_start(tobj->chan); 00334 if (res != AST_PBX_SUCCESS) 00335 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 00336 } else 00337 ast_hangup(tobj->chan); 00338 } else { 00339 ast_hangup(tobj->chan); 00340 ast_hangup(tobj->peer); 00341 } 00342 00343 ast_free(tobj); 00344 00345 return NULL; 00346 }
static void ast_bridge_call_thread_launch | ( | void * | data | ) | [static] |
create thread for the parked call
data | Create thread and attributes, call ast_bridge_call_thread |
Definition at line 354 of file features.c.
References ast_bridge_call_thread(), ast_pthread_create, and thread.
Referenced by action_bridge(), and builtin_atxfer().
00355 { 00356 pthread_t thread; 00357 pthread_attr_t attr; 00358 struct sched_param sched; 00359 00360 pthread_attr_init(&attr); 00361 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00362 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00363 pthread_attr_destroy(&attr); 00364 memset(&sched, 0, sizeof(sched)); 00365 pthread_setschedparam(thread, SCHED_RR, &sched); 00366 }
int ast_feature_detect | ( | struct ast_channel * | chan, | |
struct ast_flags * | features, | |||
char * | code, | |||
struct ast_call_feature * | feature | |||
) |
detect a feature before bridging
chan | ||
ast_flags | ptr | |
char | ptr of input code |
ast_call_feature | ptr to be set if found |
Definition at line 1842 of file features.c.
References chan, feature_group_exten::feature, and feature_interpret_helper().
Referenced by detect_disconnect().
01842 { 01843 01844 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 01845 }
static int ast_feature_interpret | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense | |||
) | [static] |
Check the dynamic features.
chan,peer,config,code,sense |
res | on success. | |
-1 | on failure. |
Definition at line 1813 of file features.c.
References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, chan, config, feature_group_exten::feature, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
01813 { 01814 01815 char dynamic_features_buf[128]; 01816 const char *peer_dynamic_features, *chan_dynamic_features; 01817 struct ast_flags features; 01818 struct ast_call_feature feature; 01819 if (sense == FEATURE_SENSE_CHAN) { 01820 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01821 } 01822 else { 01823 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01824 } 01825 01826 ast_channel_lock(peer); 01827 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 01828 ast_channel_unlock(peer); 01829 01830 ast_channel_lock(chan); 01831 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 01832 ast_channel_unlock(chan); 01833 01834 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,"")); 01835 01836 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); 01837 01838 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature); 01839 }
static struct ast_channel * ast_feature_request_and_dial | ( | struct ast_channel * | caller, | |
struct ast_channel * | transferee, | |||
const char * | type, | |||
int | format, | |||
void * | data, | |||
int | timeout, | |||
int * | outstate, | |||
const char * | cid_num, | |||
const char * | cid_name, | |||
int | igncallerstate, | |||
const char * | language | |||
) | [static] |
Get feature and dial.
caller,transferee,type,format,data,timeout,outstate,cid_num,cid_name,igncallerstate | Request channel, set channel variables, initiate call,check if they want to disconnect go into loop, check if timeout has elapsed, check if person to be transfered hung up, check for answer break loop, set cdr return channel. |
Definition at line 1900 of file features.c.
References ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), builtin_features, chan, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, len(), LOG_NOTICE, ast_channel::name, and pbx_builtin_setvar_helper().
Referenced by builtin_atxfer().
01901 { 01902 int state = 0; 01903 int cause = 0; 01904 int to; 01905 struct ast_channel *chan; 01906 struct ast_channel *monitor_chans[2]; 01907 struct ast_channel *active_channel; 01908 int res = 0, ready = 0; 01909 01910 if ((chan = ast_request(type, format, data, &cause))) { 01911 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01912 ast_string_field_set(chan, language, language); 01913 ast_channel_inherit_variables(caller, chan); 01914 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01915 01916 if (!ast_call(chan, data, timeout)) { 01917 struct timeval started; 01918 int x, len = 0; 01919 char *disconnect_code = NULL, *dialed_code = NULL; 01920 01921 ast_indicate(caller, AST_CONTROL_RINGING); 01922 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01923 ast_rwlock_rdlock(&features_lock); 01924 for (x = 0; x < FEATURES_COUNT; x++) { 01925 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01926 continue; 01927 01928 disconnect_code = builtin_features[x].exten; 01929 len = strlen(disconnect_code) + 1; 01930 dialed_code = alloca(len); 01931 memset(dialed_code, 0, len); 01932 break; 01933 } 01934 ast_rwlock_unlock(&features_lock); 01935 x = 0; 01936 started = ast_tvnow(); 01937 to = timeout; 01938 01939 ast_poll_channel_add(caller, chan); 01940 01941 while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) { 01942 struct ast_frame *f = NULL; 01943 01944 monitor_chans[0] = caller; 01945 monitor_chans[1] = chan; 01946 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01947 01948 /* see if the timeout has been violated */ 01949 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01950 state = AST_CONTROL_UNHOLD; 01951 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01952 break; /*doh! timeout*/ 01953 } 01954 01955 if (!active_channel) 01956 continue; 01957 01958 if (chan && (chan == active_channel)) { 01959 if (!ast_strlen_zero(chan->call_forward)) { 01960 if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) { 01961 return NULL; 01962 } 01963 continue; 01964 } 01965 f = ast_read(chan); 01966 if (f == NULL) { /*doh! where'd he go?*/ 01967 state = AST_CONTROL_HANGUP; 01968 res = 0; 01969 break; 01970 } 01971 01972 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01973 if (f->subclass == AST_CONTROL_RINGING) { 01974 state = f->subclass; 01975 ast_verb(3, "%s is ringing\n", chan->name); 01976 ast_indicate(caller, AST_CONTROL_RINGING); 01977 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01978 state = f->subclass; 01979 ast_verb(3, "%s is busy\n", chan->name); 01980 ast_indicate(caller, AST_CONTROL_BUSY); 01981 ast_frfree(f); 01982 f = NULL; 01983 break; 01984 } else if (f->subclass == AST_CONTROL_ANSWER) { 01985 /* This is what we are hoping for */ 01986 state = f->subclass; 01987 ast_frfree(f); 01988 f = NULL; 01989 ready=1; 01990 break; 01991 } else if (f->subclass != -1) { 01992 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01993 } 01994 /* else who cares */ 01995 } 01996 01997 } else if (caller && (active_channel == caller)) { 01998 f = ast_read(caller); 01999 if (f == NULL) { /*doh! where'd he go?*/ 02000 if (!igncallerstate) { 02001 if (ast_check_hangup(caller) && !ast_check_hangup(chan)) { 02002 /* make this a blind transfer */ 02003 ready = 1; 02004 break; 02005 } 02006 state = AST_CONTROL_HANGUP; 02007 res = 0; 02008 break; 02009 } 02010 } else { 02011 02012 if (f->frametype == AST_FRAME_DTMF) { 02013 dialed_code[x++] = f->subclass; 02014 dialed_code[x] = '\0'; 02015 if (strlen(dialed_code) == len) { 02016 x = 0; 02017 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 02018 x = 0; 02019 dialed_code[x] = '\0'; 02020 } 02021 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 02022 /* Caller Canceled the call */ 02023 state = AST_CONTROL_UNHOLD; 02024 ast_frfree(f); 02025 f = NULL; 02026 break; 02027 } 02028 } 02029 } 02030 } 02031 if (f) 02032 ast_frfree(f); 02033 } /* end while */ 02034 02035 ast_poll_channel_del(caller, chan); 02036 02037 } else 02038 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 02039 } else { 02040 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 02041 switch(cause) { 02042 case AST_CAUSE_BUSY: 02043 state = AST_CONTROL_BUSY; 02044 break; 02045 case AST_CAUSE_CONGESTION: 02046 state = AST_CONTROL_CONGESTION; 02047 break; 02048 } 02049 } 02050 02051 ast_indicate(caller, -1); 02052 if (chan && ready) { 02053 if (chan->_state == AST_STATE_UP) 02054 state = AST_CONTROL_ANSWER; 02055 res = 0; 02056 } else if(chan) { 02057 res = -1; 02058 ast_hangup(chan); 02059 chan = NULL; 02060 } else { 02061 res = -1; 02062 } 02063 02064 if (outstate) 02065 *outstate = state; 02066 02067 return chan; 02068 }
int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 4033 of file features.c.
References action_bridge(), ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application2(), bridge_exec(), cli_features, descrip, descrip2, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, synopsis, and synopsis2.
Referenced by main().
04034 { 04035 int res; 04036 04037 ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL); 04038 04039 memset(parking_ext, 0, sizeof(parking_ext)); 04040 memset(parking_con, 0, sizeof(parking_con)); 04041 04042 if ((res = load_config())) 04043 return res; 04044 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 04045 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 04046 res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL); 04047 if (!res) 04048 res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL); 04049 if (!res) { 04050 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls"); 04051 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 04052 "Park a channel", mandescr_park); 04053 ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge); 04054 } 04055 04056 res |= ast_devstate_prov_add("Park", metermaidstate); 04057 04058 return res; 04059 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 3483 of file features.c.
References load_config(), and RESULT_SUCCESS.
03484 { 03485 load_config(); 03486 03487 return RESULT_SUCCESS; 03488 }
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 1597 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by handle_request_info().
01598 { 01599 int x; 01600 for (x = 0; x < FEATURES_COUNT; x++) { 01601 if (!strcasecmp(name, builtin_features[x].sname)) 01602 return &builtin_features[x]; 01603 } 01604 return NULL; 01605 }
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 665 of file features.c.
References masq_park_call().
Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().
00666 { 00667 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00668 }
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
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 611 of file features.c.
References chan, and park_call_full().
Referenced by iax_park_thread(), and sip_park_thread().
00612 { 00613 return park_call_full(chan, peer, timeout, extout, NULL, NULL); 00614 }
const char* ast_parking_ext | ( | void | ) |
Determine system parking extension.
Definition at line 226 of file features.c.
References parking_ext.
Referenced by builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00227 { 00228 return parking_ext; 00229 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
Definition at line 3851 of file features.c.
References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, chan, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), pickup_exec(), and ss_thread().
03852 { 03853 struct ast_channel *cur = NULL; 03854 int res = -1; 03855 03856 while ((cur = ast_channel_walk_locked(cur)) != NULL) { 03857 if (!cur->pbx && 03858 (cur != chan) && 03859 (chan->pickupgroup & cur->callgroup) && 03860 ((cur->_state == AST_STATE_RINGING) || 03861 (cur->_state == AST_STATE_RING))) { 03862 break; 03863 } 03864 ast_channel_unlock(cur); 03865 } 03866 if (cur) { 03867 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 03868 res = ast_answer(chan); 03869 if (res) 03870 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 03871 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 03872 if (res) 03873 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 03874 res = ast_channel_masquerade(cur, chan); 03875 if (res) 03876 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 03877 ast_channel_unlock(cur); 03878 } else { 03879 ast_debug(1, "No call pickup possible...\n"); 03880 } 03881 return res; 03882 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 231 of file features.c.
References pickup_ext.
Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().
00232 { 00233 return pickup_ext; 00234 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 1587 of file features.c.
References ast_rwlock_rdlock(), and features_lock.
Referenced by handle_request_info().
01588 { 01589 ast_rwlock_rdlock(&features_lock); 01590 }
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 1424 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, feature_group_exten::feature, LOG_NOTICE, and ast_call_feature::sname.
01425 { 01426 if (!feature) { 01427 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01428 return; 01429 } 01430 01431 AST_RWLIST_WRLOCK(&feature_list); 01432 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01433 AST_RWLIST_UNLOCK(&feature_list); 01434 01435 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 01436 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 1592 of file features.c.
References ast_rwlock_unlock(), and features_lock.
Referenced by handle_request_info().
01593 { 01594 ast_rwlock_unlock(&features_lock); 01595 }
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 1512 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
01513 { 01514 if (!feature) { 01515 return; 01516 } 01517 01518 AST_RWLIST_WRLOCK(&feature_list); 01519 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01520 AST_RWLIST_UNLOCK(&feature_list); 01521 01522 ast_free(feature); 01523 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1526 of file features.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
01527 { 01528 struct ast_call_feature *feature; 01529 01530 AST_RWLIST_WRLOCK(&feature_list); 01531 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 01532 ast_free(feature); 01533 } 01534 AST_RWLIST_UNLOCK(&feature_list); 01535 }
static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 1552 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.
01553 { 01554 struct feature_group *fg; 01555 struct feature_group_exten *fge; 01556 01557 AST_RWLIST_WRLOCK(&feature_groups); 01558 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 01559 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 01560 ast_string_field_free_memory(fge); 01561 ast_free(fge); 01562 } 01563 01564 ast_string_field_free_memory(fg); 01565 ast_free(fg); 01566 } 01567 AST_RWLIST_UNLOCK(&feature_groups); 01568 }
static int bridge_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Bridge channels.
chan | ||
data | channel to bridge with. |
Definition at line 3913 of file features.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_channel_alloc, ast_channel_make_compatible(), ast_channel_unlock, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, chan, ast_channel::context, do_bridge_masquerade(), EVENT_FLAG_CALL, ast_channel::exten, ast_channel::language, LOG_WARNING, manager_event, ast_channel::name, pbx_builtin_setvar_helper(), ast_channel::priority, and xfersound.
Referenced by ast_features_init().
03914 { 03915 struct ast_channel *current_dest_chan, *final_dest_chan; 03916 char *tmp_data = NULL; 03917 struct ast_flags opts = { 0, }; 03918 struct ast_bridge_config bconfig = { { 0, }, }; 03919 03920 AST_DECLARE_APP_ARGS(args, 03921 AST_APP_ARG(dest_chan); 03922 AST_APP_ARG(options); 03923 ); 03924 03925 if (ast_strlen_zero(data)) { 03926 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 03927 return -1; 03928 } 03929 03930 tmp_data = ast_strdupa(data); 03931 AST_STANDARD_APP_ARGS(args, tmp_data); 03932 if (!ast_strlen_zero(args.options)) 03933 ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options); 03934 03935 /* avoid bridge with ourselves */ 03936 if (!strncmp(chan->name, args.dest_chan, 03937 strlen(chan->name) < strlen(args.dest_chan) ? 03938 strlen(chan->name) : strlen(args.dest_chan))) { 03939 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 03940 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03941 "Response: Failed\r\n" 03942 "Reason: Unable to bridge channel to itself\r\n" 03943 "Channel1: %s\r\n" 03944 "Channel2: %s\r\n", 03945 chan->name, args.dest_chan); 03946 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 03947 return 0; 03948 } 03949 03950 /* make sure we have a valid end point */ 03951 if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 03952 strlen(args.dest_chan)))) { 03953 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 03954 "cannot get its lock\n", args.dest_chan); 03955 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03956 "Response: Failed\r\n" 03957 "Reason: Cannot grab end point\r\n" 03958 "Channel1: %s\r\n" 03959 "Channel2: %s\r\n", chan->name, args.dest_chan); 03960 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 03961 return 0; 03962 } 03963 03964 /* answer the channel if needed */ 03965 if (current_dest_chan->_state != AST_STATE_UP) 03966 ast_answer(current_dest_chan); 03967 03968 /* try to allocate a place holder where current_dest_chan will be placed */ 03969 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 03970 NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) { 03971 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 03972 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03973 "Response: Failed\r\n" 03974 "Reason: cannot create placeholder\r\n" 03975 "Channel1: %s\r\n" 03976 "Channel2: %s\r\n", chan->name, args.dest_chan); 03977 } 03978 do_bridge_masquerade(current_dest_chan, final_dest_chan); 03979 03980 ast_channel_unlock(current_dest_chan); 03981 03982 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 03983 /* try to make compatible, send error if we fail */ 03984 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 03985 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 03986 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03987 "Response: Failed\r\n" 03988 "Reason: Could not make channels compatible for bridge\r\n" 03989 "Channel1: %s\r\n" 03990 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 03991 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 03992 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 03993 return 0; 03994 } 03995 03996 /* Report that the bridge will be successfull */ 03997 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03998 "Response: Success\r\n" 03999 "Channel1: %s\r\n" 04000 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 04001 04002 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 04003 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 04004 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 04005 if (ast_waitstream(final_dest_chan, "") < 0) 04006 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 04007 } 04008 } 04009 04010 /* do the bridge */ 04011 ast_bridge_call(chan, final_dest_chan, &bconfig); 04012 04013 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 04014 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 04015 if (!ast_check_hangup(final_dest_chan)) { 04016 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 04017 final_dest_chan->context, final_dest_chan->exten, 04018 final_dest_chan->priority, final_dest_chan->name); 04019 04020 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 04021 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 04022 ast_hangup(final_dest_chan); 04023 } else 04024 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 04025 } else { 04026 ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name); 04027 ast_hangup(final_dest_chan); 04028 } 04029 04030 return 0; 04031 }
static int builtin_atxfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Attended transfer.
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 1124 of file features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc, ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_parking_ext(), ast_read(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), builtin_parkcall(), chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), strsep(), ast_channel::visible_indication, and ast_channel::writeformat.
01125 { 01126 struct ast_channel *transferer; 01127 struct ast_channel *transferee; 01128 const char *transferer_real_context; 01129 char xferto[256] = ""; 01130 int res; 01131 int outstate=0; 01132 struct ast_channel *newchan; 01133 struct ast_channel *xferchan; 01134 struct ast_bridge_thread_obj *tobj; 01135 struct ast_bridge_config bconfig; 01136 struct ast_frame *f; 01137 int l; 01138 struct ast_datastore *features_datastore; 01139 struct ast_dial_features *dialfeatures = NULL; 01140 01141 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 01142 set_peers(&transferer, &transferee, peer, chan, sense); 01143 transferer_real_context = real_ctx(transferer, transferee); 01144 /* Start autoservice on chan while we talk to the originator */ 01145 ast_autoservice_start(transferee); 01146 ast_indicate(transferee, AST_CONTROL_HOLD); 01147 01148 /* Transfer */ 01149 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01150 if (res < 0) { 01151 finishup(transferee); 01152 return res; 01153 } 01154 if (res > 0) /* If they've typed a digit already, handle it */ 01155 xferto[0] = (char) res; 01156 01157 /* this is specific of atxfer */ 01158 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01159 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01160 finishup(transferee); 01161 return res; 01162 } 01163 if (res == 0) { 01164 ast_log(LOG_WARNING, "Did not read data.\n"); 01165 finishup(transferee); 01166 if (ast_stream_and_wait(transferer, "beeperr", "")) 01167 return -1; 01168 return FEATURE_RETURN_SUCCESS; 01169 } 01170 01171 /* valid extension, res == 1 */ 01172 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01173 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 01174 finishup(transferee); 01175 if (ast_stream_and_wait(transferer, "beeperr", "")) 01176 return -1; 01177 return FEATURE_RETURN_SUCCESS; 01178 } 01179 01180 /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of 01181 * the different variables for handling this properly with a builtin_atxfer */ 01182 if (!strcmp(xferto, ast_parking_ext())) { 01183 finishup(transferee); 01184 return builtin_parkcall(chan, peer, config, code, sense, data); 01185 } 01186 01187 l = strlen(xferto); 01188 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 01189 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01190 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01191 01192 if (!ast_check_hangup(transferer)) { 01193 /* Transferer is up - old behaviour */ 01194 ast_indicate(transferer, -1); 01195 if (!newchan) { 01196 finishup(transferee); 01197 /* any reason besides user requested cancel and busy triggers the failed sound */ 01198 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 01199 ast_stream_and_wait(transferer, xferfailsound, "")) 01200 return -1; 01201 if (ast_stream_and_wait(transferer, xfersound, "")) 01202 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01203 return FEATURE_RETURN_SUCCESS; 01204 } 01205 01206 if (check_compat(transferer, newchan)) { 01207 /* we do mean transferee here, NOT transferer */ 01208 finishup(transferee); 01209 return -1; 01210 } 01211 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 01212 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 01213 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 01214 res = ast_bridge_call(transferer, newchan, &bconfig); 01215 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 01216 ast_hangup(newchan); 01217 if (ast_stream_and_wait(transferer, xfersound, "")) 01218 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01219 finishup(transferee); 01220 transferer->_softhangup = 0; 01221 return FEATURE_RETURN_SUCCESS; 01222 } 01223 if (check_compat(transferee, newchan)) { 01224 finishup(transferee); 01225 return -1; 01226 } 01227 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01228 01229 if ((ast_autoservice_stop(transferee) < 0) 01230 || (ast_waitfordigit(transferee, 100) < 0) 01231 || (ast_waitfordigit(newchan, 100) < 0) 01232 || ast_check_hangup(transferee) 01233 || ast_check_hangup(newchan)) { 01234 ast_hangup(newchan); 01235 return -1; 01236 } 01237 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01238 if (!xferchan) { 01239 ast_hangup(newchan); 01240 return -1; 01241 } 01242 /* Make formats okay */ 01243 xferchan->visible_indication = transferer->visible_indication; 01244 xferchan->readformat = transferee->readformat; 01245 xferchan->writeformat = transferee->writeformat; 01246 ast_channel_masquerade(xferchan, transferee); 01247 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01248 xferchan->_state = AST_STATE_UP; 01249 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01250 xferchan->_softhangup = 0; 01251 if ((f = ast_read(xferchan))) 01252 ast_frfree(f); 01253 newchan->_state = AST_STATE_UP; 01254 ast_clear_flag(newchan, AST_FLAGS_ALL); 01255 newchan->_softhangup = 0; 01256 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01257 ast_hangup(xferchan); 01258 ast_hangup(newchan); 01259 return -1; 01260 } 01261 01262 ast_channel_lock(newchan); 01263 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 01264 dialfeatures = features_datastore->data; 01265 } 01266 ast_channel_unlock(newchan); 01267 01268 if (dialfeatures) { 01269 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 01270 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 01271 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01272 dialfeatures = NULL; 01273 } 01274 01275 ast_channel_lock(xferchan); 01276 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 01277 dialfeatures = features_datastore->data; 01278 } 01279 ast_channel_unlock(xferchan); 01280 01281 if (dialfeatures) { 01282 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01283 } 01284 01285 tobj->chan = newchan; 01286 tobj->peer = xferchan; 01287 tobj->bconfig = *config; 01288 01289 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01290 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01291 } 01292 01293 if (ast_stream_and_wait(newchan, xfersound, "")) 01294 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01295 ast_bridge_call_thread_launch(tobj); 01296 return -1; /* XXX meaning the channel is bridged ? */ 01297 } else if (!ast_check_hangup(transferee)) { 01298 /* act as blind transfer */ 01299 if (ast_autoservice_stop(transferee) < 0) { 01300 ast_hangup(newchan); 01301 return -1; 01302 } 01303 01304 if (!newchan) { 01305 unsigned int tries = 0; 01306 char *transferer_tech, *transferer_name = ast_strdupa(transferer->name); 01307 01308 transferer_tech = strsep(&transferer_name, "/"); 01309 transferer_name = strsep(&transferer_name, "-"); 01310 01311 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 01312 ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name); 01313 if (ast_stream_and_wait(transferee, "beeperr", "")) 01314 return -1; 01315 return FEATURE_RETURN_SUCCESS; 01316 } 01317 01318 ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name); 01319 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01320 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01321 while (!newchan && !atxferdropcall && tries < atxfercallbackretries) { 01322 /* Trying to transfer again */ 01323 ast_autoservice_start(transferee); 01324 ast_indicate(transferee, AST_CONTROL_HOLD); 01325 01326 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01327 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01328 if (ast_autoservice_stop(transferee) < 0) { 01329 if (newchan) 01330 ast_hangup(newchan); 01331 return -1; 01332 } 01333 if (!newchan) { 01334 /* Transfer failed, sleeping */ 01335 ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay); 01336 ast_safe_sleep(transferee, atxferloopdelay); 01337 ast_debug(1, "Trying to callback...\n"); 01338 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01339 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01340 } 01341 tries++; 01342 } 01343 } 01344 if (!newchan) 01345 return -1; 01346 01347 /* newchan is up, we should prepare transferee and bridge them */ 01348 if (check_compat(transferee, newchan)) { 01349 finishup(transferee); 01350 return -1; 01351 } 01352 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01353 01354 if ((ast_waitfordigit(transferee, 100) < 0) 01355 || (ast_waitfordigit(newchan, 100) < 0) 01356 || ast_check_hangup(transferee) 01357 || ast_check_hangup(newchan)) { 01358 ast_hangup(newchan); 01359 return -1; 01360 } 01361 01362 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01363 if (!xferchan) { 01364 ast_hangup(newchan); 01365 return -1; 01366 } 01367 /* Make formats okay */ 01368 xferchan->visible_indication = transferer->visible_indication; 01369 xferchan->readformat = transferee->readformat; 01370 xferchan->writeformat = transferee->writeformat; 01371 ast_channel_masquerade(xferchan, transferee); 01372 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01373 xferchan->_state = AST_STATE_UP; 01374 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01375 xferchan->_softhangup = 0; 01376 if ((f = ast_read(xferchan))) 01377 ast_frfree(f); 01378 newchan->_state = AST_STATE_UP; 01379 ast_clear_flag(newchan, AST_FLAGS_ALL); 01380 newchan->_softhangup = 0; 01381 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01382 ast_hangup(xferchan); 01383 ast_hangup(newchan); 01384 return -1; 01385 } 01386 tobj->chan = newchan; 01387 tobj->peer = xferchan; 01388 tobj->bconfig = *config; 01389 01390 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01391 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01392 } 01393 01394 if (ast_stream_and_wait(newchan, xfersound, "")) 01395 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01396 ast_bridge_call_thread_launch(tobj); 01397 return -1; /* XXX meaning the channel is bridged ? */ 01398 } else { 01399 /* Transferee hung up */ 01400 finishup(transferee); 01401 return -1; 01402 } 01403 }
static int builtin_automixmonitor | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 832 of file features.c.
References AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_unlock, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mixmonitor_app, mixmonitor_spy_type, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and stopmixmonitor_app.
00833 { 00834 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00835 int x = 0; 00836 size_t len; 00837 struct ast_channel *caller_chan, *callee_chan; 00838 const char *mixmonitor_spy_type = "MixMonitor"; 00839 int count = 0; 00840 00841 if (!mixmonitor_ok) { 00842 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 00843 return -1; 00844 } 00845 00846 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 00847 mixmonitor_ok = 0; 00848 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 00849 return -1; 00850 } 00851 00852 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00853 00854 if (!ast_strlen_zero(courtesytone)) { 00855 if (ast_autoservice_start(callee_chan)) 00856 return -1; 00857 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 00858 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00859 ast_autoservice_stop(callee_chan); 00860 return -1; 00861 } 00862 if (ast_autoservice_stop(callee_chan)) 00863 return -1; 00864 } 00865 00866 ast_channel_lock(callee_chan); 00867 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 00868 ast_channel_unlock(callee_chan); 00869 00870 // This means a mixmonitor is attached to the channel, running or not is unknown. 00871 if (count > 0) { 00872 00873 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 00874 00875 //Make sure they are running 00876 ast_channel_lock(callee_chan); 00877 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 00878 ast_channel_unlock(callee_chan); 00879 if (count > 0) { 00880 if (!stopmixmonitor_ok) { 00881 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 00882 return -1; 00883 } 00884 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 00885 stopmixmonitor_ok = 0; 00886 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 00887 return -1; 00888 } else { 00889 pbx_exec(callee_chan, stopmixmonitor_app, ""); 00890 return FEATURE_RETURN_SUCCESS; 00891 } 00892 } 00893 00894 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 00895 } 00896 00897 if (caller_chan && callee_chan) { 00898 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 00899 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 00900 00901 if (!touch_format) 00902 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 00903 00904 if (!touch_monitor) 00905 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 00906 00907 if (touch_monitor) { 00908 len = strlen(touch_monitor) + 50; 00909 args = alloca(len); 00910 touch_filename = alloca(len); 00911 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00912 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 00913 } else { 00914 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00915 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00916 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00917 args = alloca(len); 00918 touch_filename = alloca(len); 00919 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00920 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 00921 } 00922 00923 for( x = 0; x < strlen(args); x++) { 00924 if (args[x] == '/') 00925 args[x] = '-'; 00926 } 00927 00928 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 00929 00930 pbx_exec(callee_chan, mixmonitor_app, args); 00931 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 00932 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 00933 return FEATURE_RETURN_SUCCESS; 00934 00935 } 00936 00937 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00938 return -1; 00939 00940 }
static int builtin_automonitor | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Monitor a channel by DTMF.
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. |
FEATURE_RETURN_SUCCESS | on success. | |
-1 | on error. |
Definition at line 746 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::monitor, monitor_app, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and ast_channel_monitor::stop.
00747 { 00748 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00749 int x = 0; 00750 size_t len; 00751 struct ast_channel *caller_chan, *callee_chan; 00752 00753 if (!monitor_ok) { 00754 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00755 return -1; 00756 } 00757 00758 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00759 monitor_ok = 0; 00760 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00761 return -1; 00762 } 00763 00764 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00765 00766 if (!ast_strlen_zero(courtesytone)) { 00767 if (ast_autoservice_start(callee_chan)) 00768 return -1; 00769 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 00770 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00771 ast_autoservice_stop(callee_chan); 00772 return -1; 00773 } 00774 if (ast_autoservice_stop(callee_chan)) 00775 return -1; 00776 } 00777 00778 if (callee_chan->monitor) { 00779 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 00780 callee_chan->monitor->stop(callee_chan, 1); 00781 return FEATURE_RETURN_SUCCESS; 00782 } 00783 00784 if (caller_chan && callee_chan) { 00785 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00786 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00787 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 00788 00789 if (!touch_format) 00790 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00791 00792 if (!touch_monitor) 00793 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00794 00795 if (!touch_monitor_prefix) 00796 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 00797 00798 if (touch_monitor) { 00799 len = strlen(touch_monitor) + 50; 00800 args = alloca(len); 00801 touch_filename = alloca(len); 00802 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 00803 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 00804 } else { 00805 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00806 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00807 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00808 args = alloca(len); 00809 touch_filename = alloca(len); 00810 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 00811 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 00812 } 00813 00814 for(x = 0; x < strlen(args); x++) { 00815 if (args[x] == '/') 00816 args[x] = '-'; 00817 } 00818 00819 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 00820 00821 pbx_exec(callee_chan, monitor_app, args); 00822 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00823 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00824 00825 return FEATURE_RETURN_SUCCESS; 00826 } 00827 00828 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00829 return -1; 00830 }
static int builtin_blindtransfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Blind transfer user to another extension.
chan | channel to be transfered | |
peer | channel initiated blind transfer | |
config | ||
code | ||
data | ||
sense | feature options |
FEATURE_RETURN_SUCCESS. | ||
-1 | on failure. |
Definition at line 992 of file features.c.
References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), AST_FLAG_BRIDGE_HANGUP_DONT, ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, ast_stopstream(), ast_stream_and_wait(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_cdr::dstchannel, FEATURE_RETURN_PARKFAILED, FEATURE_RETURN_SUCCESS, finishup(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, masq_park_call_announce(), ast_channel::name, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), and set_peers().
00993 { 00994 struct ast_channel *transferer; 00995 struct ast_channel *transferee; 00996 const char *transferer_real_context; 00997 char xferto[256]; 00998 int res; 00999 int parkstatus = 0; 01000 01001 set_peers(&transferer, &transferee, peer, chan, sense); 01002 transferer_real_context = real_ctx(transferer, transferee); 01003 /* Start autoservice on chan while we talk to the originator */ 01004 ast_autoservice_start(transferee); 01005 ast_indicate(transferee, AST_CONTROL_HOLD); 01006 01007 memset(xferto, 0, sizeof(xferto)); 01008 01009 /* Transfer */ 01010 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01011 if (res < 0) { 01012 finishup(transferee); 01013 return -1; /* error ? */ 01014 } 01015 if (res > 0) /* If they've typed a digit already, handle it */ 01016 xferto[0] = (char) res; 01017 01018 ast_stopstream(transferer); 01019 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01020 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01021 finishup(transferee); 01022 return res; 01023 } 01024 if (!strcmp(xferto, ast_parking_ext())) { 01025 res = finishup(transferee); 01026 if (res) 01027 res = -1; 01028 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, NULL))) { /* success */ 01029 /* We return non-zero, but tell the PBX not to hang the channel when 01030 the thread dies -- We have to be careful now though. We are responsible for 01031 hanging up the channel, else it will never be hung up! */ 01032 01033 return 0; 01034 } else { 01035 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus); 01036 } 01037 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 01038 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01039 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 01040 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 01041 res=finishup(transferee); 01042 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 01043 transferer->cdr=ast_cdr_alloc(); 01044 if (transferer->cdr) { 01045 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 01046 ast_cdr_start(transferer->cdr); 01047 } 01048 } 01049 if (transferer->cdr) { 01050 struct ast_cdr *swap = transferer->cdr; 01051 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 01052 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 01053 transferer->cdr->channel, transferer->cdr->dstchannel); 01054 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 01055 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel); 01056 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto); 01057 /* swap cdrs-- it will save us some time & work */ 01058 transferer->cdr = transferee->cdr; 01059 transferee->cdr = swap; 01060 } 01061 if (!transferee->pbx) { 01062 /* Doh! Use our handy async_goto functions */ 01063 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n" 01064 ,transferee->name, xferto, transferer_real_context); 01065 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 01066 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 01067 } else { 01068 /* Set the channel's new extension, since it exists, using transferer context */ 01069 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 01070 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name); 01071 set_c_e_p(transferee, transferer_real_context, xferto, 0); 01072 } 01073 check_goto_on_transfer(transferer); 01074 return res; 01075 } else { 01076 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 01077 } 01078 if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { 01079 finishup(transferee); 01080 return -1; 01081 } 01082 ast_stopstream(transferer); 01083 res = finishup(transferee); 01084 if (res) { 01085 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name); 01086 return res; 01087 } 01088 return FEATURE_RETURN_SUCCESS; 01089 }
static int builtin_disconnect | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 942 of file features.c.
References ast_verb, and FEATURE_RETURN_HANGUP.
00943 { 00944 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 00945 return FEATURE_RETURN_HANGUP; 00946 }
static int builtin_parkcall | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
support routing for one touch call parking
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 705 of file features.c.
References ast_channel::_state, ast_answer(), ast_safe_sleep(), AST_STATE_UP, chan, masq_park_call_announce(), and set_peers().
Referenced by builtin_atxfer().
00706 { 00707 struct ast_channel *parker; 00708 struct ast_channel *parkee; 00709 int res = 0; 00710 00711 set_peers(&parker, &parkee, peer, chan, sense); 00712 /* we used to set chan's exten and priority to "s" and 1 00713 here, but this generates (in some cases) an invalid 00714 extension, and if "s" exists, could errantly 00715 cause execution of extensions you don't expect. It 00716 makes more sense to let nature take its course 00717 when chan finishes, and let the pbx do its thing 00718 and hang up when the park is over. 00719 */ 00720 if (chan->_state != AST_STATE_UP) 00721 res = ast_answer(chan); 00722 if (!res) 00723 res = ast_safe_sleep(chan, 1000); 00724 00725 if (!res) { /* one direction used to call park_call.... */ 00726 res = masq_park_call_announce(parkee, parker, 0, NULL, NULL); 00727 /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ 00728 } 00729 return res; 00730 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 2676 of file features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, and ast_test_flag.
Referenced by do_parking_thread().
02677 { 02678 int i = 0; 02679 enum { 02680 OPT_CALLEE_REDIRECT = 't', 02681 OPT_CALLER_REDIRECT = 'T', 02682 OPT_CALLEE_AUTOMON = 'w', 02683 OPT_CALLER_AUTOMON = 'W', 02684 OPT_CALLEE_DISCONNECT = 'h', 02685 OPT_CALLER_DISCONNECT = 'H', 02686 OPT_CALLEE_PARKCALL = 'k', 02687 OPT_CALLER_PARKCALL = 'K', 02688 }; 02689 02690 memset(options, 0, len); 02691 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 02692 options[i++] = OPT_CALLER_REDIRECT; 02693 } 02694 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 02695 options[i++] = OPT_CALLER_AUTOMON; 02696 } 02697 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 02698 options[i++] = OPT_CALLER_DISCONNECT; 02699 } 02700 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 02701 options[i++] = OPT_CALLER_PARKCALL; 02702 } 02703 02704 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 02705 options[i++] = OPT_CALLEE_REDIRECT; 02706 } 02707 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 02708 options[i++] = OPT_CALLEE_AUTOMON; 02709 } 02710 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 02711 options[i++] = OPT_CALLEE_DISCONNECT; 02712 } 02713 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 02714 options[i++] = OPT_CALLEE_PARKCALL; 02715 } 02716 02717 return options; 02718 }
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 1098 of file features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by builtin_atxfer().
01099 { 01100 if (ast_channel_make_compatible(c, newchan) < 0) { 01101 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 01102 c->name, newchan->name); 01103 ast_hangup(newchan); 01104 return -1; 01105 } 01106 return 0; 01107 }
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 265 of file features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_channel_alloc, ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), chan, f, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.
Referenced by builtin_blindtransfer().
00266 { 00267 struct ast_channel *xferchan; 00268 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00269 char *x, *goto_on_transfer; 00270 struct ast_frame *f; 00271 00272 if (ast_strlen_zero(val)) 00273 return; 00274 00275 goto_on_transfer = ast_strdupa(val); 00276 00277 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name))) 00278 return; 00279 00280 for (x = goto_on_transfer; x && *x; x++) { 00281 if (*x == '^') 00282 *x = '|'; 00283 } 00284 /* Make formats okay */ 00285 xferchan->readformat = chan->readformat; 00286 xferchan->writeformat = chan->writeformat; 00287 ast_channel_masquerade(xferchan, chan); 00288 ast_parseable_goto(xferchan, goto_on_transfer); 00289 xferchan->_state = AST_STATE_UP; 00290 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00291 xferchan->_softhangup = 0; 00292 if ((f = ast_read(xferchan))) { 00293 ast_frfree(f); 00294 f = NULL; 00295 ast_pbx_start(xferchan); 00296 } else { 00297 ast_hangup(xferchan); 00298 } 00299 }
static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 210 of file features.c.
References ast_free.
00211 { 00212 struct ast_dial_features *df = data; 00213 if (df) { 00214 ast_free(df); 00215 } 00216 }
static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 197 of file features.c.
References ast_calloc.
00198 { 00199 struct ast_dial_features *df = data, *df_copy; 00200 00201 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00202 return NULL; 00203 } 00204 00205 memcpy(df_copy, df, sizeof(*df)); 00206 00207 return df_copy; 00208 }
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 3523 of file features.c.
References ast_channel::_state, ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_explicit_goto(), ast_moh_stop(), ast_setstate(), chan, ast_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
Referenced by action_bridge(), and bridge_exec().
03524 { 03525 ast_moh_stop(chan); 03526 ast_channel_lock(chan); 03527 ast_setstate(tmpchan, chan->_state); 03528 tmpchan->readformat = chan->readformat; 03529 tmpchan->writeformat = chan->writeformat; 03530 ast_channel_masquerade(tmpchan, chan); 03531 ast_channel_lock(tmpchan); 03532 ast_do_masquerade(tmpchan); 03533 /* when returning from bridge, the channel will continue at the next priority */ 03534 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 03535 ast_channel_unlock(tmpchan); 03536 ast_channel_unlock(chan); 03537 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
ignore | unused var. |
Definition at line 2728 of file features.c.
References ast_add_extension2(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), AST_MAX_FDS, ast_pbx_start(), ast_read(), ast_samp2tv(), ast_select(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, buf, callback_dialoptions(), chan, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, f, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, ast_channel::name, notify_metermaids(), parking_con, parking_con_dial, parkmohclass, pbx_builtin_setvar_helper(), post_manager_event(), ast_channel::priority, registrar, S_OR, and set_c_e_p().
Referenced by ast_features_init().
02729 { 02730 char parkingslot[AST_MAX_EXTENSION]; 02731 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 02732 02733 FD_ZERO(&rfds); 02734 FD_ZERO(&efds); 02735 02736 for (;;) { 02737 struct parkeduser *pu; 02738 int ms = -1; /* select timeout, uninitialized */ 02739 int max = -1; /* max fd, none there yet */ 02740 fd_set nrfds, nefds; /* args for the next select */ 02741 FD_ZERO(&nrfds); 02742 FD_ZERO(&nefds); 02743 02744 AST_LIST_LOCK(&parkinglot); 02745 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) { 02746 struct ast_channel *chan = pu->chan; /* shorthand */ 02747 int tms; /* timeout for this item */ 02748 int x; /* fd index in channel */ 02749 struct ast_context *con; 02750 02751 if (pu->notquiteyet) /* Pretend this one isn't here yet */ 02752 continue; 02753 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 02754 if (tms > pu->parkingtime) { 02755 ast_indicate(chan, AST_CONTROL_UNHOLD); 02756 /* Get chan, exten from derived kludge */ 02757 if (pu->peername[0]) { 02758 char *peername = ast_strdupa(pu->peername); 02759 char *cp = strrchr(peername, '-'); 02760 char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 02761 int i; 02762 02763 if (cp) 02764 *cp = 0; 02765 ast_copy_string(peername_flat,peername,sizeof(peername_flat)); 02766 for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) { 02767 if (peername_flat[i] == '/') 02768 peername_flat[i]= '0'; 02769 } 02770 con = ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar); 02771 if (!con) 02772 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 02773 if (con) { 02774 char returnexten[AST_MAX_EXTENSION]; 02775 struct ast_datastore *features_datastore; 02776 struct ast_dial_features *dialfeatures = NULL; 02777 02778 ast_channel_lock(chan); 02779 02780 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 02781 dialfeatures = features_datastore->data; 02782 02783 ast_channel_unlock(chan); 02784 02785 if (!strncmp(peername, "Parked/", 7)) { 02786 peername += 7; 02787 } 02788 02789 if (dialfeatures) { 02790 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 02791 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 02792 } else { /* Existing default */ 02793 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername); 02794 } 02795 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar); 02796 } 02797 if (comebacktoorigin) { 02798 set_c_e_p(chan, parking_con_dial, peername_flat, 1); 02799 } else { 02800 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum); 02801 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 02802 pbx_builtin_setvar_helper(pu->chan, "PARKINGSLOT", parkingslot); 02803 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 02804 } 02805 } else { 02806 /* They've been waiting too long, send them back to where they came. Theoretically they 02807 should have their original extensions and such, but we copy to be on the safe side */ 02808 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 02809 } 02810 02811 post_manager_event("ParkedCallTimeOut", pu); 02812 02813 ast_verb(2, "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority); 02814 /* Start up the PBX, or hang them up */ 02815 if (ast_pbx_start(chan)) { 02816 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 02817 ast_hangup(chan); 02818 } 02819 /* And take them out of the parking lot */ 02820 AST_LIST_REMOVE_CURRENT(list); 02821 con = ast_context_find(parking_con); 02822 if (con) { 02823 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 02824 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02825 else 02826 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE); 02827 } else 02828 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02829 ast_free(pu); 02830 } else { /* still within parking time, process descriptors */ 02831 for (x = 0; x < AST_MAX_FDS; x++) { 02832 struct ast_frame *f; 02833 02834 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 02835 continue; /* nothing on this descriptor */ 02836 02837 if (FD_ISSET(chan->fds[x], &efds)) 02838 ast_set_flag(chan, AST_FLAG_EXCEPTION); 02839 else 02840 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 02841 chan->fdno = x; 02842 02843 /* See if they need servicing */ 02844 f = ast_read(chan); 02845 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 02846 if (f) 02847 ast_frfree(f); 02848 post_manager_event("ParkedCallGiveUp", pu); 02849 02850 /* There's a problem, hang them up*/ 02851 ast_verb(2, "%s got tired of being parked\n", chan->name); 02852 ast_hangup(chan); 02853 /* And take them out of the parking lot */ 02854 AST_LIST_REMOVE_CURRENT(list); 02855 con = ast_context_find(parking_con); 02856 if (con) { 02857 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 02858 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02859 else 02860 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE); 02861 } else 02862 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02863 ast_free(pu); 02864 break; 02865 } else { 02866 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02867 ast_frfree(f); 02868 if (pu->moh_trys < 3 && !chan->generatordata) { 02869 ast_debug(1, "MOH on parked call stopped by outside source. Restarting.\n"); 02870 ast_indicate_data(chan, AST_CONTROL_HOLD, 02871 S_OR(parkmohclass, NULL), 02872 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 02873 pu->moh_trys++; 02874 } 02875 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 02876 } 02877 02878 } /* end for */ 02879 if (x >= AST_MAX_FDS) { 02880 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 02881 if (chan->fds[x] > -1) { 02882 FD_SET(chan->fds[x], &nrfds); 02883 FD_SET(chan->fds[x], &nefds); 02884 if (chan->fds[x] > max) 02885 max = chan->fds[x]; 02886 } 02887 } 02888 /* Keep track of our shortest wait */ 02889 if (tms < ms || ms < 0) 02890 ms = tms; 02891 } 02892 } 02893 } /* end while */ 02894 AST_LIST_TRAVERSE_SAFE_END 02895 AST_LIST_UNLOCK(&parkinglot); 02896 rfds = nrfds; 02897 efds = nefds; 02898 { 02899 struct timeval tv = ast_samp2tv(ms, 1000); 02900 /* Wait for something to happen */ 02901 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 02902 } 02903 pthread_testcancel(); 02904 } 02905 return NULL; /* Never reached */ 02906 }
static int feature_exec_app | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
exec an app by feature
chan,peer,config,code,sense,data | Find a feature, determine which channel activated |
-1 | error. | |
-2 | when an application cannot be found. |
Definition at line 1615 of file features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, chan, feature_group_exten::feature, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().
01616 { 01617 struct ast_app *app; 01618 struct ast_call_feature *feature = data; 01619 struct ast_channel *work, *idle; 01620 int res; 01621 01622 if (!feature) { /* shouldn't ever happen! */ 01623 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01624 return -1; 01625 } 01626 01627 if (sense == FEATURE_SENSE_CHAN) { 01628 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01629 return FEATURE_RETURN_KEEPTRYING; 01630 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01631 work = chan; 01632 idle = peer; 01633 } else { 01634 work = peer; 01635 idle = chan; 01636 } 01637 } else { 01638 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01639 return FEATURE_RETURN_KEEPTRYING; 01640 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01641 work = peer; 01642 idle = chan; 01643 } else { 01644 work = chan; 01645 idle = peer; 01646 } 01647 } 01648 01649 if (!(app = pbx_findapp(feature->app))) { 01650 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01651 return -2; 01652 } 01653 01654 ast_autoservice_start(idle); 01655 01656 if (!ast_strlen_zero(feature->moh_class)) 01657 ast_moh_start(idle, feature->moh_class, NULL); 01658 01659 res = pbx_exec(work, app, feature->app_args); 01660 01661 if (!ast_strlen_zero(feature->moh_class)) 01662 ast_moh_stop(idle); 01663 01664 ast_autoservice_stop(idle); 01665 01666 if (res) { 01667 return FEATURE_RETURN_SUCCESSBREAK; 01668 } 01669 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01670 }
static int feature_interpret_helper | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
char * | dynamic_features_buf, | |||
struct ast_flags * | features, | |||
int | operation, | |||
struct ast_call_feature * | feature | |||
) | [static] |
Helper function for feature_interpret and ast_feature_detect.
chan,peer,config,code,sense,dynamic_features | char buf,feature flags,operation,feature |
res | on success. | |
-1 | on failure. |
Definition at line 1710 of file features.c.
References ast_debug, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_STOREDIGITS, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strlen_zero(), ast_test_flag, ast_verb, builtin_features, chan, config, feature_group_exten::entry, ast_call_feature::exten, feature_group_exten::exten, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), find_group(), ast_call_feature::fname, ast_call_feature::operation, ast_call_feature::sname, and strsep().
Referenced by ast_feature_detect(), and ast_feature_interpret().
01713 { 01714 int x; 01715 struct feature_group *fg = NULL; 01716 struct feature_group_exten *fge; 01717 struct ast_call_feature *tmpfeature; 01718 char *tmp, *tok; 01719 int res = AST_FEATURE_RETURN_PASSDIGITS; 01720 int feature_detected = 0; 01721 01722 if (!(peer && chan && config) && operation) { 01723 return -1; /* can not run feature operation */ 01724 } 01725 01726 ast_rwlock_rdlock(&features_lock); 01727 for (x = 0; x < FEATURES_COUNT; x++) { 01728 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 01729 !ast_strlen_zero(builtin_features[x].exten)) { 01730 /* Feature is up for consideration */ 01731 if (!strcmp(builtin_features[x].exten, code)) { 01732 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 01733 if (operation) { 01734 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01735 } 01736 memcpy(feature, &builtin_features[x], sizeof(feature)); 01737 feature_detected = 1; 01738 break; 01739 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01740 if (res == AST_FEATURE_RETURN_PASSDIGITS) 01741 res = AST_FEATURE_RETURN_STOREDIGITS; 01742 } 01743 } 01744 } 01745 ast_rwlock_unlock(&features_lock); 01746 01747 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 01748 return res; 01749 } 01750 01751 tmp = dynamic_features_buf; 01752 01753 while ((tok = strsep(&tmp, "#"))) { 01754 AST_RWLIST_RDLOCK(&feature_groups); 01755 01756 fg = find_group(tok); 01757 01758 if (fg) { 01759 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 01760 if (strcasecmp(fge->exten, code)) 01761 continue; 01762 if (operation) { 01763 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 01764 } 01765 memcpy(feature, fge->feature, sizeof(feature)); 01766 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 01767 AST_RWLIST_UNLOCK(&feature_groups); 01768 break; 01769 } 01770 res = AST_FEATURE_RETURN_PASSDIGITS; 01771 } 01772 if (fge) 01773 break; 01774 } 01775 01776 AST_RWLIST_UNLOCK(&feature_groups); 01777 01778 AST_RWLIST_RDLOCK(&feature_list); 01779 01780 if (!(tmpfeature = find_dynamic_feature(tok))) { 01781 AST_RWLIST_UNLOCK(&feature_list); 01782 continue; 01783 } 01784 01785 /* Feature is up for consideration */ 01786 if (!strcmp(tmpfeature->exten, code)) { 01787 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 01788 if (operation) { 01789 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 01790 } 01791 memcpy(feature, tmpfeature, sizeof(feature)); 01792 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 01793 AST_RWLIST_UNLOCK(&feature_list); 01794 break; 01795 } 01796 res = AST_FEATURE_RETURN_PASSDIGITS; 01797 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 01798 res = AST_FEATURE_RETURN_STOREDIGITS; 01799 01800 AST_RWLIST_UNLOCK(&feature_list); 01801 } 01802 01803 return res; 01804 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a call feature by name
Definition at line 1538 of file features.c.
References AST_RWLIST_TRAVERSE, and ast_call_feature::sname.
Referenced by feature_interpret_helper(), and set_config_flags().
01539 { 01540 struct ast_call_feature *tmp; 01541 01542 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01543 if (!strcasecmp(tmp->sname, name)) { 01544 break; 01545 } 01546 } 01547 01548 return tmp; 01549 }
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 1576 of file features.c.
References AST_LIST_TRAVERSE, feature_group_exten::entry, and feature_group::gname.
Referenced by feature_interpret_helper().
01576 { 01577 struct feature_group *fg = NULL; 01578 01579 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 01580 if (!strcasecmp(fg->gname, name)) 01581 break; 01582 } 01583 01584 return fg; 01585 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 948 of file features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, ast_indicate(), and chan.
Referenced by builtin_atxfer(), and builtin_blindtransfer().
00949 { 00950 ast_indicate(chan, AST_CONTROL_UNHOLD); 00951 00952 return ast_autoservice_stop(chan); 00953 }
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 3433 of file features.c.
References ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), builtin_features, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, ast_call_feature::exten, ast_cli_args::fd, FEATURES_COUNT, features_lock, ast_call_feature::fname, HFS_FORMAT, parking_con, parking_ext, parking_start, parking_stop, ast_call_feature::sname, and ast_cli_entry::usage.
03434 { 03435 int i; 03436 struct ast_call_feature *feature; 03437 #define HFS_FORMAT "%-25s %-7s %-7s\n" 03438 03439 switch (cmd) { 03440 03441 case CLI_INIT: 03442 e->command = "features show"; 03443 e->usage = 03444 "Usage: features show\n" 03445 " Lists configured features\n"; 03446 return NULL; 03447 case CLI_GENERATE: 03448 return NULL; 03449 } 03450 03451 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 03452 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 03453 03454 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 03455 03456 ast_rwlock_rdlock(&features_lock); 03457 for (i = 0; i < FEATURES_COUNT; i++) 03458 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 03459 ast_rwlock_unlock(&features_lock); 03460 03461 ast_cli(a->fd, "\n"); 03462 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 03463 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 03464 if (AST_RWLIST_EMPTY(&feature_list)) { 03465 ast_cli(a->fd, "(none)\n"); 03466 } else { 03467 AST_RWLIST_RDLOCK(&feature_list); 03468 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 03469 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 03470 } 03471 AST_RWLIST_UNLOCK(&feature_list); 03472 } 03473 ast_cli(a->fd, "\nCall parking\n"); 03474 ast_cli(a->fd, "------------\n"); 03475 ast_cli(a->fd,"%-20s: %s\n", "Parking extension", parking_ext); 03476 ast_cli(a->fd,"%-20s: %s\n", "Parking context", parking_con); 03477 ast_cli(a->fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 03478 ast_cli(a->fd,"\n"); 03479 03480 return CLI_SUCCESS; 03481 }
static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 3490 of file features.c.
References CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, load_config(), and ast_cli_entry::usage.
03491 { 03492 switch (cmd) { 03493 case CLI_INIT: 03494 e->command = "features reload"; 03495 e->usage = 03496 "Usage: features reload\n" 03497 " Reloads configured call features from features.conf\n"; 03498 return NULL; 03499 case CLI_GENERATE: 03500 return NULL; 03501 } 03502 load_config(); 03503 03504 return CLI_SUCCESS; 03505 }
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 3673 of file features.c.
References 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, parkeduser::list, ast_channel::name, parkeduser::parkingexten, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.
Referenced by handle_parkedcalls_deprecated().
03674 { 03675 struct parkeduser *cur; 03676 int numparked = 0; 03677 03678 switch (cmd) { 03679 case CLI_INIT: 03680 e->command = "parkedcalls show"; 03681 e->usage = 03682 "Usage: parkedcalls show\n" 03683 " List currently parked calls\n"; 03684 return NULL; 03685 case CLI_GENERATE: 03686 return NULL; 03687 } 03688 03689 if (a->argc > e->args) 03690 return CLI_SHOWUSAGE; 03691 03692 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 03693 , "Context", "Extension", "Pri", "Timeout"); 03694 03695 AST_LIST_LOCK(&parkinglot); 03696 AST_LIST_TRAVERSE(&parkinglot, cur, list) { 03697 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 03698 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 03699 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 03700 03701 numparked++; 03702 } 03703 AST_LIST_UNLOCK(&parkinglot); 03704 ast_cli(a->fd, "%d parked call%s.\n", numparked, ESS(numparked)); 03705 03706 03707 return CLI_SUCCESS; 03708 }
static char* handle_parkedcalls_deprecated | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 3710 of file features.c.
References CLI_INIT, ast_cli_entry::command, and handle_parkedcalls().
03711 { 03712 char *res = handle_parkedcalls(e, cmd, a); 03713 if (cmd == CLI_INIT) 03714 e->command = "show parkedcalls"; 03715 return res; 03716 }
static int load_config | ( | void | ) | [static] |
Definition at line 3118 of file features.c.
References adsipark, ast_config_load, ast_copy_string(), ast_log(), AST_MAX_EXTENSION, ast_strlen_zero(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, comebacktoorigin, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_WARNING, parkaddhints, parkedcallhangup, parkedcallrecording, parkedcallreparking, parkedcalltransfers, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkmohclass, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.
Referenced by ast_features_init(), ast_features_reload(), handle_features_reload(), handle_voicemail_reload(), load_module(), and reload().
03119 { 03120 int start = 0, end = 0; 03121 int res; 03122 int i; 03123 struct ast_context *con = NULL; 03124 struct ast_config *cfg = NULL; 03125 struct ast_variable *var = NULL; 03126 struct feature_group *fg = NULL; 03127 struct ast_flags config_flags = { 0 }; 03128 char old_parking_ext[AST_MAX_EXTENSION]; 03129 char old_parking_con[AST_MAX_EXTENSION] = ""; 03130 char *ctg; 03131 static const char *categories[] = { 03132 /* Categories in features.conf that are not 03133 * to be parsed as group categories 03134 */ 03135 "general", 03136 "featuremap", 03137 "applicationmap" 03138 }; 03139 03140 if (!ast_strlen_zero(parking_con)) { 03141 strcpy(old_parking_ext, parking_ext); 03142 strcpy(old_parking_con, parking_con); 03143 } 03144 03145 /* Reset to defaults */ 03146 strcpy(parking_con, "parkedcalls"); 03147 strcpy(parking_con_dial, "park-dial"); 03148 strcpy(parking_ext, "700"); 03149 strcpy(pickup_ext, "*8"); 03150 strcpy(parkmohclass, "default"); 03151 courtesytone[0] = '\0'; 03152 strcpy(xfersound, "beep"); 03153 strcpy(xferfailsound, "pbx-invalid"); 03154 parking_start = 701; 03155 parking_stop = 750; 03156 parkfindnext = 0; 03157 adsipark = 0; 03158 comebacktoorigin = 1; 03159 parkaddhints = 0; 03160 parkedcalltransfers = 0; 03161 parkedcallreparking = 0; 03162 parkedcallrecording = 0; 03163 parkedcallhangup = 0; 03164 03165 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03166 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03167 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03168 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 03169 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 03170 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 03171 03172 cfg = ast_config_load("features.conf", config_flags); 03173 if (!cfg) { 03174 ast_log(LOG_WARNING,"Could not load features.conf\n"); 03175 return 0; 03176 } 03177 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 03178 if (!strcasecmp(var->name, "parkext")) { 03179 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 03180 } else if (!strcasecmp(var->name, "context")) { 03181 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 03182 } else if (!strcasecmp(var->name, "parkingtime")) { 03183 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 03184 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 03185 parkingtime = DEFAULT_PARK_TIME; 03186 } else 03187 parkingtime = parkingtime * 1000; 03188 } else if (!strcasecmp(var->name, "parkpos")) { 03189 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 03190 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); 03191 } else { 03192 parking_start = start; 03193 parking_stop = end; 03194 } 03195 } else if (!strcasecmp(var->name, "findslot")) { 03196 parkfindnext = (!strcasecmp(var->value, "next")); 03197 } else if (!strcasecmp(var->name, "parkinghints")) { 03198 parkaddhints = ast_true(var->value); 03199 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 03200 if (!strcasecmp(var->value, "both")) 03201 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 03202 else if (!strcasecmp(var->value, "caller")) 03203 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 03204 else if (!strcasecmp(var->value, "callee")) 03205 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 03206 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 03207 if (!strcasecmp(var->value, "both")) 03208 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 03209 else if (!strcasecmp(var->value, "caller")) 03210 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 03211 else if (!strcasecmp(var->value, "callee")) 03212 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 03213 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 03214 if (!strcasecmp(var->value, "both")) 03215 parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 03216 else if (!strcasecmp(var->value, "caller")) 03217 parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 03218 else if (!strcasecmp(var->value, "callee")) 03219 parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 03220 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 03221 if (!strcasecmp(var->value, "both")) 03222 parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 03223 else if (!strcasecmp(var->value, "caller")) 03224 parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 03225 else if (!strcasecmp(var->value, "callee")) 03226 parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 03227 } else if (!strcasecmp(var->name, "adsipark")) { 03228 adsipark = ast_true(var->value); 03229 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03230 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03231 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03232 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03233 } else 03234 transferdigittimeout = transferdigittimeout * 1000; 03235 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03236 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03237 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03238 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03239 } 03240 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03241 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03242 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03243 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03244 } else 03245 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03246 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 03247 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) { 03248 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 03249 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 03250 } else 03251 atxferloopdelay *= 1000; 03252 } else if (!strcasecmp(var->name, "atxferdropcall")) { 03253 atxferdropcall = ast_true(var->value); 03254 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 03255 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) { 03256 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 03257 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 03258 } 03259 } else if (!strcasecmp(var->name, "courtesytone")) { 03260 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03261 } else if (!strcasecmp(var->name, "parkedplay")) { 03262 if (!strcasecmp(var->value, "both")) 03263 parkedplay = 2; 03264 else if (!strcasecmp(var->value, "parked")) 03265 parkedplay = 1; 03266 else 03267 parkedplay = 0; 03268 } else if (!strcasecmp(var->name, "xfersound")) { 03269 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03270 } else if (!strcasecmp(var->name, "xferfailsound")) { 03271 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03272 } else if (!strcasecmp(var->name, "pickupexten")) { 03273 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03274 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 03275 comebacktoorigin = ast_true(var->value); 03276 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03277 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 03278 } 03279 } 03280 03281 unmap_features(); 03282 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03283 if (remap_feature(var->name, var->value)) 03284 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03285 } 03286 03287 /* Map a key combination to an application*/ 03288 ast_unregister_features(); 03289 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03290 char *tmp_val = ast_strdupa(var->value); 03291 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 03292 struct ast_call_feature *feature; 03293 03294 /* strsep() sets the argument to NULL if match not found, and it 03295 * is safe to use it with a NULL argument, so we don't check 03296 * between calls. 03297 */ 03298 exten = strsep(&tmp_val,","); 03299 activatedby = strsep(&tmp_val,","); 03300 app = strsep(&tmp_val,","); 03301 app_args = strsep(&tmp_val,","); 03302 moh_class = strsep(&tmp_val,","); 03303 03304 activateon = strsep(&activatedby, "/"); 03305 03306 /*! \todo XXX var_name or app_args ? */ 03307 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03308 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03309 app, exten, activateon, var->name); 03310 continue; 03311 } 03312 03313 AST_RWLIST_RDLOCK(&feature_list); 03314 if ((feature = find_dynamic_feature(var->name))) { 03315 AST_RWLIST_UNLOCK(&feature_list); 03316 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03317 continue; 03318 } 03319 AST_RWLIST_UNLOCK(&feature_list); 03320 03321 if (!(feature = ast_calloc(1, sizeof(*feature)))) 03322 continue; 03323 03324 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03325 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 03326 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 03327 03328 if (app_args) 03329 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 03330 03331 if (moh_class) 03332 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 03333 03334 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 03335 feature->operation = feature_exec_app; 03336 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03337 03338 /* Allow caller and calle to be specified for backwards compatability */ 03339 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03340 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03341 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03342 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03343 else { 03344 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03345 " must be 'self', or 'peer'\n", var->name); 03346 continue; 03347 } 03348 03349 if (ast_strlen_zero(activatedby)) 03350 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03351 else if (!strcasecmp(activatedby, "caller")) 03352 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03353 else if (!strcasecmp(activatedby, "callee")) 03354 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03355 else if (!strcasecmp(activatedby, "both")) 03356 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03357 else { 03358 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03359 " must be 'caller', or 'callee', or 'both'\n", var->name); 03360 continue; 03361 } 03362 03363 ast_register_feature(feature); 03364 03365 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 03366 } 03367 03368 ast_unregister_groups(); 03369 AST_RWLIST_WRLOCK(&feature_groups); 03370 03371 ctg = NULL; 03372 while ((ctg = ast_category_browse(cfg, ctg))) { 03373 for (i = 0; i < ARRAY_LEN(categories); i++) { 03374 if (!strcasecmp(categories[i], ctg)) 03375 break; 03376 } 03377 03378 if (i < ARRAY_LEN(categories)) 03379 continue; 03380 03381 if (!(fg = register_group(ctg))) 03382 continue; 03383 03384 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 03385 struct ast_call_feature *feature; 03386 03387 AST_RWLIST_RDLOCK(&feature_list); 03388 if (!(feature = find_dynamic_feature(var->name)) && 03389 !(feature = ast_find_call_feature(var->name))) { 03390 AST_RWLIST_UNLOCK(&feature_list); 03391 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 03392 continue; 03393 } 03394 AST_RWLIST_UNLOCK(&feature_list); 03395 03396 register_group_feature(fg, var->value, feature); 03397 } 03398 } 03399 03400 AST_RWLIST_UNLOCK(&feature_groups); 03401 03402 ast_config_destroy(cfg); 03403 03404 /* Remove the old parking extension */ 03405 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03406 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0)) 03407 notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE); 03408 ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03409 } 03410 03411 if (!(con = ast_context_find_or_create(NULL, NULL, parking_con, registrar))) { 03412 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 03413 return -1; 03414 } 03415 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 03416 if (parkaddhints) 03417 park_add_hints(parking_con, parking_start, parking_stop); 03418 if (!res) 03419 notify_metermaids(ast_parking_ext(), parking_con, AST_DEVICE_INUSE); 03420 return res; 03421 03422 }
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 3789 of file features.c.
References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), buf, and s.
Referenced by ast_features_init().
03790 { 03791 const char *channel = astman_get_header(m, "Channel"); 03792 const char *channel2 = astman_get_header(m, "Channel2"); 03793 const char *timeout = astman_get_header(m, "Timeout"); 03794 char buf[BUFSIZ]; 03795 int to = 0; 03796 int res = 0; 03797 int parkExt = 0; 03798 struct ast_channel *ch1, *ch2; 03799 03800 if (ast_strlen_zero(channel)) { 03801 astman_send_error(s, m, "Channel not specified"); 03802 return 0; 03803 } 03804 03805 if (ast_strlen_zero(channel2)) { 03806 astman_send_error(s, m, "Channel2 not specified"); 03807 return 0; 03808 } 03809 03810 ch1 = ast_get_channel_by_name_locked(channel); 03811 if (!ch1) { 03812 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 03813 astman_send_error(s, m, buf); 03814 return 0; 03815 } 03816 03817 ch2 = ast_get_channel_by_name_locked(channel2); 03818 if (!ch2) { 03819 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 03820 astman_send_error(s, m, buf); 03821 ast_channel_unlock(ch1); 03822 return 0; 03823 } 03824 03825 if (!ast_strlen_zero(timeout)) { 03826 sscanf(timeout, "%d", &to); 03827 } 03828 03829 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 03830 if (!res) { 03831 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 03832 astman_send_ack(s, m, "Park successful"); 03833 } else { 03834 astman_send_error(s, m, "Park failure"); 03835 } 03836 03837 ast_channel_unlock(ch1); 03838 ast_channel_unlock(ch2); 03839 03840 return 0; 03841 }
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 3734 of file features.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::list, ast_channel::name, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.
Referenced by ast_features_init().
03735 { 03736 struct parkeduser *cur; 03737 const char *id = astman_get_header(m, "ActionID"); 03738 char idText[256] = ""; 03739 03740 if (!ast_strlen_zero(id)) 03741 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 03742 03743 astman_send_ack(s, m, "Parked calls will follow"); 03744 03745 AST_LIST_LOCK(&parkinglot); 03746 03747 AST_LIST_TRAVERSE(&parkinglot, cur, list) { 03748 astman_append(s, "Event: ParkedCall\r\n" 03749 "Exten: %d\r\n" 03750 "Channel: %s\r\n" 03751 "From: %s\r\n" 03752 "Timeout: %ld\r\n" 03753 "CallerIDNum: %s\r\n" 03754 "CallerIDName: %s\r\n" 03755 "%s" 03756 "\r\n", 03757 cur->parkingnum, cur->chan->name, cur->peername, 03758 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 03759 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 03760 S_OR(cur->chan->cid.cid_name, ""), 03761 idText); 03762 } 03763 03764 astman_append(s, 03765 "Event: ParkedCallsComplete\r\n" 03766 "%s" 03767 "\r\n",idText); 03768 03769 AST_LIST_UNLOCK(&parkinglot); 03770 03771 return RESULT_SUCCESS; 03772 }
static int masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
int | play_announcement, | |||
const char * | orig_chan_name | |||
) | [static] |
Definition at line 616 of file features.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc, ast_channel_masquerade(), ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), chan, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_PARKFAILED, LOG_WARNING, 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(), and masq_park_call_announce().
00617 { 00618 struct ast_channel *chan; 00619 struct ast_frame *f; 00620 struct parkeduser *pu; 00621 int park_status; 00622 00623 if ((pu = park_space_reserve(rchan)) == NULL) { 00624 if (peer) 00625 ast_stream_and_wait(peer, "beeperr", ""); 00626 return FEATURE_RETURN_PARKFAILED; 00627 } 00628 00629 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00630 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00631 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00632 return -1; 00633 } 00634 00635 /* Make formats okay */ 00636 chan->readformat = rchan->readformat; 00637 chan->writeformat = rchan->writeformat; 00638 ast_channel_masquerade(chan, rchan); 00639 00640 /* Setup the extensions and such */ 00641 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00642 00643 /* Make the masq execute */ 00644 if ((f = ast_read(chan))) 00645 ast_frfree(f); 00646 00647 if (peer == rchan) { 00648 peer = chan; 00649 } 00650 00651 if (!play_announcement && !orig_chan_name) { 00652 orig_chan_name = ast_strdupa(chan->name); 00653 } 00654 00655 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu); 00656 if (park_status == 1) { 00657 /* would be nice to play "invalid parking extension" */ 00658 ast_hangup(chan); 00659 return -1; 00660 } 00661 return 0; 00662 }
static int masq_park_call_announce | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
const char * | orig_chan_name | |||
) | [static] |
Definition at line 670 of file features.c.
References masq_park_call().
Referenced by builtin_blindtransfer(), builtin_parkcall(), and park_call_exec().
00671 { 00672 return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name); 00673 }
static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 401 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().
00402 { 00403 char *context; 00404 char *exten; 00405 00406 context = ast_strdupa(data); 00407 00408 exten = strsep(&context, "@"); 00409 if (!context) 00410 return AST_DEVICE_INVALID; 00411 00412 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 00413 00414 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 00415 return AST_DEVICE_NOT_INUSE; 00416 00417 return AST_DEVICE_INUSE; 00418 }
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 392 of file features.c.
References ast_debug, ast_devstate_changed(), and devstate2str().
Referenced by do_parking_thread(), park_call_full(), and park_exec().
00393 { 00394 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 00395 exten, context, devstate2str(state)); 00396 00397 ast_devstate_changed(state, "park:%s@%s", exten, context); 00398 }
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 3105 of file features.c.
References ast_add_extension(), AST_MAX_EXTENSION, PRIORITY_HINT, and registrar.
03106 { 03107 int numext; 03108 char device[AST_MAX_EXTENSION]; 03109 char exten[10]; 03110 03111 for (numext = start; numext <= stop; numext++) { 03112 snprintf(exten, sizeof(exten), "%d", numext); 03113 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 03114 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 03115 } 03116 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 2909 of file features.c.
References ast_channel::_state, ast_answer(), ast_copy_string(), AST_MAX_EXTENSION, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, chan, ast_channel::exten, masq_park_call_announce(), ast_channel::name, orig_exten(), and ast_channel::priority.
Referenced by ast_features_init().
02910 { 02911 char *orig_chan_name = ast_strdupa(chan->name); 02912 char orig_exten[AST_MAX_EXTENSION]; 02913 int orig_priority = chan->priority; 02914 02915 /* Data is unused at the moment but could contain a parking 02916 lot context eventually */ 02917 int res = 0; 02918 02919 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 02920 02921 /* Setup the exten/priority to be s/1 since we don't know 02922 where this call should return */ 02923 strcpy(chan->exten, "s"); 02924 chan->priority = 1; 02925 /* Answer if call is not up */ 02926 if (chan->_state != AST_STATE_UP) 02927 res = ast_answer(chan); 02928 /* Sleep to allow VoIP streams to settle down */ 02929 if (!res) 02930 res = ast_safe_sleep(chan, 1000); 02931 /* Park the call */ 02932 if (!res) { 02933 res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name); 02934 /* Continue on in the dialplan */ 02935 if (res == 1) { 02936 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 02937 chan->priority = orig_priority; 02938 res = 0; 02939 } else if (!res) { 02940 res = 1; 02941 } 02942 } 02943 02944 return res; 02945 }
static int park_call_full | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
const char * | orig_chan_name, | |||
struct parkeduser * | pu | |||
) | [static] |
Definition at line 489 of file features.c.
References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available, ast_adsi_unload_session, ast_bridged_channel(), AST_CHANNEL_NAME, ast_channel_unlock, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HOLD, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_get_channel_by_name_locked(), ast_indicate_data(), ast_log(), ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_tvnow(), ast_verb, parkeduser::chan, chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, park_space_reserve(), parkedcall, parking_con, parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, parkmohclass, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, registrar, S_OR, parkeduser::start, ast_channel::tech, ast_channel_tech::type, and ast_channel::uniqueid.
Referenced by ast_park_call(), and masq_park_call().
00490 { 00491 struct ast_context *con; 00492 const char *event_from; 00493 00494 /* Get a valid space if not already done */ 00495 if (pu == NULL) 00496 pu = park_space_reserve(chan); 00497 if (pu == NULL) 00498 return 1; /* Continue execution if possible */ 00499 00500 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum); 00501 00502 chan->appl = "Parked Call"; 00503 chan->data = NULL; 00504 00505 pu->chan = chan; 00506 00507 /* Put the parked channel on hold if we have two different channels */ 00508 if (chan != peer) { 00509 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00510 S_OR(parkmohclass, NULL), 00511 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00512 } 00513 00514 pu->start = ast_tvnow(); 00515 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00516 if (extout) 00517 *extout = pu->parkingnum; 00518 00519 if (peer) { 00520 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels 00521 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking 00522 and we need the callback name to be that of transferer. Since local,1/2 have the same 00523 name we can be tricky and just grab the bridged channel from the other side of the local 00524 */ 00525 if (!strcasecmp(peer->tech->type, "Local")) { 00526 struct ast_channel *tmpchan, *base_peer; 00527 char other_side[AST_CHANNEL_NAME]; 00528 char *c; 00529 ast_copy_string(other_side, S_OR(orig_chan_name, peer->name), sizeof(other_side)); 00530 if ((c = strrchr(other_side, ';'))) { 00531 *++c = '1'; 00532 } 00533 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) { 00534 if ((base_peer = ast_bridged_channel(tmpchan))) { 00535 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 00536 } 00537 ast_channel_unlock(tmpchan); 00538 } 00539 } else { 00540 ast_copy_string(pu->peername, S_OR(orig_chan_name, peer->name), sizeof(pu->peername)); 00541 } 00542 } 00543 00544 /* Remember what had been dialed, so that if the parking 00545 expires, we try to come back to the same place */ 00546 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00547 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00548 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00549 00550 /* If parking a channel directly, don't quiet yet get parking running on it. 00551 * All parking lot entries are put into the parking lot with notquiteyet on. */ 00552 if (peer != chan) 00553 pu->notquiteyet = 0; 00554 00555 /* Wake up the (presumably select()ing) thread */ 00556 pthread_kill(parking_thread, SIGURG); 00557 ast_verb(2, "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); 00558 00559 if (peer) { 00560 event_from = peer->name; 00561 } else { 00562 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 00563 } 00564 00565 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00566 "Exten: %s\r\n" 00567 "Channel: %s\r\n" 00568 "From: %s\r\n" 00569 "Timeout: %ld\r\n" 00570 "CallerIDNum: %s\r\n" 00571 "CallerIDName: %s\r\n" 00572 "Uniqueid: %s\r\n", 00573 pu->parkingexten, pu->chan->name, event_from ? event_from : "", 00574 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00575 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00576 S_OR(pu->chan->cid.cid_name, "<unknown>"), 00577 pu->chan->uniqueid 00578 ); 00579 00580 if (peer && adsipark && ast_adsi_available(peer)) { 00581 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00582 ast_adsi_unload_session(peer); 00583 } 00584 00585 con = ast_context_find_or_create(NULL, NULL, parking_con, registrar); 00586 if (!con) /* Still no context? Bad */ 00587 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00588 if (con) { 00589 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar)) 00590 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_INUSE); 00591 } 00592 /* Tell the peer channel the number of the parking space */ 00593 if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) { /* Only say number if it's a number and the channel hasn't been masqueraded away */ 00594 /* 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. */ 00595 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00596 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00597 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00598 } 00599 if (pu->notquiteyet) { 00600 /* Wake up parking thread if we're really done */ 00601 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00602 S_OR(parkmohclass, NULL), 00603 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00604 pu->notquiteyet = 0; 00605 pthread_kill(parking_thread, SIGURG); 00606 } 00607 return 0; 00608 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Pickup parked call.
Definition at line 2948 of file features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, ast_copy_flags, AST_DEVICE_NOT_INUSE, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_free, ast_hangup(), ast_indicate(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), chan, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, ast_datastore::data, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_callee, ast_dial_features::features_caller, ast_dial_features::is_caller, LOG_WARNING, manager_event, ast_channel::name, notify_metermaids(), parkedcallhangup, parkedcallrecording, parkedcallreparking, parkedcalltransfers, parkedplay, parking_con, parkeduser::parkingexten, parkeduser::parkingnum, pbx_builtin_setvar_helper(), and S_OR.
Referenced by ast_features_init().
02949 { 02950 int res = 0; 02951 struct ast_channel *peer=NULL; 02952 struct parkeduser *pu; 02953 struct ast_context *con; 02954 int park = 0; 02955 struct ast_bridge_config config; 02956 02957 if (data) 02958 park = atoi((char *)data); 02959 02960 AST_LIST_LOCK(&parkinglot); 02961 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) { 02962 if (!data || pu->parkingnum == park) { 02963 AST_LIST_REMOVE_CURRENT(list); 02964 break; 02965 } 02966 } 02967 AST_LIST_TRAVERSE_SAFE_END 02968 AST_LIST_UNLOCK(&parkinglot); 02969 02970 if (pu) { 02971 peer = pu->chan; 02972 con = ast_context_find(parking_con); 02973 if (con) { 02974 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 02975 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02976 else 02977 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE); 02978 } else 02979 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02980 02981 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 02982 "Exten: %s\r\n" 02983 "Channel: %s\r\n" 02984 "From: %s\r\n" 02985 "CallerIDNum: %s\r\n" 02986 "CallerIDName: %s\r\n", 02987 pu->parkingexten, pu->chan->name, chan->name, 02988 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02989 S_OR(pu->chan->cid.cid_name, "<unknown>") 02990 ); 02991 02992 ast_free(pu); 02993 } 02994 /* JK02: it helps to answer the channel if not already up */ 02995 if (chan->_state != AST_STATE_UP) 02996 ast_answer(chan); 02997 02998 if (peer) { 02999 struct ast_datastore *features_datastore; 03000 struct ast_dial_features *dialfeatures = NULL; 03001 03002 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 03003 03004 if (!ast_strlen_zero(courtesytone)) { 03005 int error = 0; 03006 ast_indicate(peer, AST_CONTROL_UNHOLD); 03007 if (parkedplay == 0) { 03008 error = ast_stream_and_wait(chan, courtesytone, ""); 03009 } else if (parkedplay == 1) { 03010 error = ast_stream_and_wait(peer, courtesytone, ""); 03011 } else if (parkedplay == 2) { 03012 if (!ast_streamfile(chan, courtesytone, chan->language) && 03013 !ast_streamfile(peer, courtesytone, chan->language)) { 03014 /*! \todo XXX we would like to wait on both! */ 03015 res = ast_waitstream(chan, ""); 03016 if (res >= 0) 03017 res = ast_waitstream(peer, ""); 03018 if (res < 0) 03019 error = 1; 03020 } 03021 } 03022 if (error) { 03023 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 03024 ast_hangup(peer); 03025 return -1; 03026 } 03027 } else 03028 ast_indicate(peer, AST_CONTROL_UNHOLD); 03029 03030 res = ast_channel_make_compatible(chan, peer); 03031 if (res < 0) { 03032 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 03033 ast_hangup(peer); 03034 return -1; 03035 } 03036 /* This runs sorta backwards, since we give the incoming channel control, as if it 03037 were the person called. */ 03038 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park); 03039 03040 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03041 ast_cdr_setdestchan(chan->cdr, peer->name); 03042 memset(&config, 0, sizeof(struct ast_bridge_config)); 03043 03044 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 03045 ast_channel_lock(peer); 03046 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 03047 dialfeatures = features_datastore->data; 03048 } 03049 ast_channel_unlock(peer); 03050 03051 if (dialfeatures) { 03052 ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL); 03053 } 03054 03055 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03056 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 03057 } 03058 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03059 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 03060 } 03061 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03062 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 03063 } 03064 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03065 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 03066 } 03067 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03068 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 03069 } 03070 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03071 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 03072 } 03073 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03074 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 03075 } 03076 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03077 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 03078 } 03079 03080 res = ast_bridge_call(chan, peer, &config); 03081 03082 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03083 ast_cdr_setdestchan(chan->cdr, peer->name); 03084 03085 /* Simulate the PBX hanging up */ 03086 ast_hangup(peer); 03087 return -1; 03088 } else { 03089 /*! \todo XXX Play a message XXX */ 03090 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) 03091 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 03092 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 03093 res = -1; 03094 } 03095 03096 return -1; 03097 }
static struct parkeduser* park_space_reserve | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 420 of file features.c.
References ast_calloc, ast_exists_extension(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), chan, parkeduser::list, LOG_WARNING, parking_con, parkeduser::parkingnum, and pbx_builtin_getvar_helper().
Referenced by masq_park_call(), and park_call_full().
00421 { 00422 struct parkeduser *pu, *cur; 00423 int i, parking_space = -1, parking_range; 00424 const char *parkingexten; 00425 00426 /* Allocate memory for parking data */ 00427 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00428 return NULL; 00429 00430 /* Lock parking lot */ 00431 AST_LIST_LOCK(&parkinglot); 00432 /* Check for channel variable PARKINGEXTEN */ 00433 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00434 if (!ast_strlen_zero(parkingexten)) { 00435 /*!\note The API forces us to specify a numeric parking slot, even 00436 * though the architecture would tend to support non-numeric extensions 00437 * (as are possible with SIP, for example). Hence, we enforce that 00438 * limitation here. If extout was not numeric, we could permit 00439 * arbitrary non-numeric extensions. 00440 */ 00441 if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) { 00442 AST_LIST_UNLOCK(&parkinglot); 00443 ast_free(pu); 00444 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); 00445 return NULL; 00446 } 00447 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00448 00449 if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) { 00450 AST_LIST_UNLOCK(&parkinglot); 00451 ast_free(pu); 00452 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00453 return NULL; 00454 } 00455 } else { 00456 /* Select parking space within range */ 00457 parking_range = parking_stop - parking_start+1; 00458 for (i = 0; i < parking_range; i++) { 00459 parking_space = (i + parking_offset) % parking_range + parking_start; 00460 AST_LIST_TRAVERSE(&parkinglot, cur, list) { 00461 if (cur->parkingnum == parking_space) 00462 break; 00463 } 00464 if (!cur) 00465 break; 00466 } 00467 00468 if (!(i < parking_range)) { 00469 ast_log(LOG_WARNING, "No more parking spaces\n"); 00470 ast_free(pu); 00471 AST_LIST_UNLOCK(&parkinglot); 00472 return NULL; 00473 } 00474 /* Set pointer for next parking */ 00475 if (parkfindnext) 00476 parking_offset = parking_space - parking_start + 1; 00477 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00478 } 00479 00480 pu->notquiteyet = 1; 00481 pu->parkingnum = parking_space; 00482 AST_LIST_INSERT_TAIL(&parkinglot, pu, list); 00483 AST_LIST_UNLOCK(&parkinglot); 00484 00485 return pu; 00486 }
return the first unlocked cdr in a possible chain
Definition at line 2073 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
02074 { 02075 struct ast_cdr *cdr_orig = cdr; 02076 while (cdr) { 02077 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 02078 return cdr; 02079 cdr = cdr->next; 02080 } 02081 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 02082 }
static void post_manager_event | ( | const char * | s, | |
struct parkeduser * | pu | |||
) | [static] |
Output parking event to manager.
Definition at line 2662 of file features.c.
References parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event, ast_channel::name, parkeduser::parkingexten, and S_OR.
Referenced by do_parking_thread().
02663 { 02664 manager_event(EVENT_FLAG_CALL, s, 02665 "Exten: %s\r\n" 02666 "Channel: %s\r\n" 02667 "CallerIDNum: %s\r\n" 02668 "CallerIDName: %s\r\n\r\n", 02669 pu->parkingexten, 02670 pu->chan->name, 02671 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02672 S_OR(pu->chan->cid.cid_name, "<unknown>") 02673 ); 02674 }
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 963 of file features.c.
References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, pbx_builtin_getvar_helper(), and s.
Referenced by builtin_atxfer(), and builtin_blindtransfer().
00964 { 00965 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00966 if (ast_strlen_zero(s)) { 00967 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00968 } 00969 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 00970 s = transferer->macrocontext; 00971 } 00972 if (ast_strlen_zero(s)) { 00973 s = transferer->context; 00974 } 00975 return s; 00976 }
static struct feature_group* register_group | ( | const char * | fgname | ) | [static] |
Add new feature group.
fgname | feature group name. |
Definition at line 1445 of file features.c.
References ast_calloc, ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_init, ast_string_field_set, ast_verb, feature_group_exten::entry, and LOG_NOTICE.
01446 { 01447 struct feature_group *fg; 01448 01449 if (!fgname) { 01450 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 01451 return NULL; 01452 } 01453 01454 if (!(fg = ast_calloc(1, sizeof(*fg)))) 01455 return NULL; 01456 01457 if (ast_string_field_init(fg, 128)) { 01458 ast_free(fg); 01459 return NULL; 01460 } 01461 01462 ast_string_field_set(fg, gname, fgname); 01463 01464 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 01465 01466 ast_verb(2, "Registered group '%s'\n", fg->gname); 01467 01468 return fg; 01469 }
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 1480 of file features.c.
References ast_calloc, ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_init, ast_string_field_set, ast_verb, feature_group_exten::entry, ast_call_feature::exten, feature_group_exten::feature, feature_group::features, feature_group::gname, LOG_NOTICE, S_OR, and ast_call_feature::sname.
01481 { 01482 struct feature_group_exten *fge; 01483 01484 if (!fg) { 01485 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 01486 return; 01487 } 01488 01489 if (!feature) { 01490 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 01491 return; 01492 } 01493 01494 if (!(fge = ast_calloc(1, sizeof(*fge)))) 01495 return; 01496 01497 if (ast_string_field_init(fge, 128)) { 01498 ast_free(fge); 01499 return; 01500 } 01501 01502 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 01503 01504 fge->feature = feature; 01505 01506 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 01507 01508 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 01509 feature->sname, fg->gname, exten); 01510 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1682 of file features.c.
References ast_copy_string(), ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, FEATURES_COUNT, and features_lock.
01683 { 01684 int x, res = -1; 01685 01686 ast_rwlock_wrlock(&features_lock); 01687 for (x = 0; x < FEATURES_COUNT; x++) { 01688 if (strcasecmp(builtin_features[x].sname, name)) 01689 continue; 01690 01691 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01692 res = 0; 01693 break; 01694 } 01695 ast_rwlock_unlock(&features_lock); 01696 01697 return res; 01698 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 2084 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().
02085 { 02086 const char *feature; 02087 02088 if (ast_strlen_zero(features)) { 02089 return; 02090 } 02091 02092 for (feature = features; *feature; feature++) { 02093 switch (*feature) { 02094 case 'T' : 02095 case 't' : 02096 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 02097 break; 02098 case 'K' : 02099 case 'k' : 02100 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 02101 break; 02102 case 'H' : 02103 case 'h' : 02104 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 02105 break; 02106 case 'W' : 02107 case 'w' : 02108 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 02109 break; 02110 default : 02111 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 02112 } 02113 } 02114 }
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 250 of file features.c.
References ast_copy_string(), chan, ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by builtin_blindtransfer(), do_parking_thread(), and masq_park_call().
00251 { 00252 ast_copy_string(chan->context, context, sizeof(chan->context)); 00253 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00254 chan->priority = pri; 00255 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 1847 of file features.c.
References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, chan, config, feature_group_exten::feature, ast_call_feature::feature_mask, FEATURES_COUNT, features_lock, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().
Referenced by ast_bridge_call().
01848 { 01849 int x; 01850 01851 ast_clear_flag(config, AST_FLAGS_ALL); 01852 01853 ast_rwlock_rdlock(&features_lock); 01854 for (x = 0; x < FEATURES_COUNT; x++) { 01855 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 01856 continue; 01857 01858 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01859 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01860 01861 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01862 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01863 } 01864 ast_rwlock_unlock(&features_lock); 01865 01866 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01867 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01868 01869 if (dynamic_features) { 01870 char *tmp = ast_strdupa(dynamic_features); 01871 char *tok; 01872 struct ast_call_feature *feature; 01873 01874 /* while we have a feature */ 01875 while ((tok = strsep(&tmp, "#"))) { 01876 AST_RWLIST_RDLOCK(&feature_list); 01877 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01878 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01879 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01880 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01881 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01882 } 01883 AST_RWLIST_UNLOCK(&feature_list); 01884 } 01885 } 01886 } 01887 }
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 681 of file features.c.
References chan, and FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
00683 { 00684 if (sense == FEATURE_SENSE_PEER) { 00685 *caller = peer; 00686 *callee = chan; 00687 } else { 00688 *callee = peer; 00689 *caller = chan; 00690 } 00691 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1672 of file features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, FEATURES_COUNT, and features_lock.
01673 { 01674 int x; 01675 01676 ast_rwlock_wrlock(&features_lock); 01677 for (x = 0; x < FEATURES_COUNT; x++) 01678 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01679 ast_rwlock_unlock(&features_lock); 01680 }
int adsipark [static] |
char* app_bridge = "Bridge" [static] |
Definition at line 3884 of file features.c.
unsigned int atxfercallbackretries [static] |
unsigned int atxferdropcall [static] |
unsigned int atxferloopdelay [static] |
int atxfernoanswertimeout [static] |
char* bridge_descrip [static] |
Definition at line 3886 of file features.c.
struct ast_app_option bridge_exec_options[128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE } } [static] |
char* bridge_synopsis = "Bridge two channels" [static] |
Definition at line 3885 of file features.c.
struct ast_call_feature builtin_features[] [static] |
Definition at line 1410 of file features.c.
Referenced by ast_feature_request_and_dial(), ast_find_call_feature(), feature_interpret_helper(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
struct ast_cli_entry cli_features[] [static] |
Initial value:
{ { .handler = handle_feature_show , .summary = "Lists configured features" ,__VA_ARGS__ }, { .handler = handle_features_reload , .summary = "Reloads configured features" ,__VA_ARGS__ }, { .handler = handle_parkedcalls , .summary = "List currently parked calls" ,__VA_ARGS__ } .deprecate_cmd = &cli_show_parkedcalls_deprecated), }
Definition at line 3720 of file features.c.
Referenced by ast_features_init(), load_module(), and unload_module().
struct ast_cli_entry cli_show_parkedcalls_deprecated = { .handler = handle_parkedcalls_deprecated , .summary = "List currently parked calls." ,__VA_ARGS__ } [static] |
Definition at line 3718 of file features.c.
int comebacktoorigin = 1 [static] |
char courtesytone[256] [static] |
Courtesy tone
Definition at line 120 of file features.c.
Referenced by load_config(), and park_exec().
char* descrip [static] |
Definition at line 144 of file features.c.
Referenced by aji_handle_presence(), ast_features_init(), and load_module().
char* descrip2 [static] |
Initial value:
{ .type = "dial-features", .destroy = dial_features_destroy, .duplicate = dial_features_duplicate, }
Definition at line 218 of file features.c.
Referenced by add_features_datastores(), builtin_atxfer(), do_parking_thread(), and park_exec().
int featuredigittimeout [static] |
ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static] |
Definition at line 1408 of file features.c.
Referenced by ast_feature_request_and_dial(), ast_rdlock_call_features(), ast_unlock_call_features(), feature_interpret_helper(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
char mandescr_bridge[] [static] |
Definition at line 3507 of file features.c.
char mandescr_park[] [static] |
Definition at line 3774 of file features.c.
struct ast_app* mixmonitor_app = NULL [static] |
int mixmonitor_ok = 1 [static] |
Definition at line 170 of file features.c.
struct ast_app* monitor_app = NULL [static] |
Definition at line 166 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 167 of file features.c.
int parkaddhints = 0 [static] |
Add parking hints automatically
Definition at line 106 of file features.c.
Referenced by load_config().
char* parkcall = "Park" [static] |
char* parkedcall = "ParkedCall" [static] |
int parkedcallhangup = 0 [static] |
Enable DTMF based disconnect on bridge when picking up parked calls
Definition at line 109 of file features.c.
Referenced by load_config(), and park_exec().
int parkedcallrecording = 0 [static] |
Enable DTMF based recording on bridge when picking up parked calls
Definition at line 110 of file features.c.
Referenced by load_config(), and park_exec().
int parkedcallreparking = 0 [static] |
Enable DTMF based parking on bridge when picking up parked calls
Definition at line 108 of file features.c.
Referenced by load_config(), and park_exec().
int parkedcalltransfers = 0 [static] |
Enable DTMF based transfers on bridge when picking up parked calls
Definition at line 107 of file features.c.
Referenced by load_config(), and park_exec().
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 121 of file features.c.
Referenced by park_exec().
int parkfindnext [static] |
char parking_con[AST_MAX_EXTENSION] [static] |
Context for which parking is made accessible
Definition at line 112 of file features.c.
Referenced by ast_features_init(), do_parking_thread(), handle_feature_show(), load_config(), park_call_full(), park_exec(), and park_space_reserve().
char parking_con_dial[AST_MAX_EXTENSION] [static] |
Context for dialback for parking (KLUDGE)
Definition at line 113 of file features.c.
Referenced by do_parking_thread(), and load_config().
char parking_ext[AST_MAX_EXTENSION] [static] |
Extension you type to park the call
Definition at line 114 of file features.c.
Referenced by ast_features_init(), ast_parking_ext(), handle_feature_show(), and load_config().
int parking_offset [static] |
Definition at line 125 of file features.c.
int parking_start [static] |
First available extension for parking
Definition at line 117 of file features.c.
Referenced by handle_feature_show(), and load_config().
int parking_stop [static] |
Last available extension for parking
Definition at line 118 of file features.c.
Referenced by handle_feature_show(), and load_config().
pthread_t parking_thread [static] |
int parkingtime = DEFAULT_PARK_TIME [static] |
No more than 45 seconds parked before you do something with them
Definition at line 111 of file features.c.
char parkmohclass[MAX_MUSICCLASS] [static] |
Music class used for parking
Definition at line 116 of file features.c.
Referenced by do_parking_thread(), load_config(), and park_call_full().
char pickup_ext[AST_MAX_EXTENSION] [static] |
Call pickup extension
Definition at line 115 of file features.c.
Referenced by ast_pickup_ext(), and load_config().
char* registrar = "features" [static] |
Registrar for operations
Definition at line 139 of file features.c.
Referenced by do_parking_thread(), park_add_hints(), park_call_full(), pbx_load_module(), and pbx_load_users().
struct ast_app* stopmixmonitor_app = NULL [static] |
int stopmixmonitor_ok = 1 [static] |
Definition at line 173 of file features.c.
char* synopsis = "Answer a parked call" [static] |
char* synopsis2 = "Park yourself" [static] |
int transferdigittimeout [static] |
char xferfailsound[256] [static] |
char xfersound[256] [static] |
Call transfer sound
Definition at line 122 of file features.c.
Referenced by action_bridge(), bridge_exec(), and load_config().