#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"
#include "asterisk/astobj2.h"
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | ast_dial_features |
struct | ast_park_call_args |
struct | ast_parkinglot |
Structure for parking lots which are put in a container. More... | |
struct | ast_parkinglot::parkinglot_parklist |
struct | feature_group |
struct | feature_group_exten |
struct | feature_groups |
struct | feature_list |
struct | parkeduser |
Description of one parked call, added to a list while active, then removed. The list belongs to a parkinglot. More... | |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
#define | DEFAULT_ATXFER_DROP_CALL 0 |
#define | DEFAULT_ATXFER_LOOP_DELAY 10000 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
#define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_PARKINGLOT "default" |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURES_COUNT ARRAY_LEN(builtin_features) |
#define | HFS_FORMAT "%-25s %-7s %-7s\n" |
#define | MAX_DIAL_FEATURE_OPTIONS 30 |
Enumerations | |
enum | { BRIDGE_OPT_PLAYTONE = (1 << 0) } |
enum | ast_park_call_options { AST_PARK_OPT_RINGING = (1 << 0), AST_PARK_OPT_RANDOMIZE = (1 << 1), AST_PARK_OPT_SILENCE = (1 << 2) } |
Functions | |
static int | action_bridge (struct mansession *s, const struct message *m) |
Bridge channels together. | |
static void | add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config) |
static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
Announce call parking by ADSI. | |
int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
Bridge a call, optionally allowing redirection. | |
static void * | ast_bridge_call_thread (void *data) |
bridge the call | |
static void | ast_bridge_call_thread_launch (void *data) |
create thread for the parked call | |
int | ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature) |
detect a feature before bridging | |
static int | ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
Check the dynamic features. | |
static struct ast_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. | |
static int | ast_park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) |
const char * | ast_parking_ext (void) |
Determine system parking extension. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
const char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_rdlock_call_features (void) |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
void | ast_unlock_call_features (void) |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
static void | ast_unregister_features (void) |
Remove all features in the list. | |
static void | ast_unregister_groups (void) |
Remove all feature groups in the list. | |
static int | bridge_exec (struct ast_channel *chan, void *data) |
Bridge channels. | |
static struct ast_parkinglot * | build_parkinglot (char *name, struct ast_variable *var) |
Build parkinglot from configuration and chain it in. | |
static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Attended transfer. | |
static int | builtin_automixmonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Monitor a channel by DTMF. | |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Blind transfer user to another extension. | |
static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
support routing for one touch call parking | |
static char * | callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len) |
static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
make channels compatible | |
static void | check_goto_on_transfer (struct ast_channel *chan) |
Check goto on transfer. | |
static struct ast_parkinglot * | create_parkinglot (char *name) |
Allocate parking lot structure. | |
static void | dial_features_destroy (void *data) |
static void * | dial_features_duplicate (void *data) |
static void | do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan) |
Actual bridge. | |
static void * | do_parking_thread (void *ignore) |
Take care of parked calls and unpark them if needed. | |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
exec an app by feature | |
static int | feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, int operation, struct ast_call_feature *feature) |
Helper function for feature_interpret and ast_feature_detect. | |
static struct ast_call_feature * | find_dynamic_feature (const char *name) |
find a call feature by name | |
static struct feature_group * | find_group (const char *name) |
Find a group by name. | |
ast_parkinglot * | find_parkinglot (const char *name) |
Find parkinglot by name. | |
static const char * | findparkinglotname (struct ast_channel *chan) |
Find parking lot name from channel. | |
static int | finishup (struct ast_channel *chan) |
static char * | handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
CLI command to list configured features. | |
static char * | handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
CLI command to list parked calls. | |
static int | load_config (void) |
int | manage_parkinglot (struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max) |
Run management on parkinglots, called once per parkinglot. | |
static int | manager_park (struct mansession *s, const struct message *m) |
Create manager event for parked calls. | |
static int | manager_parking_status (struct mansession *s, const struct message *m) |
Dump parking lot status. | |
static int | masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args) |
static int | masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
static int | masq_park_call_announce_args (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args) |
static enum ast_device_state | metermaidstate (const char *data) |
metermaids callback from devicestate.c | |
static void | notify_metermaids (const char *exten, char *context, enum ast_device_state state) |
Notify metermaids that we've changed an extension. | |
static void | park_add_hints (char *context, int start, int stop) |
Add parking hints for all defined parking lots. | |
static int | park_call_exec (struct ast_channel *chan, void *data) |
Park a call. | |
static int | park_exec (struct ast_channel *chan, void *data) |
static int | park_exec_full (struct ast_channel *chan, void *data, struct ast_parkinglot *parkinglot) |
Pickup parked call. | |
static struct parkeduser * | park_space_reserve (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) |
static struct ast_parkinglot * | parkinglot_addref (struct ast_parkinglot *parkinglot) |
static int | parkinglot_cmp_cb (void *obj, void *arg, int flags) |
static void | parkinglot_destroy (void *obj) |
Destroy a parking lot. | |
static int | parkinglot_hash_cb (const void *obj, const int flags) |
static void | parkinglot_unref (struct ast_parkinglot *parkinglot) |
Unreference parkinglot object. If no more references, then go ahead and delete it. | |
static struct ast_cdr * | pick_unlocked_cdr (struct ast_cdr *cdr) |
return the first unlocked cdr in a possible chain | |
static int | play_message_in_bridged_call (struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile) |
Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages. | |
static void | post_manager_event (const char *s, struct parkeduser *pu) |
Output parking event to manager. | |
static const char * | real_ctx (struct ast_channel *transferer, struct ast_channel *transferee) |
Find the context for the transfer. | |
static struct feature_group * | register_group (const char *fgname) |
Add new feature group. | |
static void | register_group_feature (struct feature_group *fg, const char *exten, struct ast_call_feature *feature) |
Add feature to group. | |
static int | remap_feature (const char *name, const char *value) |
static void | set_bridge_features_on_config (struct ast_bridge_config *config, const char *features) |
static void | set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri) |
store context, extension and priority | |
static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
static void | set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense) |
set caller and callee according to the direction | |
static void | unmap_features (void) |
Variables | |
static int | adsipark |
static char * | app_bridge = "Bridge" |
static unsigned int | atxfercallbackretries |
static unsigned int | atxferdropcall |
static unsigned int | atxferloopdelay |
static int | atxfernoanswertimeout |
static char * | bridge_descrip |
static struct ast_app_option | bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE } } |
static char * | bridge_synopsis = "Bridge two channels" |
static struct ast_call_feature | builtin_features [] |
static struct ast_cli_entry | cli_features [] |
static int | comebacktoorigin = 1 |
static char | courtesytone [256] |
ast_parkinglot * | default_parkinglot |
static char * | descrip |
static char * | descrip2 |
ast_datastore_info | dial_features_info |
static int | featuredigittimeout |
static ast_rwlock_t | features_lock = PTHREAD_RWLOCK_INITIALIZER |
static char | mandescr_bridge [] |
static char | mandescr_park [] |
static struct ast_app * | mixmonitor_app = NULL |
static int | mixmonitor_ok = 1 |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static struct ast_app_option | park_call_options [128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } |
static char * | parkcall = PARK_APP_NAME |
static char * | parkedcall = "ParkedCall" |
static int | parkedplay = 0 |
char | parking_ext [AST_MAX_EXTENSION] |
static pthread_t | parking_thread |
static struct ao2_container * | parkinglots |
The list of parking lots configured. Always at least one - the default parking lot. | |
static char | pickup_ext [AST_MAX_EXTENSION] |
static char * | 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 68 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 |
#define DEFAULT_PARKINGLOT "default" |
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURES_COUNT ARRAY_LEN(builtin_features) |
Definition at line 1604 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 |
Options to pass to ast_park_call_full
Definition at line 466 of file features.c.
00466 { 00467 /*! Provide ringing to the parked caller instead of music on hold */ 00468 AST_PARK_OPT_RINGING = (1 << 0), 00469 /*! Randomly choose a parking spot for the caller instead of choosing 00470 * the first one that is available. */ 00471 AST_PARK_OPT_RANDOMIZE = (1 << 1), 00472 /*! Do not announce the parking number */ 00473 AST_PARK_OPT_SILENCE = (1 << 2), 00474 };
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 4046 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().
04047 { 04048 const char *channela = astman_get_header(m, "Channel1"); 04049 const char *channelb = astman_get_header(m, "Channel2"); 04050 const char *playtone = astman_get_header(m, "Tone"); 04051 struct ast_channel *chana = NULL, *chanb = NULL; 04052 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 04053 struct ast_bridge_thread_obj *tobj = NULL; 04054 04055 /* make sure valid channels were specified */ 04056 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 04057 astman_send_error(s, m, "Missing channel parameter in request"); 04058 return 0; 04059 } 04060 04061 /* The same code must be executed for chana and chanb. To avoid a 04062 * theoretical deadlock, this code is separated so both chana and chanb will 04063 * not hold locks at the same time. */ 04064 04065 /* Start with chana */ 04066 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela)); 04067 04068 /* send errors if any of the channels could not be found/locked */ 04069 if (!chana) { 04070 char buf[256]; 04071 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 04072 astman_send_error(s, m, buf); 04073 return 0; 04074 } 04075 04076 /* Answer the channels if needed */ 04077 if (chana->_state != AST_STATE_UP) 04078 ast_answer(chana); 04079 04080 /* create the placeholder channels and grab the other channels */ 04081 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04082 NULL, NULL, 0, "Bridge/%s", chana->name))) { 04083 astman_send_error(s, m, "Unable to create temporary channel!"); 04084 ast_channel_unlock(chana); 04085 return 1; 04086 } 04087 04088 do_bridge_masquerade(chana, tmpchana); 04089 ast_channel_unlock(chana); 04090 chana = NULL; 04091 04092 /* now do chanb */ 04093 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb)); 04094 /* send errors if any of the channels could not be found/locked */ 04095 if (!chanb) { 04096 char buf[256]; 04097 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 04098 ast_hangup(tmpchana); 04099 astman_send_error(s, m, buf); 04100 return 0; 04101 } 04102 04103 /* Answer the channels if needed */ 04104 if (chanb->_state != AST_STATE_UP) 04105 ast_answer(chanb); 04106 04107 /* create the placeholder channels and grab the other channels */ 04108 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04109 NULL, NULL, 0, "Bridge/%s", chanb->name))) { 04110 astman_send_error(s, m, "Unable to create temporary channels!"); 04111 ast_hangup(tmpchana); 04112 ast_channel_unlock(chanb); 04113 return 1; 04114 } 04115 do_bridge_masquerade(chanb, tmpchanb); 04116 ast_channel_unlock(chanb); 04117 chanb = NULL; 04118 04119 /* make the channels compatible, send error if we fail doing so */ 04120 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 04121 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 04122 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 04123 ast_hangup(tmpchana); 04124 ast_hangup(tmpchanb); 04125 return 1; 04126 } 04127 04128 /* setup the bridge thread object and start the bridge */ 04129 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 04130 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 04131 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 04132 ast_hangup(tmpchana); 04133 ast_hangup(tmpchanb); 04134 return 1; 04135 } 04136 04137 tobj->chan = tmpchana; 04138 tobj->peer = tmpchanb; 04139 tobj->return_to_pbx = 1; 04140 04141 if (ast_true(playtone)) { 04142 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 04143 if (ast_waitstream(tmpchanb, "") < 0) 04144 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 04145 } 04146 } 04147 04148 ast_bridge_call_thread_launch(tobj); 04149 04150 astman_send_ack(s, m, "Launched bridge thread with success"); 04151 04152 return 0; 04153 }
static void add_features_datastores | ( | struct ast_channel * | caller, | |
struct ast_channel * | callee, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 2310 of file features.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_datastore_alloc(), ast_datastore_free(), AST_FLAGS_ALL, ast_log(), config, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, and LOG_WARNING.
Referenced by ast_bridge_call().
02311 { 02312 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 02313 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 02314 02315 ast_channel_lock(caller); 02316 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 02317 ast_channel_unlock(caller); 02318 if (!ds_caller_features) { 02319 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) { 02320 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 02321 return; 02322 } 02323 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 02324 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02325 ast_datastore_free(ds_caller_features); 02326 return; 02327 } 02328 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 02329 caller_features->is_caller = 1; 02330 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 02331 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 02332 ds_caller_features->data = caller_features; 02333 ast_channel_lock(caller); 02334 ast_channel_datastore_add(caller, ds_caller_features); 02335 ast_channel_unlock(caller); 02336 } else { 02337 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 02338 * flags over from the atxfer to the caller */ 02339 return; 02340 } 02341 02342 ast_channel_lock(callee); 02343 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 02344 ast_channel_unlock(callee); 02345 if (!ds_callee_features) { 02346 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) { 02347 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 02348 return; 02349 } 02350 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 02351 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02352 ast_datastore_free(ds_callee_features); 02353 return; 02354 } 02355 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 02356 callee_features->is_caller = 0; 02357 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 02358 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 02359 ds_callee_features->data = callee_features; 02360 ast_channel_lock(callee); 02361 ast_channel_datastore_add(callee, ds_callee_features); 02362 ast_channel_unlock(callee); 02363 } 02364 02365 return; 02366 }
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 404 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session, ast_adsi_print, chan, and justify.
Referenced by ast_park_call_full().
00405 { 00406 int res; 00407 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00408 char tmp[256]; 00409 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00410 00411 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00412 message[0] = tmp; 00413 res = ast_adsi_load_session(chan, NULL, 0, 1); 00414 if (res == -1) 00415 return res; 00416 return ast_adsi_print(chan, message, justify, 1); 00417 }
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 2377 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_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, config, ast_channel::context, ast_channel::data, ast_option_header::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, 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(), park_exec_full(), and try_calling().
02378 { 02379 /* Copy voice back and forth between the two channels. Give the peer 02380 the ability to transfer calls with '#<extension' syntax. */ 02381 struct ast_frame *f; 02382 struct ast_channel *who; 02383 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02384 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02385 char orig_channame[AST_MAX_EXTENSION]; 02386 char orig_peername[AST_MAX_EXTENSION]; 02387 int res; 02388 int diff; 02389 int hasfeatures=0; 02390 int hadfeatures=0; 02391 int autoloopflag; 02392 struct ast_option_header *aoh; 02393 struct ast_bridge_config backup_config; 02394 struct ast_cdr *bridge_cdr = NULL; 02395 struct ast_cdr *orig_peer_cdr = NULL; 02396 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02397 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02398 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02399 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02400 02401 memset(&backup_config, 0, sizeof(backup_config)); 02402 02403 config->start_time = ast_tvnow(); 02404 02405 if (chan && peer) { 02406 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02407 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02408 } else if (chan) { 02409 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02410 } 02411 02412 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02413 add_features_datastores(chan, peer, config); 02414 02415 /* This is an interesting case. One example is if a ringing channel gets redirected to 02416 * an extension that picks up a parked call. This will make sure that the call taken 02417 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02418 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02419 ast_indicate(peer, AST_CONTROL_RINGING); 02420 } 02421 02422 if (monitor_ok) { 02423 const char *monitor_exec; 02424 struct ast_channel *src = NULL; 02425 if (!monitor_app) { 02426 if (!(monitor_app = pbx_findapp("Monitor"))) 02427 monitor_ok=0; 02428 } 02429 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02430 src = chan; 02431 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02432 src = peer; 02433 if (monitor_app && src) { 02434 char *tmp = ast_strdupa(monitor_exec); 02435 pbx_exec(src, monitor_app, tmp); 02436 } 02437 } 02438 02439 set_config_flags(chan, peer, config); 02440 config->firstpass = 1; 02441 02442 /* Answer if need be */ 02443 if (chan->_state != AST_STATE_UP) { 02444 if (ast_raw_answer(chan, 1)) { 02445 return -1; 02446 } 02447 } 02448 02449 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02450 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02451 orig_peer_cdr = peer_cdr; 02452 02453 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02454 02455 if (chan_cdr) { 02456 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02457 ast_cdr_update(chan); 02458 bridge_cdr = ast_cdr_dup(chan_cdr); 02459 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 02460 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 02461 } else { 02462 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02463 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02464 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02465 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02466 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02467 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 02468 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 02469 ast_cdr_setcid(bridge_cdr, chan); 02470 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02471 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02472 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02473 /* Destination information */ 02474 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02475 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02476 if (peer_cdr) { 02477 bridge_cdr->start = peer_cdr->start; 02478 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02479 } else { 02480 ast_cdr_start(bridge_cdr); 02481 } 02482 } 02483 ast_debug(4,"bridge answer set, chan answer set\n"); 02484 /* peer_cdr->answer will be set when a macro runs on the peer; 02485 in that case, the bridge answer will be delayed while the 02486 macro plays on the peer channel. The peer answered the call 02487 before the macro started playing. To the phone system, 02488 this is billable time for the call, even tho the caller 02489 hears nothing but ringing while the macro does its thing. */ 02490 if (peer_cdr && !ast_tvzero(peer_cdr->answer)) { 02491 bridge_cdr->answer = peer_cdr->answer; 02492 chan_cdr->answer = peer_cdr->answer; 02493 bridge_cdr->disposition = peer_cdr->disposition; 02494 chan_cdr->disposition = peer_cdr->disposition; 02495 } else { 02496 ast_cdr_answer(bridge_cdr); 02497 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02498 } 02499 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02500 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02501 if (peer_cdr) { 02502 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02503 } 02504 } 02505 } 02506 for (;;) { 02507 struct ast_channel *other; /* used later */ 02508 02509 res = ast_channel_bridge(chan, peer, config, &f, &who); 02510 02511 /* When frame is not set, we are probably involved in a situation 02512 where we've timed out. 02513 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02514 and also for DTMF_END. If we flow into the following 'if' for both, then 02515 our wait times are cut in half, as both will subtract from the 02516 feature_timer. Not good! 02517 */ 02518 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02519 /* Update time limit for next pass */ 02520 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02521 if (res == AST_BRIDGE_RETRY) { 02522 /* The feature fully timed out but has not been updated. Skip 02523 * the potential round error from the diff calculation and 02524 * explicitly set to expired. */ 02525 config->feature_timer = -1; 02526 } else { 02527 config->feature_timer -= diff; 02528 } 02529 02530 if (hasfeatures) { 02531 /* Running on backup config, meaning a feature might be being 02532 activated, but that's no excuse to keep things going 02533 indefinitely! */ 02534 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02535 ast_debug(1, "Timed out, realtime this time!\n"); 02536 config->feature_timer = 0; 02537 who = chan; 02538 if (f) 02539 ast_frfree(f); 02540 f = NULL; 02541 res = 0; 02542 } else if (config->feature_timer <= 0) { 02543 /* Not *really* out of time, just out of time for 02544 digits to come in for features. */ 02545 ast_debug(1, "Timed out for feature!\n"); 02546 if (!ast_strlen_zero(peer_featurecode)) { 02547 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02548 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02549 } 02550 if (!ast_strlen_zero(chan_featurecode)) { 02551 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02552 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02553 } 02554 if (f) 02555 ast_frfree(f); 02556 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02557 if (!hasfeatures) { 02558 /* Restore original (possibly time modified) bridge config */ 02559 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02560 memset(&backup_config, 0, sizeof(backup_config)); 02561 } 02562 hadfeatures = hasfeatures; 02563 /* Continue as we were */ 02564 continue; 02565 } else if (!f) { 02566 /* The bridge returned without a frame and there is a feature in progress. 02567 * However, we don't think the feature has quite yet timed out, so just 02568 * go back into the bridge. */ 02569 continue; 02570 } 02571 } else { 02572 if (config->feature_timer <=0) { 02573 /* We ran out of time */ 02574 config->feature_timer = 0; 02575 who = chan; 02576 if (f) 02577 ast_frfree(f); 02578 f = NULL; 02579 res = 0; 02580 } 02581 } 02582 } 02583 if (res < 0) { 02584 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02585 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02586 goto before_you_go; 02587 } 02588 02589 if (!f || (f->frametype == AST_FRAME_CONTROL && 02590 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02591 f->subclass == AST_CONTROL_CONGESTION))) { 02592 res = -1; 02593 break; 02594 } 02595 /* many things should be sent to the 'other' channel */ 02596 other = (who == chan) ? peer : chan; 02597 if (f->frametype == AST_FRAME_CONTROL) { 02598 switch (f->subclass) { 02599 case AST_CONTROL_RINGING: 02600 case AST_CONTROL_FLASH: 02601 case -1: 02602 ast_indicate(other, f->subclass); 02603 break; 02604 case AST_CONTROL_HOLD: 02605 case AST_CONTROL_UNHOLD: 02606 ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); 02607 break; 02608 case AST_CONTROL_OPTION: 02609 aoh = f->data.ptr; 02610 /* Forward option Requests */ 02611 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02612 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02613 f->datalen - sizeof(struct ast_option_header), 0); 02614 } 02615 break; 02616 } 02617 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02618 /* eat it */ 02619 } else if (f->frametype == AST_FRAME_DTMF) { 02620 char *featurecode; 02621 int sense; 02622 02623 hadfeatures = hasfeatures; 02624 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02625 if (who == chan) { 02626 sense = FEATURE_SENSE_CHAN; 02627 featurecode = chan_featurecode; 02628 } else { 02629 sense = FEATURE_SENSE_PEER; 02630 featurecode = peer_featurecode; 02631 } 02632 /*! append the event to featurecode. we rely on the string being zero-filled, and 02633 * not overflowing it. 02634 * \todo XXX how do we guarantee the latter ? 02635 */ 02636 featurecode[strlen(featurecode)] = f->subclass; 02637 /* Get rid of the frame before we start doing "stuff" with the channels */ 02638 ast_frfree(f); 02639 f = NULL; 02640 config->feature_timer = backup_config.feature_timer; 02641 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 02642 switch(res) { 02643 case AST_FEATURE_RETURN_PASSDIGITS: 02644 ast_dtmf_stream(other, who, featurecode, 0, 0); 02645 /* Fall through */ 02646 case AST_FEATURE_RETURN_SUCCESS: 02647 memset(featurecode, 0, sizeof(chan_featurecode)); 02648 break; 02649 } 02650 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 02651 res = 0; 02652 } else 02653 break; 02654 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02655 if (hadfeatures && !hasfeatures) { 02656 /* Restore backup */ 02657 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02658 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02659 } else if (hasfeatures) { 02660 if (!hadfeatures) { 02661 /* Backup configuration */ 02662 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02663 /* Setup temporary config options */ 02664 config->play_warning = 0; 02665 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02666 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02667 config->warning_freq = 0; 02668 config->warning_sound = NULL; 02669 config->end_sound = NULL; 02670 config->start_sound = NULL; 02671 config->firstpass = 0; 02672 } 02673 config->start_time = ast_tvnow(); 02674 config->feature_timer = featuredigittimeout; 02675 ast_debug(1, "Set time limit to %ld\n", config->feature_timer); 02676 } 02677 } 02678 if (f) 02679 ast_frfree(f); 02680 02681 } 02682 before_you_go: 02683 02684 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02685 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02686 if (bridge_cdr) { 02687 ast_cdr_discard(bridge_cdr); 02688 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02689 } 02690 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02691 } 02692 02693 if (config->end_bridge_callback) { 02694 config->end_bridge_callback(config->end_bridge_callback_data); 02695 } 02696 02697 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 02698 * if it were, then chan belongs to a different thread now, and might have been hung up long 02699 * ago. 02700 */ 02701 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02702 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02703 struct ast_cdr *swapper = NULL; 02704 char savelastapp[AST_MAX_EXTENSION]; 02705 char savelastdata[AST_MAX_EXTENSION]; 02706 char save_exten[AST_MAX_EXTENSION]; 02707 int save_prio; 02708 int found = 0; /* set if we find at least one match */ 02709 int spawn_error = 0; 02710 02711 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02712 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02713 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02714 ast_cdr_end(bridge_cdr); 02715 } 02716 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02717 dialplan code operate on it */ 02718 ast_channel_lock(chan); 02719 if (bridge_cdr) { 02720 swapper = chan->cdr; 02721 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02722 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02723 chan->cdr = bridge_cdr; 02724 } 02725 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02726 save_prio = chan->priority; 02727 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02728 chan->priority = 1; 02729 ast_channel_unlock(chan); 02730 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 02731 chan->priority++; 02732 } 02733 if (found && spawn_error) { 02734 /* Something bad happened, or a hangup has been requested. */ 02735 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02736 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02737 } 02738 /* swap it back */ 02739 ast_channel_lock(chan); 02740 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02741 chan->priority = save_prio; 02742 if (bridge_cdr) { 02743 if (chan->cdr == bridge_cdr) { 02744 chan->cdr = swapper; 02745 } else { 02746 bridge_cdr = NULL; 02747 } 02748 } 02749 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02750 ast_channel_unlock(chan); 02751 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02752 if (bridge_cdr) { 02753 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02754 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02755 } 02756 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02757 } 02758 02759 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02760 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02761 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 02762 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02763 02764 /* we can post the bridge CDR at this point */ 02765 if (bridge_cdr) { 02766 ast_cdr_end(bridge_cdr); 02767 ast_cdr_detach(bridge_cdr); 02768 } 02769 02770 /* do a specialized reset on the beginning channel 02771 CDR's, if they still exist, so as not to mess up 02772 issues in future bridges; 02773 02774 Here are the rules of the game: 02775 1. The chan and peer channel pointers will not change 02776 during the life of the bridge. 02777 2. But, in transfers, the channel names will change. 02778 between the time the bridge is started, and the 02779 time the channel ends. 02780 Usually, when a channel changes names, it will 02781 also change CDR pointers. 02782 3. Usually, only one of the two channels (chan or peer) 02783 will change names. 02784 4. Usually, if a channel changes names during a bridge, 02785 it is because of a transfer. Usually, in these situations, 02786 it is normal to see 2 bridges running simultaneously, and 02787 it is not unusual to see the two channels that change 02788 swapped between bridges. 02789 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02790 to attend to; if the chan or peer changed names, 02791 we have the before and after attached CDR's. 02792 */ 02793 02794 if (new_chan_cdr) { 02795 struct ast_channel *chan_ptr = NULL; 02796 02797 if (strcasecmp(orig_channame, chan->name) != 0) { 02798 /* old channel */ 02799 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02800 if (chan_ptr) { 02801 if (!ast_bridged_channel(chan_ptr)) { 02802 struct ast_cdr *cur; 02803 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02804 if (cur == chan_cdr) { 02805 break; 02806 } 02807 } 02808 if (cur) 02809 ast_cdr_specialized_reset(chan_cdr,0); 02810 } 02811 ast_channel_unlock(chan_ptr); 02812 } 02813 /* new channel */ 02814 ast_cdr_specialized_reset(new_chan_cdr,0); 02815 } else { 02816 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02817 } 02818 } 02819 02820 { 02821 struct ast_channel *chan_ptr = NULL; 02822 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02823 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)) 02824 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02825 if (strcasecmp(orig_peername, peer->name) != 0) { 02826 /* old channel */ 02827 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02828 if (chan_ptr) { 02829 if (!ast_bridged_channel(chan_ptr)) { 02830 struct ast_cdr *cur; 02831 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02832 if (cur == peer_cdr) { 02833 break; 02834 } 02835 } 02836 if (cur) 02837 ast_cdr_specialized_reset(peer_cdr,0); 02838 } 02839 ast_channel_unlock(chan_ptr); 02840 } 02841 /* new channel */ 02842 ast_cdr_specialized_reset(new_peer_cdr,0); 02843 } else { 02844 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02845 } 02846 } 02847 02848 return res; 02849 }
static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
data | thread bridge. |
Definition at line 339 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().
00340 { 00341 struct ast_bridge_thread_obj *tobj = data; 00342 int res; 00343 00344 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00345 tobj->chan->data = tobj->peer->name; 00346 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00347 tobj->peer->data = tobj->chan->name; 00348 00349 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00350 00351 if (tobj->return_to_pbx) { 00352 if (!ast_check_hangup(tobj->peer)) { 00353 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 00354 res = ast_pbx_start(tobj->peer); 00355 if (res != AST_PBX_SUCCESS) 00356 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 00357 } else 00358 ast_hangup(tobj->peer); 00359 if (!ast_check_hangup(tobj->chan)) { 00360 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 00361 res = ast_pbx_start(tobj->chan); 00362 if (res != AST_PBX_SUCCESS) 00363 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 00364 } else 00365 ast_hangup(tobj->chan); 00366 } else { 00367 ast_hangup(tobj->chan); 00368 ast_hangup(tobj->peer); 00369 } 00370 00371 ast_free(tobj); 00372 00373 return NULL; 00374 }
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 382 of file features.c.
References ast_bridge_call_thread(), ast_pthread_create, and thread.
Referenced by action_bridge(), and builtin_atxfer().
00383 { 00384 pthread_t thread; 00385 pthread_attr_t attr; 00386 struct sched_param sched; 00387 00388 pthread_attr_init(&attr); 00389 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00390 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00391 pthread_attr_destroy(&attr); 00392 memset(&sched, 0, sizeof(sched)); 00393 pthread_setschedparam(thread, SCHED_RR, &sched); 00394 }
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 2042 of file features.c.
References chan, feature_group_exten::feature, and feature_interpret_helper().
Referenced by detect_disconnect().
02042 { 02043 02044 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 02045 }
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 2013 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().
02013 { 02014 02015 char dynamic_features_buf[128]; 02016 const char *peer_dynamic_features, *chan_dynamic_features; 02017 struct ast_flags features; 02018 struct ast_call_feature feature; 02019 if (sense == FEATURE_SENSE_CHAN) { 02020 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 02021 } 02022 else { 02023 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 02024 } 02025 02026 ast_channel_lock(peer); 02027 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 02028 ast_channel_unlock(peer); 02029 02030 ast_channel_lock(chan); 02031 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 02032 ast_channel_unlock(chan); 02033 02034 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,"")); 02035 02036 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); 02037 02038 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature); 02039 }
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 2100 of file features.c.
References ast_channel::_state, ast_call(), 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_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().
02101 { 02102 int state = 0; 02103 int cause = 0; 02104 int to; 02105 struct ast_channel *chan; 02106 struct ast_channel *monitor_chans[2]; 02107 struct ast_channel *active_channel; 02108 int res = 0, ready = 0; 02109 02110 if ((chan = ast_request(type, format, data, &cause))) { 02111 ast_set_callerid(chan, cid_num, cid_name, cid_num); 02112 ast_string_field_set(chan, language, language); 02113 ast_channel_inherit_variables(caller, chan); 02114 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 02115 02116 if (!ast_call(chan, data, timeout)) { 02117 struct timeval started; 02118 int x, len = 0; 02119 char *disconnect_code = NULL, *dialed_code = NULL; 02120 02121 ast_indicate(caller, AST_CONTROL_RINGING); 02122 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 02123 ast_rwlock_rdlock(&features_lock); 02124 for (x = 0; x < FEATURES_COUNT; x++) { 02125 if (strcasecmp(builtin_features[x].sname, "disconnect")) 02126 continue; 02127 02128 disconnect_code = builtin_features[x].exten; 02129 len = strlen(disconnect_code) + 1; 02130 dialed_code = alloca(len); 02131 memset(dialed_code, 0, len); 02132 break; 02133 } 02134 ast_rwlock_unlock(&features_lock); 02135 x = 0; 02136 started = ast_tvnow(); 02137 to = timeout; 02138 02139 ast_poll_channel_add(caller, chan); 02140 02141 while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) { 02142 struct ast_frame *f = NULL; 02143 02144 monitor_chans[0] = caller; 02145 monitor_chans[1] = chan; 02146 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 02147 02148 /* see if the timeout has been violated */ 02149 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 02150 state = AST_CONTROL_UNHOLD; 02151 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 02152 break; /*doh! timeout*/ 02153 } 02154 02155 if (!active_channel) 02156 continue; 02157 02158 if (chan && (chan == active_channel)){ 02159 f = ast_read(chan); 02160 if (f == NULL) { /*doh! where'd he go?*/ 02161 state = AST_CONTROL_HANGUP; 02162 res = 0; 02163 break; 02164 } 02165 02166 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 02167 if (f->subclass == AST_CONTROL_RINGING) { 02168 state = f->subclass; 02169 ast_verb(3, "%s is ringing\n", chan->name); 02170 ast_indicate(caller, AST_CONTROL_RINGING); 02171 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 02172 state = f->subclass; 02173 ast_verb(3, "%s is busy\n", chan->name); 02174 ast_indicate(caller, AST_CONTROL_BUSY); 02175 ast_frfree(f); 02176 f = NULL; 02177 break; 02178 } else if (f->subclass == AST_CONTROL_ANSWER) { 02179 /* This is what we are hoping for */ 02180 state = f->subclass; 02181 ast_frfree(f); 02182 f = NULL; 02183 ready=1; 02184 break; 02185 } else if (f->subclass != -1) { 02186 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 02187 } 02188 /* else who cares */ 02189 } 02190 02191 } else if (caller && (active_channel == caller)) { 02192 f = ast_read(caller); 02193 if (f == NULL) { /*doh! where'd he go?*/ 02194 if (!igncallerstate) { 02195 if (ast_check_hangup(caller) && !ast_check_hangup(chan)) { 02196 /* make this a blind transfer */ 02197 ready = 1; 02198 break; 02199 } 02200 state = AST_CONTROL_HANGUP; 02201 res = 0; 02202 break; 02203 } 02204 } else { 02205 02206 if (f->frametype == AST_FRAME_DTMF) { 02207 dialed_code[x++] = f->subclass; 02208 dialed_code[x] = '\0'; 02209 if (strlen(dialed_code) == len) { 02210 x = 0; 02211 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 02212 x = 0; 02213 dialed_code[x] = '\0'; 02214 } 02215 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 02216 /* Caller Canceled the call */ 02217 state = AST_CONTROL_UNHOLD; 02218 ast_frfree(f); 02219 f = NULL; 02220 break; 02221 } 02222 } 02223 } 02224 } 02225 if (f) 02226 ast_frfree(f); 02227 } /* end while */ 02228 02229 ast_poll_channel_del(caller, chan); 02230 02231 } else 02232 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 02233 } else { 02234 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 02235 switch(cause) { 02236 case AST_CAUSE_BUSY: 02237 state = AST_CONTROL_BUSY; 02238 break; 02239 case AST_CAUSE_CONGESTION: 02240 state = AST_CONTROL_CONGESTION; 02241 break; 02242 } 02243 } 02244 02245 ast_indicate(caller, -1); 02246 if (chan && ready) { 02247 if (chan->_state == AST_STATE_UP) 02248 state = AST_CONTROL_ANSWER; 02249 res = 0; 02250 } else if(chan) { 02251 res = -1; 02252 ast_hangup(chan); 02253 chan = NULL; 02254 } else { 02255 res = -1; 02256 } 02257 02258 if (outstate) 02259 *outstate = state; 02260 02261 return chan; 02262 }
int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 4535 of file features.c.
References action_bridge(), ao2_container_alloc, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application2(), bridge_exec(), cli_features, descrip, descrip2, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), parkinglots, synopsis, and synopsis2.
Referenced by main().
04536 { 04537 int res; 04538 04539 ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL); 04540 04541 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 04542 04543 if ((res = load_config())) 04544 return res; 04545 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 04546 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 04547 res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL); 04548 if (!res) 04549 res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL); 04550 if (!res) { 04551 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls"); 04552 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park); 04553 ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge); 04554 } 04555 04556 res |= ast_devstate_prov_add("Park", metermaidstate); 04557 04558 return res; 04559 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 3969 of file features.c.
References load_config().
Referenced by handle_features_reload().
03970 { 03971 int res; 03972 /* Release parking lot list */ 03973 //ASTOBJ_CONTAINER_MARKALL(&parkinglots); 03974 // TODO: I don't think any marking is necessary 03975 03976 /* Reload configuration */ 03977 res = load_config(); 03978 03979 //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy); 03980 return res; 03981 }
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 1795 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
01796 { 01797 int x; 01798 for (x = 0; x < FEATURES_COUNT; x++) { 01799 if (!strcasecmp(name, builtin_features[x].sname)) 01800 return &builtin_features[x]; 01801 } 01802 return NULL; 01803 }
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 808 of file features.c.
References masq_park_call().
Referenced by handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().
00809 { 00810 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00811 }
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 742 of file features.c.
References ast_park_call_full(), chan, and ast_park_call_args::timeout.
Referenced by iax_park_thread(), and sip_park_thread().
00743 { 00744 struct ast_park_call_args args = { 00745 .timeout = timeout, 00746 .extout = extout, 00747 }; 00748 00749 return ast_park_call_full(chan, peer, &args); 00750 }
static int ast_park_call_full | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 604 of file features.c.
References adsi_announce_park(), adsipark, ast_channel::appl, ast_add_extension2(), ast_adsi_available, ast_adsi_unload_session, ast_bridged_channel(), AST_CHANNEL_NAME, ast_channel_unlock, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HOLD, AST_CONTROL_RINGING, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RINGING, AST_PARK_OPT_SILENCE, ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, parkeduser::chan, chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, ast_park_call_args::extout, ast_channel::language, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_park_call_args::orig_chan_name, park_space_reserve(), parkedcall, ast_parkinglot::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, ast_parkinglot::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, ast_park_call_args::pu, registrar, ast_park_call_args::return_con, ast_park_call_args::return_ext, S_OR, parkeduser::start, ast_channel::tech, ast_park_call_args::timeout, ast_channel_tech::type, and ast_channel::uniqueid.
Referenced by ast_park_call(), and masq_park_call().
00605 { 00606 struct ast_context *con; 00607 int parkingnum_copy; 00608 struct parkeduser *pu = args->pu; 00609 const char *event_from; 00610 00611 if (pu == NULL) 00612 pu = park_space_reserve(chan, peer, args); 00613 if (pu == NULL) 00614 return 1; /* Continue execution if possible */ 00615 00616 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum); 00617 00618 chan->appl = "Parked Call"; 00619 chan->data = NULL; 00620 00621 pu->chan = chan; 00622 00623 /* Put the parked channel on hold if we have two different channels */ 00624 if (chan != peer) { 00625 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 00626 ast_indicate(pu->chan, AST_CONTROL_RINGING); 00627 } else { 00628 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00629 S_OR(pu->parkinglot->mohclass, NULL), 00630 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 00631 } 00632 } 00633 00634 pu->start = ast_tvnow(); 00635 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime; 00636 parkingnum_copy = pu->parkingnum; 00637 if (args->extout) 00638 *(args->extout) = pu->parkingnum; 00639 00640 if (peer) { 00641 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels 00642 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking 00643 and we need the callback name to be that of transferer. Since local,1/2 have the same 00644 name we can be tricky and just grab the bridged channel from the other side of the local 00645 */ 00646 if (!strcasecmp(peer->tech->type, "Local")) { 00647 struct ast_channel *tmpchan, *base_peer; 00648 char other_side[AST_CHANNEL_NAME]; 00649 char *c; 00650 ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side)); 00651 if ((c = strrchr(other_side, ';'))) { 00652 *++c = '1'; 00653 } 00654 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) { 00655 if ((base_peer = ast_bridged_channel(tmpchan))) { 00656 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 00657 } 00658 ast_channel_unlock(tmpchan); 00659 } 00660 } else { 00661 ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername)); 00662 } 00663 } 00664 00665 /* Remember what had been dialed, so that if the parking 00666 expires, we try to come back to the same place */ 00667 ast_copy_string(pu->context, 00668 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 00669 sizeof(pu->context)); 00670 ast_copy_string(pu->exten, 00671 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 00672 sizeof(pu->exten)); 00673 pu->priority = pu->priority ? pu->priority : 00674 (chan->macropriority ? chan->macropriority : chan->priority); 00675 00676 /* If parking a channel directly, don't quiet yet get parking running on it. 00677 * All parking lot entries are put into the parking lot with notquiteyet on. */ 00678 if (peer != chan) 00679 pu->notquiteyet = 0; 00680 00681 /* Wake up the (presumably select()ing) thread */ 00682 pthread_kill(parking_thread, SIGURG); 00683 ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); 00684 00685 if (peer) { 00686 event_from = peer->name; 00687 } else { 00688 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 00689 } 00690 00691 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00692 "Exten: %s\r\n" 00693 "Channel: %s\r\n" 00694 "Parkinglot: %s\r\n" 00695 "From: %s\r\n" 00696 "Timeout: %ld\r\n" 00697 "CallerIDNum: %s\r\n" 00698 "CallerIDName: %s\r\n" 00699 "Uniqueid: %s\r\n", 00700 pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "", 00701 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00702 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00703 S_OR(pu->chan->cid.cid_name, "<unknown>"), 00704 pu->chan->uniqueid 00705 ); 00706 00707 if (peer && adsipark && ast_adsi_available(peer)) { 00708 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00709 ast_adsi_unload_session(peer); 00710 } 00711 00712 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar); 00713 if (!con) /* Still no context? Bad */ 00714 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con); 00715 if (con) { 00716 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar)) 00717 notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE); 00718 } 00719 00720 AST_LIST_UNLOCK(&pu->parkinglot->parkings); 00721 00722 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 00723 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) { 00724 /* 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. */ 00725 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00726 /* Tell the peer channel the number of the parking space */ 00727 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00728 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00729 } 00730 if (peer == chan) { /* pu->notquiteyet = 1 */ 00731 /* Wake up parking thread if we're really done */ 00732 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00733 S_OR(pu->parkinglot->mohclass, NULL), 00734 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 00735 pu->notquiteyet = 0; 00736 pthread_kill(parking_thread, SIGURG); 00737 } 00738 return 0; 00739 }
const char* ast_parking_ext | ( | void | ) |
Determine system parking extension.
Definition at line 242 of file features.c.
References parking_ext.
Referenced by build_parkinglot(), builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00243 { 00244 return parking_ext; 00245 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
Definition at line 4353 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().
04354 { 04355 struct ast_channel *cur = NULL; 04356 int res = -1; 04357 04358 while ((cur = ast_channel_walk_locked(cur)) != NULL) { 04359 if (!cur->pbx && 04360 (cur != chan) && 04361 (chan->pickupgroup & cur->callgroup) && 04362 ((cur->_state == AST_STATE_RINGING) || 04363 (cur->_state == AST_STATE_RING))) { 04364 break; 04365 } 04366 ast_channel_unlock(cur); 04367 } 04368 if (cur) { 04369 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 04370 res = ast_answer(chan); 04371 if (res) 04372 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 04373 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 04374 if (res) 04375 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 04376 res = ast_channel_masquerade(cur, chan); 04377 if (res) 04378 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 04379 ast_channel_unlock(cur); 04380 } else { 04381 ast_debug(1, "No call pickup possible...\n"); 04382 } 04383 return res; 04384 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 247 of file features.c.
References pickup_ext.
Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().
00248 { 00249 return pickup_ext; 00250 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 1785 of file features.c.
References ast_rwlock_rdlock(), and features_lock.
Referenced by handle_request_info().
01786 { 01787 ast_rwlock_rdlock(&features_lock); 01788 }
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 1622 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, feature_group_exten::feature, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
01623 { 01624 if (!feature) { 01625 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01626 return; 01627 } 01628 01629 AST_RWLIST_WRLOCK(&feature_list); 01630 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01631 AST_RWLIST_UNLOCK(&feature_list); 01632 01633 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 01634 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 1790 of file features.c.
References ast_rwlock_unlock(), and features_lock.
Referenced by handle_request_info().
01791 { 01792 ast_rwlock_unlock(&features_lock); 01793 }
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 1710 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
01711 { 01712 if (!feature) { 01713 return; 01714 } 01715 01716 AST_RWLIST_WRLOCK(&feature_list); 01717 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01718 AST_RWLIST_UNLOCK(&feature_list); 01719 01720 ast_free(feature); 01721 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1724 of file features.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, feature_group_exten::feature, and ast_call_feature::feature_entry.
01725 { 01726 struct ast_call_feature *feature; 01727 01728 AST_RWLIST_WRLOCK(&feature_list); 01729 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 01730 ast_free(feature); 01731 } 01732 AST_RWLIST_UNLOCK(&feature_list); 01733 }
static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 1750 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.
01751 { 01752 struct feature_group *fg; 01753 struct feature_group_exten *fge; 01754 01755 AST_RWLIST_WRLOCK(&feature_groups); 01756 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 01757 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 01758 ast_string_field_free_memory(fge); 01759 ast_free(fge); 01760 } 01761 01762 ast_string_field_free_memory(fg); 01763 ast_free(fg); 01764 } 01765 AST_RWLIST_UNLOCK(&feature_groups); 01766 }
static int bridge_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Bridge channels.
chan | ||
data | channel to bridge with. |
Definition at line 4415 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().
04416 { 04417 struct ast_channel *current_dest_chan, *final_dest_chan; 04418 char *tmp_data = NULL; 04419 struct ast_flags opts = { 0, }; 04420 struct ast_bridge_config bconfig = { { 0, }, }; 04421 04422 AST_DECLARE_APP_ARGS(args, 04423 AST_APP_ARG(dest_chan); 04424 AST_APP_ARG(options); 04425 ); 04426 04427 if (ast_strlen_zero(data)) { 04428 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 04429 return -1; 04430 } 04431 04432 tmp_data = ast_strdupa(data); 04433 AST_STANDARD_APP_ARGS(args, tmp_data); 04434 if (!ast_strlen_zero(args.options)) 04435 ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options); 04436 04437 /* avoid bridge with ourselves */ 04438 if (!strncmp(chan->name, args.dest_chan, 04439 strlen(chan->name) < strlen(args.dest_chan) ? 04440 strlen(chan->name) : strlen(args.dest_chan))) { 04441 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 04442 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04443 "Response: Failed\r\n" 04444 "Reason: Unable to bridge channel to itself\r\n" 04445 "Channel1: %s\r\n" 04446 "Channel2: %s\r\n", 04447 chan->name, args.dest_chan); 04448 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 04449 return 0; 04450 } 04451 04452 /* make sure we have a valid end point */ 04453 if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 04454 strlen(args.dest_chan)))) { 04455 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 04456 "cannot get its lock\n", args.dest_chan); 04457 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04458 "Response: Failed\r\n" 04459 "Reason: Cannot grab end point\r\n" 04460 "Channel1: %s\r\n" 04461 "Channel2: %s\r\n", chan->name, args.dest_chan); 04462 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 04463 return 0; 04464 } 04465 04466 /* answer the channel if needed */ 04467 if (current_dest_chan->_state != AST_STATE_UP) 04468 ast_answer(current_dest_chan); 04469 04470 /* try to allocate a place holder where current_dest_chan will be placed */ 04471 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04472 NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) { 04473 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 04474 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04475 "Response: Failed\r\n" 04476 "Reason: cannot create placeholder\r\n" 04477 "Channel1: %s\r\n" 04478 "Channel2: %s\r\n", chan->name, args.dest_chan); 04479 } 04480 do_bridge_masquerade(current_dest_chan, final_dest_chan); 04481 04482 ast_channel_unlock(current_dest_chan); 04483 04484 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 04485 /* try to make compatible, send error if we fail */ 04486 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 04487 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 04488 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04489 "Response: Failed\r\n" 04490 "Reason: Could not make channels compatible for bridge\r\n" 04491 "Channel1: %s\r\n" 04492 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 04493 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 04494 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 04495 return 0; 04496 } 04497 04498 /* Report that the bridge will be successfull */ 04499 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04500 "Response: Success\r\n" 04501 "Channel1: %s\r\n" 04502 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 04503 04504 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 04505 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 04506 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 04507 if (ast_waitstream(final_dest_chan, "") < 0) 04508 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 04509 } 04510 } 04511 04512 /* do the bridge */ 04513 ast_bridge_call(chan, final_dest_chan, &bconfig); 04514 04515 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 04516 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 04517 if (!ast_check_hangup(final_dest_chan)) { 04518 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 04519 final_dest_chan->context, final_dest_chan->exten, 04520 final_dest_chan->priority, final_dest_chan->name); 04521 04522 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 04523 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 04524 ast_hangup(final_dest_chan); 04525 } else 04526 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 04527 } else { 04528 ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name); 04529 ast_hangup(final_dest_chan); 04530 } 04531 04532 return 0; 04533 }
static struct ast_parkinglot* build_parkinglot | ( | char * | name, | |
struct ast_variable * | var | |||
) | [static] |
Build parkinglot from configuration and chain it in.
Definition at line 3450 of file features.c.
References ao2_link, ao2_lock(), ao2_unlock(), ast_add_extension2(), ast_context_find_or_create(), ast_copy_string(), ast_free_ptr, ast_log(), ast_parking_ext(), ast_strlen_zero(), create_parkinglot(), DEFAULT_PARK_TIME, find_parkinglot(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, option_debug, parkcall, parkinglot, parkinglot_destroy(), parkinglot_unref(), parkinglots, registrar, strdup, ast_variable::value, and var.
Referenced by load_config().
03451 { 03452 struct ast_parkinglot *parkinglot; 03453 struct ast_context *con = NULL; 03454 03455 struct ast_variable *confvar = var; 03456 int error = 0; 03457 int start = 0, end = 0; 03458 int oldparkinglot = 0; 03459 03460 parkinglot = find_parkinglot(name); 03461 if (parkinglot) 03462 oldparkinglot = 1; 03463 else 03464 parkinglot = create_parkinglot(name); 03465 03466 if (!parkinglot) 03467 return NULL; 03468 03469 ao2_lock(parkinglot); 03470 03471 if (option_debug) 03472 ast_log(LOG_DEBUG, "Building parking lot %s\n", name); 03473 03474 /* Do some config stuff */ 03475 while(confvar) { 03476 if (!strcasecmp(confvar->name, "context")) { 03477 ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con)); 03478 } else if (!strcasecmp(confvar->name, "parkingtime")) { 03479 if ((sscanf(confvar->value, "%d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) { 03480 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value); 03481 parkinglot->parkingtime = DEFAULT_PARK_TIME; 03482 } else 03483 parkinglot->parkingtime = parkinglot->parkingtime * 1000; 03484 } else if (!strcasecmp(confvar->name, "parkpos")) { 03485 if (sscanf(confvar->value, "%d-%d", &start, &end) != 2) { 03486 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", confvar->lineno); 03487 error = 1; 03488 } else { 03489 parkinglot->parking_start = start; 03490 parkinglot->parking_stop = end; 03491 } 03492 } else if (!strcasecmp(confvar->name, "findslot")) { 03493 parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next")); 03494 } 03495 confvar = confvar->next; 03496 } 03497 /* make sure parkingtime is set if not specified */ 03498 if (parkinglot->parkingtime == 0) { 03499 parkinglot->parkingtime = DEFAULT_PARK_TIME; 03500 } 03501 03502 if (!var) { /* Default parking lot */ 03503 ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con)); 03504 ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial)); 03505 ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass)); 03506 } 03507 03508 /* Check for errors */ 03509 if (ast_strlen_zero(parkinglot->parking_con)) { 03510 ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name); 03511 error = 1; 03512 } 03513 03514 /* Create context */ 03515 if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) { 03516 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con); 03517 error = 1; 03518 } 03519 03520 /* Add a parking extension into the context */ 03521 if (!oldparkinglot) { 03522 if (!ast_strlen_zero(ast_parking_ext())) { 03523 if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1) 03524 error = 1; 03525 } 03526 } 03527 03528 ao2_unlock(parkinglot); 03529 03530 if (error) { 03531 ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name); 03532 parkinglot_destroy(parkinglot); 03533 return NULL; 03534 } 03535 if (option_debug) 03536 ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end); 03537 03538 03539 /* Move it into the list, if it wasn't already there */ 03540 if (!oldparkinglot) { 03541 ao2_link(parkinglots, parkinglot); 03542 } 03543 parkinglot_unref(parkinglot); 03544 03545 return parkinglot; 03546 }
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 1307 of file features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FEATURE_RETURN_SUCCESS, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_parking_ext(), ast_read(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, builtin_parkcall(), chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, f, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xferfailsound, and xfersound.
01308 { 01309 struct ast_channel *transferer; 01310 struct ast_channel *transferee; 01311 const char *transferer_real_context; 01312 char xferto[256] = ""; 01313 int res; 01314 int outstate=0; 01315 struct ast_channel *newchan; 01316 struct ast_channel *xferchan; 01317 struct ast_bridge_thread_obj *tobj; 01318 struct ast_bridge_config bconfig; 01319 struct ast_frame *f; 01320 int l; 01321 struct ast_datastore *features_datastore; 01322 struct ast_dial_features *dialfeatures = NULL; 01323 01324 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 01325 set_peers(&transferer, &transferee, peer, chan, sense); 01326 transferer_real_context = real_ctx(transferer, transferee); 01327 /* Start autoservice on chan while we talk to the originator */ 01328 ast_autoservice_start(transferee); 01329 ast_indicate(transferee, AST_CONTROL_HOLD); 01330 01331 /* Transfer */ 01332 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01333 if (res < 0) { 01334 finishup(transferee); 01335 return res; 01336 } 01337 if (res > 0) /* If they've typed a digit already, handle it */ 01338 xferto[0] = (char) res; 01339 01340 /* this is specific of atxfer */ 01341 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01342 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01343 finishup(transferee); 01344 return res; 01345 } 01346 if (res == 0) { 01347 ast_log(LOG_WARNING, "Did not read data.\n"); 01348 finishup(transferee); 01349 if (ast_stream_and_wait(transferer, "beeperr", "")) 01350 return -1; 01351 return AST_FEATURE_RETURN_SUCCESS; 01352 } 01353 01354 /* valid extension, res == 1 */ 01355 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01356 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 01357 finishup(transferee); 01358 if (ast_stream_and_wait(transferer, "beeperr", "")) 01359 return -1; 01360 return AST_FEATURE_RETURN_SUCCESS; 01361 } 01362 01363 /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of 01364 * the different variables for handling this properly with a builtin_atxfer */ 01365 if (!strcmp(xferto, ast_parking_ext())) { 01366 finishup(transferee); 01367 return builtin_parkcall(chan, peer, config, code, sense, data); 01368 } 01369 01370 l = strlen(xferto); 01371 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 01372 01373 /* If we are performing an attended transfer and we have two channels involved then 01374 copy sound file information to play upon attended transfer completion */ 01375 if (transferee) { 01376 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 01377 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 01378 01379 if (!ast_strlen_zero(chan1_attended_sound)) { 01380 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 01381 } 01382 if (!ast_strlen_zero(chan2_attended_sound)) { 01383 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 01384 } 01385 } 01386 01387 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01388 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01389 01390 if (!ast_check_hangup(transferer)) { 01391 /* Transferer is up - old behaviour */ 01392 ast_indicate(transferer, -1); 01393 if (!newchan) { 01394 finishup(transferee); 01395 /* any reason besides user requested cancel and busy triggers the failed sound */ 01396 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 01397 ast_stream_and_wait(transferer, xferfailsound, "")) 01398 return -1; 01399 if (ast_stream_and_wait(transferer, xfersound, "")) 01400 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01401 return AST_FEATURE_RETURN_SUCCESS; 01402 } 01403 01404 if (check_compat(transferer, newchan)) { 01405 /* we do mean transferee here, NOT transferer */ 01406 finishup(transferee); 01407 return -1; 01408 } 01409 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 01410 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 01411 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 01412 res = ast_bridge_call(transferer, newchan, &bconfig); 01413 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 01414 ast_hangup(newchan); 01415 if (ast_stream_and_wait(transferer, xfersound, "")) 01416 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01417 finishup(transferee); 01418 transferer->_softhangup = 0; 01419 return AST_FEATURE_RETURN_SUCCESS; 01420 } 01421 if (check_compat(transferee, newchan)) { 01422 finishup(transferee); 01423 return -1; 01424 } 01425 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01426 01427 if ((ast_autoservice_stop(transferee) < 0) 01428 || (ast_waitfordigit(transferee, 100) < 0) 01429 || (ast_waitfordigit(newchan, 100) < 0) 01430 || ast_check_hangup(transferee) 01431 || ast_check_hangup(newchan)) { 01432 ast_hangup(newchan); 01433 return -1; 01434 } 01435 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01436 if (!xferchan) { 01437 ast_hangup(newchan); 01438 return -1; 01439 } 01440 /* Make formats okay */ 01441 xferchan->visible_indication = transferer->visible_indication; 01442 xferchan->readformat = transferee->readformat; 01443 xferchan->writeformat = transferee->writeformat; 01444 ast_channel_masquerade(xferchan, transferee); 01445 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01446 xferchan->_state = AST_STATE_UP; 01447 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01448 xferchan->_softhangup = 0; 01449 if ((f = ast_read(xferchan))) 01450 ast_frfree(f); 01451 newchan->_state = AST_STATE_UP; 01452 ast_clear_flag(newchan, AST_FLAGS_ALL); 01453 newchan->_softhangup = 0; 01454 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01455 ast_hangup(xferchan); 01456 ast_hangup(newchan); 01457 return -1; 01458 } 01459 01460 ast_channel_lock(newchan); 01461 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 01462 dialfeatures = features_datastore->data; 01463 } 01464 ast_channel_unlock(newchan); 01465 01466 if (dialfeatures) { 01467 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 01468 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 01469 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01470 dialfeatures = NULL; 01471 } 01472 01473 ast_channel_lock(xferchan); 01474 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 01475 dialfeatures = features_datastore->data; 01476 } 01477 ast_channel_unlock(xferchan); 01478 01479 if (dialfeatures) { 01480 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01481 } 01482 01483 tobj->chan = newchan; 01484 tobj->peer = xferchan; 01485 tobj->bconfig = *config; 01486 01487 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01488 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01489 } 01490 01491 if (ast_stream_and_wait(newchan, xfersound, "")) 01492 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01493 ast_bridge_call_thread_launch(tobj); 01494 return -1; /* XXX meaning the channel is bridged ? */ 01495 } else if (!ast_check_hangup(transferee)) { 01496 /* act as blind transfer */ 01497 if (ast_autoservice_stop(transferee) < 0) { 01498 ast_hangup(newchan); 01499 return -1; 01500 } 01501 01502 if (!newchan) { 01503 unsigned int tries = 0; 01504 char *transferer_tech, *transferer_name = ast_strdupa(transferer->name); 01505 01506 transferer_tech = strsep(&transferer_name, "/"); 01507 transferer_name = strsep(&transferer_name, "-"); 01508 01509 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 01510 ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name); 01511 if (ast_stream_and_wait(transferee, "beeperr", "")) 01512 return -1; 01513 return AST_FEATURE_RETURN_SUCCESS; 01514 } 01515 01516 ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name); 01517 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01518 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01519 while (!newchan && !atxferdropcall && tries < atxfercallbackretries) { 01520 /* Trying to transfer again */ 01521 ast_autoservice_start(transferee); 01522 ast_indicate(transferee, AST_CONTROL_HOLD); 01523 01524 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01525 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01526 if (ast_autoservice_stop(transferee) < 0) { 01527 if (newchan) 01528 ast_hangup(newchan); 01529 return -1; 01530 } 01531 if (!newchan) { 01532 /* Transfer failed, sleeping */ 01533 ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay); 01534 ast_safe_sleep(transferee, atxferloopdelay); 01535 ast_debug(1, "Trying to callback...\n"); 01536 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01537 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01538 } 01539 tries++; 01540 } 01541 } 01542 if (!newchan) 01543 return -1; 01544 01545 /* newchan is up, we should prepare transferee and bridge them */ 01546 if (check_compat(transferee, newchan)) { 01547 finishup(transferee); 01548 return -1; 01549 } 01550 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01551 01552 if ((ast_waitfordigit(transferee, 100) < 0) 01553 || (ast_waitfordigit(newchan, 100) < 0) 01554 || ast_check_hangup(transferee) 01555 || ast_check_hangup(newchan)) { 01556 ast_hangup(newchan); 01557 return -1; 01558 } 01559 01560 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01561 if (!xferchan) { 01562 ast_hangup(newchan); 01563 return -1; 01564 } 01565 /* Make formats okay */ 01566 xferchan->visible_indication = transferer->visible_indication; 01567 xferchan->readformat = transferee->readformat; 01568 xferchan->writeformat = transferee->writeformat; 01569 ast_channel_masquerade(xferchan, transferee); 01570 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01571 xferchan->_state = AST_STATE_UP; 01572 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01573 xferchan->_softhangup = 0; 01574 if ((f = ast_read(xferchan))) 01575 ast_frfree(f); 01576 newchan->_state = AST_STATE_UP; 01577 ast_clear_flag(newchan, AST_FLAGS_ALL); 01578 newchan->_softhangup = 0; 01579 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01580 ast_hangup(xferchan); 01581 ast_hangup(newchan); 01582 return -1; 01583 } 01584 tobj->chan = newchan; 01585 tobj->peer = xferchan; 01586 tobj->bconfig = *config; 01587 01588 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01589 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01590 } 01591 01592 if (ast_stream_and_wait(newchan, xfersound, "")) 01593 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01594 ast_bridge_call_thread_launch(tobj); 01595 return -1; /* XXX meaning the channel is bridged ? */ 01596 } else { 01597 /* Transferee hung up */ 01598 finishup(transferee); 01599 return -1; 01600 } 01601 }
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 1016 of file features.c.
References AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_unlock, AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, courtesytone, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), stopmixmonitor_app, and stopmixmonitor_ok.
01017 { 01018 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 01019 int x = 0; 01020 size_t len; 01021 struct ast_channel *caller_chan, *callee_chan; 01022 const char *mixmonitor_spy_type = "MixMonitor"; 01023 int count = 0; 01024 01025 if (!mixmonitor_ok) { 01026 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01027 return -1; 01028 } 01029 01030 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 01031 mixmonitor_ok = 0; 01032 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01033 return -1; 01034 } 01035 01036 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 01037 01038 if (!ast_strlen_zero(courtesytone)) { 01039 if (ast_autoservice_start(callee_chan)) 01040 return -1; 01041 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 01042 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01043 ast_autoservice_stop(callee_chan); 01044 return -1; 01045 } 01046 if (ast_autoservice_stop(callee_chan)) 01047 return -1; 01048 } 01049 01050 ast_channel_lock(callee_chan); 01051 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01052 ast_channel_unlock(callee_chan); 01053 01054 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 01055 if (count > 0) { 01056 01057 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 01058 01059 /* Make sure they are running */ 01060 ast_channel_lock(callee_chan); 01061 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01062 ast_channel_unlock(callee_chan); 01063 if (count > 0) { 01064 if (!stopmixmonitor_ok) { 01065 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01066 return -1; 01067 } 01068 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 01069 stopmixmonitor_ok = 0; 01070 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01071 return -1; 01072 } else { 01073 pbx_exec(callee_chan, stopmixmonitor_app, ""); 01074 return AST_FEATURE_RETURN_SUCCESS; 01075 } 01076 } 01077 01078 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 01079 } 01080 01081 if (caller_chan && callee_chan) { 01082 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 01083 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 01084 01085 if (!touch_format) 01086 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 01087 01088 if (!touch_monitor) 01089 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 01090 01091 if (touch_monitor) { 01092 len = strlen(touch_monitor) + 50; 01093 args = alloca(len); 01094 touch_filename = alloca(len); 01095 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 01096 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 01097 } else { 01098 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 01099 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 01100 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 01101 args = alloca(len); 01102 touch_filename = alloca(len); 01103 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 01104 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 01105 } 01106 01107 for( x = 0; x < strlen(args); x++) { 01108 if (args[x] == '/') 01109 args[x] = '-'; 01110 } 01111 01112 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 01113 01114 pbx_exec(callee_chan, mixmonitor_app, args); 01115 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01116 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01117 return AST_FEATURE_RETURN_SUCCESS; 01118 01119 } 01120 01121 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01122 return -1; 01123 01124 }
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. |
AST_FEATURE_RETURN_SUCCESS | on success. | |
-1 | on error. |
Definition at line 923 of file features.c.
References AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, courtesytone, len(), LOG_ERROR, LOG_NOTICE, ast_channel::monitor, monitor_app, monitor_ok, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_OR, set_peers(), and ast_channel_monitor::stop.
00924 { 00925 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00926 int x = 0; 00927 size_t len; 00928 struct ast_channel *caller_chan, *callee_chan; 00929 const char *automon_message_start = NULL; 00930 const char *automon_message_stop = NULL; 00931 00932 if (!monitor_ok) { 00933 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00934 return -1; 00935 } 00936 00937 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00938 monitor_ok = 0; 00939 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00940 return -1; 00941 } 00942 00943 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00944 if (caller_chan) { /* Find extra messages */ 00945 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 00946 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 00947 } 00948 00949 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 00950 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 00951 return -1; 00952 } 00953 } 00954 00955 if (callee_chan->monitor) { 00956 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 00957 if (!ast_strlen_zero(automon_message_stop)) { 00958 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 00959 } 00960 callee_chan->monitor->stop(callee_chan, 1); 00961 return AST_FEATURE_RETURN_SUCCESS; 00962 } 00963 00964 if (caller_chan && callee_chan) { 00965 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00966 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00967 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 00968 00969 if (!touch_format) 00970 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00971 00972 if (!touch_monitor) 00973 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00974 00975 if (!touch_monitor_prefix) 00976 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 00977 00978 if (touch_monitor) { 00979 len = strlen(touch_monitor) + 50; 00980 args = alloca(len); 00981 touch_filename = alloca(len); 00982 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 00983 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 00984 } else { 00985 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00986 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00987 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00988 args = alloca(len); 00989 touch_filename = alloca(len); 00990 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 00991 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 00992 } 00993 00994 for(x = 0; x < strlen(args); x++) { 00995 if (args[x] == '/') 00996 args[x] = '-'; 00997 } 00998 00999 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 01000 01001 pbx_exec(callee_chan, monitor_app, args); 01002 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01003 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01004 01005 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 01006 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 01007 } 01008 01009 return AST_FEATURE_RETURN_SUCCESS; 01010 } 01011 01012 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01013 return -1; 01014 }
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 |
AST_FEATURE_RETURN_SUCCESS. | ||
-1 | on failure. |
Definition at line 1176 of file features.c.
References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), AST_FEATURE_RETURN_PARKFAILED, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, ast_stopstream(), ast_stream_and_wait(), ast_verb, ast_channel::cdr, chan, ast_cdr::channel, check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_cdr::dstchannel, finishup(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, masq_park_call_announce(), ast_channel::name, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), transferdigittimeout, and xferfailsound.
01177 { 01178 struct ast_channel *transferer; 01179 struct ast_channel *transferee; 01180 const char *transferer_real_context; 01181 char xferto[256]; 01182 int res, parkstatus = 0; 01183 01184 set_peers(&transferer, &transferee, peer, chan, sense); 01185 transferer_real_context = real_ctx(transferer, transferee); 01186 /* Start autoservice on chan while we talk to the originator */ 01187 ast_autoservice_start(transferee); 01188 ast_indicate(transferee, AST_CONTROL_HOLD); 01189 01190 memset(xferto, 0, sizeof(xferto)); 01191 01192 /* Transfer */ 01193 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01194 if (res < 0) { 01195 finishup(transferee); 01196 return -1; /* error ? */ 01197 } 01198 if (res > 0) /* If they've typed a digit already, handle it */ 01199 xferto[0] = (char) res; 01200 01201 ast_stopstream(transferer); 01202 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01203 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01204 finishup(transferee); 01205 return res; 01206 } 01207 if (!strcmp(xferto, ast_parking_ext())) { 01208 res = finishup(transferee); 01209 if (res) 01210 res = -1; 01211 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) { /* success */ 01212 /* We return non-zero, but tell the PBX not to hang the channel when 01213 the thread dies -- We have to be careful now though. We are responsible for 01214 hanging up the channel, else it will never be hung up! */ 01215 01216 return 0; 01217 } else { 01218 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus); 01219 } 01220 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 01221 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01222 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 01223 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 01224 res=finishup(transferee); 01225 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 01226 transferer->cdr=ast_cdr_alloc(); 01227 if (transferer->cdr) { 01228 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 01229 ast_cdr_start(transferer->cdr); 01230 } 01231 } 01232 if (transferer->cdr) { 01233 struct ast_cdr *swap = transferer->cdr; 01234 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 01235 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 01236 transferer->cdr->channel, transferer->cdr->dstchannel); 01237 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 01238 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel); 01239 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto); 01240 /* swap cdrs-- it will save us some time & work */ 01241 transferer->cdr = transferee->cdr; 01242 transferee->cdr = swap; 01243 } 01244 if (!transferee->pbx) { 01245 /* Doh! Use our handy async_goto functions */ 01246 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n" 01247 ,transferee->name, xferto, transferer_real_context); 01248 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 01249 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 01250 } else { 01251 /* Set the channel's new extension, since it exists, using transferer context */ 01252 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 01253 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name); 01254 set_c_e_p(transferee, transferer_real_context, xferto, 0); 01255 } 01256 check_goto_on_transfer(transferer); 01257 return res; 01258 } else { 01259 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 01260 } 01261 if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { 01262 finishup(transferee); 01263 return -1; 01264 } 01265 ast_stopstream(transferer); 01266 res = finishup(transferee); 01267 if (res) { 01268 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name); 01269 return res; 01270 } 01271 return AST_FEATURE_RETURN_SUCCESS; 01272 }
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 1126 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
01127 { 01128 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 01129 return AST_FEATURE_RETURN_HANGUP; 01130 }
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 853 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().
00854 { 00855 struct ast_channel *parker; 00856 struct ast_channel *parkee; 00857 int res = 0; 00858 00859 set_peers(&parker, &parkee, peer, chan, sense); 00860 /* we used to set chan's exten and priority to "s" and 1 00861 here, but this generates (in some cases) an invalid 00862 extension, and if "s" exists, could errantly 00863 cause execution of extensions you don't expect. It 00864 makes more sense to let nature take its course 00865 when chan finishes, and let the pbx do its thing 00866 and hang up when the park is over. 00867 */ 00868 if (chan->_state != AST_STATE_UP) 00869 res = ast_answer(chan); 00870 if (!res) 00871 res = ast_safe_sleep(chan, 1000); 00872 00873 if (!res) { /* one direction used to call park_call.... */ 00874 res = masq_park_call_announce(parkee, parker, 0, NULL); 00875 /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ 00876 } 00877 00878 return res; 00879 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 2870 of file features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, and ast_test_flag.
Referenced by manage_parkinglot().
02871 { 02872 int i = 0; 02873 enum { 02874 OPT_CALLEE_REDIRECT = 't', 02875 OPT_CALLER_REDIRECT = 'T', 02876 OPT_CALLEE_AUTOMON = 'w', 02877 OPT_CALLER_AUTOMON = 'W', 02878 OPT_CALLEE_DISCONNECT = 'h', 02879 OPT_CALLER_DISCONNECT = 'H', 02880 OPT_CALLEE_PARKCALL = 'k', 02881 OPT_CALLER_PARKCALL = 'K', 02882 }; 02883 02884 memset(options, 0, len); 02885 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 02886 options[i++] = OPT_CALLER_REDIRECT; 02887 } 02888 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 02889 options[i++] = OPT_CALLER_AUTOMON; 02890 } 02891 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 02892 options[i++] = OPT_CALLER_DISCONNECT; 02893 } 02894 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 02895 options[i++] = OPT_CALLER_PARKCALL; 02896 } 02897 02898 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 02899 options[i++] = OPT_CALLEE_REDIRECT; 02900 } 02901 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 02902 options[i++] = OPT_CALLEE_AUTOMON; 02903 } 02904 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 02905 options[i++] = OPT_CALLEE_DISCONNECT; 02906 } 02907 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 02908 options[i++] = OPT_CALLEE_PARKCALL; 02909 } 02910 02911 return options; 02912 }
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 1281 of file features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by builtin_atxfer().
01282 { 01283 if (ast_channel_make_compatible(c, newchan) < 0) { 01284 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 01285 c->name, newchan->name); 01286 ast_hangup(newchan); 01287 return -1; 01288 } 01289 return 0; 01290 }
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 293 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().
00294 { 00295 struct ast_channel *xferchan; 00296 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00297 char *x, *goto_on_transfer; 00298 struct ast_frame *f; 00299 00300 if (ast_strlen_zero(val)) 00301 return; 00302 00303 goto_on_transfer = ast_strdupa(val); 00304 00305 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name))) 00306 return; 00307 00308 for (x = goto_on_transfer; x && *x; x++) { 00309 if (*x == '^') 00310 *x = '|'; 00311 } 00312 /* Make formats okay */ 00313 xferchan->readformat = chan->readformat; 00314 xferchan->writeformat = chan->writeformat; 00315 ast_channel_masquerade(xferchan, chan); 00316 ast_parseable_goto(xferchan, goto_on_transfer); 00317 xferchan->_state = AST_STATE_UP; 00318 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00319 xferchan->_softhangup = 0; 00320 if ((f = ast_read(xferchan))) { 00321 ast_frfree(f); 00322 f = NULL; 00323 ast_pbx_start(xferchan); 00324 } else { 00325 ast_hangup(xferchan); 00326 } 00327 }
static struct ast_parkinglot* create_parkinglot | ( | char * | name | ) | [static] |
Allocate parking lot structure.
Definition at line 3422 of file features.c.
References ao2_alloc, ast_copy_string(), and parkinglot_destroy().
Referenced by build_parkinglot().
03423 { 03424 struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL; 03425 03426 if (!name) 03427 return NULL; 03428 03429 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 03430 if (!newlot) 03431 return NULL; 03432 03433 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 03434 03435 return newlot; 03436 }
static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 220 of file features.c.
References ast_free.
00221 { 00222 struct ast_dial_features *df = data; 00223 if (df) { 00224 ast_free(df); 00225 } 00226 }
static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 207 of file features.c.
References ast_calloc.
00208 { 00209 struct ast_dial_features *df = data, *df_copy; 00210 00211 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00212 return NULL; 00213 } 00214 00215 memcpy(df_copy, df, sizeof(*df)); 00216 00217 return df_copy; 00218 }
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 4016 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().
04017 { 04018 ast_moh_stop(chan); 04019 ast_channel_lock(chan); 04020 ast_setstate(tmpchan, chan->_state); 04021 tmpchan->readformat = chan->readformat; 04022 tmpchan->writeformat = chan->writeformat; 04023 ast_channel_masquerade(tmpchan, chan); 04024 ast_channel_lock(tmpchan); 04025 ast_do_masquerade(tmpchan); 04026 /* when returning from bridge, the channel will continue at the next priority */ 04027 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 04028 ast_channel_unlock(tmpchan); 04029 ast_channel_unlock(chan); 04030 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
ignore | unused var. |
Definition at line 3090 of file features.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_samp2tv(), ast_select(), manage_parkinglot(), and parkinglots.
Referenced by ast_features_init().
03091 { 03092 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 03093 fd_set nrfds, nefds; /* args for the next select */ 03094 FD_ZERO(&rfds); 03095 FD_ZERO(&efds); 03096 03097 for (;;) { 03098 int res = 0; 03099 int ms = -1; /* select timeout, uninitialized */ 03100 int max = -1; /* max fd, none there yet */ 03101 struct ao2_iterator iter; 03102 struct ast_parkinglot *curlot; 03103 FD_ZERO(&nrfds); 03104 FD_ZERO(&nefds); 03105 iter = ao2_iterator_init(parkinglots, 0); 03106 03107 while ((curlot = ao2_iterator_next(&iter))) { 03108 res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max); 03109 ao2_ref(curlot, -1); 03110 } 03111 03112 rfds = nrfds; 03113 efds = nefds; 03114 { 03115 struct timeval wait = ast_samp2tv(ms, 1000); 03116 /* Wait for something to happen */ 03117 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL); 03118 } 03119 pthread_testcancel(); 03120 } 03121 return NULL; /* Never reached */ 03122 }
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 |
AST_FEATURE_RETURN_NO_HANGUP_PEER | ||
-1 | error. | |
-2 | when an application cannot be found. |
Definition at line 1814 of file features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, chan, feature_group_exten::feature, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().
01815 { 01816 struct ast_app *app; 01817 struct ast_call_feature *feature = data; 01818 struct ast_channel *work, *idle; 01819 int res; 01820 01821 if (!feature) { /* shouldn't ever happen! */ 01822 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01823 return -1; 01824 } 01825 01826 if (sense == FEATURE_SENSE_CHAN) { 01827 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01828 return AST_FEATURE_RETURN_KEEPTRYING; 01829 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01830 work = chan; 01831 idle = peer; 01832 } else { 01833 work = peer; 01834 idle = chan; 01835 } 01836 } else { 01837 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01838 return AST_FEATURE_RETURN_KEEPTRYING; 01839 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01840 work = peer; 01841 idle = chan; 01842 } else { 01843 work = chan; 01844 idle = peer; 01845 } 01846 } 01847 01848 if (!(app = pbx_findapp(feature->app))) { 01849 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01850 return -2; 01851 } 01852 01853 ast_autoservice_start(idle); 01854 01855 if (!ast_strlen_zero(feature->moh_class)) 01856 ast_moh_start(idle, feature->moh_class, NULL); 01857 01858 res = pbx_exec(work, app, feature->app_args); 01859 01860 if (!ast_strlen_zero(feature->moh_class)) 01861 ast_moh_stop(idle); 01862 01863 ast_autoservice_stop(idle); 01864 01865 if (res) { 01866 return AST_FEATURE_RETURN_SUCCESSBREAK; 01867 } 01868 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01869 }
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 1909 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().
01912 { 01913 int x; 01914 struct feature_group *fg = NULL; 01915 struct feature_group_exten *fge; 01916 struct ast_call_feature *tmpfeature; 01917 char *tmp, *tok; 01918 int res = AST_FEATURE_RETURN_PASSDIGITS; 01919 int feature_detected = 0; 01920 01921 if (!(peer && chan && config) && operation) { 01922 return -1; /* can not run feature operation */ 01923 } 01924 01925 ast_rwlock_rdlock(&features_lock); 01926 for (x = 0; x < FEATURES_COUNT; x++) { 01927 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 01928 !ast_strlen_zero(builtin_features[x].exten)) { 01929 /* Feature is up for consideration */ 01930 if (!strcmp(builtin_features[x].exten, code)) { 01931 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 01932 if (operation) { 01933 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01934 } 01935 memcpy(feature, &builtin_features[x], sizeof(feature)); 01936 feature_detected = 1; 01937 break; 01938 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01939 if (res == AST_FEATURE_RETURN_PASSDIGITS) 01940 res = AST_FEATURE_RETURN_STOREDIGITS; 01941 } 01942 } 01943 } 01944 ast_rwlock_unlock(&features_lock); 01945 01946 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 01947 return res; 01948 } 01949 01950 tmp = dynamic_features_buf; 01951 01952 while ((tok = strsep(&tmp, "#"))) { 01953 AST_RWLIST_RDLOCK(&feature_groups); 01954 01955 fg = find_group(tok); 01956 01957 if (fg) { 01958 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 01959 if (strcasecmp(fge->exten, code)) 01960 continue; 01961 if (operation) { 01962 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 01963 } 01964 memcpy(feature, fge->feature, sizeof(feature)); 01965 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 01966 AST_RWLIST_UNLOCK(&feature_groups); 01967 break; 01968 } 01969 res = AST_FEATURE_RETURN_PASSDIGITS; 01970 } 01971 if (fge) 01972 break; 01973 } 01974 01975 AST_RWLIST_UNLOCK(&feature_groups); 01976 01977 AST_RWLIST_RDLOCK(&feature_list); 01978 01979 if (!(tmpfeature = find_dynamic_feature(tok))) { 01980 AST_RWLIST_UNLOCK(&feature_list); 01981 continue; 01982 } 01983 01984 /* Feature is up for consideration */ 01985 if (!strcmp(tmpfeature->exten, code)) { 01986 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 01987 if (operation) { 01988 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 01989 } 01990 memcpy(feature, tmpfeature, sizeof(feature)); 01991 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 01992 AST_RWLIST_UNLOCK(&feature_list); 01993 break; 01994 } 01995 res = AST_FEATURE_RETURN_PASSDIGITS; 01996 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 01997 res = AST_FEATURE_RETURN_STOREDIGITS; 01998 01999 AST_RWLIST_UNLOCK(&feature_list); 02000 } 02001 02002 return res; 02003 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a call feature by name
Definition at line 1736 of file features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by feature_interpret_helper(), and set_config_flags().
01737 { 01738 struct ast_call_feature *tmp; 01739 01740 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01741 if (!strcasecmp(tmp->sname, name)) { 01742 break; 01743 } 01744 } 01745 01746 return tmp; 01747 }
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 1774 of file features.c.
References AST_LIST_TRAVERSE, feature_group_exten::entry, and feature_group::gname.
Referenced by feature_interpret_helper().
01774 { 01775 struct feature_group *fg = NULL; 01776 01777 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 01778 if (!strcasecmp(fg->gname, name)) 01779 break; 01780 } 01781 01782 return fg; 01783 }
struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) |
Find parkinglot by name.
Definition at line 3125 of file features.c.
References ao2_find, ast_copy_string(), ast_log(), ast_strlen_zero(), LOG_DEBUG, ast_parkinglot::name, OBJ_POINTER, option_debug, parkinglot, and parkinglots.
Referenced by build_parkinglot(), park_exec_full(), and park_space_reserve().
03126 { 03127 struct ast_parkinglot *parkinglot = NULL; 03128 struct ast_parkinglot tmp_parkinglot; 03129 03130 if (ast_strlen_zero(name)) 03131 return NULL; 03132 03133 ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name)); 03134 03135 parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER); 03136 03137 if (parkinglot && option_debug) 03138 ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name); 03139 03140 return parkinglot; 03141 }
static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 420 of file features.c.
References ast_strlen_zero(), chan, ast_channel::parkinglot, parkinglot, and pbx_builtin_getvar_helper().
Referenced by park_exec_full(), and park_space_reserve().
00421 { 00422 const char *temp, *parkinglot = NULL; 00423 00424 /* Check if the channel has a parking lot */ 00425 if (!ast_strlen_zero(chan->parkinglot)) 00426 parkinglot = chan->parkinglot; 00427 00428 /* Channel variables override everything */ 00429 00430 if ((temp = pbx_builtin_getvar_helper(chan, "PARKINGLOT"))) 00431 return temp; 00432 00433 return parkinglot; 00434 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1132 of file features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, ast_indicate(), and chan.
Referenced by builtin_atxfer(), and builtin_blindtransfer().
01133 { 01134 ast_indicate(chan, AST_CONTROL_UNHOLD); 01135 01136 return ast_autoservice_stop(chan); 01137 }
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 3909 of file features.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), builtin_features, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, ast_call_feature::exten, ast_cli_args::fd, FEATURES_COUNT, features_lock, ast_call_feature::fname, HFS_FORMAT, ast_parkinglot::name, ast_parkinglot::parking_con, parking_ext, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglots, ast_call_feature::sname, and ast_cli_entry::usage.
03910 { 03911 int i; 03912 struct ast_call_feature *feature; 03913 struct ao2_iterator iter; 03914 struct ast_parkinglot *curlot; 03915 #define HFS_FORMAT "%-25s %-7s %-7s\n" 03916 03917 switch (cmd) { 03918 03919 case CLI_INIT: 03920 e->command = "features show"; 03921 e->usage = 03922 "Usage: features show\n" 03923 " Lists configured features\n"; 03924 return NULL; 03925 case CLI_GENERATE: 03926 return NULL; 03927 } 03928 03929 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 03930 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 03931 03932 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 03933 03934 ast_rwlock_rdlock(&features_lock); 03935 for (i = 0; i < FEATURES_COUNT; i++) 03936 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 03937 ast_rwlock_unlock(&features_lock); 03938 03939 ast_cli(a->fd, "\n"); 03940 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 03941 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 03942 if (AST_RWLIST_EMPTY(&feature_list)) { 03943 ast_cli(a->fd, "(none)\n"); 03944 } else { 03945 AST_RWLIST_RDLOCK(&feature_list); 03946 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 03947 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 03948 } 03949 AST_RWLIST_UNLOCK(&feature_list); 03950 } 03951 03952 // loop through all the parking lots 03953 iter = ao2_iterator_init(parkinglots, 0); 03954 03955 while ((curlot = ao2_iterator_next(&iter))) { 03956 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 03957 ast_cli(a->fd, "------------\n"); 03958 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", parking_ext); 03959 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->parking_con); 03960 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop); 03961 ast_cli(a->fd,"\n"); 03962 ao2_ref(curlot, -1); 03963 } 03964 03965 03966 return CLI_SUCCESS; 03967 }
static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 3983 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
03984 { 03985 switch (cmd) { 03986 case CLI_INIT: 03987 e->command = "features reload"; 03988 e->usage = 03989 "Usage: features reload\n" 03990 " Reloads configured call features from features.conf\n"; 03991 return NULL; 03992 case CLI_GENERATE: 03993 return NULL; 03994 } 03995 ast_features_reload(); 03996 03997 return CLI_SUCCESS; 03998 }
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 4166 of file features.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_entry::args, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, parkeduser::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, parkeduser::context, ESS, parkeduser::exten, ast_cli_args::fd, ast_channel::name, ast_parkinglot::name, parkeduser::parkingexten, parkinglots, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.
04167 { 04168 struct parkeduser *cur; 04169 int numparked = 0; 04170 struct ao2_iterator iter; 04171 struct ast_parkinglot *curlot; 04172 04173 switch (cmd) { 04174 case CLI_INIT: 04175 e->command = "parkedcalls show"; 04176 e->usage = 04177 "Usage: parkedcalls show\n" 04178 " List currently parked calls\n"; 04179 return NULL; 04180 case CLI_GENERATE: 04181 return NULL; 04182 } 04183 04184 if (a->argc > e->args) 04185 return CLI_SHOWUSAGE; 04186 04187 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 04188 , "Context", "Extension", "Pri", "Timeout"); 04189 04190 iter = ao2_iterator_init(parkinglots, 0); 04191 while ((curlot = ao2_iterator_next(&iter))) { 04192 int lotparked = 0; 04193 ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name); 04194 04195 AST_LIST_LOCK(&curlot->parkings); 04196 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 04197 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 04198 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 04199 ,cur->priority, 04200 (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) ); 04201 numparked++; 04202 numparked += lotparked; 04203 } 04204 AST_LIST_UNLOCK(&curlot->parkings); 04205 if (lotparked) 04206 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name); 04207 04208 ao2_ref(curlot, -1); 04209 } 04210 04211 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 04212 04213 return CLI_SUCCESS; 04214 }
static int load_config | ( | void | ) | [static] |
Definition at line 3568 of file features.c.
References adsipark, ao2_lock(), ao2_unlock(), ast_config_load2(), ast_copy_string(), ast_log(), ast_variable_browse(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, config_flags, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_TIME, DEFAULT_PARKINGLOT, default_parkinglot, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_DEBUG, LOG_ERROR, LOG_WARNING, option_debug, ast_parkinglot::parkaddhints, ast_parkinglot::parkedcallhangup, ast_parkinglot::parkedcallrecording, ast_parkinglot::parkedcallreparking, ast_parkinglot::parkedcalltransfers, ast_parkinglot::parking_con, parking_ext, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.
Referenced by ast_features_init(), ast_features_reload(), handle_voicemail_reload(), load_module(), and reload().
03569 { 03570 int start = 0, end = 0; 03571 int res; 03572 int i; 03573 struct ast_context *con = NULL; 03574 struct ast_config *cfg = NULL; 03575 struct ast_variable *var = NULL; 03576 struct feature_group *fg = NULL; 03577 struct ast_flags config_flags = { 0 }; 03578 char old_parking_ext[AST_MAX_EXTENSION]; 03579 char old_parking_con[AST_MAX_EXTENSION] = ""; 03580 char *ctg; 03581 static const char *categories[] = { 03582 /* Categories in features.conf that are not 03583 * to be parsed as group categories 03584 */ 03585 "general", 03586 "featuremap", 03587 "applicationmap" 03588 }; 03589 03590 if (default_parkinglot) { 03591 strcpy(old_parking_con, default_parkinglot->parking_con); 03592 strcpy(old_parking_ext, parking_ext); 03593 } else { 03594 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 03595 if (default_parkinglot) { 03596 ao2_lock(default_parkinglot); 03597 default_parkinglot->parking_start = 701; 03598 default_parkinglot->parking_stop = 750; 03599 default_parkinglot->parking_offset = 0; 03600 default_parkinglot->parkfindnext = 0; 03601 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 03602 ao2_unlock(default_parkinglot); 03603 } 03604 } 03605 if (default_parkinglot) { 03606 if (option_debug) 03607 ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n"); 03608 } else { 03609 ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n"); 03610 return -1; 03611 } 03612 03613 03614 /* Reset to defaults */ 03615 strcpy(parking_ext, "700"); 03616 strcpy(pickup_ext, "*8"); 03617 courtesytone[0] = '\0'; 03618 strcpy(xfersound, "beep"); 03619 strcpy(xferfailsound, "pbx-invalid"); 03620 adsipark = 0; 03621 comebacktoorigin = 1; 03622 03623 default_parkinglot->parkaddhints = 0; 03624 default_parkinglot->parkedcalltransfers = 0; 03625 default_parkinglot->parkedcallreparking = 0; 03626 default_parkinglot->parkedcallrecording = 0; 03627 default_parkinglot->parkedcallhangup = 0; 03628 03629 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03630 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03631 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03632 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 03633 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 03634 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 03635 03636 cfg = ast_config_load2("features.conf", "features", config_flags); 03637 if (!cfg) { 03638 ast_log(LOG_WARNING,"Could not load features.conf\n"); 03639 return 0; 03640 } 03641 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 03642 if (!strcasecmp(var->name, "parkext")) { 03643 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 03644 } else if (!strcasecmp(var->name, "context")) { 03645 ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con)); 03646 } else if (!strcasecmp(var->name, "parkingtime")) { 03647 if ((sscanf(var->value, "%d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) { 03648 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 03649 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 03650 } else 03651 default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000; 03652 } else if (!strcasecmp(var->name, "parkpos")) { 03653 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 03654 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); 03655 } else if (default_parkinglot) { 03656 default_parkinglot->parking_start = start; 03657 default_parkinglot->parking_stop = end; 03658 } else { 03659 ast_log(LOG_WARNING, "No default parking lot!\n"); 03660 } 03661 } else if (!strcasecmp(var->name, "findslot")) { 03662 default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next")); 03663 } else if (!strcasecmp(var->name, "parkinghints")) { 03664 default_parkinglot->parkaddhints = ast_true(var->value); 03665 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 03666 if (!strcasecmp(var->value, "both")) 03667 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 03668 else if (!strcasecmp(var->value, "caller")) 03669 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 03670 else if (!strcasecmp(var->value, "callee")) 03671 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 03672 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 03673 if (!strcasecmp(var->value, "both")) 03674 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 03675 else if (!strcasecmp(var->value, "caller")) 03676 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 03677 else if (!strcasecmp(var->value, "callee")) 03678 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 03679 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 03680 if (!strcasecmp(var->value, "both")) 03681 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 03682 else if (!strcasecmp(var->value, "caller")) 03683 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 03684 else if (!strcasecmp(var->value, "callee")) 03685 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 03686 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 03687 if (!strcasecmp(var->value, "both")) 03688 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 03689 else if (!strcasecmp(var->value, "caller")) 03690 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 03691 else if (!strcasecmp(var->value, "callee")) 03692 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 03693 } else if (!strcasecmp(var->name, "adsipark")) { 03694 adsipark = ast_true(var->value); 03695 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03696 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03697 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03698 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03699 } else 03700 transferdigittimeout = transferdigittimeout * 1000; 03701 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03702 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03703 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03704 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03705 } 03706 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03707 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03708 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03709 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03710 } else 03711 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03712 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 03713 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) { 03714 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 03715 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 03716 } else 03717 atxferloopdelay *= 1000; 03718 } else if (!strcasecmp(var->name, "atxferdropcall")) { 03719 atxferdropcall = ast_true(var->value); 03720 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 03721 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) { 03722 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 03723 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 03724 } 03725 } else if (!strcasecmp(var->name, "courtesytone")) { 03726 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03727 } else if (!strcasecmp(var->name, "parkedplay")) { 03728 if (!strcasecmp(var->value, "both")) 03729 parkedplay = 2; 03730 else if (!strcasecmp(var->value, "parked")) 03731 parkedplay = 1; 03732 else 03733 parkedplay = 0; 03734 } else if (!strcasecmp(var->name, "xfersound")) { 03735 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03736 } else if (!strcasecmp(var->name, "xferfailsound")) { 03737 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03738 } else if (!strcasecmp(var->name, "pickupexten")) { 03739 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03740 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 03741 comebacktoorigin = ast_true(var->value); 03742 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03743 ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass)); 03744 } 03745 } 03746 03747 unmap_features(); 03748 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03749 if (remap_feature(var->name, var->value)) 03750 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03751 } 03752 03753 /* Map a key combination to an application*/ 03754 ast_unregister_features(); 03755 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03756 char *tmp_val = ast_strdupa(var->value); 03757 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 03758 struct ast_call_feature *feature; 03759 03760 /* strsep() sets the argument to NULL if match not found, and it 03761 * is safe to use it with a NULL argument, so we don't check 03762 * between calls. 03763 */ 03764 exten = strsep(&tmp_val,","); 03765 activatedby = strsep(&tmp_val,","); 03766 app = strsep(&tmp_val,","); 03767 app_args = strsep(&tmp_val,","); 03768 moh_class = strsep(&tmp_val,","); 03769 03770 activateon = strsep(&activatedby, "/"); 03771 03772 /*! \todo XXX var_name or app_args ? */ 03773 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03774 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03775 app, exten, activateon, var->name); 03776 continue; 03777 } 03778 03779 AST_RWLIST_RDLOCK(&feature_list); 03780 if ((feature = find_dynamic_feature(var->name))) { 03781 AST_RWLIST_UNLOCK(&feature_list); 03782 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03783 continue; 03784 } 03785 AST_RWLIST_UNLOCK(&feature_list); 03786 03787 if (!(feature = ast_calloc(1, sizeof(*feature)))) 03788 continue; 03789 03790 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03791 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 03792 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 03793 03794 if (app_args) 03795 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 03796 03797 if (moh_class) 03798 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 03799 03800 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 03801 feature->operation = feature_exec_app; 03802 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03803 03804 /* Allow caller and calle to be specified for backwards compatability */ 03805 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03806 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03807 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03808 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03809 else { 03810 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03811 " must be 'self', or 'peer'\n", var->name); 03812 continue; 03813 } 03814 03815 if (ast_strlen_zero(activatedby)) 03816 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03817 else if (!strcasecmp(activatedby, "caller")) 03818 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03819 else if (!strcasecmp(activatedby, "callee")) 03820 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03821 else if (!strcasecmp(activatedby, "both")) 03822 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03823 else { 03824 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03825 " must be 'caller', or 'callee', or 'both'\n", var->name); 03826 continue; 03827 } 03828 03829 ast_register_feature(feature); 03830 03831 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 03832 } 03833 03834 ast_unregister_groups(); 03835 AST_RWLIST_WRLOCK(&feature_groups); 03836 03837 ctg = NULL; 03838 while ((ctg = ast_category_browse(cfg, ctg))) { 03839 /* Is this a parkinglot definition ? */ 03840 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 03841 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 03842 if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) 03843 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 03844 else 03845 ast_debug(1, "Configured parking context %s\n", ctg); 03846 continue; 03847 } 03848 /* No, check if it's a group */ 03849 for (i = 0; i < ARRAY_LEN(categories); i++) { 03850 if (!strcasecmp(categories[i], ctg)) 03851 break; 03852 } 03853 03854 if (i < ARRAY_LEN(categories)) 03855 continue; 03856 03857 if (!(fg = register_group(ctg))) 03858 continue; 03859 03860 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 03861 struct ast_call_feature *feature; 03862 03863 AST_RWLIST_RDLOCK(&feature_list); 03864 if (!(feature = find_dynamic_feature(var->name)) && 03865 !(feature = ast_find_call_feature(var->name))) { 03866 AST_RWLIST_UNLOCK(&feature_list); 03867 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 03868 continue; 03869 } 03870 AST_RWLIST_UNLOCK(&feature_list); 03871 03872 register_group_feature(fg, var->value, feature); 03873 } 03874 } 03875 03876 AST_RWLIST_UNLOCK(&feature_groups); 03877 03878 ast_config_destroy(cfg); 03879 03880 /* Remove the old parking extension */ 03881 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03882 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0)) 03883 notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE); 03884 ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03885 } 03886 03887 if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) { 03888 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con); 03889 return -1; 03890 } 03891 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 03892 if (default_parkinglot->parkaddhints) 03893 park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop); 03894 if (!res) 03895 notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE); 03896 return res; 03897 03898 }
int manage_parkinglot | ( | struct ast_parkinglot * | curlot, | |
fd_set * | rfds, | |||
fd_set * | efds, | |||
fd_set * | nrfds, | |||
fd_set * | nefds, | |||
int * | fs, | |||
int * | max | |||
) |
Run management on parkinglots, called once per parkinglot.
Definition at line 2915 of file features.c.
References ast_add_extension2(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, ast_log(), AST_MAX_FDS, ast_pbx_start(), ast_read(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, buf, callback_dialoptions(), parkeduser::chan, chan, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, free, parkeduser::list, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), and parkeduser::start.
Referenced by do_parking_thread().
02916 { 02917 02918 struct parkeduser *pu; 02919 int res = 0; 02920 char parkingslot[AST_MAX_EXTENSION]; 02921 02922 /* Lock parking list */ 02923 AST_LIST_LOCK(&curlot->parkings); 02924 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 02925 struct ast_channel *chan = pu->chan; /* shorthand */ 02926 int tms; /* timeout for this item */ 02927 int x; /* fd index in channel */ 02928 struct ast_context *con; 02929 02930 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 02931 continue; 02932 } 02933 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 02934 if (tms > pu->parkingtime) { 02935 /* Stop music on hold */ 02936 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 02937 /* Get chan, exten from derived kludge */ 02938 if (pu->peername[0]) { 02939 char *peername = ast_strdupa(pu->peername); 02940 char *cp = strrchr(peername, '-'); 02941 char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 02942 int i; 02943 02944 if (cp) 02945 *cp = 0; 02946 ast_copy_string(peername_flat,peername,sizeof(peername_flat)); 02947 for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) { 02948 if (peername_flat[i] == '/') 02949 peername_flat[i]= '0'; 02950 } 02951 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar); 02952 if (!con) { 02953 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial); 02954 } 02955 if (con) { 02956 char returnexten[AST_MAX_EXTENSION]; 02957 struct ast_datastore *features_datastore; 02958 struct ast_dial_features *dialfeatures = NULL; 02959 02960 ast_channel_lock(chan); 02961 02962 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 02963 dialfeatures = features_datastore->data; 02964 02965 ast_channel_unlock(chan); 02966 02967 if (!strncmp(peername, "Parked/", 7)) { 02968 peername += 7; 02969 } 02970 02971 if (dialfeatures) { 02972 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 02973 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 02974 } else { /* Existing default */ 02975 ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name); 02976 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername); 02977 } 02978 02979 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar); 02980 } 02981 if (comebacktoorigin) { 02982 set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1); 02983 } else { 02984 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum); 02985 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 02986 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 02987 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 02988 } 02989 } else { 02990 /* They've been waiting too long, send them back to where they came. Theoretically they 02991 should have their original extensions and such, but we copy to be on the safe side */ 02992 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 02993 } 02994 post_manager_event("ParkedCallTimeOut", pu); 02995 02996 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, pu->chan->exten, pu->chan->priority); 02997 /* Start up the PBX, or hang them up */ 02998 if (ast_pbx_start(chan)) { 02999 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name); 03000 ast_hangup(chan); 03001 } 03002 /* And take them out of the parking lot */ 03003 con = ast_context_find(pu->parkinglot->parking_con); 03004 if (con) { 03005 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03006 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n"); 03007 else 03008 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 03009 } else 03010 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 03011 AST_LIST_REMOVE_CURRENT(list); 03012 free(pu); 03013 } else { /* still within parking time, process descriptors */ 03014 for (x = 0; x < AST_MAX_FDS; x++) { 03015 struct ast_frame *f; 03016 03017 if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds))) 03018 continue; 03019 03020 if (FD_ISSET(chan->fds[x], efds)) 03021 ast_set_flag(chan, AST_FLAG_EXCEPTION); 03022 else 03023 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 03024 chan->fdno = x; 03025 03026 /* See if they need servicing */ 03027 f = ast_read(pu->chan); 03028 /* Hangup? */ 03029 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 03030 if (f) 03031 ast_frfree(f); 03032 post_manager_event("ParkedCallGiveUp", pu); 03033 03034 /* There's a problem, hang them up*/ 03035 ast_verb(2, "%s got tired of being parked\n", chan->name); 03036 ast_hangup(chan); 03037 /* And take them out of the parking lot */ 03038 con = ast_context_find(curlot->parking_con); 03039 if (con) { 03040 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03041 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 03042 else 03043 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 03044 } else 03045 ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name); 03046 AST_LIST_REMOVE_CURRENT(list); 03047 free(pu); 03048 break; 03049 } else { 03050 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 03051 ast_frfree(f); 03052 if (pu->moh_trys < 3 && !chan->generatordata) { 03053 ast_debug(1, "MOH on parked call stopped by outside source. Restarting on channel %s.\n", chan->name); 03054 ast_indicate_data(chan, AST_CONTROL_HOLD, 03055 S_OR(curlot->mohclass, NULL), 03056 (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0)); 03057 pu->moh_trys++; 03058 } 03059 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 03060 } 03061 } /* End for */ 03062 if (x >= AST_MAX_FDS) { 03063 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 03064 if (chan->fds[x] > -1) { 03065 FD_SET(chan->fds[x], nrfds); 03066 FD_SET(chan->fds[x], nefds); 03067 if (chan->fds[x] > *max) 03068 *max = chan->fds[x]; 03069 } 03070 } 03071 /* Keep track of our shortest wait */ 03072 if (tms < *ms || *ms < 0) 03073 *ms = tms; 03074 } 03075 } 03076 } 03077 AST_LIST_TRAVERSE_SAFE_END; 03078 AST_LIST_UNLOCK(&curlot->parkings); 03079 return res; 03080 }
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 4291 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().
04292 { 04293 const char *channel = astman_get_header(m, "Channel"); 04294 const char *channel2 = astman_get_header(m, "Channel2"); 04295 const char *timeout = astman_get_header(m, "Timeout"); 04296 char buf[BUFSIZ]; 04297 int to = 0; 04298 int res = 0; 04299 int parkExt = 0; 04300 struct ast_channel *ch1, *ch2; 04301 04302 if (ast_strlen_zero(channel)) { 04303 astman_send_error(s, m, "Channel not specified"); 04304 return 0; 04305 } 04306 04307 if (ast_strlen_zero(channel2)) { 04308 astman_send_error(s, m, "Channel2 not specified"); 04309 return 0; 04310 } 04311 04312 ch1 = ast_get_channel_by_name_locked(channel); 04313 if (!ch1) { 04314 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 04315 astman_send_error(s, m, buf); 04316 return 0; 04317 } 04318 04319 ch2 = ast_get_channel_by_name_locked(channel2); 04320 if (!ch2) { 04321 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 04322 astman_send_error(s, m, buf); 04323 ast_channel_unlock(ch1); 04324 return 0; 04325 } 04326 04327 if (!ast_strlen_zero(timeout)) { 04328 sscanf(timeout, "%d", &to); 04329 } 04330 04331 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 04332 if (!res) { 04333 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 04334 astman_send_ack(s, m, "Park successful"); 04335 } else { 04336 astman_send_error(s, m, "Park failure"); 04337 } 04338 04339 ast_channel_unlock(ch1); 04340 ast_channel_unlock(ch2); 04341 04342 return 0; 04343 }
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 4230 of file features.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::name, parkinglots, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.
Referenced by ast_features_init().
04231 { 04232 struct parkeduser *cur; 04233 const char *id = astman_get_header(m, "ActionID"); 04234 char idText[256] = ""; 04235 struct ao2_iterator iter; 04236 struct ast_parkinglot *curlot; 04237 04238 if (!ast_strlen_zero(id)) 04239 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 04240 04241 astman_send_ack(s, m, "Parked calls will follow"); 04242 04243 iter = ao2_iterator_init(parkinglots, 0); 04244 while ((curlot = ao2_iterator_next(&iter))) { 04245 04246 AST_LIST_LOCK(&curlot->parkings); 04247 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 04248 astman_append(s, "Event: ParkedCall\r\n" 04249 "Exten: %d\r\n" 04250 "Channel: %s\r\n" 04251 "From: %s\r\n" 04252 "Timeout: %ld\r\n" 04253 "CallerIDNum: %s\r\n" 04254 "CallerIDName: %s\r\n" 04255 "%s" 04256 "\r\n", 04257 cur->parkingnum, cur->chan->name, cur->peername, 04258 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 04259 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 04260 S_OR(cur->chan->cid.cid_name, ""), 04261 idText); 04262 } 04263 AST_LIST_UNLOCK(&curlot->parkings); 04264 ao2_ref(curlot, -1); 04265 } 04266 04267 astman_append(s, 04268 "Event: ParkedCallsComplete\r\n" 04269 "%s" 04270 "\r\n",idText); 04271 04272 04273 return RESULT_SUCCESS; 04274 }
static int masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
int | play_announcement, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 752 of file features.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), AST_FEATURE_RETURN_PARKFAILED, ast_frfree, ast_hangup(), ast_log(), ast_park_call_full(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), chan, ast_channel::context, ast_channel::exten, ast_park_call_args::extout, f, LOG_WARNING, ast_channel::name, ast_park_call_args::orig_chan_name, park_space_reserve(), ast_channel::priority, ast_park_call_args::pu, ast_channel::readformat, set_c_e_p(), ast_park_call_args::timeout, and ast_channel::writeformat.
Referenced by ast_masq_park_call(), masq_park_call_announce(), and masq_park_call_announce_args().
00753 { 00754 struct ast_channel *chan; 00755 struct ast_frame *f; 00756 int park_status; 00757 struct ast_park_call_args park_args = {0,}; 00758 00759 if (!args) { 00760 args = &park_args; 00761 args->timeout = timeout; 00762 args->extout = extout; 00763 } 00764 00765 if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) { 00766 if (peer) 00767 ast_stream_and_wait(peer, "beeperr", ""); 00768 return AST_FEATURE_RETURN_PARKFAILED; 00769 } 00770 00771 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00772 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00773 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00774 return -1; 00775 } 00776 00777 /* Make formats okay */ 00778 chan->readformat = rchan->readformat; 00779 chan->writeformat = rchan->writeformat; 00780 ast_channel_masquerade(chan, rchan); 00781 00782 /* Setup the extensions and such */ 00783 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00784 00785 /* Make the masq execute */ 00786 if ((f = ast_read(chan))) 00787 ast_frfree(f); 00788 00789 if (peer == rchan) { 00790 peer = chan; 00791 } 00792 00793 if (!play_announcement && args == &park_args) { 00794 args->orig_chan_name = ast_strdupa(chan->name); 00795 } 00796 00797 park_status = ast_park_call_full(chan, peer, args); 00798 if (park_status == 1) { 00799 /* would be nice to play "invalid parking extension" */ 00800 ast_hangup(chan); 00801 return -1; 00802 } 00803 00804 return 0; 00805 }
static int masq_park_call_announce | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout | |||
) | [static] |
Definition at line 818 of file features.c.
References masq_park_call().
Referenced by builtin_blindtransfer(), and builtin_parkcall().
00819 { 00820 return masq_park_call(rchan, peer, timeout, extout, 1, NULL); 00821 }
static int masq_park_call_announce_args | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 813 of file features.c.
References masq_park_call().
Referenced by park_call_exec().
00814 { 00815 return masq_park_call(rchan, peer, 0, NULL, 1, args); 00816 }
static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 446 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().
00447 { 00448 char *context; 00449 char *exten; 00450 00451 context = ast_strdupa(data); 00452 00453 exten = strsep(&context, "@"); 00454 if (!context) 00455 return AST_DEVICE_INVALID; 00456 00457 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 00458 00459 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 00460 return AST_DEVICE_NOT_INUSE; 00461 00462 return AST_DEVICE_INUSE; 00463 }
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 437 of file features.c.
References ast_debug, ast_devstate_changed(), and devstate2str().
Referenced by ast_park_call_full(), manage_parkinglot(), and park_exec_full().
00438 { 00439 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 00440 exten, context, devstate2str(state)); 00441 00442 ast_devstate_changed(state, "park:%s@%s", exten, context); 00443 }
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 3555 of file features.c.
References ast_add_extension(), PRIORITY_HINT, and registrar.
03556 { 03557 int numext; 03558 char device[AST_MAX_EXTENSION]; 03559 char exten[10]; 03560 03561 for (numext = start; numext <= stop; numext++) { 03562 snprintf(exten, sizeof(exten), "%d", numext); 03563 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 03564 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 03565 } 03566 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 3150 of file features.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), chan, ast_channel::exten, ast_park_call_args::flags, ast_flags::flags, LOG_WARNING, masq_park_call_announce_args(), ast_channel::name, ast_park_call_args::orig_chan_name, orig_exten(), park_call_options, parse(), ast_channel::priority, ast_park_call_args::return_con, ast_park_call_args::return_ext, ast_park_call_args::return_pri, and ast_park_call_args::timeout.
Referenced by ast_features_init().
03151 { 03152 /* Cache the original channel name in case we get masqueraded in the middle 03153 * of a park--it is still theoretically possible for a transfer to happen before 03154 * we get here, but it is _really_ unlikely */ 03155 char *orig_chan_name = ast_strdupa(chan->name); 03156 char orig_exten[AST_MAX_EXTENSION]; 03157 int orig_priority = chan->priority; 03158 03159 /* Data is unused at the moment but could contain a parking 03160 lot context eventually */ 03161 int res = 0; 03162 03163 char *parse = NULL; 03164 AST_DECLARE_APP_ARGS(app_args, 03165 AST_APP_ARG(timeout); 03166 AST_APP_ARG(return_con); 03167 AST_APP_ARG(return_ext); 03168 AST_APP_ARG(return_pri); 03169 AST_APP_ARG(options); 03170 ); 03171 03172 parse = ast_strdupa(data); 03173 AST_STANDARD_APP_ARGS(app_args, parse); 03174 03175 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 03176 03177 /* Setup the exten/priority to be s/1 since we don't know 03178 where this call should return */ 03179 strcpy(chan->exten, "s"); 03180 chan->priority = 1; 03181 03182 /* Answer if call is not up */ 03183 if (chan->_state != AST_STATE_UP) 03184 res = ast_answer(chan); 03185 03186 /* Sleep to allow VoIP streams to settle down */ 03187 if (!res) 03188 res = ast_safe_sleep(chan, 1000); 03189 03190 /* Park the call */ 03191 if (!res) { 03192 struct ast_park_call_args args = { 03193 .orig_chan_name = orig_chan_name, 03194 }; 03195 struct ast_flags flags = { 0 }; 03196 03197 if (parse) { 03198 if (!ast_strlen_zero(app_args.timeout)) { 03199 if (sscanf(app_args.timeout, "%d", &args.timeout) != 1) { 03200 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 03201 args.timeout = 0; 03202 } 03203 } 03204 if (!ast_strlen_zero(app_args.return_con)) { 03205 args.return_con = app_args.return_con; 03206 } 03207 if (!ast_strlen_zero(app_args.return_ext)) { 03208 args.return_ext = app_args.return_ext; 03209 } 03210 if (!ast_strlen_zero(app_args.return_pri)) { 03211 if (sscanf(app_args.return_pri, "%d", &args.return_pri) != 1) { 03212 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 03213 args.return_pri = 0; 03214 } 03215 } 03216 } 03217 03218 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 03219 args.flags = flags.flags; 03220 03221 res = masq_park_call_announce_args(chan, chan, &args); 03222 /* Continue on in the dialplan */ 03223 if (res == 1) { 03224 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 03225 chan->priority = orig_priority; 03226 res = 0; 03227 } else if (!res) { 03228 res = 1; 03229 } 03230 } 03231 03232 return res; 03233 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3399 of file features.c.
References chan, default_parkinglot, and park_exec_full().
Referenced by ast_features_init().
03400 { 03401 return park_exec_full(chan, data, default_parkinglot); 03402 }
static int park_exec_full | ( | struct ast_channel * | chan, | |
void * | data, | |||
struct ast_parkinglot * | parkinglot | |||
) | [static] |
Pickup parked call.
Definition at line 3236 of file features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, ast_copy_flags, AST_DEVICE_NOT_INUSE, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_free, ast_hangup(), ast_indicate(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), parkeduser::chan, chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, ast_datastore::data, default_parkinglot, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_callee, ast_dial_features::features_caller, find_parkinglot(), findparkinglotname(), ast_dial_features::is_caller, LOG_WARNING, manager_event, ast_channel::name, notify_metermaids(), parkedplay, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), and S_OR.
Referenced by park_exec().
03237 { 03238 int res = 0; 03239 struct ast_channel *peer=NULL; 03240 struct parkeduser *pu; 03241 struct ast_context *con; 03242 int park = 0; 03243 struct ast_bridge_config config; 03244 03245 if (data) 03246 park = atoi((char *)data); 03247 03248 parkinglot = find_parkinglot(findparkinglotname(chan)); 03249 if (!parkinglot) 03250 parkinglot = default_parkinglot; 03251 03252 AST_LIST_LOCK(&parkinglot->parkings); 03253 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 03254 if (!data || pu->parkingnum == park) { 03255 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 03256 AST_LIST_UNLOCK(&parkinglot->parkings); 03257 return -1; 03258 } 03259 AST_LIST_REMOVE_CURRENT(list); 03260 break; 03261 } 03262 } 03263 AST_LIST_TRAVERSE_SAFE_END; 03264 AST_LIST_UNLOCK(&parkinglot->parkings); 03265 03266 if (pu) { 03267 peer = pu->chan; 03268 con = ast_context_find(parkinglot->parking_con); 03269 if (con) { 03270 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03271 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 03272 else 03273 notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE); 03274 } else 03275 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 03276 03277 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 03278 "Exten: %s\r\n" 03279 "Channel: %s\r\n" 03280 "From: %s\r\n" 03281 "CallerIDNum: %s\r\n" 03282 "CallerIDName: %s\r\n", 03283 pu->parkingexten, pu->chan->name, chan->name, 03284 S_OR(pu->chan->cid.cid_num, "<unknown>"), 03285 S_OR(pu->chan->cid.cid_name, "<unknown>") 03286 ); 03287 03288 ast_free(pu); 03289 } 03290 /* JK02: it helps to answer the channel if not already up */ 03291 if (chan->_state != AST_STATE_UP) 03292 ast_answer(chan); 03293 03294 //XXX Why do we unlock here ? 03295 // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain 03296 //ASTOBJ_UNLOCK(parkinglot); 03297 03298 if (peer) { 03299 struct ast_datastore *features_datastore; 03300 struct ast_dial_features *dialfeatures = NULL; 03301 03302 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 03303 03304 if (!ast_strlen_zero(courtesytone)) { 03305 int error = 0; 03306 ast_indicate(peer, AST_CONTROL_UNHOLD); 03307 if (parkedplay == 0) { 03308 error = ast_stream_and_wait(chan, courtesytone, ""); 03309 } else if (parkedplay == 1) { 03310 error = ast_stream_and_wait(peer, courtesytone, ""); 03311 } else if (parkedplay == 2) { 03312 if (!ast_streamfile(chan, courtesytone, chan->language) && 03313 !ast_streamfile(peer, courtesytone, chan->language)) { 03314 /*! \todo XXX we would like to wait on both! */ 03315 res = ast_waitstream(chan, ""); 03316 if (res >= 0) 03317 res = ast_waitstream(peer, ""); 03318 if (res < 0) 03319 error = 1; 03320 } 03321 } 03322 if (error) { 03323 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 03324 ast_hangup(peer); 03325 return -1; 03326 } 03327 } else 03328 ast_indicate(peer, AST_CONTROL_UNHOLD); 03329 03330 res = ast_channel_make_compatible(chan, peer); 03331 if (res < 0) { 03332 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 03333 ast_hangup(peer); 03334 return -1; 03335 } 03336 /* This runs sorta backwards, since we give the incoming channel control, as if it 03337 were the person called. */ 03338 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park); 03339 03340 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03341 ast_cdr_setdestchan(chan->cdr, peer->name); 03342 memset(&config, 0, sizeof(struct ast_bridge_config)); 03343 03344 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 03345 ast_channel_lock(peer); 03346 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 03347 dialfeatures = features_datastore->data; 03348 } 03349 ast_channel_unlock(peer); 03350 03351 if (dialfeatures) { 03352 ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL); 03353 } 03354 03355 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03356 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 03357 } 03358 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03359 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 03360 } 03361 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03362 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 03363 } 03364 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03365 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 03366 } 03367 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03368 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 03369 } 03370 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03371 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 03372 } 03373 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03374 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 03375 } 03376 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03377 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 03378 } 03379 03380 res = ast_bridge_call(chan, peer, &config); 03381 03382 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03383 ast_cdr_setdestchan(chan->cdr, peer->name); 03384 03385 /* Simulate the PBX hanging up */ 03386 ast_hangup(peer); 03387 return res; 03388 } else { 03389 /*! \todo XXX Play a message XXX */ 03390 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) 03391 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 03392 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 03393 res = -1; 03394 } 03395 03396 return res; 03397 }
static struct parkeduser* park_space_reserve | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 493 of file features.c.
References ast_calloc, ast_exists_extension(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strlen_zero(), ast_test_flag, chan, default_parkinglot, find_parkinglot(), findparkinglotname(), free, parkeduser::list, LOG_DEBUG, LOG_WARNING, option_debug, parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, and pbx_builtin_getvar_helper().
Referenced by ast_park_call_full(), and masq_park_call().
00495 { 00496 struct parkeduser *pu; 00497 int i, parking_space = -1, parking_range; 00498 const char *parkinglotname = NULL; 00499 const char *parkingexten; 00500 struct ast_parkinglot *parkinglot = NULL; 00501 00502 if (peer) 00503 parkinglotname = findparkinglotname(peer); 00504 00505 if (parkinglotname) { 00506 if (option_debug) 00507 ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname); 00508 parkinglot = find_parkinglot(parkinglotname); 00509 } 00510 if (!parkinglot) 00511 parkinglot = default_parkinglot; 00512 00513 parkinglot_addref(parkinglot); 00514 if (option_debug) 00515 ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name); 00516 00517 /* Allocate memory for parking data */ 00518 if (!(pu = ast_calloc(1, sizeof(*pu)))) { 00519 parkinglot_unref(parkinglot); 00520 return NULL; 00521 } 00522 00523 /* Lock parking list */ 00524 AST_LIST_LOCK(&parkinglot->parkings); 00525 /* Check for channel variable PARKINGEXTEN */ 00526 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00527 if (!ast_strlen_zero(parkingexten)) { 00528 /*!\note The API forces us to specify a numeric parking slot, even 00529 * though the architecture would tend to support non-numeric extensions 00530 * (as are possible with SIP, for example). Hence, we enforce that 00531 * limitation here. If extout was not numeric, we could permit 00532 * arbitrary non-numeric extensions. 00533 */ 00534 if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) { 00535 AST_LIST_UNLOCK(&parkinglot->parkings); 00536 parkinglot_unref(parkinglot); 00537 free(pu); 00538 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); 00539 return NULL; 00540 } 00541 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00542 00543 if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) { 00544 AST_LIST_UNLOCK(&parkinglot->parkings); 00545 parkinglot_unref(parkinglot); 00546 ast_free(pu); 00547 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con); 00548 return NULL; 00549 } 00550 } else { 00551 int start; 00552 struct parkeduser *cur = NULL; 00553 00554 /* Select parking space within range */ 00555 parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1; 00556 00557 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) { 00558 start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1); 00559 } else { 00560 start = parkinglot->parking_start; 00561 } 00562 00563 for (i = start; 1; i++) { 00564 if (i == parkinglot->parking_stop + 1) { 00565 i = parkinglot->parking_start - 1; 00566 continue; 00567 } 00568 00569 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 00570 if (cur->parkingnum == i) { 00571 break; 00572 } 00573 } 00574 00575 if (!cur || i == start - 1) { 00576 parking_space = i; 00577 break; 00578 } 00579 } 00580 00581 if (i == start - 1 && cur) { 00582 ast_log(LOG_WARNING, "No more parking spaces\n"); 00583 ast_free(pu); 00584 AST_LIST_UNLOCK(&parkinglot->parkings); 00585 parkinglot_unref(parkinglot); 00586 return NULL; 00587 } 00588 /* Set pointer for next parking */ 00589 if (parkinglot->parkfindnext) 00590 parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1; 00591 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00592 } 00593 00594 pu->notquiteyet = 1; 00595 pu->parkingnum = parking_space; 00596 pu->parkinglot = parkinglot; 00597 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list); 00598 parkinglot_unref(parkinglot); 00599 00600 return pu; 00601 }
static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 3413 of file features.c.
References ao2_ref, ast_log(), LOG_DEBUG, option_debug, and parkinglot.
Referenced by park_space_reserve().
03414 { 03415 int refcount = ao2_ref(parkinglot, +1); 03416 if (option_debug > 2) 03417 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1); 03418 return parkinglot; 03419 }
static int parkinglot_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 267 of file features.c.
References CMP_MATCH, CMP_STOP, and parkinglot.
Referenced by ast_features_init().
00268 { 00269 struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg; 00270 00271 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0; 00272 }
static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 3439 of file features.c.
References ao2_unlink, ast_context_destroy(), ast_context_find(), ast_parkinglot::parking_con, parkinglots, and registrar.
Referenced by build_parkinglot(), and create_parkinglot().
03440 { 03441 struct ast_parkinglot *ruin = obj; 03442 struct ast_context *con; 03443 con = ast_context_find(ruin->parking_con); 03444 if (con) 03445 ast_context_destroy(con, registrar); 03446 ao2_unlink(parkinglots, ruin); 03447 }
static int parkinglot_hash_cb | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 260 of file features.c.
References ast_str_case_hash(), and parkinglot.
Referenced by ast_features_init().
00261 { 00262 const struct ast_parkinglot *parkinglot = obj; 00263 00264 return ast_str_case_hash(parkinglot->name); 00265 }
static void parkinglot_unref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Unreference parkinglot object. If no more references, then go ahead and delete it.
Definition at line 3406 of file features.c.
References ao2_ref, ast_log(), LOG_DEBUG, option_debug, and parkinglot.
Referenced by build_parkinglot(), and park_space_reserve().
03407 { 03408 int refcount = ao2_ref(parkinglot, -1); 03409 if (option_debug > 2) 03410 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1); 03411 }
return the first unlocked cdr in a possible chain
Definition at line 2267 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
02268 { 02269 struct ast_cdr *cdr_orig = cdr; 02270 while (cdr) { 02271 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 02272 return cdr; 02273 cdr = cdr->next; 02274 } 02275 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 02276 }
static int play_message_in_bridged_call | ( | struct ast_channel * | caller_chan, | |
struct ast_channel * | callee_chan, | |||
const char * | audiofile | |||
) | [static] |
Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages.
Definition at line 884 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_stream_and_wait(), and LOG_WARNING.
Referenced by builtin_automonitor().
00885 { 00886 /* First play for caller, put other channel on auto service */ 00887 if (ast_autoservice_start(callee_chan)) 00888 return -1; 00889 if (ast_stream_and_wait(caller_chan, audiofile, "")) { 00890 ast_log(LOG_WARNING, "Failed to play automon message!\n"); 00891 ast_autoservice_stop(callee_chan); 00892 return -1; 00893 } 00894 if (ast_autoservice_stop(callee_chan)) 00895 return -1; 00896 /* Then play for callee, put other channel on auto service */ 00897 if (ast_autoservice_start(caller_chan)) 00898 return -1; 00899 if (ast_stream_and_wait(callee_chan, audiofile, "")) { 00900 ast_log(LOG_WARNING, "Failed to play automon message !\n"); 00901 ast_autoservice_stop(caller_chan); 00902 return -1; 00903 } 00904 if (ast_autoservice_stop(caller_chan)) 00905 return -1; 00906 return(0); 00907 }
static void post_manager_event | ( | const char * | s, | |
struct parkeduser * | pu | |||
) | [static] |
Output parking event to manager.
Definition at line 2852 of file features.c.
References parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event, ast_parkinglot::name, ast_channel::name, parkeduser::parkingexten, parkeduser::parkinglot, S_OR, and ast_channel::uniqueid.
Referenced by manage_parkinglot().
02853 { 02854 manager_event(EVENT_FLAG_CALL, s, 02855 "Exten: %s\r\n" 02856 "Channel: %s\r\n" 02857 "Parkinglot: %s\r\n" 02858 "CallerIDNum: %s\r\n" 02859 "CallerIDName: %s\r\n" 02860 "UniqueID: %s\r\n\r\n", 02861 pu->parkingexten, 02862 pu->chan->name, 02863 pu->parkinglot->name, 02864 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02865 S_OR(pu->chan->cid.cid_name, "<unknown>"), 02866 pu->chan->uniqueid 02867 ); 02868 }
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 1147 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().
01148 { 01149 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 01150 if (ast_strlen_zero(s)) { 01151 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 01152 } 01153 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 01154 s = transferer->macrocontext; 01155 } 01156 if (ast_strlen_zero(s)) { 01157 s = transferer->context; 01158 } 01159 return s; 01160 }
static struct feature_group* register_group | ( | const char * | fgname | ) | [static] |
Add new feature group.
fgname | feature group name. |
Definition at line 1643 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.
01644 { 01645 struct feature_group *fg; 01646 01647 if (!fgname) { 01648 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 01649 return NULL; 01650 } 01651 01652 if (!(fg = ast_calloc(1, sizeof(*fg)))) 01653 return NULL; 01654 01655 if (ast_string_field_init(fg, 128)) { 01656 ast_free(fg); 01657 return NULL; 01658 } 01659 01660 ast_string_field_set(fg, gname, fgname); 01661 01662 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 01663 01664 ast_verb(2, "Registered group '%s'\n", fg->gname); 01665 01666 return fg; 01667 }
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 1678 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.
01679 { 01680 struct feature_group_exten *fge; 01681 01682 if (!fg) { 01683 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 01684 return; 01685 } 01686 01687 if (!feature) { 01688 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 01689 return; 01690 } 01691 01692 if (!(fge = ast_calloc(1, sizeof(*fge)))) 01693 return; 01694 01695 if (ast_string_field_init(fge, 128)) { 01696 ast_free(fge); 01697 return; 01698 } 01699 01700 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 01701 01702 fge->feature = feature; 01703 01704 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 01705 01706 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 01707 feature->sname, fg->gname, exten); 01708 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1881 of file features.c.
References ast_copy_string(), ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, FEATURES_COUNT, and features_lock.
01882 { 01883 int x, res = -1; 01884 01885 ast_rwlock_wrlock(&features_lock); 01886 for (x = 0; x < FEATURES_COUNT; x++) { 01887 if (strcasecmp(builtin_features[x].sname, name)) 01888 continue; 01889 01890 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01891 res = 0; 01892 break; 01893 } 01894 ast_rwlock_unlock(&features_lock); 01895 01896 return res; 01897 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 2278 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().
02279 { 02280 const char *feature; 02281 02282 if (ast_strlen_zero(features)) { 02283 return; 02284 } 02285 02286 for (feature = features; *feature; feature++) { 02287 switch (*feature) { 02288 case 'T' : 02289 case 't' : 02290 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 02291 break; 02292 case 'K' : 02293 case 'k' : 02294 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 02295 break; 02296 case 'H' : 02297 case 'h' : 02298 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 02299 break; 02300 case 'W' : 02301 case 'w' : 02302 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 02303 break; 02304 default : 02305 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 02306 } 02307 } 02308 }
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 278 of file features.c.
References ast_copy_string(), chan, ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by builtin_blindtransfer(), manage_parkinglot(), and masq_park_call().
00279 { 00280 ast_copy_string(chan->context, context, sizeof(chan->context)); 00281 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00282 chan->priority = pri; 00283 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 2047 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().
02048 { 02049 int x; 02050 02051 ast_clear_flag(config, AST_FLAGS_ALL); 02052 02053 ast_rwlock_rdlock(&features_lock); 02054 for (x = 0; x < FEATURES_COUNT; x++) { 02055 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 02056 continue; 02057 02058 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 02059 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 02060 02061 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 02062 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 02063 } 02064 ast_rwlock_unlock(&features_lock); 02065 02066 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 02067 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 02068 02069 if (dynamic_features) { 02070 char *tmp = ast_strdupa(dynamic_features); 02071 char *tok; 02072 struct ast_call_feature *feature; 02073 02074 /* while we have a feature */ 02075 while ((tok = strsep(&tmp, "#"))) { 02076 AST_RWLIST_RDLOCK(&feature_list); 02077 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 02078 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 02079 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 02080 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 02081 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 02082 } 02083 AST_RWLIST_UNLOCK(&feature_list); 02084 } 02085 } 02086 } 02087 }
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 829 of file features.c.
References chan, and FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
00831 { 00832 if (sense == FEATURE_SENSE_PEER) { 00833 *caller = peer; 00834 *callee = chan; 00835 } else { 00836 *callee = peer; 00837 *caller = chan; 00838 } 00839 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1871 of file features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, FEATURES_COUNT, and features_lock.
01872 { 01873 int x; 01874 01875 ast_rwlock_wrlock(&features_lock); 01876 for (x = 0; x < FEATURES_COUNT; x++) 01877 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01878 ast_rwlock_unlock(&features_lock); 01879 }
int adsipark [static] |
char* app_bridge = "Bridge" [static] |
Definition at line 4386 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 4388 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 4387 of file features.c.
struct ast_call_feature builtin_features[] [static] |
Definition at line 1608 of file features.c.
Referenced by ast_feature_request_and_dial(), ast_find_call_feature(), feature_interpret_helper(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
struct ast_cli_entry cli_features[] [static] |
Initial value:
{ { .handler = handle_feature_show , .summary = "Lists configured features" ,__VA_ARGS__ }, { .handler = handle_features_reload , .summary = "Reloads configured features" ,__VA_ARGS__ }, { .handler = handle_parkedcalls , .summary = "List currently parked calls" ,__VA_ARGS__ }, }
Definition at line 4216 of file features.c.
Referenced by ast_features_init().
int comebacktoorigin = 1 [static] |
char courtesytone[256] [static] |
Courtesy tone
Definition at line 137 of file features.c.
Referenced by builtin_automixmonitor(), builtin_automonitor(), load_config(), and park_exec_full().
struct ast_parkinglot* default_parkinglot |
Definition at line 134 of file features.c.
Referenced by load_config(), park_exec(), park_exec_full(), and park_space_reserve().
char* descrip [static] |
Definition at line 158 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 228 of file features.c.
Referenced by add_features_datastores(), builtin_atxfer(), manage_parkinglot(), and park_exec_full().
int featuredigittimeout [static] |
ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static] |
Definition at line 1606 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 4000 of file features.c.
char mandescr_park[] [static] |
Definition at line 4276 of file features.c.
struct ast_app* mixmonitor_app = NULL [static] |
int mixmonitor_ok = 1 [static] |
struct ast_app* monitor_app = NULL [static] |
Definition at line 191 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 192 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
struct ast_app_option park_call_options[128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } [static] |
char* parkcall = PARK_APP_NAME [static] |
Definition at line 165 of file features.c.
Referenced by ast_features_init(), and build_parkinglot().
char* parkedcall = "ParkedCall" [static] |
Definition at line 89 of file features.c.
Referenced by ast_features_init(), and ast_park_call_full().
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 138 of file features.c.
Referenced by park_exec_full().
char parking_ext[AST_MAX_EXTENSION] |
Extension you type to park the call
Definition at line 135 of file features.c.
Referenced by ast_parking_ext(), handle_feature_show(), and load_config().
pthread_t parking_thread [static] |
Definition at line 200 of file features.c.
Referenced by ast_features_init(), and ast_park_call_full().
struct ao2_container* parkinglots [static] |
The list of parking lots configured. Always at least one - the default parking lot.
Definition at line 132 of file features.c.
Referenced by ast_features_init(), build_parkinglot(), do_parking_thread(), find_parkinglot(), handle_feature_show(), handle_parkedcalls(), manager_parking_status(), and parkinglot_destroy().
char pickup_ext[AST_MAX_EXTENSION] [static] |
Call pickup extension
Definition at line 91 of file features.c.
Referenced by ast_pickup_ext(), and load_config().
char* registrar = "features" [static] |
Registrar for operations
Definition at line 153 of file features.c.
Referenced by ast_park_call_full(), build_parkinglot(), manage_parkinglot(), park_add_hints(), parkinglot_destroy(), pbx_load_module(), and pbx_load_users().
struct ast_app* stopmixmonitor_app = NULL [static] |
int stopmixmonitor_ok = 1 [static] |
char* synopsis = "Answer a parked call" [static] |
char* synopsis2 = "Park yourself" [static] |
int transferdigittimeout [static] |
Definition at line 144 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 140 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().
char xfersound[256] [static] |
Call transfer sound
Definition at line 139 of file features.c.
Referenced by action_bridge(), bridge_exec(), builtin_atxfer(), and load_config().