#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"
#include "asterisk/astobj2.h"
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 69 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 1621 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 468 of file features.c.
00468 { 00469 /*! Provide ringing to the parked caller instead of music on hold */ 00470 AST_PARK_OPT_RINGING = (1 << 0), 00471 /*! Randomly choose a parking spot for the caller instead of choosing 00472 * the first one that is available. */ 00473 AST_PARK_OPT_RANDOMIZE = (1 << 1), 00474 /*! Do not announce the parking number */ 00475 AST_PARK_OPT_SILENCE = (1 << 2), 00476 };
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 4129 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().
04130 { 04131 const char *channela = astman_get_header(m, "Channel1"); 04132 const char *channelb = astman_get_header(m, "Channel2"); 04133 const char *playtone = astman_get_header(m, "Tone"); 04134 struct ast_channel *chana = NULL, *chanb = NULL; 04135 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 04136 struct ast_bridge_thread_obj *tobj = NULL; 04137 04138 /* make sure valid channels were specified */ 04139 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 04140 astman_send_error(s, m, "Missing channel parameter in request"); 04141 return 0; 04142 } 04143 04144 /* The same code must be executed for chana and chanb. To avoid a 04145 * theoretical deadlock, this code is separated so both chana and chanb will 04146 * not hold locks at the same time. */ 04147 04148 /* Start with chana */ 04149 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela)); 04150 04151 /* send errors if any of the channels could not be found/locked */ 04152 if (!chana) { 04153 char buf[256]; 04154 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 04155 astman_send_error(s, m, buf); 04156 return 0; 04157 } 04158 04159 /* Answer the channels if needed */ 04160 if (chana->_state != AST_STATE_UP) 04161 ast_answer(chana); 04162 04163 /* create the placeholder channels and grab the other channels */ 04164 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04165 NULL, NULL, 0, "Bridge/%s", chana->name))) { 04166 astman_send_error(s, m, "Unable to create temporary channel!"); 04167 ast_channel_unlock(chana); 04168 return 1; 04169 } 04170 04171 do_bridge_masquerade(chana, tmpchana); 04172 ast_channel_unlock(chana); 04173 chana = NULL; 04174 04175 /* now do chanb */ 04176 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb)); 04177 /* send errors if any of the channels could not be found/locked */ 04178 if (!chanb) { 04179 char buf[256]; 04180 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 04181 ast_hangup(tmpchana); 04182 astman_send_error(s, m, buf); 04183 return 0; 04184 } 04185 04186 /* Answer the channels if needed */ 04187 if (chanb->_state != AST_STATE_UP) 04188 ast_answer(chanb); 04189 04190 /* create the placeholder channels and grab the other channels */ 04191 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04192 NULL, NULL, 0, "Bridge/%s", chanb->name))) { 04193 astman_send_error(s, m, "Unable to create temporary channels!"); 04194 ast_hangup(tmpchana); 04195 ast_channel_unlock(chanb); 04196 return 1; 04197 } 04198 do_bridge_masquerade(chanb, tmpchanb); 04199 ast_channel_unlock(chanb); 04200 chanb = NULL; 04201 04202 /* make the channels compatible, send error if we fail doing so */ 04203 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 04204 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 04205 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 04206 ast_hangup(tmpchana); 04207 ast_hangup(tmpchanb); 04208 return 1; 04209 } 04210 04211 /* setup the bridge thread object and start the bridge */ 04212 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 04213 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 04214 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 04215 ast_hangup(tmpchana); 04216 ast_hangup(tmpchanb); 04217 return 1; 04218 } 04219 04220 tobj->chan = tmpchana; 04221 tobj->peer = tmpchanb; 04222 tobj->return_to_pbx = 1; 04223 04224 if (ast_true(playtone)) { 04225 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 04226 if (ast_waitstream(tmpchanb, "") < 0) 04227 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 04228 } 04229 } 04230 04231 ast_bridge_call_thread_launch(tobj); 04232 04233 astman_send_ack(s, m, "Launched bridge thread with success"); 04234 04235 return 0; 04236 }
static void add_features_datastores | ( | struct ast_channel * | caller, | |
struct ast_channel * | callee, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 2337 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().
02338 { 02339 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 02340 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 02341 02342 ast_channel_lock(caller); 02343 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 02344 ast_channel_unlock(caller); 02345 if (!ds_caller_features) { 02346 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) { 02347 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 02348 return; 02349 } 02350 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 02351 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02352 ast_datastore_free(ds_caller_features); 02353 return; 02354 } 02355 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 02356 caller_features->is_caller = 1; 02357 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 02358 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 02359 ds_caller_features->data = caller_features; 02360 ast_channel_lock(caller); 02361 ast_channel_datastore_add(caller, ds_caller_features); 02362 ast_channel_unlock(caller); 02363 } else { 02364 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 02365 * flags over from the atxfer to the caller */ 02366 return; 02367 } 02368 02369 ast_channel_lock(callee); 02370 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 02371 ast_channel_unlock(callee); 02372 if (!ds_callee_features) { 02373 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) { 02374 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 02375 return; 02376 } 02377 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 02378 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02379 ast_datastore_free(ds_callee_features); 02380 return; 02381 } 02382 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 02383 callee_features->is_caller = 0; 02384 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 02385 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 02386 ds_callee_features->data = callee_features; 02387 ast_channel_lock(callee); 02388 ast_channel_datastore_add(callee, ds_callee_features); 02389 ast_channel_unlock(callee); 02390 } 02391 02392 return; 02393 }
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 406 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session, ast_adsi_print, chan, and justify.
Referenced by ast_park_call_full().
00407 { 00408 int res; 00409 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00410 char tmp[256]; 00411 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00412 00413 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00414 message[0] = tmp; 00415 res = ast_adsi_load_session(chan, NULL, 0, 1); 00416 if (res == -1) 00417 return res; 00418 return ast_adsi_print(chan, message, justify, 1); 00419 }
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 2404 of file features.c.
References ast_channel::_state, ast_channel::accountcode, ast_cdr::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_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_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_tvcmp(), 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, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_cdr::uniqueid, ast_channel::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.
Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), and park_exec_full().
02405 { 02406 /* Copy voice back and forth between the two channels. Give the peer 02407 the ability to transfer calls with '#<extension' syntax. */ 02408 struct ast_frame *f; 02409 struct ast_channel *who; 02410 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02411 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02412 char orig_channame[AST_MAX_EXTENSION]; 02413 char orig_peername[AST_MAX_EXTENSION]; 02414 int res; 02415 int diff; 02416 int hasfeatures=0; 02417 int hadfeatures=0; 02418 int autoloopflag; 02419 struct ast_option_header *aoh; 02420 struct ast_bridge_config backup_config; 02421 struct ast_cdr *bridge_cdr = NULL; 02422 struct ast_cdr *orig_peer_cdr = NULL; 02423 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 02424 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 02425 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02426 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02427 02428 memset(&backup_config, 0, sizeof(backup_config)); 02429 02430 config->start_time = ast_tvnow(); 02431 02432 if (chan && peer) { 02433 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02434 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02435 } else if (chan) { 02436 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02437 } 02438 02439 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02440 add_features_datastores(chan, peer, config); 02441 02442 /* This is an interesting case. One example is if a ringing channel gets redirected to 02443 * an extension that picks up a parked call. This will make sure that the call taken 02444 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02445 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02446 ast_indicate(peer, AST_CONTROL_RINGING); 02447 } 02448 02449 if (monitor_ok) { 02450 const char *monitor_exec; 02451 struct ast_channel *src = NULL; 02452 if (!monitor_app) { 02453 if (!(monitor_app = pbx_findapp("Monitor"))) 02454 monitor_ok=0; 02455 } 02456 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02457 src = chan; 02458 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02459 src = peer; 02460 if (monitor_app && src) { 02461 char *tmp = ast_strdupa(monitor_exec); 02462 pbx_exec(src, monitor_app, tmp); 02463 } 02464 } 02465 02466 set_config_flags(chan, peer, config); 02467 config->firstpass = 1; 02468 02469 /* Answer if need be */ 02470 if (chan->_state != AST_STATE_UP) { 02471 if (ast_raw_answer(chan, 1)) { 02472 return -1; 02473 } 02474 } 02475 02476 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02477 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02478 orig_peer_cdr = peer_cdr; 02479 02480 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02481 02482 if (chan_cdr) { 02483 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02484 ast_cdr_update(chan); 02485 bridge_cdr = ast_cdr_dup(chan_cdr); 02486 /* rip any forked CDR's off of the chan_cdr and attach 02487 * them to the bridge_cdr instead */ 02488 bridge_cdr->next = chan_cdr->next; 02489 chan_cdr->next = NULL; 02490 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02491 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02492 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 02493 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02494 } 02495 ast_cdr_setaccount(peer, chan->accountcode); 02496 02497 } else { 02498 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02499 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02500 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02501 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02502 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02503 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02504 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02505 ast_cdr_setcid(bridge_cdr, chan); 02506 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02507 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02508 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02509 /* Destination information */ 02510 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02511 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02512 if (peer_cdr) { 02513 bridge_cdr->start = peer_cdr->start; 02514 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02515 } else { 02516 ast_cdr_start(bridge_cdr); 02517 } 02518 } 02519 ast_debug(4,"bridge answer set, chan answer set\n"); 02520 /* peer_cdr->answer will be set when a macro runs on the peer; 02521 in that case, the bridge answer will be delayed while the 02522 macro plays on the peer channel. The peer answered the call 02523 before the macro started playing. To the phone system, 02524 this is billable time for the call, even tho the caller 02525 hears nothing but ringing while the macro does its thing. */ 02526 02527 /* Another case where the peer cdr's time will be set, is when 02528 A self-parks by pickup up phone and dialing 700, then B 02529 picks up A by dialing its parking slot; there may be more 02530 practical paths that get the same result, tho... in which 02531 case you get the previous answer time from the Park... which 02532 is before the bridge's start time, so I added in the 02533 tvcmp check to the if below */ 02534 02535 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 02536 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 02537 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 02538 if (chan_cdr) { 02539 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 02540 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 02541 } 02542 } else { 02543 ast_cdr_answer(bridge_cdr); 02544 if (chan_cdr) { 02545 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02546 } 02547 } 02548 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 02549 if (chan_cdr) { 02550 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02551 } 02552 if (peer_cdr) { 02553 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02554 } 02555 } 02556 /* the DIALED flag may be set if a dialed channel is transfered 02557 * and then bridged to another channel. In order for the 02558 * bridge CDR to be written, the DIALED flag must not be 02559 * present. */ 02560 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 02561 } 02562 for (;;) { 02563 struct ast_channel *other; /* used later */ 02564 02565 res = ast_channel_bridge(chan, peer, config, &f, &who); 02566 02567 /* When frame is not set, we are probably involved in a situation 02568 where we've timed out. 02569 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02570 and also for DTMF_END. If we flow into the following 'if' for both, then 02571 our wait times are cut in half, as both will subtract from the 02572 feature_timer. Not good! 02573 */ 02574 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02575 /* Update time limit for next pass */ 02576 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02577 if (res == AST_BRIDGE_RETRY) { 02578 /* The feature fully timed out but has not been updated. Skip 02579 * the potential round error from the diff calculation and 02580 * explicitly set to expired. */ 02581 config->feature_timer = -1; 02582 } else { 02583 config->feature_timer -= diff; 02584 } 02585 02586 if (hasfeatures) { 02587 /* Running on backup config, meaning a feature might be being 02588 activated, but that's no excuse to keep things going 02589 indefinitely! */ 02590 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02591 ast_debug(1, "Timed out, realtime this time!\n"); 02592 config->feature_timer = 0; 02593 who = chan; 02594 if (f) 02595 ast_frfree(f); 02596 f = NULL; 02597 res = 0; 02598 } else if (config->feature_timer <= 0) { 02599 /* Not *really* out of time, just out of time for 02600 digits to come in for features. */ 02601 ast_debug(1, "Timed out for feature!\n"); 02602 if (!ast_strlen_zero(peer_featurecode)) { 02603 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02604 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02605 } 02606 if (!ast_strlen_zero(chan_featurecode)) { 02607 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02608 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02609 } 02610 if (f) 02611 ast_frfree(f); 02612 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02613 if (!hasfeatures) { 02614 /* Restore original (possibly time modified) bridge config */ 02615 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02616 memset(&backup_config, 0, sizeof(backup_config)); 02617 } 02618 hadfeatures = hasfeatures; 02619 /* Continue as we were */ 02620 continue; 02621 } else if (!f) { 02622 /* The bridge returned without a frame and there is a feature in progress. 02623 * However, we don't think the feature has quite yet timed out, so just 02624 * go back into the bridge. */ 02625 continue; 02626 } 02627 } else { 02628 if (config->feature_timer <=0) { 02629 /* We ran out of time */ 02630 config->feature_timer = 0; 02631 who = chan; 02632 if (f) 02633 ast_frfree(f); 02634 f = NULL; 02635 res = 0; 02636 } 02637 } 02638 } 02639 if (res < 0) { 02640 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02641 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02642 goto before_you_go; 02643 } 02644 02645 if (!f || (f->frametype == AST_FRAME_CONTROL && 02646 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02647 f->subclass == AST_CONTROL_CONGESTION))) { 02648 res = -1; 02649 break; 02650 } 02651 /* many things should be sent to the 'other' channel */ 02652 other = (who == chan) ? peer : chan; 02653 if (f->frametype == AST_FRAME_CONTROL) { 02654 switch (f->subclass) { 02655 case AST_CONTROL_RINGING: 02656 case AST_CONTROL_FLASH: 02657 case -1: 02658 ast_indicate(other, f->subclass); 02659 break; 02660 case AST_CONTROL_HOLD: 02661 case AST_CONTROL_UNHOLD: 02662 ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); 02663 break; 02664 case AST_CONTROL_OPTION: 02665 aoh = f->data.ptr; 02666 /* Forward option Requests */ 02667 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02668 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02669 f->datalen - sizeof(struct ast_option_header), 0); 02670 } 02671 break; 02672 } 02673 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02674 /* eat it */ 02675 } else if (f->frametype == AST_FRAME_DTMF) { 02676 char *featurecode; 02677 int sense; 02678 02679 hadfeatures = hasfeatures; 02680 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02681 if (who == chan) { 02682 sense = FEATURE_SENSE_CHAN; 02683 featurecode = chan_featurecode; 02684 } else { 02685 sense = FEATURE_SENSE_PEER; 02686 featurecode = peer_featurecode; 02687 } 02688 /*! append the event to featurecode. we rely on the string being zero-filled, and 02689 * not overflowing it. 02690 * \todo XXX how do we guarantee the latter ? 02691 */ 02692 featurecode[strlen(featurecode)] = f->subclass; 02693 /* Get rid of the frame before we start doing "stuff" with the channels */ 02694 ast_frfree(f); 02695 f = NULL; 02696 config->feature_timer = backup_config.feature_timer; 02697 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 02698 switch(res) { 02699 case AST_FEATURE_RETURN_PASSDIGITS: 02700 ast_dtmf_stream(other, who, featurecode, 0, 0); 02701 /* Fall through */ 02702 case AST_FEATURE_RETURN_SUCCESS: 02703 memset(featurecode, 0, sizeof(chan_featurecode)); 02704 break; 02705 } 02706 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 02707 res = 0; 02708 } else 02709 break; 02710 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02711 if (hadfeatures && !hasfeatures) { 02712 /* Restore backup */ 02713 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02714 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02715 } else if (hasfeatures) { 02716 if (!hadfeatures) { 02717 /* Backup configuration */ 02718 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02719 /* Setup temporary config options */ 02720 config->play_warning = 0; 02721 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02722 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02723 config->warning_freq = 0; 02724 config->warning_sound = NULL; 02725 config->end_sound = NULL; 02726 config->start_sound = NULL; 02727 config->firstpass = 0; 02728 } 02729 config->start_time = ast_tvnow(); 02730 config->feature_timer = featuredigittimeout; 02731 ast_debug(1, "Set time limit to %ld\n", config->feature_timer); 02732 } 02733 } 02734 if (f) 02735 ast_frfree(f); 02736 02737 } 02738 before_you_go: 02739 02740 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02741 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02742 if (bridge_cdr) { 02743 ast_cdr_discard(bridge_cdr); 02744 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02745 } 02746 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02747 } 02748 02749 if (config->end_bridge_callback) { 02750 config->end_bridge_callback(config->end_bridge_callback_data); 02751 } 02752 02753 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 02754 * if it were, then chan belongs to a different thread now, and might have been hung up long 02755 * ago. 02756 */ 02757 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02758 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02759 struct ast_cdr *swapper = NULL; 02760 char savelastapp[AST_MAX_EXTENSION]; 02761 char savelastdata[AST_MAX_EXTENSION]; 02762 char save_exten[AST_MAX_EXTENSION]; 02763 int save_prio; 02764 int found = 0; /* set if we find at least one match */ 02765 int spawn_error = 0; 02766 02767 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02768 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02769 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02770 ast_cdr_end(bridge_cdr); 02771 } 02772 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02773 dialplan code operate on it */ 02774 ast_channel_lock(chan); 02775 if (bridge_cdr) { 02776 swapper = chan->cdr; 02777 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02778 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02779 chan->cdr = bridge_cdr; 02780 } 02781 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02782 save_prio = chan->priority; 02783 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02784 chan->priority = 1; 02785 ast_channel_unlock(chan); 02786 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 02787 chan->priority++; 02788 } 02789 if (spawn_error && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num) || ast_check_hangup(chan))) { 02790 /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */ 02791 spawn_error = 0; 02792 } 02793 if (found && spawn_error) { 02794 /* Something bad happened, or a hangup has been requested. */ 02795 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02796 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02797 } 02798 /* swap it back */ 02799 ast_channel_lock(chan); 02800 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02801 chan->priority = save_prio; 02802 if (bridge_cdr) { 02803 if (chan->cdr == bridge_cdr) { 02804 chan->cdr = swapper; 02805 } else { 02806 bridge_cdr = NULL; 02807 } 02808 } 02809 if (!spawn_error) { 02810 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02811 } 02812 ast_channel_unlock(chan); 02813 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02814 if (bridge_cdr) { 02815 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02816 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02817 } 02818 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02819 } 02820 02821 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02822 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02823 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 02824 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02825 02826 /* we can post the bridge CDR at this point */ 02827 if (bridge_cdr) { 02828 ast_cdr_end(bridge_cdr); 02829 ast_cdr_detach(bridge_cdr); 02830 } 02831 02832 /* do a specialized reset on the beginning channel 02833 CDR's, if they still exist, so as not to mess up 02834 issues in future bridges; 02835 02836 Here are the rules of the game: 02837 1. The chan and peer channel pointers will not change 02838 during the life of the bridge. 02839 2. But, in transfers, the channel names will change. 02840 between the time the bridge is started, and the 02841 time the channel ends. 02842 Usually, when a channel changes names, it will 02843 also change CDR pointers. 02844 3. Usually, only one of the two channels (chan or peer) 02845 will change names. 02846 4. Usually, if a channel changes names during a bridge, 02847 it is because of a transfer. Usually, in these situations, 02848 it is normal to see 2 bridges running simultaneously, and 02849 it is not unusual to see the two channels that change 02850 swapped between bridges. 02851 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02852 to attend to; if the chan or peer changed names, 02853 we have the before and after attached CDR's. 02854 */ 02855 02856 if (new_chan_cdr) { 02857 struct ast_channel *chan_ptr = NULL; 02858 02859 if (strcasecmp(orig_channame, chan->name) != 0) { 02860 /* old channel */ 02861 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02862 if (chan_ptr) { 02863 if (!ast_bridged_channel(chan_ptr)) { 02864 struct ast_cdr *cur; 02865 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02866 if (cur == chan_cdr) { 02867 break; 02868 } 02869 } 02870 if (cur) 02871 ast_cdr_specialized_reset(chan_cdr,0); 02872 } 02873 ast_channel_unlock(chan_ptr); 02874 } 02875 /* new channel */ 02876 ast_cdr_specialized_reset(new_chan_cdr,0); 02877 } else { 02878 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02879 } 02880 } 02881 02882 { 02883 struct ast_channel *chan_ptr = NULL; 02884 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02885 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)) 02886 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02887 if (strcasecmp(orig_peername, peer->name) != 0) { 02888 /* old channel */ 02889 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02890 if (chan_ptr) { 02891 if (!ast_bridged_channel(chan_ptr)) { 02892 struct ast_cdr *cur; 02893 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02894 if (cur == peer_cdr) { 02895 break; 02896 } 02897 } 02898 if (cur) 02899 ast_cdr_specialized_reset(peer_cdr,0); 02900 } 02901 ast_channel_unlock(chan_ptr); 02902 } 02903 /* new channel */ 02904 ast_cdr_specialized_reset(new_peer_cdr,0); 02905 } else { 02906 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02907 } 02908 } 02909 02910 return res; 02911 }
static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
data | thread bridge. |
Definition at line 341 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().
00342 { 00343 struct ast_bridge_thread_obj *tobj = data; 00344 int res; 00345 00346 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00347 tobj->chan->data = tobj->peer->name; 00348 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00349 tobj->peer->data = tobj->chan->name; 00350 00351 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00352 00353 if (tobj->return_to_pbx) { 00354 if (!ast_check_hangup(tobj->peer)) { 00355 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 00356 res = ast_pbx_start(tobj->peer); 00357 if (res != AST_PBX_SUCCESS) 00358 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 00359 } else 00360 ast_hangup(tobj->peer); 00361 if (!ast_check_hangup(tobj->chan)) { 00362 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 00363 res = ast_pbx_start(tobj->chan); 00364 if (res != AST_PBX_SUCCESS) 00365 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 00366 } else 00367 ast_hangup(tobj->chan); 00368 } else { 00369 ast_hangup(tobj->chan); 00370 ast_hangup(tobj->peer); 00371 } 00372 00373 ast_free(tobj); 00374 00375 return NULL; 00376 }
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 384 of file features.c.
References ast_bridge_call_thread(), ast_pthread_create, and thread.
Referenced by action_bridge(), and builtin_atxfer().
00385 { 00386 pthread_t thread; 00387 pthread_attr_t attr; 00388 struct sched_param sched; 00389 00390 pthread_attr_init(&attr); 00391 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00392 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00393 pthread_attr_destroy(&attr); 00394 memset(&sched, 0, sizeof(sched)); 00395 pthread_setschedparam(thread, SCHED_RR, &sched); 00396 }
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 2059 of file features.c.
References chan, feature_group_exten::feature, and feature_interpret_helper().
Referenced by detect_disconnect().
02059 { 02060 02061 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 02062 }
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 2030 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().
02030 { 02031 02032 char dynamic_features_buf[128]; 02033 const char *peer_dynamic_features, *chan_dynamic_features; 02034 struct ast_flags features; 02035 struct ast_call_feature feature; 02036 if (sense == FEATURE_SENSE_CHAN) { 02037 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 02038 } 02039 else { 02040 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 02041 } 02042 02043 ast_channel_lock(peer); 02044 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 02045 ast_channel_unlock(peer); 02046 02047 ast_channel_lock(chan); 02048 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 02049 ast_channel_unlock(chan); 02050 02051 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,"")); 02052 02053 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); 02054 02055 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature); 02056 }
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 2117 of file features.c.
References ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), 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().
02118 { 02119 int state = 0; 02120 int cause = 0; 02121 int to; 02122 struct ast_channel *chan; 02123 struct ast_channel *monitor_chans[2]; 02124 struct ast_channel *active_channel; 02125 int res = 0, ready = 0; 02126 02127 if ((chan = ast_request(type, format, data, &cause))) { 02128 ast_set_callerid(chan, cid_num, cid_name, cid_num); 02129 ast_string_field_set(chan, language, language); 02130 ast_channel_inherit_variables(caller, chan); 02131 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 02132 02133 if (!ast_call(chan, data, timeout)) { 02134 struct timeval started; 02135 int x, len = 0; 02136 char *disconnect_code = NULL, *dialed_code = NULL; 02137 02138 ast_indicate(caller, AST_CONTROL_RINGING); 02139 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 02140 ast_rwlock_rdlock(&features_lock); 02141 for (x = 0; x < FEATURES_COUNT; x++) { 02142 if (strcasecmp(builtin_features[x].sname, "disconnect")) 02143 continue; 02144 02145 disconnect_code = builtin_features[x].exten; 02146 len = strlen(disconnect_code) + 1; 02147 dialed_code = alloca(len); 02148 memset(dialed_code, 0, len); 02149 break; 02150 } 02151 ast_rwlock_unlock(&features_lock); 02152 x = 0; 02153 started = ast_tvnow(); 02154 to = timeout; 02155 02156 ast_poll_channel_add(caller, chan); 02157 02158 while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) { 02159 struct ast_frame *f = NULL; 02160 02161 monitor_chans[0] = caller; 02162 monitor_chans[1] = chan; 02163 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 02164 02165 /* see if the timeout has been violated */ 02166 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 02167 state = AST_CONTROL_UNHOLD; 02168 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 02169 break; /*doh! timeout*/ 02170 } 02171 02172 if (!active_channel) 02173 continue; 02174 02175 if (chan && (chan == active_channel)) { 02176 if (!ast_strlen_zero(chan->call_forward)) { 02177 if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) { 02178 return NULL; 02179 } 02180 continue; 02181 } 02182 f = ast_read(chan); 02183 if (f == NULL) { /*doh! where'd he go?*/ 02184 state = AST_CONTROL_HANGUP; 02185 res = 0; 02186 break; 02187 } 02188 02189 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 02190 if (f->subclass == AST_CONTROL_RINGING) { 02191 state = f->subclass; 02192 ast_verb(3, "%s is ringing\n", chan->name); 02193 ast_indicate(caller, AST_CONTROL_RINGING); 02194 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 02195 state = f->subclass; 02196 ast_verb(3, "%s is busy\n", chan->name); 02197 ast_indicate(caller, AST_CONTROL_BUSY); 02198 ast_frfree(f); 02199 f = NULL; 02200 break; 02201 } else if (f->subclass == AST_CONTROL_ANSWER) { 02202 /* This is what we are hoping for */ 02203 state = f->subclass; 02204 ast_frfree(f); 02205 f = NULL; 02206 ready=1; 02207 break; 02208 } else if (f->subclass != -1 && f->subclass != AST_CONTROL_PROGRESS) { 02209 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 02210 } 02211 /* else who cares */ 02212 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 02213 ast_write(caller, f); 02214 } 02215 02216 } else if (caller && (active_channel == caller)) { 02217 f = ast_read(caller); 02218 if (f == NULL) { /*doh! where'd he go?*/ 02219 if (!igncallerstate) { 02220 if (ast_check_hangup(caller) && !ast_check_hangup(chan)) { 02221 /* make this a blind transfer */ 02222 ready = 1; 02223 break; 02224 } 02225 state = AST_CONTROL_HANGUP; 02226 res = 0; 02227 break; 02228 } 02229 } else { 02230 02231 if (f->frametype == AST_FRAME_DTMF) { 02232 dialed_code[x++] = f->subclass; 02233 dialed_code[x] = '\0'; 02234 if (strlen(dialed_code) == len) { 02235 x = 0; 02236 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 02237 x = 0; 02238 dialed_code[x] = '\0'; 02239 } 02240 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 02241 /* Caller Canceled the call */ 02242 state = AST_CONTROL_UNHOLD; 02243 ast_frfree(f); 02244 f = NULL; 02245 break; 02246 } 02247 } 02248 } 02249 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 02250 ast_write(chan, f); 02251 } 02252 if (f) 02253 ast_frfree(f); 02254 } /* end while */ 02255 02256 ast_poll_channel_del(caller, chan); 02257 02258 } else 02259 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 02260 } else { 02261 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 02262 switch(cause) { 02263 case AST_CAUSE_BUSY: 02264 state = AST_CONTROL_BUSY; 02265 break; 02266 case AST_CAUSE_CONGESTION: 02267 state = AST_CONTROL_CONGESTION; 02268 break; 02269 } 02270 } 02271 02272 ast_indicate(caller, -1); 02273 if (chan && ready) { 02274 if (chan->_state == AST_STATE_UP) 02275 state = AST_CONTROL_ANSWER; 02276 res = 0; 02277 } else if(chan) { 02278 res = -1; 02279 ast_hangup(chan); 02280 chan = NULL; 02281 } else { 02282 res = -1; 02283 } 02284 02285 if (outstate) 02286 *outstate = state; 02287 02288 return chan; 02289 }
int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 4616 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().
04617 { 04618 int res; 04619 04620 ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL); 04621 04622 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 04623 04624 if ((res = load_config())) 04625 return res; 04626 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 04627 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 04628 res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL); 04629 if (!res) 04630 res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL); 04631 if (!res) { 04632 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls"); 04633 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park); 04634 ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge); 04635 } 04636 04637 res |= ast_devstate_prov_add("Park", metermaidstate); 04638 04639 return res; 04640 }
int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 4052 of file features.c.
References load_config().
Referenced by handle_features_reload().
04053 { 04054 int res; 04055 /* Release parking lot list */ 04056 //ASTOBJ_CONTAINER_MARKALL(&parkinglots); 04057 // TODO: I don't think any marking is necessary 04058 04059 /* Reload configuration */ 04060 res = load_config(); 04061 04062 //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy); 04063 return res; 04064 }
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 1812 of file features.c.
References builtin_features, FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), and handle_request_info().
01813 { 01814 int x; 01815 for (x = 0; x < FEATURES_COUNT; x++) { 01816 if (!strcasecmp(name, builtin_features[x].sname)) 01817 return &builtin_features[x]; 01818 } 01819 return NULL; 01820 }
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 825 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().
00826 { 00827 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00828 }
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 754 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().
00755 { 00756 struct ast_park_call_args args = { 00757 .timeout = timeout, 00758 .extout = extout, 00759 }; 00760 00761 return ast_park_call_full(chan, peer, &args); 00762 }
static int ast_park_call_full | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 609 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, parkeduser::options_specified, ast_park_call_args::orig_chan_name, park_space_reserve(), parkedcall, ast_parkinglot::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, ast_parkinglot::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, ast_park_call_args::pu, registrar, ast_park_call_args::return_con, ast_park_call_args::return_ext, ast_park_call_args::return_pri, S_OR, parkeduser::start, ast_channel::tech, ast_park_call_args::timeout, ast_channel_tech::type, and ast_channel::uniqueid.
Referenced by ast_park_call(), and masq_park_call().
00610 { 00611 struct ast_context *con; 00612 int parkingnum_copy; 00613 struct parkeduser *pu = args->pu; 00614 const char *event_from; 00615 00616 if (pu == NULL) 00617 pu = park_space_reserve(chan, peer, args); 00618 if (pu == NULL) 00619 return 1; /* Continue execution if possible */ 00620 00621 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum); 00622 00623 chan->appl = "Parked Call"; 00624 chan->data = NULL; 00625 00626 pu->chan = chan; 00627 00628 /* Put the parked channel on hold if we have two different channels */ 00629 if (chan != peer) { 00630 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 00631 ast_indicate(pu->chan, AST_CONTROL_RINGING); 00632 } else { 00633 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00634 S_OR(pu->parkinglot->mohclass, NULL), 00635 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 00636 } 00637 } 00638 00639 pu->start = ast_tvnow(); 00640 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime; 00641 parkingnum_copy = pu->parkingnum; 00642 if (args->extout) 00643 *(args->extout) = pu->parkingnum; 00644 00645 if (peer) { 00646 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels 00647 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking 00648 and we need the callback name to be that of transferer. Since local,1/2 have the same 00649 name we can be tricky and just grab the bridged channel from the other side of the local 00650 */ 00651 if (!strcasecmp(peer->tech->type, "Local")) { 00652 struct ast_channel *tmpchan, *base_peer; 00653 char other_side[AST_CHANNEL_NAME]; 00654 char *c; 00655 ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side)); 00656 if ((c = strrchr(other_side, ';'))) { 00657 *++c = '1'; 00658 } 00659 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) { 00660 if ((base_peer = ast_bridged_channel(tmpchan))) { 00661 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 00662 } 00663 ast_channel_unlock(tmpchan); 00664 } 00665 } else { 00666 ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername)); 00667 } 00668 } 00669 00670 /* Remember what had been dialed, so that if the parking 00671 expires, we try to come back to the same place */ 00672 00673 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri); 00674 00675 /* If extension has options specified, they override all other possibilities 00676 such as the returntoorigin flag and transferred context. Information on 00677 extension options is lost here, so we set a flag */ 00678 00679 ast_copy_string(pu->context, 00680 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 00681 sizeof(pu->context)); 00682 ast_copy_string(pu->exten, 00683 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 00684 sizeof(pu->exten)); 00685 pu->priority = args->return_pri ? args->return_pri : 00686 (chan->macropriority ? chan->macropriority : chan->priority); 00687 00688 /* If parking a channel directly, don't quiet yet get parking running on it. 00689 * All parking lot entries are put into the parking lot with notquiteyet on. */ 00690 if (peer != chan) 00691 pu->notquiteyet = 0; 00692 00693 /* Wake up the (presumably select()ing) thread */ 00694 pthread_kill(parking_thread, SIGURG); 00695 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)); 00696 00697 if (peer) { 00698 event_from = peer->name; 00699 } else { 00700 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 00701 } 00702 00703 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00704 "Exten: %s\r\n" 00705 "Channel: %s\r\n" 00706 "Parkinglot: %s\r\n" 00707 "From: %s\r\n" 00708 "Timeout: %ld\r\n" 00709 "CallerIDNum: %s\r\n" 00710 "CallerIDName: %s\r\n" 00711 "Uniqueid: %s\r\n", 00712 pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "", 00713 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00714 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00715 S_OR(pu->chan->cid.cid_name, "<unknown>"), 00716 pu->chan->uniqueid 00717 ); 00718 00719 if (peer && adsipark && ast_adsi_available(peer)) { 00720 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00721 ast_adsi_unload_session(peer); 00722 } 00723 00724 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar); 00725 if (!con) /* Still no context? Bad */ 00726 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con); 00727 if (con) { 00728 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar)) 00729 notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE); 00730 } 00731 00732 AST_LIST_UNLOCK(&pu->parkinglot->parkings); 00733 00734 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 00735 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) { 00736 /* 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. */ 00737 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00738 /* Tell the peer channel the number of the parking space */ 00739 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00740 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00741 } 00742 if (peer == chan) { /* pu->notquiteyet = 1 */ 00743 /* Wake up parking thread if we're really done */ 00744 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00745 S_OR(pu->parkinglot->mohclass, NULL), 00746 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 00747 pu->notquiteyet = 0; 00748 pthread_kill(parking_thread, SIGURG); 00749 } 00750 return 0; 00751 }
const char* ast_parking_ext | ( | void | ) |
Determine system parking extension.
Definition at line 244 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().
00245 { 00246 return parking_ext; 00247 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
chan | channel that initiated pickup. |
Definition at line 4436 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().
04437 { 04438 struct ast_channel *cur = NULL; 04439 int res = -1; 04440 04441 while ((cur = ast_channel_walk_locked(cur)) != NULL) { 04442 if (!cur->pbx && 04443 (cur != chan) && 04444 (chan->pickupgroup & cur->callgroup) && 04445 ((cur->_state == AST_STATE_RINGING) || 04446 (cur->_state == AST_STATE_RING))) { 04447 break; 04448 } 04449 ast_channel_unlock(cur); 04450 } 04451 if (cur) { 04452 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 04453 res = ast_answer(chan); 04454 if (res) 04455 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 04456 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 04457 if (res) 04458 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 04459 res = ast_channel_masquerade(cur, chan); 04460 if (res) 04461 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 04462 ast_channel_unlock(cur); 04463 } else { 04464 ast_debug(1, "No call pickup possible...\n"); 04465 } 04466 return res; 04467 }
const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 249 of file features.c.
References pickup_ext.
Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().
00250 { 00251 return pickup_ext; 00252 }
void ast_rdlock_call_features | ( | void | ) |
Definition at line 1802 of file features.c.
References ast_rwlock_rdlock(), and features_lock.
Referenced by handle_request_info().
01803 { 01804 ast_rwlock_rdlock(&features_lock); 01805 }
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 1639 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.
01640 { 01641 if (!feature) { 01642 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01643 return; 01644 } 01645 01646 AST_RWLIST_WRLOCK(&feature_list); 01647 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01648 AST_RWLIST_UNLOCK(&feature_list); 01649 01650 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 01651 }
void ast_unlock_call_features | ( | void | ) |
Definition at line 1807 of file features.c.
References ast_rwlock_unlock(), and features_lock.
Referenced by handle_request_info().
01808 { 01809 ast_rwlock_unlock(&features_lock); 01810 }
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 1727 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and feature_group_exten::feature.
01728 { 01729 if (!feature) { 01730 return; 01731 } 01732 01733 AST_RWLIST_WRLOCK(&feature_list); 01734 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01735 AST_RWLIST_UNLOCK(&feature_list); 01736 01737 ast_free(feature); 01738 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1741 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.
01742 { 01743 struct ast_call_feature *feature; 01744 01745 AST_RWLIST_WRLOCK(&feature_list); 01746 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 01747 ast_free(feature); 01748 } 01749 AST_RWLIST_UNLOCK(&feature_list); 01750 }
static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 1767 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.
01768 { 01769 struct feature_group *fg; 01770 struct feature_group_exten *fge; 01771 01772 AST_RWLIST_WRLOCK(&feature_groups); 01773 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 01774 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 01775 ast_string_field_free_memory(fge); 01776 ast_free(fge); 01777 } 01778 01779 ast_string_field_free_memory(fg); 01780 ast_free(fg); 01781 } 01782 AST_RWLIST_UNLOCK(&feature_groups); 01783 }
static int bridge_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Bridge channels.
chan | ||
data | channel to bridge with. |
Definition at line 4498 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().
04499 { 04500 struct ast_channel *current_dest_chan, *final_dest_chan; 04501 char *tmp_data = NULL; 04502 struct ast_flags opts = { 0, }; 04503 struct ast_bridge_config bconfig = { { 0, }, }; 04504 04505 AST_DECLARE_APP_ARGS(args, 04506 AST_APP_ARG(dest_chan); 04507 AST_APP_ARG(options); 04508 ); 04509 04510 if (ast_strlen_zero(data)) { 04511 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 04512 return -1; 04513 } 04514 04515 tmp_data = ast_strdupa(data); 04516 AST_STANDARD_APP_ARGS(args, tmp_data); 04517 if (!ast_strlen_zero(args.options)) 04518 ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options); 04519 04520 /* avoid bridge with ourselves */ 04521 if (!strcmp(chan->name, args.dest_chan)) { 04522 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 04523 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04524 "Response: Failed\r\n" 04525 "Reason: Unable to bridge channel to itself\r\n" 04526 "Channel1: %s\r\n" 04527 "Channel2: %s\r\n", 04528 chan->name, args.dest_chan); 04529 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 04530 return 0; 04531 } 04532 04533 /* make sure we have a valid end point */ 04534 if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 04535 strlen(args.dest_chan)))) { 04536 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 04537 "cannot get its lock\n", args.dest_chan); 04538 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04539 "Response: Failed\r\n" 04540 "Reason: Cannot grab end point\r\n" 04541 "Channel1: %s\r\n" 04542 "Channel2: %s\r\n", chan->name, args.dest_chan); 04543 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 04544 return 0; 04545 } 04546 04547 /* answer the channel if needed */ 04548 if (current_dest_chan->_state != AST_STATE_UP) 04549 ast_answer(current_dest_chan); 04550 04551 /* try to allocate a place holder where current_dest_chan will be placed */ 04552 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04553 NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) { 04554 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 04555 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04556 "Response: Failed\r\n" 04557 "Reason: cannot create placeholder\r\n" 04558 "Channel1: %s\r\n" 04559 "Channel2: %s\r\n", chan->name, args.dest_chan); 04560 } 04561 do_bridge_masquerade(current_dest_chan, final_dest_chan); 04562 04563 ast_channel_unlock(current_dest_chan); 04564 04565 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 04566 /* try to make compatible, send error if we fail */ 04567 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 04568 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 04569 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04570 "Response: Failed\r\n" 04571 "Reason: Could not make channels compatible for bridge\r\n" 04572 "Channel1: %s\r\n" 04573 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 04574 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 04575 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 04576 return 0; 04577 } 04578 04579 /* Report that the bridge will be successfull */ 04580 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04581 "Response: Success\r\n" 04582 "Channel1: %s\r\n" 04583 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 04584 04585 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 04586 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 04587 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 04588 if (ast_waitstream(final_dest_chan, "") < 0) 04589 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 04590 } 04591 } 04592 04593 /* do the bridge */ 04594 ast_bridge_call(chan, final_dest_chan, &bconfig); 04595 04596 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 04597 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 04598 if (!ast_check_hangup(final_dest_chan)) { 04599 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 04600 final_dest_chan->context, final_dest_chan->exten, 04601 final_dest_chan->priority, final_dest_chan->name); 04602 04603 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 04604 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 04605 ast_hangup(final_dest_chan); 04606 } else 04607 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 04608 } else { 04609 ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name); 04610 ast_hangup(final_dest_chan); 04611 } 04612 04613 return 0; 04614 }
static struct ast_parkinglot* build_parkinglot | ( | char * | name, | |
struct ast_variable * | var | |||
) | [static] |
Build parkinglot from configuration and chain it in.
Definition at line 3522 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().
03523 { 03524 struct ast_parkinglot *parkinglot; 03525 struct ast_context *con = NULL; 03526 03527 struct ast_variable *confvar = var; 03528 int error = 0; 03529 int start = 0, end = 0; 03530 int oldparkinglot = 0; 03531 03532 parkinglot = find_parkinglot(name); 03533 if (parkinglot) 03534 oldparkinglot = 1; 03535 else 03536 parkinglot = create_parkinglot(name); 03537 03538 if (!parkinglot) 03539 return NULL; 03540 03541 ao2_lock(parkinglot); 03542 03543 if (option_debug) 03544 ast_log(LOG_DEBUG, "Building parking lot %s\n", name); 03545 03546 /* Do some config stuff */ 03547 while(confvar) { 03548 if (!strcasecmp(confvar->name, "context")) { 03549 ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con)); 03550 } else if (!strcasecmp(confvar->name, "parkingtime")) { 03551 if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) { 03552 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value); 03553 parkinglot->parkingtime = DEFAULT_PARK_TIME; 03554 } else 03555 parkinglot->parkingtime = parkinglot->parkingtime * 1000; 03556 } else if (!strcasecmp(confvar->name, "parkpos")) { 03557 if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) { 03558 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); 03559 error = 1; 03560 } else { 03561 parkinglot->parking_start = start; 03562 parkinglot->parking_stop = end; 03563 } 03564 } else if (!strcasecmp(confvar->name, "findslot")) { 03565 parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next")); 03566 } 03567 confvar = confvar->next; 03568 } 03569 /* make sure parkingtime is set if not specified */ 03570 if (parkinglot->parkingtime == 0) { 03571 parkinglot->parkingtime = DEFAULT_PARK_TIME; 03572 } 03573 03574 if (!var) { /* Default parking lot */ 03575 ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con)); 03576 ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial)); 03577 ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass)); 03578 } 03579 03580 /* Check for errors */ 03581 if (ast_strlen_zero(parkinglot->parking_con)) { 03582 ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name); 03583 error = 1; 03584 } 03585 03586 /* Create context */ 03587 if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) { 03588 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con); 03589 error = 1; 03590 } 03591 03592 /* Add a parking extension into the context */ 03593 if (!error && !oldparkinglot) { 03594 if (!ast_strlen_zero(ast_parking_ext())) { 03595 if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1) 03596 error = 1; 03597 } 03598 } 03599 03600 ao2_unlock(parkinglot); 03601 03602 if (error) { 03603 ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name); 03604 parkinglot_destroy(parkinglot); 03605 return NULL; 03606 } 03607 if (option_debug) 03608 ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end); 03609 03610 03611 /* Move it into the list, if it wasn't already there */ 03612 if (!oldparkinglot) { 03613 ao2_link(parkinglots, parkinglot); 03614 } 03615 parkinglot_unref(parkinglot); 03616 03617 return parkinglot; 03618 }
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 1324 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.
01325 { 01326 struct ast_channel *transferer; 01327 struct ast_channel *transferee; 01328 const char *transferer_real_context; 01329 char xferto[256] = ""; 01330 int res; 01331 int outstate=0; 01332 struct ast_channel *newchan; 01333 struct ast_channel *xferchan; 01334 struct ast_bridge_thread_obj *tobj; 01335 struct ast_bridge_config bconfig; 01336 struct ast_frame *f; 01337 int l; 01338 struct ast_datastore *features_datastore; 01339 struct ast_dial_features *dialfeatures = NULL; 01340 01341 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 01342 set_peers(&transferer, &transferee, peer, chan, sense); 01343 transferer_real_context = real_ctx(transferer, transferee); 01344 /* Start autoservice on chan while we talk to the originator */ 01345 ast_autoservice_start(transferee); 01346 ast_indicate(transferee, AST_CONTROL_HOLD); 01347 01348 /* Transfer */ 01349 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01350 if (res < 0) { 01351 finishup(transferee); 01352 return res; 01353 } 01354 if (res > 0) /* If they've typed a digit already, handle it */ 01355 xferto[0] = (char) res; 01356 01357 /* this is specific of atxfer */ 01358 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01359 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01360 finishup(transferee); 01361 return res; 01362 } 01363 if (res == 0) { 01364 ast_log(LOG_WARNING, "Did not read data.\n"); 01365 finishup(transferee); 01366 if (ast_stream_and_wait(transferer, "beeperr", "")) 01367 return -1; 01368 return AST_FEATURE_RETURN_SUCCESS; 01369 } 01370 01371 /* valid extension, res == 1 */ 01372 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01373 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 01374 finishup(transferee); 01375 if (ast_stream_and_wait(transferer, "beeperr", "")) 01376 return -1; 01377 return AST_FEATURE_RETURN_SUCCESS; 01378 } 01379 01380 /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of 01381 * the different variables for handling this properly with a builtin_atxfer */ 01382 if (!strcmp(xferto, ast_parking_ext())) { 01383 finishup(transferee); 01384 return builtin_parkcall(chan, peer, config, code, sense, data); 01385 } 01386 01387 l = strlen(xferto); 01388 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 01389 01390 /* If we are performing an attended transfer and we have two channels involved then 01391 copy sound file information to play upon attended transfer completion */ 01392 if (transferee) { 01393 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 01394 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 01395 01396 if (!ast_strlen_zero(chan1_attended_sound)) { 01397 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 01398 } 01399 if (!ast_strlen_zero(chan2_attended_sound)) { 01400 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 01401 } 01402 } 01403 01404 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01405 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01406 01407 if (!ast_check_hangup(transferer)) { 01408 /* Transferer is up - old behaviour */ 01409 ast_indicate(transferer, -1); 01410 if (!newchan) { 01411 finishup(transferee); 01412 /* any reason besides user requested cancel and busy triggers the failed sound */ 01413 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 01414 ast_stream_and_wait(transferer, xferfailsound, "")) 01415 return -1; 01416 if (ast_stream_and_wait(transferer, xfersound, "")) 01417 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01418 return AST_FEATURE_RETURN_SUCCESS; 01419 } 01420 01421 if (check_compat(transferer, newchan)) { 01422 /* we do mean transferee here, NOT transferer */ 01423 finishup(transferee); 01424 return -1; 01425 } 01426 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 01427 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 01428 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 01429 res = ast_bridge_call(transferer, newchan, &bconfig); 01430 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 01431 ast_hangup(newchan); 01432 if (ast_stream_and_wait(transferer, xfersound, "")) 01433 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01434 finishup(transferee); 01435 transferer->_softhangup = 0; 01436 return AST_FEATURE_RETURN_SUCCESS; 01437 } 01438 if (check_compat(transferee, newchan)) { 01439 finishup(transferee); 01440 return -1; 01441 } 01442 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01443 01444 if ((ast_autoservice_stop(transferee) < 0) 01445 || (ast_waitfordigit(transferee, 100) < 0) 01446 || (ast_waitfordigit(newchan, 100) < 0) 01447 || ast_check_hangup(transferee) 01448 || ast_check_hangup(newchan)) { 01449 ast_hangup(newchan); 01450 return -1; 01451 } 01452 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01453 if (!xferchan) { 01454 ast_hangup(newchan); 01455 return -1; 01456 } 01457 /* Make formats okay */ 01458 xferchan->visible_indication = transferer->visible_indication; 01459 xferchan->readformat = transferee->readformat; 01460 xferchan->writeformat = transferee->writeformat; 01461 ast_channel_masquerade(xferchan, transferee); 01462 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01463 xferchan->_state = AST_STATE_UP; 01464 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01465 xferchan->_softhangup = 0; 01466 if ((f = ast_read(xferchan))) 01467 ast_frfree(f); 01468 newchan->_state = AST_STATE_UP; 01469 ast_clear_flag(newchan, AST_FLAGS_ALL); 01470 newchan->_softhangup = 0; 01471 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01472 ast_hangup(xferchan); 01473 ast_hangup(newchan); 01474 return -1; 01475 } 01476 01477 ast_channel_lock(newchan); 01478 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 01479 dialfeatures = features_datastore->data; 01480 } 01481 ast_channel_unlock(newchan); 01482 01483 if (dialfeatures) { 01484 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 01485 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 01486 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01487 dialfeatures = NULL; 01488 } 01489 01490 ast_channel_lock(xferchan); 01491 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 01492 dialfeatures = features_datastore->data; 01493 } 01494 ast_channel_unlock(xferchan); 01495 01496 if (dialfeatures) { 01497 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01498 } 01499 01500 tobj->chan = newchan; 01501 tobj->peer = xferchan; 01502 tobj->bconfig = *config; 01503 01504 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01505 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01506 } 01507 01508 if (ast_stream_and_wait(newchan, xfersound, "")) 01509 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01510 ast_bridge_call_thread_launch(tobj); 01511 return -1; /* XXX meaning the channel is bridged ? */ 01512 } else if (!ast_check_hangup(transferee)) { 01513 /* act as blind transfer */ 01514 if (ast_autoservice_stop(transferee) < 0) { 01515 ast_hangup(newchan); 01516 return -1; 01517 } 01518 01519 if (!newchan) { 01520 unsigned int tries = 0; 01521 char *transferer_tech, *transferer_name = ast_strdupa(transferer->name); 01522 01523 transferer_tech = strsep(&transferer_name, "/"); 01524 transferer_name = strsep(&transferer_name, "-"); 01525 01526 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 01527 ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name); 01528 if (ast_stream_and_wait(transferee, "beeperr", "")) 01529 return -1; 01530 return AST_FEATURE_RETURN_SUCCESS; 01531 } 01532 01533 ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name); 01534 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01535 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01536 while (!newchan && !atxferdropcall && tries < atxfercallbackretries) { 01537 /* Trying to transfer again */ 01538 ast_autoservice_start(transferee); 01539 ast_indicate(transferee, AST_CONTROL_HOLD); 01540 01541 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01542 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01543 if (ast_autoservice_stop(transferee) < 0) { 01544 if (newchan) 01545 ast_hangup(newchan); 01546 return -1; 01547 } 01548 if (!newchan) { 01549 /* Transfer failed, sleeping */ 01550 ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay); 01551 ast_safe_sleep(transferee, atxferloopdelay); 01552 ast_debug(1, "Trying to callback...\n"); 01553 newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01554 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01555 } 01556 tries++; 01557 } 01558 } 01559 if (!newchan) 01560 return -1; 01561 01562 /* newchan is up, we should prepare transferee and bridge them */ 01563 if (check_compat(transferee, newchan)) { 01564 finishup(transferee); 01565 return -1; 01566 } 01567 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01568 01569 if ((ast_waitfordigit(transferee, 100) < 0) 01570 || (ast_waitfordigit(newchan, 100) < 0) 01571 || ast_check_hangup(transferee) 01572 || ast_check_hangup(newchan)) { 01573 ast_hangup(newchan); 01574 return -1; 01575 } 01576 01577 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01578 if (!xferchan) { 01579 ast_hangup(newchan); 01580 return -1; 01581 } 01582 /* Make formats okay */ 01583 xferchan->visible_indication = transferer->visible_indication; 01584 xferchan->readformat = transferee->readformat; 01585 xferchan->writeformat = transferee->writeformat; 01586 ast_channel_masquerade(xferchan, transferee); 01587 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01588 xferchan->_state = AST_STATE_UP; 01589 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01590 xferchan->_softhangup = 0; 01591 if ((f = ast_read(xferchan))) 01592 ast_frfree(f); 01593 newchan->_state = AST_STATE_UP; 01594 ast_clear_flag(newchan, AST_FLAGS_ALL); 01595 newchan->_softhangup = 0; 01596 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01597 ast_hangup(xferchan); 01598 ast_hangup(newchan); 01599 return -1; 01600 } 01601 tobj->chan = newchan; 01602 tobj->peer = xferchan; 01603 tobj->bconfig = *config; 01604 01605 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01606 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01607 } 01608 01609 if (ast_stream_and_wait(newchan, xfersound, "")) 01610 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01611 ast_bridge_call_thread_launch(tobj); 01612 return -1; /* XXX meaning the channel is bridged ? */ 01613 } else { 01614 /* Transferee hung up */ 01615 finishup(transferee); 01616 return -1; 01617 } 01618 }
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 1033 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.
01034 { 01035 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 01036 int x = 0; 01037 size_t len; 01038 struct ast_channel *caller_chan, *callee_chan; 01039 const char *mixmonitor_spy_type = "MixMonitor"; 01040 int count = 0; 01041 01042 if (!mixmonitor_ok) { 01043 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01044 return -1; 01045 } 01046 01047 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 01048 mixmonitor_ok = 0; 01049 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01050 return -1; 01051 } 01052 01053 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 01054 01055 if (!ast_strlen_zero(courtesytone)) { 01056 if (ast_autoservice_start(callee_chan)) 01057 return -1; 01058 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 01059 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01060 ast_autoservice_stop(callee_chan); 01061 return -1; 01062 } 01063 if (ast_autoservice_stop(callee_chan)) 01064 return -1; 01065 } 01066 01067 ast_channel_lock(callee_chan); 01068 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01069 ast_channel_unlock(callee_chan); 01070 01071 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 01072 if (count > 0) { 01073 01074 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 01075 01076 /* Make sure they are running */ 01077 ast_channel_lock(callee_chan); 01078 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01079 ast_channel_unlock(callee_chan); 01080 if (count > 0) { 01081 if (!stopmixmonitor_ok) { 01082 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01083 return -1; 01084 } 01085 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 01086 stopmixmonitor_ok = 0; 01087 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01088 return -1; 01089 } else { 01090 pbx_exec(callee_chan, stopmixmonitor_app, ""); 01091 return AST_FEATURE_RETURN_SUCCESS; 01092 } 01093 } 01094 01095 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 01096 } 01097 01098 if (caller_chan && callee_chan) { 01099 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 01100 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 01101 01102 if (!touch_format) 01103 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 01104 01105 if (!touch_monitor) 01106 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 01107 01108 if (touch_monitor) { 01109 len = strlen(touch_monitor) + 50; 01110 args = alloca(len); 01111 touch_filename = alloca(len); 01112 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 01113 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 01114 } else { 01115 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 01116 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 01117 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 01118 args = alloca(len); 01119 touch_filename = alloca(len); 01120 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 01121 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 01122 } 01123 01124 for( x = 0; x < strlen(args); x++) { 01125 if (args[x] == '/') 01126 args[x] = '-'; 01127 } 01128 01129 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 01130 01131 pbx_exec(callee_chan, mixmonitor_app, args); 01132 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01133 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01134 return AST_FEATURE_RETURN_SUCCESS; 01135 01136 } 01137 01138 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01139 return -1; 01140 01141 }
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 940 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.
00941 { 00942 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00943 int x = 0; 00944 size_t len; 00945 struct ast_channel *caller_chan, *callee_chan; 00946 const char *automon_message_start = NULL; 00947 const char *automon_message_stop = NULL; 00948 00949 if (!monitor_ok) { 00950 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00951 return -1; 00952 } 00953 00954 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00955 monitor_ok = 0; 00956 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00957 return -1; 00958 } 00959 00960 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00961 if (caller_chan) { /* Find extra messages */ 00962 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 00963 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 00964 } 00965 00966 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 00967 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 00968 return -1; 00969 } 00970 } 00971 00972 if (callee_chan->monitor) { 00973 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 00974 if (!ast_strlen_zero(automon_message_stop)) { 00975 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 00976 } 00977 callee_chan->monitor->stop(callee_chan, 1); 00978 return AST_FEATURE_RETURN_SUCCESS; 00979 } 00980 00981 if (caller_chan && callee_chan) { 00982 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00983 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00984 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 00985 00986 if (!touch_format) 00987 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00988 00989 if (!touch_monitor) 00990 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00991 00992 if (!touch_monitor_prefix) 00993 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 00994 00995 if (touch_monitor) { 00996 len = strlen(touch_monitor) + 50; 00997 args = alloca(len); 00998 touch_filename = alloca(len); 00999 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 01000 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 01001 } else { 01002 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 01003 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 01004 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 01005 args = alloca(len); 01006 touch_filename = alloca(len); 01007 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 01008 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 01009 } 01010 01011 for(x = 0; x < strlen(args); x++) { 01012 if (args[x] == '/') 01013 args[x] = '-'; 01014 } 01015 01016 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 01017 01018 pbx_exec(callee_chan, monitor_app, args); 01019 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01020 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01021 01022 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 01023 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 01024 } 01025 01026 return AST_FEATURE_RETURN_SUCCESS; 01027 } 01028 01029 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01030 return -1; 01031 }
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 1193 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.
01194 { 01195 struct ast_channel *transferer; 01196 struct ast_channel *transferee; 01197 const char *transferer_real_context; 01198 char xferto[256]; 01199 int res, parkstatus = 0; 01200 01201 set_peers(&transferer, &transferee, peer, chan, sense); 01202 transferer_real_context = real_ctx(transferer, transferee); 01203 /* Start autoservice on chan while we talk to the originator */ 01204 ast_autoservice_start(transferee); 01205 ast_indicate(transferee, AST_CONTROL_HOLD); 01206 01207 memset(xferto, 0, sizeof(xferto)); 01208 01209 /* Transfer */ 01210 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01211 if (res < 0) { 01212 finishup(transferee); 01213 return -1; /* error ? */ 01214 } 01215 if (res > 0) /* If they've typed a digit already, handle it */ 01216 xferto[0] = (char) res; 01217 01218 ast_stopstream(transferer); 01219 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01220 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01221 finishup(transferee); 01222 return res; 01223 } 01224 if (!strcmp(xferto, ast_parking_ext())) { 01225 res = finishup(transferee); 01226 if (res) 01227 res = -1; 01228 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) { /* success */ 01229 /* We return non-zero, but tell the PBX not to hang the channel when 01230 the thread dies -- We have to be careful now though. We are responsible for 01231 hanging up the channel, else it will never be hung up! */ 01232 01233 return 0; 01234 } else { 01235 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus); 01236 } 01237 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 01238 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01239 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 01240 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 01241 res=finishup(transferee); 01242 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 01243 transferer->cdr=ast_cdr_alloc(); 01244 if (transferer->cdr) { 01245 ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */ 01246 ast_cdr_start(transferer->cdr); 01247 } 01248 } 01249 if (transferer->cdr) { 01250 struct ast_cdr *swap = transferer->cdr; 01251 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 01252 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 01253 transferer->cdr->channel, transferer->cdr->dstchannel); 01254 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 01255 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel); 01256 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto); 01257 /* swap cdrs-- it will save us some time & work */ 01258 transferer->cdr = transferee->cdr; 01259 transferee->cdr = swap; 01260 } 01261 if (!transferee->pbx) { 01262 /* Doh! Use our handy async_goto functions */ 01263 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n" 01264 ,transferee->name, xferto, transferer_real_context); 01265 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 01266 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 01267 } else { 01268 /* Set the channel's new extension, since it exists, using transferer context */ 01269 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 01270 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name); 01271 set_c_e_p(transferee, transferer_real_context, xferto, 0); 01272 } 01273 check_goto_on_transfer(transferer); 01274 return res; 01275 } else { 01276 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 01277 } 01278 if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { 01279 finishup(transferee); 01280 return -1; 01281 } 01282 ast_stopstream(transferer); 01283 res = finishup(transferee); 01284 if (res) { 01285 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name); 01286 return res; 01287 } 01288 return AST_FEATURE_RETURN_SUCCESS; 01289 }
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 1143 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
01144 { 01145 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 01146 return AST_FEATURE_RETURN_HANGUP; 01147 }
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 870 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().
00871 { 00872 struct ast_channel *parker; 00873 struct ast_channel *parkee; 00874 int res = 0; 00875 00876 set_peers(&parker, &parkee, peer, chan, sense); 00877 /* we used to set chan's exten and priority to "s" and 1 00878 here, but this generates (in some cases) an invalid 00879 extension, and if "s" exists, could errantly 00880 cause execution of extensions you don't expect. It 00881 makes more sense to let nature take its course 00882 when chan finishes, and let the pbx do its thing 00883 and hang up when the park is over. 00884 */ 00885 if (chan->_state != AST_STATE_UP) 00886 res = ast_answer(chan); 00887 if (!res) 00888 res = ast_safe_sleep(chan, 1000); 00889 00890 if (!res) { /* one direction used to call park_call.... */ 00891 res = masq_park_call_announce(parkee, parker, 0, NULL); 00892 /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ 00893 } 00894 00895 return res; 00896 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 2932 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().
02933 { 02934 int i = 0; 02935 enum { 02936 OPT_CALLEE_REDIRECT = 't', 02937 OPT_CALLER_REDIRECT = 'T', 02938 OPT_CALLEE_AUTOMON = 'w', 02939 OPT_CALLER_AUTOMON = 'W', 02940 OPT_CALLEE_DISCONNECT = 'h', 02941 OPT_CALLER_DISCONNECT = 'H', 02942 OPT_CALLEE_PARKCALL = 'k', 02943 OPT_CALLER_PARKCALL = 'K', 02944 }; 02945 02946 memset(options, 0, len); 02947 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 02948 options[i++] = OPT_CALLER_REDIRECT; 02949 } 02950 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 02951 options[i++] = OPT_CALLER_AUTOMON; 02952 } 02953 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 02954 options[i++] = OPT_CALLER_DISCONNECT; 02955 } 02956 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 02957 options[i++] = OPT_CALLER_PARKCALL; 02958 } 02959 02960 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 02961 options[i++] = OPT_CALLEE_REDIRECT; 02962 } 02963 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 02964 options[i++] = OPT_CALLEE_AUTOMON; 02965 } 02966 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 02967 options[i++] = OPT_CALLEE_DISCONNECT; 02968 } 02969 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 02970 options[i++] = OPT_CALLEE_PARKCALL; 02971 } 02972 02973 return options; 02974 }
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 1298 of file features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by builtin_atxfer().
01299 { 01300 if (ast_channel_make_compatible(c, newchan) < 0) { 01301 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 01302 c->name, newchan->name); 01303 ast_hangup(newchan); 01304 return -1; 01305 } 01306 return 0; 01307 }
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 295 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().
00296 { 00297 struct ast_channel *xferchan; 00298 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00299 char *x, *goto_on_transfer; 00300 struct ast_frame *f; 00301 00302 if (ast_strlen_zero(val)) 00303 return; 00304 00305 goto_on_transfer = ast_strdupa(val); 00306 00307 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name))) 00308 return; 00309 00310 for (x = goto_on_transfer; x && *x; x++) { 00311 if (*x == '^') 00312 *x = '|'; 00313 } 00314 /* Make formats okay */ 00315 xferchan->readformat = chan->readformat; 00316 xferchan->writeformat = chan->writeformat; 00317 ast_channel_masquerade(xferchan, chan); 00318 ast_parseable_goto(xferchan, goto_on_transfer); 00319 xferchan->_state = AST_STATE_UP; 00320 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00321 xferchan->_softhangup = 0; 00322 if ((f = ast_read(xferchan))) { 00323 ast_frfree(f); 00324 f = NULL; 00325 ast_pbx_start(xferchan); 00326 } else { 00327 ast_hangup(xferchan); 00328 } 00329 }
static struct ast_parkinglot* create_parkinglot | ( | char * | name | ) | [static] |
Allocate parking lot structure.
Definition at line 3493 of file features.c.
References ao2_alloc, ast_copy_string(), AST_LIST_HEAD_INIT, and parkinglot_destroy().
Referenced by build_parkinglot().
03494 { 03495 struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL; 03496 03497 if (!name) 03498 return NULL; 03499 03500 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 03501 if (!newlot) 03502 return NULL; 03503 03504 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 03505 AST_LIST_HEAD_INIT(&newlot->parkings); 03506 03507 return newlot; 03508 }
static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 222 of file features.c.
References ast_free.
00223 { 00224 struct ast_dial_features *df = data; 00225 if (df) { 00226 ast_free(df); 00227 } 00228 }
static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 209 of file features.c.
References ast_calloc.
00210 { 00211 struct ast_dial_features *df = data, *df_copy; 00212 00213 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00214 return NULL; 00215 } 00216 00217 memcpy(df_copy, df, sizeof(*df)); 00218 00219 return df_copy; 00220 }
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 4099 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().
04100 { 04101 ast_moh_stop(chan); 04102 ast_channel_lock(chan); 04103 ast_setstate(tmpchan, chan->_state); 04104 tmpchan->readformat = chan->readformat; 04105 tmpchan->writeformat = chan->writeformat; 04106 ast_channel_masquerade(tmpchan, chan); 04107 ast_channel_lock(tmpchan); 04108 ast_do_masquerade(tmpchan); 04109 /* when returning from bridge, the channel will continue at the next priority */ 04110 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 04111 ast_channel_unlock(tmpchan); 04112 ast_channel_unlock(chan); 04113 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
ignore | unused var. |
Definition at line 3157 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().
03158 { 03159 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 03160 fd_set nrfds, nefds; /* args for the next select */ 03161 FD_ZERO(&rfds); 03162 FD_ZERO(&efds); 03163 03164 for (;;) { 03165 int res = 0; 03166 int ms = -1; /* select timeout, uninitialized */ 03167 int max = -1; /* max fd, none there yet */ 03168 struct ao2_iterator iter; 03169 struct ast_parkinglot *curlot; 03170 FD_ZERO(&nrfds); 03171 FD_ZERO(&nefds); 03172 iter = ao2_iterator_init(parkinglots, 0); 03173 03174 while ((curlot = ao2_iterator_next(&iter))) { 03175 res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max); 03176 ao2_ref(curlot, -1); 03177 } 03178 03179 rfds = nrfds; 03180 efds = nefds; 03181 { 03182 struct timeval wait = ast_samp2tv(ms, 1000); 03183 /* Wait for something to happen */ 03184 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL); 03185 } 03186 pthread_testcancel(); 03187 } 03188 return NULL; /* Never reached */ 03189 }
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 1831 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().
01832 { 01833 struct ast_app *app; 01834 struct ast_call_feature *feature = data; 01835 struct ast_channel *work, *idle; 01836 int res; 01837 01838 if (!feature) { /* shouldn't ever happen! */ 01839 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01840 return -1; 01841 } 01842 01843 if (sense == FEATURE_SENSE_CHAN) { 01844 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01845 return AST_FEATURE_RETURN_KEEPTRYING; 01846 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01847 work = chan; 01848 idle = peer; 01849 } else { 01850 work = peer; 01851 idle = chan; 01852 } 01853 } else { 01854 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01855 return AST_FEATURE_RETURN_KEEPTRYING; 01856 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01857 work = peer; 01858 idle = chan; 01859 } else { 01860 work = chan; 01861 idle = peer; 01862 } 01863 } 01864 01865 if (!(app = pbx_findapp(feature->app))) { 01866 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01867 return -2; 01868 } 01869 01870 ast_autoservice_start(idle); 01871 01872 if (!ast_strlen_zero(feature->moh_class)) 01873 ast_moh_start(idle, feature->moh_class, NULL); 01874 01875 res = pbx_exec(work, app, feature->app_args); 01876 01877 if (!ast_strlen_zero(feature->moh_class)) 01878 ast_moh_stop(idle); 01879 01880 ast_autoservice_stop(idle); 01881 01882 if (res) { 01883 return AST_FEATURE_RETURN_SUCCESSBREAK; 01884 } 01885 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01886 }
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 1926 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().
01929 { 01930 int x; 01931 struct feature_group *fg = NULL; 01932 struct feature_group_exten *fge; 01933 struct ast_call_feature *tmpfeature; 01934 char *tmp, *tok; 01935 int res = AST_FEATURE_RETURN_PASSDIGITS; 01936 int feature_detected = 0; 01937 01938 if (!(peer && chan && config) && operation) { 01939 return -1; /* can not run feature operation */ 01940 } 01941 01942 ast_rwlock_rdlock(&features_lock); 01943 for (x = 0; x < FEATURES_COUNT; x++) { 01944 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 01945 !ast_strlen_zero(builtin_features[x].exten)) { 01946 /* Feature is up for consideration */ 01947 if (!strcmp(builtin_features[x].exten, code)) { 01948 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 01949 if (operation) { 01950 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01951 } 01952 memcpy(feature, &builtin_features[x], sizeof(feature)); 01953 feature_detected = 1; 01954 break; 01955 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01956 if (res == AST_FEATURE_RETURN_PASSDIGITS) 01957 res = AST_FEATURE_RETURN_STOREDIGITS; 01958 } 01959 } 01960 } 01961 ast_rwlock_unlock(&features_lock); 01962 01963 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 01964 return res; 01965 } 01966 01967 tmp = dynamic_features_buf; 01968 01969 while ((tok = strsep(&tmp, "#"))) { 01970 AST_RWLIST_RDLOCK(&feature_groups); 01971 01972 fg = find_group(tok); 01973 01974 if (fg) { 01975 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 01976 if (strcasecmp(fge->exten, code)) 01977 continue; 01978 if (operation) { 01979 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 01980 } 01981 memcpy(feature, fge->feature, sizeof(feature)); 01982 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 01983 AST_RWLIST_UNLOCK(&feature_groups); 01984 break; 01985 } 01986 res = AST_FEATURE_RETURN_PASSDIGITS; 01987 } 01988 if (fge) 01989 break; 01990 } 01991 01992 AST_RWLIST_UNLOCK(&feature_groups); 01993 01994 AST_RWLIST_RDLOCK(&feature_list); 01995 01996 if (!(tmpfeature = find_dynamic_feature(tok))) { 01997 AST_RWLIST_UNLOCK(&feature_list); 01998 continue; 01999 } 02000 02001 /* Feature is up for consideration */ 02002 if (!strcmp(tmpfeature->exten, code)) { 02003 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 02004 if (operation) { 02005 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 02006 } 02007 memcpy(feature, tmpfeature, sizeof(feature)); 02008 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 02009 AST_RWLIST_UNLOCK(&feature_list); 02010 break; 02011 } 02012 res = AST_FEATURE_RETURN_PASSDIGITS; 02013 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 02014 res = AST_FEATURE_RETURN_STOREDIGITS; 02015 02016 AST_RWLIST_UNLOCK(&feature_list); 02017 } 02018 02019 return res; 02020 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a call feature by name
Definition at line 1753 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().
01754 { 01755 struct ast_call_feature *tmp; 01756 01757 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01758 if (!strcasecmp(tmp->sname, name)) { 01759 break; 01760 } 01761 } 01762 01763 return tmp; 01764 }
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 1791 of file features.c.
References AST_LIST_TRAVERSE, feature_group_exten::entry, and feature_group::gname.
Referenced by feature_interpret_helper().
01791 { 01792 struct feature_group *fg = NULL; 01793 01794 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 01795 if (!strcasecmp(fg->gname, name)) 01796 break; 01797 } 01798 01799 return fg; 01800 }
struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) |
Find parkinglot by name.
Definition at line 3192 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().
03193 { 03194 struct ast_parkinglot *parkinglot = NULL; 03195 struct ast_parkinglot tmp_parkinglot; 03196 03197 if (ast_strlen_zero(name)) 03198 return NULL; 03199 03200 ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name)); 03201 03202 parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER); 03203 03204 if (parkinglot && option_debug) 03205 ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name); 03206 03207 return parkinglot; 03208 }
static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 422 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().
00423 { 00424 const char *temp, *parkinglot = NULL; 00425 00426 /* Check if the channel has a parking lot */ 00427 if (!ast_strlen_zero(chan->parkinglot)) 00428 parkinglot = chan->parkinglot; 00429 00430 /* Channel variables override everything */ 00431 00432 if ((temp = pbx_builtin_getvar_helper(chan, "PARKINGLOT"))) 00433 return temp; 00434 00435 return parkinglot; 00436 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1149 of file features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, ast_indicate(), and chan.
Referenced by builtin_atxfer(), and builtin_blindtransfer().
01150 { 01151 ast_indicate(chan, AST_CONTROL_UNHOLD); 01152 01153 return ast_autoservice_stop(chan); 01154 }
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 3992 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.
03993 { 03994 int i; 03995 struct ast_call_feature *feature; 03996 struct ao2_iterator iter; 03997 struct ast_parkinglot *curlot; 03998 #define HFS_FORMAT "%-25s %-7s %-7s\n" 03999 04000 switch (cmd) { 04001 04002 case CLI_INIT: 04003 e->command = "features show"; 04004 e->usage = 04005 "Usage: features show\n" 04006 " Lists configured features\n"; 04007 return NULL; 04008 case CLI_GENERATE: 04009 return NULL; 04010 } 04011 04012 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 04013 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 04014 04015 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 04016 04017 ast_rwlock_rdlock(&features_lock); 04018 for (i = 0; i < FEATURES_COUNT; i++) 04019 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 04020 ast_rwlock_unlock(&features_lock); 04021 04022 ast_cli(a->fd, "\n"); 04023 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 04024 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 04025 if (AST_RWLIST_EMPTY(&feature_list)) { 04026 ast_cli(a->fd, "(none)\n"); 04027 } else { 04028 AST_RWLIST_RDLOCK(&feature_list); 04029 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 04030 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 04031 } 04032 AST_RWLIST_UNLOCK(&feature_list); 04033 } 04034 04035 // loop through all the parking lots 04036 iter = ao2_iterator_init(parkinglots, 0); 04037 04038 while ((curlot = ao2_iterator_next(&iter))) { 04039 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 04040 ast_cli(a->fd, "------------\n"); 04041 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", parking_ext); 04042 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->parking_con); 04043 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop); 04044 ast_cli(a->fd,"\n"); 04045 ao2_ref(curlot, -1); 04046 } 04047 04048 04049 return CLI_SUCCESS; 04050 }
static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 4066 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
04067 { 04068 switch (cmd) { 04069 case CLI_INIT: 04070 e->command = "features reload"; 04071 e->usage = 04072 "Usage: features reload\n" 04073 " Reloads configured call features from features.conf\n"; 04074 return NULL; 04075 case CLI_GENERATE: 04076 return NULL; 04077 } 04078 ast_features_reload(); 04079 04080 return CLI_SUCCESS; 04081 }
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 4249 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.
04250 { 04251 struct parkeduser *cur; 04252 int numparked = 0; 04253 struct ao2_iterator iter; 04254 struct ast_parkinglot *curlot; 04255 04256 switch (cmd) { 04257 case CLI_INIT: 04258 e->command = "parkedcalls show"; 04259 e->usage = 04260 "Usage: parkedcalls show\n" 04261 " List currently parked calls\n"; 04262 return NULL; 04263 case CLI_GENERATE: 04264 return NULL; 04265 } 04266 04267 if (a->argc > e->args) 04268 return CLI_SHOWUSAGE; 04269 04270 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 04271 , "Context", "Extension", "Pri", "Timeout"); 04272 04273 iter = ao2_iterator_init(parkinglots, 0); 04274 while ((curlot = ao2_iterator_next(&iter))) { 04275 int lotparked = 0; 04276 ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name); 04277 04278 AST_LIST_LOCK(&curlot->parkings); 04279 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 04280 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 04281 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 04282 ,cur->priority, 04283 (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) ); 04284 numparked++; 04285 numparked += lotparked; 04286 } 04287 AST_LIST_UNLOCK(&curlot->parkings); 04288 if (lotparked) 04289 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name); 04290 04291 ao2_ref(curlot, -1); 04292 } 04293 04294 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 04295 04296 return CLI_SUCCESS; 04297 }
static int load_config | ( | void | ) | [static] |
Definition at line 3640 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().
03641 { 03642 int start = 0, end = 0; 03643 int res; 03644 int i; 03645 struct ast_context *con = NULL; 03646 struct ast_config *cfg = NULL; 03647 struct ast_variable *var = NULL; 03648 struct feature_group *fg = NULL; 03649 struct ast_flags config_flags = { 0 }; 03650 char old_parking_ext[AST_MAX_EXTENSION]; 03651 char old_parking_con[AST_MAX_EXTENSION] = ""; 03652 char *ctg; 03653 static const char *categories[] = { 03654 /* Categories in features.conf that are not 03655 * to be parsed as group categories 03656 */ 03657 "general", 03658 "featuremap", 03659 "applicationmap" 03660 }; 03661 03662 if (default_parkinglot) { 03663 strcpy(old_parking_con, default_parkinglot->parking_con); 03664 strcpy(old_parking_ext, parking_ext); 03665 } else { 03666 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 03667 if (default_parkinglot) { 03668 ao2_lock(default_parkinglot); 03669 default_parkinglot->parking_start = 701; 03670 default_parkinglot->parking_stop = 750; 03671 default_parkinglot->parking_offset = 0; 03672 default_parkinglot->parkfindnext = 0; 03673 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 03674 ao2_unlock(default_parkinglot); 03675 } 03676 } 03677 if (default_parkinglot) { 03678 if (option_debug) 03679 ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n"); 03680 } else { 03681 ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n"); 03682 return -1; 03683 } 03684 03685 03686 /* Reset to defaults */ 03687 strcpy(parking_ext, "700"); 03688 strcpy(pickup_ext, "*8"); 03689 courtesytone[0] = '\0'; 03690 strcpy(xfersound, "beep"); 03691 strcpy(xferfailsound, "pbx-invalid"); 03692 adsipark = 0; 03693 comebacktoorigin = 1; 03694 03695 default_parkinglot->parkaddhints = 0; 03696 default_parkinglot->parkedcalltransfers = 0; 03697 default_parkinglot->parkedcallreparking = 0; 03698 default_parkinglot->parkedcallrecording = 0; 03699 default_parkinglot->parkedcallhangup = 0; 03700 03701 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03702 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03703 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03704 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 03705 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 03706 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 03707 03708 cfg = ast_config_load2("features.conf", "features", config_flags); 03709 if (!cfg) { 03710 ast_log(LOG_WARNING,"Could not load features.conf\n"); 03711 return 0; 03712 } 03713 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 03714 if (!strcasecmp(var->name, "parkext")) { 03715 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 03716 } else if (!strcasecmp(var->name, "context")) { 03717 ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con)); 03718 } else if (!strcasecmp(var->name, "parkingtime")) { 03719 if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) { 03720 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 03721 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 03722 } else 03723 default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000; 03724 } else if (!strcasecmp(var->name, "parkpos")) { 03725 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 03726 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); 03727 } else if (default_parkinglot) { 03728 default_parkinglot->parking_start = start; 03729 default_parkinglot->parking_stop = end; 03730 } else { 03731 ast_log(LOG_WARNING, "No default parking lot!\n"); 03732 } 03733 } else if (!strcasecmp(var->name, "findslot")) { 03734 default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next")); 03735 } else if (!strcasecmp(var->name, "parkinghints")) { 03736 default_parkinglot->parkaddhints = ast_true(var->value); 03737 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 03738 if (!strcasecmp(var->value, "both")) 03739 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 03740 else if (!strcasecmp(var->value, "caller")) 03741 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 03742 else if (!strcasecmp(var->value, "callee")) 03743 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 03744 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 03745 if (!strcasecmp(var->value, "both")) 03746 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 03747 else if (!strcasecmp(var->value, "caller")) 03748 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 03749 else if (!strcasecmp(var->value, "callee")) 03750 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 03751 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 03752 if (!strcasecmp(var->value, "both")) 03753 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 03754 else if (!strcasecmp(var->value, "caller")) 03755 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 03756 else if (!strcasecmp(var->value, "callee")) 03757 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 03758 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 03759 if (!strcasecmp(var->value, "both")) 03760 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 03761 else if (!strcasecmp(var->value, "caller")) 03762 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 03763 else if (!strcasecmp(var->value, "callee")) 03764 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 03765 } else if (!strcasecmp(var->name, "adsipark")) { 03766 adsipark = ast_true(var->value); 03767 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03768 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03769 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03770 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03771 } else 03772 transferdigittimeout = transferdigittimeout * 1000; 03773 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03774 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03775 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03776 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03777 } 03778 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03779 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03780 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03781 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03782 } else 03783 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03784 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 03785 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 03786 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 03787 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 03788 } else 03789 atxferloopdelay *= 1000; 03790 } else if (!strcasecmp(var->name, "atxferdropcall")) { 03791 atxferdropcall = ast_true(var->value); 03792 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 03793 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 03794 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 03795 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 03796 } 03797 } else if (!strcasecmp(var->name, "courtesytone")) { 03798 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03799 } else if (!strcasecmp(var->name, "parkedplay")) { 03800 if (!strcasecmp(var->value, "both")) 03801 parkedplay = 2; 03802 else if (!strcasecmp(var->value, "parked")) 03803 parkedplay = 1; 03804 else 03805 parkedplay = 0; 03806 } else if (!strcasecmp(var->name, "xfersound")) { 03807 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03808 } else if (!strcasecmp(var->name, "xferfailsound")) { 03809 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03810 } else if (!strcasecmp(var->name, "pickupexten")) { 03811 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03812 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 03813 comebacktoorigin = ast_true(var->value); 03814 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03815 ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass)); 03816 } 03817 } 03818 03819 unmap_features(); 03820 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03821 if (remap_feature(var->name, var->value)) 03822 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03823 } 03824 03825 /* Map a key combination to an application*/ 03826 ast_unregister_features(); 03827 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03828 char *tmp_val = ast_strdupa(var->value); 03829 char *activateon; 03830 struct ast_call_feature *feature; 03831 AST_DECLARE_APP_ARGS(args, 03832 AST_APP_ARG(exten); 03833 AST_APP_ARG(activatedby); 03834 AST_APP_ARG(app); 03835 AST_APP_ARG(app_args); 03836 AST_APP_ARG(moh_class); 03837 ); 03838 03839 AST_STANDARD_APP_ARGS(args, tmp_val); 03840 if (strchr(args.app, '(')) { 03841 /* New syntax */ 03842 args.moh_class = args.app_args; 03843 args.app_args = strchr(args.app, '('); 03844 *args.app_args++ = '\0'; 03845 if (args.app_args[strlen(args.app_args) - 1] == ')') { 03846 args.app_args[strlen(args.app_args) - 1] = '\0'; 03847 } 03848 } 03849 03850 activateon = strsep(&args.activatedby, "/"); 03851 03852 /*! \todo XXX var_name or app_args ? */ 03853 if (ast_strlen_zero(args.app) || ast_strlen_zero(args.exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03854 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03855 args.app, args.exten, activateon, var->name); 03856 continue; 03857 } 03858 03859 AST_RWLIST_RDLOCK(&feature_list); 03860 if ((feature = find_dynamic_feature(var->name))) { 03861 AST_RWLIST_UNLOCK(&feature_list); 03862 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03863 continue; 03864 } 03865 AST_RWLIST_UNLOCK(&feature_list); 03866 03867 if (!(feature = ast_calloc(1, sizeof(*feature)))) { 03868 continue; 03869 } 03870 03871 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03872 ast_copy_string(feature->app, args.app, FEATURE_APP_LEN); 03873 ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN); 03874 03875 if (args.app_args) { 03876 ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN); 03877 } 03878 03879 if (args.moh_class) { 03880 ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN); 03881 } 03882 03883 ast_copy_string(feature->exten, args.exten, sizeof(feature->exten)); 03884 feature->operation = feature_exec_app; 03885 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03886 03887 /* Allow caller and calle to be specified for backwards compatability */ 03888 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03889 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03890 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03891 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03892 else { 03893 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03894 " must be 'self', or 'peer'\n", var->name); 03895 continue; 03896 } 03897 03898 if (ast_strlen_zero(args.activatedby)) 03899 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03900 else if (!strcasecmp(args.activatedby, "caller")) 03901 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03902 else if (!strcasecmp(args.activatedby, "callee")) 03903 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03904 else if (!strcasecmp(args.activatedby, "both")) 03905 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03906 else { 03907 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03908 " must be 'caller', or 'callee', or 'both'\n", var->name); 03909 continue; 03910 } 03911 03912 ast_register_feature(feature); 03913 03914 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, args.app, args.app_args, args.exten); 03915 } 03916 03917 ast_unregister_groups(); 03918 AST_RWLIST_WRLOCK(&feature_groups); 03919 03920 ctg = NULL; 03921 while ((ctg = ast_category_browse(cfg, ctg))) { 03922 /* Is this a parkinglot definition ? */ 03923 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 03924 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 03925 if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) 03926 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 03927 else 03928 ast_debug(1, "Configured parking context %s\n", ctg); 03929 continue; 03930 } 03931 /* No, check if it's a group */ 03932 for (i = 0; i < ARRAY_LEN(categories); i++) { 03933 if (!strcasecmp(categories[i], ctg)) 03934 break; 03935 } 03936 03937 if (i < ARRAY_LEN(categories)) 03938 continue; 03939 03940 if (!(fg = register_group(ctg))) 03941 continue; 03942 03943 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 03944 struct ast_call_feature *feature; 03945 03946 AST_RWLIST_RDLOCK(&feature_list); 03947 if (!(feature = find_dynamic_feature(var->name)) && 03948 !(feature = ast_find_call_feature(var->name))) { 03949 AST_RWLIST_UNLOCK(&feature_list); 03950 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 03951 continue; 03952 } 03953 AST_RWLIST_UNLOCK(&feature_list); 03954 03955 register_group_feature(fg, var->value, feature); 03956 } 03957 } 03958 03959 AST_RWLIST_UNLOCK(&feature_groups); 03960 03961 ast_config_destroy(cfg); 03962 03963 /* Remove the old parking extension */ 03964 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03965 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0)) 03966 notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE); 03967 ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03968 } 03969 03970 if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) { 03971 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con); 03972 return -1; 03973 } 03974 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 03975 if (default_parkinglot->parkaddhints) 03976 park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop); 03977 if (!res) 03978 notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE); 03979 return res; 03980 03981 }
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 2977 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, parkeduser::options_specified, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), and parkeduser::start.
Referenced by do_parking_thread().
02978 { 02979 02980 struct parkeduser *pu; 02981 int res = 0; 02982 char parkingslot[AST_MAX_EXTENSION]; 02983 02984 /* Lock parking list */ 02985 AST_LIST_LOCK(&curlot->parkings); 02986 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 02987 struct ast_channel *chan = pu->chan; /* shorthand */ 02988 int tms; /* timeout for this item */ 02989 int x; /* fd index in channel */ 02990 struct ast_context *con; 02991 02992 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 02993 continue; 02994 } 02995 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 02996 if (tms > pu->parkingtime) { 02997 /* Stop music on hold */ 02998 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 02999 /* Get chan, exten from derived kludge */ 03000 if (pu->peername[0]) { 03001 char *peername = ast_strdupa(pu->peername); 03002 char *cp = strrchr(peername, '-'); 03003 char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 03004 int i; 03005 03006 if (cp) 03007 *cp = 0; 03008 ast_copy_string(peername_flat,peername,sizeof(peername_flat)); 03009 for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) { 03010 if (peername_flat[i] == '/') 03011 peername_flat[i]= '0'; 03012 } 03013 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar); 03014 if (!con) { 03015 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial); 03016 } 03017 if (con) { 03018 char returnexten[AST_MAX_EXTENSION]; 03019 struct ast_datastore *features_datastore; 03020 struct ast_dial_features *dialfeatures = NULL; 03021 03022 ast_channel_lock(chan); 03023 03024 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 03025 dialfeatures = features_datastore->data; 03026 03027 ast_channel_unlock(chan); 03028 03029 if (!strncmp(peername, "Parked/", 7)) { 03030 peername += 7; 03031 } 03032 03033 if (dialfeatures) { 03034 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 03035 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 03036 } else { /* Existing default */ 03037 ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name); 03038 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername); 03039 } 03040 03041 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar); 03042 } 03043 if (pu->options_specified == 1) { 03044 /* Park() was called with overriding return arguments, respect those arguments */ 03045 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 03046 } else { 03047 if (comebacktoorigin) { 03048 set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1); 03049 } else { 03050 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum); 03051 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 03052 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 03053 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 03054 } 03055 } 03056 } else { 03057 /* They've been waiting too long, send them back to where they came. Theoretically they 03058 should have their original extensions and such, but we copy to be on the safe side */ 03059 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 03060 } 03061 post_manager_event("ParkedCallTimeOut", pu); 03062 03063 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); 03064 /* Start up the PBX, or hang them up */ 03065 if (ast_pbx_start(chan)) { 03066 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name); 03067 ast_hangup(chan); 03068 } 03069 /* And take them out of the parking lot */ 03070 con = ast_context_find(pu->parkinglot->parking_con); 03071 if (con) { 03072 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03073 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n"); 03074 else 03075 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 03076 } else 03077 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 03078 AST_LIST_REMOVE_CURRENT(list); 03079 free(pu); 03080 } else { /* still within parking time, process descriptors */ 03081 for (x = 0; x < AST_MAX_FDS; x++) { 03082 struct ast_frame *f; 03083 03084 if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds))) 03085 continue; 03086 03087 if (FD_ISSET(chan->fds[x], efds)) 03088 ast_set_flag(chan, AST_FLAG_EXCEPTION); 03089 else 03090 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 03091 chan->fdno = x; 03092 03093 /* See if they need servicing */ 03094 f = ast_read(pu->chan); 03095 /* Hangup? */ 03096 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 03097 if (f) 03098 ast_frfree(f); 03099 post_manager_event("ParkedCallGiveUp", pu); 03100 03101 /* There's a problem, hang them up*/ 03102 ast_verb(2, "%s got tired of being parked\n", chan->name); 03103 ast_hangup(chan); 03104 /* And take them out of the parking lot */ 03105 con = ast_context_find(curlot->parking_con); 03106 if (con) { 03107 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03108 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 03109 else 03110 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 03111 } else 03112 ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name); 03113 AST_LIST_REMOVE_CURRENT(list); 03114 free(pu); 03115 break; 03116 } else { 03117 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 03118 ast_frfree(f); 03119 if (pu->moh_trys < 3 && !chan->generatordata) { 03120 ast_debug(1, "MOH on parked call stopped by outside source. Restarting on channel %s.\n", chan->name); 03121 ast_indicate_data(chan, AST_CONTROL_HOLD, 03122 S_OR(curlot->mohclass, NULL), 03123 (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0)); 03124 pu->moh_trys++; 03125 } 03126 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 03127 } 03128 } /* End for */ 03129 if (x >= AST_MAX_FDS) { 03130 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 03131 if (chan->fds[x] > -1) { 03132 FD_SET(chan->fds[x], nrfds); 03133 FD_SET(chan->fds[x], nefds); 03134 if (chan->fds[x] > *max) 03135 *max = chan->fds[x]; 03136 } 03137 } 03138 /* Keep track of our shortest wait */ 03139 if (tms < *ms || *ms < 0) 03140 *ms = tms; 03141 } 03142 } 03143 } 03144 AST_LIST_TRAVERSE_SAFE_END; 03145 AST_LIST_UNLOCK(&curlot->parkings); 03146 return res; 03147 }
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 4374 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().
04375 { 04376 const char *channel = astman_get_header(m, "Channel"); 04377 const char *channel2 = astman_get_header(m, "Channel2"); 04378 const char *timeout = astman_get_header(m, "Timeout"); 04379 char buf[BUFSIZ]; 04380 int to = 0; 04381 int res = 0; 04382 int parkExt = 0; 04383 struct ast_channel *ch1, *ch2; 04384 04385 if (ast_strlen_zero(channel)) { 04386 astman_send_error(s, m, "Channel not specified"); 04387 return 0; 04388 } 04389 04390 if (ast_strlen_zero(channel2)) { 04391 astman_send_error(s, m, "Channel2 not specified"); 04392 return 0; 04393 } 04394 04395 ch1 = ast_get_channel_by_name_locked(channel); 04396 if (!ch1) { 04397 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 04398 astman_send_error(s, m, buf); 04399 return 0; 04400 } 04401 04402 ch2 = ast_get_channel_by_name_locked(channel2); 04403 if (!ch2) { 04404 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 04405 astman_send_error(s, m, buf); 04406 ast_channel_unlock(ch1); 04407 return 0; 04408 } 04409 04410 if (!ast_strlen_zero(timeout)) { 04411 sscanf(timeout, "%30d", &to); 04412 } 04413 04414 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 04415 if (!res) { 04416 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 04417 astman_send_ack(s, m, "Park successful"); 04418 } else { 04419 astman_send_error(s, m, "Park failure"); 04420 } 04421 04422 ast_channel_unlock(ch1); 04423 ast_channel_unlock(ch2); 04424 04425 return 0; 04426 }
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 4313 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().
04314 { 04315 struct parkeduser *cur; 04316 const char *id = astman_get_header(m, "ActionID"); 04317 char idText[256] = ""; 04318 struct ao2_iterator iter; 04319 struct ast_parkinglot *curlot; 04320 04321 if (!ast_strlen_zero(id)) 04322 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 04323 04324 astman_send_ack(s, m, "Parked calls will follow"); 04325 04326 iter = ao2_iterator_init(parkinglots, 0); 04327 while ((curlot = ao2_iterator_next(&iter))) { 04328 04329 AST_LIST_LOCK(&curlot->parkings); 04330 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 04331 astman_append(s, "Event: ParkedCall\r\n" 04332 "Exten: %d\r\n" 04333 "Channel: %s\r\n" 04334 "From: %s\r\n" 04335 "Timeout: %ld\r\n" 04336 "CallerIDNum: %s\r\n" 04337 "CallerIDName: %s\r\n" 04338 "%s" 04339 "\r\n", 04340 cur->parkingnum, cur->chan->name, cur->peername, 04341 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 04342 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 04343 S_OR(cur->chan->cid.cid_name, ""), 04344 idText); 04345 } 04346 AST_LIST_UNLOCK(&curlot->parkings); 04347 ao2_ref(curlot, -1); 04348 } 04349 04350 astman_append(s, 04351 "Event: ParkedCallsComplete\r\n" 04352 "%s" 04353 "\r\n",idText); 04354 04355 04356 return RESULT_SUCCESS; 04357 }
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 764 of file features.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc, ast_channel_masquerade(), ast_copy_string(), 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::macrocontext, ast_channel::macroexten, ast_channel::macropriority, 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().
00765 { 00766 struct ast_channel *chan; 00767 struct ast_frame *f; 00768 int park_status; 00769 struct ast_park_call_args park_args = {0,}; 00770 00771 if (!args) { 00772 args = &park_args; 00773 args->timeout = timeout; 00774 args->extout = extout; 00775 } 00776 00777 if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) { 00778 if (peer) 00779 ast_stream_and_wait(peer, "beeperr", ""); 00780 return AST_FEATURE_RETURN_PARKFAILED; 00781 } 00782 00783 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00784 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00785 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00786 return -1; 00787 } 00788 00789 /* Make formats okay */ 00790 chan->readformat = rchan->readformat; 00791 chan->writeformat = rchan->writeformat; 00792 ast_channel_masquerade(chan, rchan); 00793 00794 /* Setup the extensions and such */ 00795 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00796 00797 /* Setup the macro extension and such */ 00798 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext)); 00799 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten)); 00800 chan->macropriority = rchan->macropriority; 00801 00802 /* Make the masq execute */ 00803 if ((f = ast_read(chan))) 00804 ast_frfree(f); 00805 00806 if (peer == rchan) { 00807 peer = chan; 00808 } 00809 00810 if (peer && (!play_announcement && args == &park_args)) { 00811 args->orig_chan_name = ast_strdupa(peer->name); 00812 } 00813 00814 park_status = ast_park_call_full(chan, peer, args); 00815 if (park_status == 1) { 00816 /* would be nice to play "invalid parking extension" */ 00817 ast_hangup(chan); 00818 return -1; 00819 } 00820 00821 return 0; 00822 }
static int masq_park_call_announce | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout | |||
) | [static] |
Definition at line 835 of file features.c.
References masq_park_call().
Referenced by builtin_blindtransfer(), and builtin_parkcall().
00836 { 00837 return masq_park_call(rchan, peer, timeout, extout, 1, NULL); 00838 }
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 830 of file features.c.
References masq_park_call().
Referenced by park_call_exec().
00831 { 00832 return masq_park_call(rchan, peer, 0, NULL, 1, args); 00833 }
static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 448 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().
00449 { 00450 char *context; 00451 char *exten; 00452 00453 context = ast_strdupa(data); 00454 00455 exten = strsep(&context, "@"); 00456 if (!context) 00457 return AST_DEVICE_INVALID; 00458 00459 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 00460 00461 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 00462 return AST_DEVICE_NOT_INUSE; 00463 00464 return AST_DEVICE_INUSE; 00465 }
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 439 of file features.c.
References ast_debug, ast_devstate_changed(), and devstate2str().
Referenced by ast_park_call_full(), manage_parkinglot(), and park_exec_full().
00440 { 00441 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 00442 exten, context, devstate2str(state)); 00443 00444 ast_devstate_changed(state, "park:%s@%s", exten, context); 00445 }
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 3627 of file features.c.
References ast_add_extension(), PRIORITY_HINT, and registrar.
03628 { 03629 int numext; 03630 char device[AST_MAX_EXTENSION]; 03631 char exten[10]; 03632 03633 for (numext = start; numext <= stop; numext++) { 03634 snprintf(exten, sizeof(exten), "%d", numext); 03635 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 03636 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 03637 } 03638 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 3217 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().
03218 { 03219 /* Cache the original channel name in case we get masqueraded in the middle 03220 * of a park--it is still theoretically possible for a transfer to happen before 03221 * we get here, but it is _really_ unlikely */ 03222 char *orig_chan_name = ast_strdupa(chan->name); 03223 char orig_exten[AST_MAX_EXTENSION]; 03224 int orig_priority = chan->priority; 03225 03226 /* Data is unused at the moment but could contain a parking 03227 lot context eventually */ 03228 int res = 0; 03229 03230 char *parse = NULL; 03231 AST_DECLARE_APP_ARGS(app_args, 03232 AST_APP_ARG(timeout); 03233 AST_APP_ARG(return_con); 03234 AST_APP_ARG(return_ext); 03235 AST_APP_ARG(return_pri); 03236 AST_APP_ARG(options); 03237 ); 03238 03239 parse = ast_strdupa(data); 03240 AST_STANDARD_APP_ARGS(app_args, parse); 03241 03242 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 03243 03244 /* Setup the exten/priority to be s/1 since we don't know 03245 where this call should return */ 03246 strcpy(chan->exten, "s"); 03247 chan->priority = 1; 03248 03249 /* Answer if call is not up */ 03250 if (chan->_state != AST_STATE_UP) 03251 res = ast_answer(chan); 03252 03253 /* Sleep to allow VoIP streams to settle down */ 03254 if (!res) 03255 res = ast_safe_sleep(chan, 1000); 03256 03257 /* Park the call */ 03258 if (!res) { 03259 struct ast_park_call_args args = { 03260 .orig_chan_name = orig_chan_name, 03261 }; 03262 struct ast_flags flags = { 0 }; 03263 03264 if (parse) { 03265 if (!ast_strlen_zero(app_args.timeout)) { 03266 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) { 03267 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 03268 args.timeout = 0; 03269 } 03270 } 03271 if (!ast_strlen_zero(app_args.return_con)) { 03272 args.return_con = app_args.return_con; 03273 } 03274 if (!ast_strlen_zero(app_args.return_ext)) { 03275 args.return_ext = app_args.return_ext; 03276 } 03277 if (!ast_strlen_zero(app_args.return_pri)) { 03278 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) { 03279 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 03280 args.return_pri = 0; 03281 } 03282 } 03283 } 03284 03285 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 03286 args.flags = flags.flags; 03287 03288 res = masq_park_call_announce_args(chan, chan, &args); 03289 /* Continue on in the dialplan */ 03290 if (res == 1) { 03291 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 03292 chan->priority = orig_priority; 03293 res = 0; 03294 } else if (!res) { 03295 res = 1; 03296 } 03297 } 03298 03299 return res; 03300 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3470 of file features.c.
References chan, default_parkinglot, and park_exec_full().
Referenced by ast_features_init().
03471 { 03472 return park_exec_full(chan, data, default_parkinglot); 03473 }
static int park_exec_full | ( | struct ast_channel * | chan, | |
void * | data, | |||
struct ast_parkinglot * | parkinglot | |||
) | [static] |
Pickup parked call.
Definition at line 3303 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_caller, find_parkinglot(), findparkinglotname(), 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().
03304 { 03305 int res = 0; 03306 struct ast_channel *peer=NULL; 03307 struct parkeduser *pu; 03308 struct ast_context *con; 03309 int park = 0; 03310 struct ast_bridge_config config; 03311 03312 if (data) 03313 park = atoi((char *)data); 03314 03315 parkinglot = find_parkinglot(findparkinglotname(chan)); 03316 if (!parkinglot) 03317 parkinglot = default_parkinglot; 03318 03319 AST_LIST_LOCK(&parkinglot->parkings); 03320 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 03321 if (!data || pu->parkingnum == park) { 03322 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 03323 AST_LIST_UNLOCK(&parkinglot->parkings); 03324 return -1; 03325 } 03326 AST_LIST_REMOVE_CURRENT(list); 03327 break; 03328 } 03329 } 03330 AST_LIST_TRAVERSE_SAFE_END; 03331 AST_LIST_UNLOCK(&parkinglot->parkings); 03332 03333 if (pu) { 03334 peer = pu->chan; 03335 con = ast_context_find(parkinglot->parking_con); 03336 if (con) { 03337 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03338 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 03339 else 03340 notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE); 03341 } else 03342 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 03343 03344 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 03345 "Exten: %s\r\n" 03346 "Channel: %s\r\n" 03347 "From: %s\r\n" 03348 "CallerIDNum: %s\r\n" 03349 "CallerIDName: %s\r\n", 03350 pu->parkingexten, pu->chan->name, chan->name, 03351 S_OR(pu->chan->cid.cid_num, "<unknown>"), 03352 S_OR(pu->chan->cid.cid_name, "<unknown>") 03353 ); 03354 03355 ast_free(pu); 03356 } 03357 /* JK02: it helps to answer the channel if not already up */ 03358 if (chan->_state != AST_STATE_UP) 03359 ast_answer(chan); 03360 03361 //XXX Why do we unlock here ? 03362 // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain 03363 //ASTOBJ_UNLOCK(parkinglot); 03364 03365 if (peer) { 03366 struct ast_datastore *features_datastore; 03367 struct ast_dial_features *dialfeatures = NULL; 03368 03369 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 03370 03371 if (!ast_strlen_zero(courtesytone)) { 03372 int error = 0; 03373 ast_indicate(peer, AST_CONTROL_UNHOLD); 03374 if (parkedplay == 0) { 03375 error = ast_stream_and_wait(chan, courtesytone, ""); 03376 } else if (parkedplay == 1) { 03377 error = ast_stream_and_wait(peer, courtesytone, ""); 03378 } else if (parkedplay == 2) { 03379 if (!ast_streamfile(chan, courtesytone, chan->language) && 03380 !ast_streamfile(peer, courtesytone, chan->language)) { 03381 /*! \todo XXX we would like to wait on both! */ 03382 res = ast_waitstream(chan, ""); 03383 if (res >= 0) 03384 res = ast_waitstream(peer, ""); 03385 if (res < 0) 03386 error = 1; 03387 } 03388 } 03389 if (error) { 03390 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 03391 ast_hangup(peer); 03392 return -1; 03393 } 03394 } else 03395 ast_indicate(peer, AST_CONTROL_UNHOLD); 03396 03397 res = ast_channel_make_compatible(chan, peer); 03398 if (res < 0) { 03399 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 03400 ast_hangup(peer); 03401 return -1; 03402 } 03403 /* This runs sorta backwards, since we give the incoming channel control, as if it 03404 were the person called. */ 03405 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park); 03406 03407 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03408 ast_cdr_setdestchan(chan->cdr, peer->name); 03409 memset(&config, 0, sizeof(struct ast_bridge_config)); 03410 03411 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 03412 ast_channel_lock(peer); 03413 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 03414 dialfeatures = features_datastore->data; 03415 } 03416 ast_channel_unlock(peer); 03417 03418 /* When the datastores for both caller and callee are created, both the callee and caller channels 03419 * use the features_caller flag variable to represent themselves. With that said, the config.features_callee 03420 * flags should be copied from the datastore's caller feature flags regardless if peer was a callee 03421 * or caller. */ 03422 if (dialfeatures) { 03423 ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 03424 } 03425 03426 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03427 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 03428 } 03429 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03430 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 03431 } 03432 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03433 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 03434 } 03435 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03436 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 03437 } 03438 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03439 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 03440 } 03441 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03442 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 03443 } 03444 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03445 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 03446 } 03447 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03448 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 03449 } 03450 03451 res = ast_bridge_call(chan, peer, &config); 03452 03453 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03454 ast_cdr_setdestchan(chan->cdr, peer->name); 03455 03456 /* Simulate the PBX hanging up */ 03457 ast_hangup(peer); 03458 return -1; 03459 } else { 03460 /*! \todo XXX Play a message XXX */ 03461 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) 03462 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 03463 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 03464 res = -1; 03465 } 03466 03467 return -1; 03468 }
static struct parkeduser* park_space_reserve | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_park_call_args * | args | |||
) | [static] |
Definition at line 495 of file features.c.
References ast_calloc, ast_channel_lock, ast_channel_unlock, ast_exists_extension(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strdupa, ast_strlen_zero(), ast_test_flag, chan, default_parkinglot, find_parkinglot(), findparkinglotname(), free, parkeduser::list, LOG_DEBUG, LOG_WARNING, option_debug, parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_park_call_full(), and masq_park_call().
00497 { 00498 struct parkeduser *pu; 00499 int i, parking_space = -1, parking_range; 00500 const char *parkinglotname = NULL; 00501 const char *parkingexten; 00502 struct ast_parkinglot *parkinglot = NULL; 00503 00504 if (peer) 00505 parkinglotname = findparkinglotname(peer); 00506 else /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */ 00507 parkinglotname = findparkinglotname(chan); 00508 00509 if (parkinglotname) { 00510 if (option_debug) 00511 ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname); 00512 parkinglot = find_parkinglot(parkinglotname); 00513 } 00514 if (!parkinglot) { 00515 parkinglot = parkinglot_addref(default_parkinglot); 00516 } 00517 00518 if (option_debug) 00519 ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name); 00520 00521 /* Allocate memory for parking data */ 00522 if (!(pu = ast_calloc(1, sizeof(*pu)))) { 00523 parkinglot_unref(parkinglot); 00524 return NULL; 00525 } 00526 00527 /* Lock parking list */ 00528 AST_LIST_LOCK(&parkinglot->parkings); 00529 /* Check for channel variable PARKINGEXTEN */ 00530 ast_channel_lock(chan); 00531 parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"), "")); 00532 ast_channel_unlock(chan); 00533 if (!ast_strlen_zero(parkingexten)) { 00534 /*!\note The API forces us to specify a numeric parking slot, even 00535 * though the architecture would tend to support non-numeric extensions 00536 * (as are possible with SIP, for example). Hence, we enforce that 00537 * limitation here. If extout was not numeric, we could permit 00538 * arbitrary non-numeric extensions. 00539 */ 00540 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) { 00541 AST_LIST_UNLOCK(&parkinglot->parkings); 00542 parkinglot_unref(parkinglot); 00543 free(pu); 00544 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); 00545 return NULL; 00546 } 00547 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00548 00549 if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) { 00550 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con); 00551 AST_LIST_UNLOCK(&parkinglot->parkings); 00552 parkinglot_unref(parkinglot); 00553 ast_free(pu); 00554 return NULL; 00555 } 00556 } else { 00557 int start; 00558 struct parkeduser *cur = NULL; 00559 00560 /* Select parking space within range */ 00561 parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1; 00562 00563 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) { 00564 start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1); 00565 } else { 00566 start = parkinglot->parking_start; 00567 } 00568 00569 for (i = start; 1; i++) { 00570 if (i == parkinglot->parking_stop + 1) { 00571 i = parkinglot->parking_start - 1; 00572 break; 00573 } 00574 00575 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 00576 if (cur->parkingnum == i) { 00577 break; 00578 } 00579 } 00580 if (!cur) { 00581 parking_space = i; 00582 break; 00583 } 00584 } 00585 00586 if (i == start - 1 && cur) { 00587 ast_log(LOG_WARNING, "No more parking spaces\n"); 00588 ast_free(pu); 00589 AST_LIST_UNLOCK(&parkinglot->parkings); 00590 parkinglot_unref(parkinglot); 00591 return NULL; 00592 } 00593 /* Set pointer for next parking */ 00594 if (parkinglot->parkfindnext) 00595 parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1; 00596 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00597 } 00598 00599 pu->notquiteyet = 1; 00600 pu->parkingnum = parking_space; 00601 pu->parkinglot = parkinglot_addref(parkinglot); 00602 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list); 00603 parkinglot_unref(parkinglot); 00604 00605 return pu; 00606 }
static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Definition at line 3484 of file features.c.
References ao2_ref, ast_log(), LOG_DEBUG, option_debug, and parkinglot.
Referenced by park_space_reserve().
03485 { 03486 int refcount = ao2_ref(parkinglot, +1); 03487 if (option_debug > 2) 03488 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1); 03489 return parkinglot; 03490 }
static int parkinglot_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 269 of file features.c.
References CMP_MATCH, CMP_STOP, and parkinglot.
Referenced by ast_features_init().
00270 { 00271 struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg; 00272 00273 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0; 00274 }
static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 3511 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().
03512 { 03513 struct ast_parkinglot *ruin = obj; 03514 struct ast_context *con; 03515 con = ast_context_find(ruin->parking_con); 03516 if (con) 03517 ast_context_destroy(con, registrar); 03518 ao2_unlink(parkinglots, ruin); 03519 }
static int parkinglot_hash_cb | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 262 of file features.c.
References ast_str_case_hash(), and parkinglot.
Referenced by ast_features_init().
00263 { 00264 const struct ast_parkinglot *parkinglot = obj; 00265 00266 return ast_str_case_hash(parkinglot->name); 00267 }
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 3477 of file features.c.
References ao2_ref, ast_log(), LOG_DEBUG, option_debug, and parkinglot.
Referenced by build_parkinglot(), and park_space_reserve().
03478 { 03479 int refcount = ao2_ref(parkinglot, -1); 03480 if (option_debug > 2) 03481 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1); 03482 }
return the first unlocked cdr in a possible chain
Definition at line 2294 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
02295 { 02296 struct ast_cdr *cdr_orig = cdr; 02297 while (cdr) { 02298 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 02299 return cdr; 02300 cdr = cdr->next; 02301 } 02302 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 02303 }
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 901 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_stream_and_wait(), and LOG_WARNING.
Referenced by builtin_automonitor().
00902 { 00903 /* First play for caller, put other channel on auto service */ 00904 if (ast_autoservice_start(callee_chan)) 00905 return -1; 00906 if (ast_stream_and_wait(caller_chan, audiofile, "")) { 00907 ast_log(LOG_WARNING, "Failed to play automon message!\n"); 00908 ast_autoservice_stop(callee_chan); 00909 return -1; 00910 } 00911 if (ast_autoservice_stop(callee_chan)) 00912 return -1; 00913 /* Then play for callee, put other channel on auto service */ 00914 if (ast_autoservice_start(caller_chan)) 00915 return -1; 00916 if (ast_stream_and_wait(callee_chan, audiofile, "")) { 00917 ast_log(LOG_WARNING, "Failed to play automon message !\n"); 00918 ast_autoservice_stop(caller_chan); 00919 return -1; 00920 } 00921 if (ast_autoservice_stop(caller_chan)) 00922 return -1; 00923 return(0); 00924 }
static void post_manager_event | ( | const char * | s, | |
struct parkeduser * | pu | |||
) | [static] |
Output parking event to manager.
Definition at line 2914 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().
02915 { 02916 manager_event(EVENT_FLAG_CALL, s, 02917 "Exten: %s\r\n" 02918 "Channel: %s\r\n" 02919 "Parkinglot: %s\r\n" 02920 "CallerIDNum: %s\r\n" 02921 "CallerIDName: %s\r\n" 02922 "UniqueID: %s\r\n\r\n", 02923 pu->parkingexten, 02924 pu->chan->name, 02925 pu->parkinglot->name, 02926 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02927 S_OR(pu->chan->cid.cid_name, "<unknown>"), 02928 pu->chan->uniqueid 02929 ); 02930 }
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 1164 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().
01165 { 01166 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 01167 if (ast_strlen_zero(s)) { 01168 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 01169 } 01170 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 01171 s = transferer->macrocontext; 01172 } 01173 if (ast_strlen_zero(s)) { 01174 s = transferer->context; 01175 } 01176 return s; 01177 }
static struct feature_group* register_group | ( | const char * | fgname | ) | [static] |
Add new feature group.
fgname | feature group name. |
Definition at line 1660 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.
01661 { 01662 struct feature_group *fg; 01663 01664 if (!fgname) { 01665 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 01666 return NULL; 01667 } 01668 01669 if (!(fg = ast_calloc(1, sizeof(*fg)))) 01670 return NULL; 01671 01672 if (ast_string_field_init(fg, 128)) { 01673 ast_free(fg); 01674 return NULL; 01675 } 01676 01677 ast_string_field_set(fg, gname, fgname); 01678 01679 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 01680 01681 ast_verb(2, "Registered group '%s'\n", fg->gname); 01682 01683 return fg; 01684 }
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 1695 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.
01696 { 01697 struct feature_group_exten *fge; 01698 01699 if (!fg) { 01700 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 01701 return; 01702 } 01703 01704 if (!feature) { 01705 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 01706 return; 01707 } 01708 01709 if (!(fge = ast_calloc(1, sizeof(*fge)))) 01710 return; 01711 01712 if (ast_string_field_init(fge, 128)) { 01713 ast_free(fge); 01714 return; 01715 } 01716 01717 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 01718 01719 fge->feature = feature; 01720 01721 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 01722 01723 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 01724 feature->sname, fg->gname, exten); 01725 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1898 of file features.c.
References ast_copy_string(), ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, FEATURES_COUNT, and features_lock.
01899 { 01900 int x, res = -1; 01901 01902 ast_rwlock_wrlock(&features_lock); 01903 for (x = 0; x < FEATURES_COUNT; x++) { 01904 if (strcasecmp(builtin_features[x].sname, name)) 01905 continue; 01906 01907 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01908 res = 0; 01909 break; 01910 } 01911 ast_rwlock_unlock(&features_lock); 01912 01913 return res; 01914 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 2305 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().
02306 { 02307 const char *feature; 02308 02309 if (ast_strlen_zero(features)) { 02310 return; 02311 } 02312 02313 for (feature = features; *feature; feature++) { 02314 switch (*feature) { 02315 case 'T' : 02316 case 't' : 02317 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 02318 break; 02319 case 'K' : 02320 case 'k' : 02321 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 02322 break; 02323 case 'H' : 02324 case 'h' : 02325 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 02326 break; 02327 case 'W' : 02328 case 'w' : 02329 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 02330 break; 02331 default : 02332 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 02333 } 02334 } 02335 }
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 280 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().
00281 { 00282 ast_copy_string(chan->context, context, sizeof(chan->context)); 00283 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00284 chan->priority = pri; 00285 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 2064 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().
02065 { 02066 int x; 02067 02068 ast_clear_flag(config, AST_FLAGS_ALL); 02069 02070 ast_rwlock_rdlock(&features_lock); 02071 for (x = 0; x < FEATURES_COUNT; x++) { 02072 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 02073 continue; 02074 02075 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 02076 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 02077 02078 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 02079 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 02080 } 02081 ast_rwlock_unlock(&features_lock); 02082 02083 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 02084 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 02085 02086 if (dynamic_features) { 02087 char *tmp = ast_strdupa(dynamic_features); 02088 char *tok; 02089 struct ast_call_feature *feature; 02090 02091 /* while we have a feature */ 02092 while ((tok = strsep(&tmp, "#"))) { 02093 AST_RWLIST_RDLOCK(&feature_list); 02094 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 02095 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 02096 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 02097 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 02098 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 02099 } 02100 AST_RWLIST_UNLOCK(&feature_list); 02101 } 02102 } 02103 } 02104 }
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 846 of file features.c.
References chan, and FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
00848 { 00849 if (sense == FEATURE_SENSE_PEER) { 00850 *caller = peer; 00851 *callee = chan; 00852 } else { 00853 *callee = peer; 00854 *caller = chan; 00855 } 00856 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1888 of file features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, FEATURES_COUNT, and features_lock.
01889 { 01890 int x; 01891 01892 ast_rwlock_wrlock(&features_lock); 01893 for (x = 0; x < FEATURES_COUNT; x++) 01894 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01895 ast_rwlock_unlock(&features_lock); 01896 }
int adsipark [static] |
char* app_bridge = "Bridge" [static] |
Definition at line 4469 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 4471 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 4470 of file features.c.
struct ast_call_feature builtin_features[] [static] |
Definition at line 1625 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 4299 of file features.c.
Referenced by ast_features_init().
int comebacktoorigin = 1 [static] |
char courtesytone[256] [static] |
Courtesy tone
Definition at line 139 of file features.c.
Referenced by builtin_automixmonitor(), builtin_automonitor(), load_config(), and park_exec_full().
struct ast_parkinglot* default_parkinglot |
Definition at line 136 of file features.c.
Referenced by load_config(), park_exec(), park_exec_full(), and park_space_reserve().
char* descrip [static] |
Definition at line 160 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 230 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 1623 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 4083 of file features.c.
char mandescr_park[] [static] |
Definition at line 4359 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 193 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 194 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 167 of file features.c.
Referenced by ast_features_init(), and build_parkinglot().
char* parkedcall = "ParkedCall" [static] |
Definition at line 90 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 140 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 137 of file features.c.
Referenced by ast_parking_ext(), handle_feature_show(), and load_config().
pthread_t parking_thread [static] |
Definition at line 202 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 134 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 92 of file features.c.
Referenced by ast_pickup_ext(), and load_config().
char* registrar = "features" [static] |
Registrar for operations
Definition at line 155 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 146 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 142 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().
char xfersound[256] [static] |
Call transfer sound
Definition at line 141 of file features.c.
Referenced by action_bridge(), bridge_exec(), builtin_atxfer(), and load_config().