Routines implementing call features as call pickup, parking and transfer. More...
#include "asterisk.h"#include "asterisk/_private.h"#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#include <netinet/in.h>#include "asterisk/lock.h"#include "asterisk/file.h"#include "asterisk/channel.h"#include "asterisk/pbx.h"#include "asterisk/causes.h"#include "asterisk/module.h"#include "asterisk/translate.h"#include "asterisk/app.h"#include "asterisk/say.h"#include "asterisk/features.h"#include "asterisk/musiconhold.h"#include "asterisk/config.h"#include "asterisk/cli.h"#include "asterisk/manager.h"#include "asterisk/utils.h"#include "asterisk/adsi.h"#include "asterisk/devicestate.h"#include "asterisk/monitor.h"#include "asterisk/audiohook.h"#include "asterisk/global_datastores.h"#include "asterisk/astobj2.h"
Go to the source code of this file.
Data Structures | |
| struct | ast_bridge_thread_obj |
| struct | ast_dial_features |
| struct | ast_park_call_args |
| struct | ast_parkinglot |
| Structure for parking lots which are put in a container. More... | |
| struct | 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... | |
| struct | parkinglot_parklist |
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 | FEATURE_SENSE_CHAN (1 << 0) |
| #define | FEATURE_SENSE_PEER (1 << 1) |
| #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 the call and set CDR | |
| int | ast_features_init (void) |
| int | ast_features_reload (void) |
| Reload call features from features.conf. | |
| struct 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. | |
| 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_list | |
| void | ast_unlock_call_features (void) |
| void | ast_unregister_feature (struct ast_call_feature *feature) |
| unregister feature from feature_set | |
| static void | ast_unregister_features (void) |
| Remove all features in the list. | |
| static void | ast_unregister_groups (void) |
| Remove all feature groups in the list. | |
| static void * | bridge_call_thread (void *data) |
| bridge the call | |
| static void | bridge_call_thread_launch (void *data) |
| create thread for the parked call | |
| static int | bridge_exec (struct ast_channel *chan, 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 (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 * | 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. | |
| static int | find_channel_by_group (struct ast_channel *c, void *data) |
| 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. | |
| struct 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_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) |
| 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 struct ast_app_option | bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE } } |
| static struct ast_call_feature | builtin_features [] |
| static struct ast_cli_entry | cli_features [] |
| static int | comebacktoorigin = 1 |
| static char | courtesytone [256] |
| struct ast_parkinglot * | default_parkinglot |
| struct 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 | pickupfailsound [256] |
| static char | pickupsound [256] |
| static char * | registrar = "features" |
| static struct ast_app * | stopmixmonitor_app = NULL |
| static int | stopmixmonitor_ok = 1 |
| static int | transferdigittimeout |
| static char | xferfailsound [256] |
| static char | xfersound [256] |
Routines implementing call features as call pickup, parking and transfer.
Definition in file features.c.
| #define AST_MAX_WATCHERS 256 |
Definition at line 171 of file features.c.
| #define DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
Definition at line 169 of file features.c.
Referenced by load_config().
| #define DEFAULT_ATXFER_DROP_CALL 0 |
Definition at line 167 of file features.c.
Referenced by load_config().
| #define DEFAULT_ATXFER_LOOP_DELAY 10000 |
Definition at line 168 of file features.c.
Referenced by load_config().
| #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
Definition at line 164 of file features.c.
Referenced by load_config().
| #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
Definition at line 165 of file features.c.
Referenced by load_config().
| #define DEFAULT_PARK_TIME 45000 |
Definition at line 162 of file features.c.
Referenced by build_parkinglot(), and load_config().
| #define DEFAULT_PARKINGLOT "default" |
| #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
Definition at line 163 of file features.c.
Referenced by load_config().
| #define FEATURE_SENSE_CHAN (1 << 0) |
Definition at line 909 of file features.c.
Referenced by ast_bridge_call(), feature_exec_app(), and feature_interpret().
| #define FEATURE_SENSE_PEER (1 << 1) |
Definition at line 910 of file features.c.
Referenced by ast_bridge_call(), and set_peers().
| #define FEATURES_COUNT ARRAY_LEN(builtin_features) |
Definition at line 1693 of file features.c.
Referenced by ast_find_call_feature(), feature_interpret(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
| #define HFS_FORMAT "%-25s %-7s %-7s\n" |
Referenced by handle_feature_show().
| #define MAX_DIAL_FEATURE_OPTIONS 30 |
Definition at line 172 of file features.c.
Referenced by manage_parkinglot().
| anonymous enum |
Definition at line 4507 of file features.c.
04507 { 04508 BRIDGE_OPT_PLAYTONE = (1 << 0), 04509 };
Options to pass to park_call_full
Definition at line 539 of file features.c.
00539 { 00540 /*! Provide ringing to the parked caller instead of music on hold */ 00541 AST_PARK_OPT_RINGING = (1 << 0), 00542 /*! Randomly choose a parking spot for the caller instead of choosing 00543 * the first one that is available. */ 00544 AST_PARK_OPT_RANDOMIZE = (1 << 1), 00545 /*! Do not announce the parking number */ 00546 AST_PARK_OPT_SILENCE = (1 << 2), 00547 };
| 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 4156 of file features.c.
References ast_channel::_state, ast_answer(), 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(), bridge_call_thread_launch(), buf, ast_bridge_thread_obj::chan, do_bridge_masquerade(), errno, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, playtone(), ast_bridge_thread_obj::return_to_pbx, and xfersound.
Referenced by ast_features_init().
04157 { 04158 const char *channela = astman_get_header(m, "Channel1"); 04159 const char *channelb = astman_get_header(m, "Channel2"); 04160 const char *playtone = astman_get_header(m, "Tone"); 04161 struct ast_channel *chana = NULL, *chanb = NULL; 04162 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 04163 struct ast_bridge_thread_obj *tobj = NULL; 04164 04165 /* make sure valid channels were specified */ 04166 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 04167 astman_send_error(s, m, "Missing channel parameter in request"); 04168 return 0; 04169 } 04170 04171 /* The same code must be executed for chana and chanb. To avoid a 04172 * theoretical deadlock, this code is separated so both chana and chanb will 04173 * not hold locks at the same time. */ 04174 04175 /* Start with chana */ 04176 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela)); 04177 04178 /* send errors if any of the channels could not be found/locked */ 04179 if (!chana) { 04180 char buf[256]; 04181 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 04182 astman_send_error(s, m, buf); 04183 return 0; 04184 } 04185 04186 /* Answer the channels if needed */ 04187 if (chana->_state != AST_STATE_UP) 04188 ast_answer(chana); 04189 04190 /* create the placeholder channels and grab the other channels */ 04191 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04192 NULL, NULL, 0, "Bridge/%s", chana->name))) { 04193 astman_send_error(s, m, "Unable to create temporary channel!"); 04194 ast_channel_unlock(chana); 04195 return 1; 04196 } 04197 04198 do_bridge_masquerade(chana, tmpchana); 04199 ast_channel_unlock(chana); 04200 chana = NULL; 04201 04202 /* now do chanb */ 04203 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb)); 04204 /* send errors if any of the channels could not be found/locked */ 04205 if (!chanb) { 04206 char buf[256]; 04207 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 04208 ast_hangup(tmpchana); 04209 astman_send_error(s, m, buf); 04210 return 0; 04211 } 04212 04213 /* Answer the channels if needed */ 04214 if (chanb->_state != AST_STATE_UP) 04215 ast_answer(chanb); 04216 04217 /* create the placeholder channels and grab the other channels */ 04218 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04219 NULL, NULL, 0, "Bridge/%s", chanb->name))) { 04220 astman_send_error(s, m, "Unable to create temporary channels!"); 04221 ast_hangup(tmpchana); 04222 ast_channel_unlock(chanb); 04223 return 1; 04224 } 04225 do_bridge_masquerade(chanb, tmpchanb); 04226 ast_channel_unlock(chanb); 04227 chanb = NULL; 04228 04229 /* make the channels compatible, send error if we fail doing so */ 04230 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 04231 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 04232 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 04233 ast_hangup(tmpchana); 04234 ast_hangup(tmpchanb); 04235 return 1; 04236 } 04237 04238 /* setup the bridge thread object and start the bridge */ 04239 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 04240 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 04241 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 04242 ast_hangup(tmpchana); 04243 ast_hangup(tmpchanb); 04244 return 1; 04245 } 04246 04247 tobj->chan = tmpchana; 04248 tobj->peer = tmpchanb; 04249 tobj->return_to_pbx = 1; 04250 04251 if (ast_true(playtone)) { 04252 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 04253 if (ast_waitstream(tmpchanb, "") < 0) 04254 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 04255 } 04256 } 04257 04258 bridge_call_thread_launch(tobj); 04259 04260 astman_send_ack(s, m, "Launched bridge thread with success"); 04261 04262 return 0; 04263 }
| static void add_features_datastores | ( | struct ast_channel * | caller, | |
| struct ast_channel * | callee, | |||
| struct ast_bridge_config * | config | |||
| ) | [static] |
Definition at line 2374 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(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, ast_dial_features::features_callee, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, ast_datastore::inheritance, ast_dial_features::is_caller, and LOG_WARNING.
Referenced by ast_bridge_call().
02375 { 02376 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 02377 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 02378 02379 ast_channel_lock(caller); 02380 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 02381 ast_channel_unlock(caller); 02382 if (!ds_caller_features) { 02383 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) { 02384 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 02385 return; 02386 } 02387 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 02388 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02389 ast_datastore_free(ds_caller_features); 02390 return; 02391 } 02392 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 02393 caller_features->is_caller = 1; 02394 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 02395 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 02396 ds_caller_features->data = caller_features; 02397 ast_channel_lock(caller); 02398 ast_channel_datastore_add(caller, ds_caller_features); 02399 ast_channel_unlock(caller); 02400 } else { 02401 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 02402 * flags over from the atxfer to the caller */ 02403 return; 02404 } 02405 02406 ast_channel_lock(callee); 02407 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 02408 ast_channel_unlock(callee); 02409 if (!ds_callee_features) { 02410 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) { 02411 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 02412 return; 02413 } 02414 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 02415 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02416 ast_datastore_free(ds_callee_features); 02417 return; 02418 } 02419 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 02420 callee_features->is_caller = 0; 02421 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 02422 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 02423 ds_callee_features->data = callee_features; 02424 ast_channel_lock(callee); 02425 ast_channel_datastore_add(callee, ds_callee_features); 02426 ast_channel_unlock(callee); 02427 } 02428 02429 return; 02430 }
| 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 477 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session, ast_adsi_print, and justify.
Referenced by park_call_full().
00478 { 00479 int res; 00480 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00481 char tmp[256]; 00482 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00483 00484 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00485 message[0] = tmp; 00486 res = ast_adsi_load_session(chan, NULL, 0, 1); 00487 if (res == -1) 00488 return res; 00489 return ast_adsi_print(chan, message, justify, 1); 00490 }
| int ast_bridge_call | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config | |||
| ) |
bridge the call and set CDR
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 2441 of file features.c.
References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setaccount(), ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_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_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_bridge_config::end_sound, ast_channel::exten, f, feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_frame::frametype, 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_bridge_config::play_warning, ast_channel::priority, ast_frame::ptr, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, ast_channel::visible_indication, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by app_exec(), bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), park_exec_full(), and try_calling().
02442 { 02443 /* Copy voice back and forth between the two channels. Give the peer 02444 the ability to transfer calls with '#<extension' syntax. */ 02445 struct ast_frame *f; 02446 struct ast_channel *who; 02447 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02448 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02449 char orig_channame[AST_MAX_EXTENSION]; 02450 char orig_peername[AST_MAX_EXTENSION]; 02451 int res; 02452 int diff; 02453 int hasfeatures=0; 02454 int hadfeatures=0; 02455 int autoloopflag; 02456 struct ast_option_header *aoh; 02457 struct ast_bridge_config backup_config; 02458 struct ast_cdr *bridge_cdr = NULL; 02459 struct ast_cdr *orig_peer_cdr = NULL; 02460 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02461 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02462 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02463 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02464 02465 memset(&backup_config, 0, sizeof(backup_config)); 02466 02467 config->start_time = ast_tvnow(); 02468 02469 if (chan && peer) { 02470 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02471 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02472 } else if (chan) { 02473 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02474 } 02475 02476 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02477 add_features_datastores(chan, peer, config); 02478 02479 /* This is an interesting case. One example is if a ringing channel gets redirected to 02480 * an extension that picks up a parked call. This will make sure that the call taken 02481 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02482 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02483 ast_indicate(peer, AST_CONTROL_RINGING); 02484 } 02485 02486 if (monitor_ok) { 02487 const char *monitor_exec; 02488 struct ast_channel *src = NULL; 02489 if (!monitor_app) { 02490 if (!(monitor_app = pbx_findapp("Monitor"))) 02491 monitor_ok=0; 02492 } 02493 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02494 src = chan; 02495 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02496 src = peer; 02497 if (monitor_app && src) { 02498 char *tmp = ast_strdupa(monitor_exec); 02499 pbx_exec(src, monitor_app, tmp); 02500 } 02501 } 02502 02503 set_config_flags(chan, peer, config); 02504 config->firstpass = 1; 02505 02506 /* Answer if need be */ 02507 if (chan->_state != AST_STATE_UP) { 02508 if (ast_raw_answer(chan, 1)) { 02509 return -1; 02510 } 02511 } 02512 02513 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02514 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02515 orig_peer_cdr = peer_cdr; 02516 02517 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02518 02519 if (chan_cdr) { 02520 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02521 ast_cdr_update(chan); 02522 bridge_cdr = ast_cdr_dup(chan_cdr); 02523 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02524 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02525 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 02526 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02527 } 02528 if (peer_cdr && ast_strlen_zero(peer->accountcode)) { 02529 ast_cdr_setaccount(peer, chan->accountcode); 02530 } 02531 02532 } else { 02533 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02534 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02535 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02536 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02537 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02538 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02539 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02540 ast_cdr_setcid(bridge_cdr, chan); 02541 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02542 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02543 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02544 /* Destination information */ 02545 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02546 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02547 if (peer_cdr) { 02548 bridge_cdr->start = peer_cdr->start; 02549 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02550 } else { 02551 ast_cdr_start(bridge_cdr); 02552 } 02553 } 02554 ast_debug(4,"bridge answer set, chan answer set\n"); 02555 /* peer_cdr->answer will be set when a macro runs on the peer; 02556 in that case, the bridge answer will be delayed while the 02557 macro plays on the peer channel. The peer answered the call 02558 before the macro started playing. To the phone system, 02559 this is billable time for the call, even tho the caller 02560 hears nothing but ringing while the macro does its thing. */ 02561 02562 /* Another case where the peer cdr's time will be set, is when 02563 A self-parks by pickup up phone and dialing 700, then B 02564 picks up A by dialing its parking slot; there may be more 02565 practical paths that get the same result, tho... in which 02566 case you get the previous answer time from the Park... which 02567 is before the bridge's start time, so I added in the 02568 tvcmp check to the if below */ 02569 02570 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 02571 bridge_cdr->answer = peer_cdr->answer; 02572 bridge_cdr->disposition = peer_cdr->disposition; 02573 if (chan_cdr) { 02574 chan_cdr->answer = peer_cdr->answer; 02575 chan_cdr->disposition = peer_cdr->disposition; 02576 } 02577 } else { 02578 ast_cdr_answer(bridge_cdr); 02579 if (chan_cdr) { 02580 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02581 } 02582 } 02583 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 02584 if (chan_cdr) { 02585 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02586 } 02587 if (peer_cdr) { 02588 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02589 } 02590 } 02591 } 02592 for (;;) { 02593 struct ast_channel *other; /* used later */ 02594 02595 res = ast_channel_bridge(chan, peer, config, &f, &who); 02596 02597 /* When frame is not set, we are probably involved in a situation 02598 where we've timed out. 02599 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02600 and also for DTMF_END. If we flow into the following 'if' for both, then 02601 our wait times are cut in half, as both will subtract from the 02602 feature_timer. Not good! 02603 */ 02604 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02605 /* Update time limit for next pass */ 02606 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02607 if (res == AST_BRIDGE_RETRY) { 02608 /* The feature fully timed out but has not been updated. Skip 02609 * the potential round error from the diff calculation and 02610 * explicitly set to expired. */ 02611 config->feature_timer = -1; 02612 } else { 02613 config->feature_timer -= diff; 02614 } 02615 02616 if (hasfeatures) { 02617 /* Running on backup config, meaning a feature might be being 02618 activated, but that's no excuse to keep things going 02619 indefinitely! */ 02620 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02621 ast_debug(1, "Timed out, realtime this time!\n"); 02622 config->feature_timer = 0; 02623 who = chan; 02624 if (f) 02625 ast_frfree(f); 02626 f = NULL; 02627 res = 0; 02628 } else if (config->feature_timer <= 0) { 02629 /* Not *really* out of time, just out of time for 02630 digits to come in for features. */ 02631 ast_debug(1, "Timed out for feature!\n"); 02632 if (!ast_strlen_zero(peer_featurecode)) { 02633 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02634 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02635 } 02636 if (!ast_strlen_zero(chan_featurecode)) { 02637 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02638 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02639 } 02640 if (f) 02641 ast_frfree(f); 02642 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02643 if (!hasfeatures) { 02644 /* Restore original (possibly time modified) bridge config */ 02645 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02646 memset(&backup_config, 0, sizeof(backup_config)); 02647 } 02648 hadfeatures = hasfeatures; 02649 /* Continue as we were */ 02650 continue; 02651 } else if (!f) { 02652 /* The bridge returned without a frame and there is a feature in progress. 02653 * However, we don't think the feature has quite yet timed out, so just 02654 * go back into the bridge. */ 02655 continue; 02656 } 02657 } else { 02658 if (config->feature_timer <=0) { 02659 /* We ran out of time */ 02660 config->feature_timer = 0; 02661 who = chan; 02662 if (f) 02663 ast_frfree(f); 02664 f = NULL; 02665 res = 0; 02666 } 02667 } 02668 } 02669 if (res < 0) { 02670 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02671 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02672 goto before_you_go; 02673 } 02674 02675 if (!f || (f->frametype == AST_FRAME_CONTROL && 02676 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02677 f->subclass == AST_CONTROL_CONGESTION))) { 02678 res = -1; 02679 break; 02680 } 02681 /* many things should be sent to the 'other' channel */ 02682 other = (who == chan) ? peer : chan; 02683 if (f->frametype == AST_FRAME_CONTROL) { 02684 switch (f->subclass) { 02685 case AST_CONTROL_RINGING: 02686 case AST_CONTROL_FLASH: 02687 case -1: 02688 ast_indicate(other, f->subclass); 02689 break; 02690 case AST_CONTROL_HOLD: 02691 case AST_CONTROL_UNHOLD: 02692 ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); 02693 break; 02694 case AST_CONTROL_OPTION: 02695 aoh = f->data.ptr; 02696 /* Forward option Requests */ 02697 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02698 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02699 f->datalen - sizeof(struct ast_option_header), 0); 02700 } 02701 break; 02702 } 02703 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02704 /* eat it */ 02705 } else if (f->frametype == AST_FRAME_DTMF) { 02706 char *featurecode; 02707 int sense; 02708 02709 hadfeatures = hasfeatures; 02710 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02711 if (who == chan) { 02712 sense = FEATURE_SENSE_CHAN; 02713 featurecode = chan_featurecode; 02714 } else { 02715 sense = FEATURE_SENSE_PEER; 02716 featurecode = peer_featurecode; 02717 } 02718 /*! append the event to featurecode. we rely on the string being zero-filled, and 02719 * not overflowing it. 02720 * \todo XXX how do we guarantee the latter ? 02721 */ 02722 featurecode[strlen(featurecode)] = f->subclass; 02723 /* Get rid of the frame before we start doing "stuff" with the channels */ 02724 ast_frfree(f); 02725 f = NULL; 02726 config->feature_timer = backup_config.feature_timer; 02727 res = feature_interpret(chan, peer, config, featurecode, sense); 02728 switch(res) { 02729 case AST_FEATURE_RETURN_PASSDIGITS: 02730 ast_dtmf_stream(other, who, featurecode, 0, 0); 02731 /* Fall through */ 02732 case AST_FEATURE_RETURN_SUCCESS: 02733 memset(featurecode, 0, sizeof(chan_featurecode)); 02734 break; 02735 } 02736 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 02737 res = 0; 02738 } else 02739 break; 02740 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02741 if (hadfeatures && !hasfeatures) { 02742 /* Restore backup */ 02743 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02744 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02745 } else if (hasfeatures) { 02746 if (!hadfeatures) { 02747 /* Backup configuration */ 02748 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02749 /* Setup temporary config options */ 02750 config->play_warning = 0; 02751 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02752 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02753 config->warning_freq = 0; 02754 config->warning_sound = NULL; 02755 config->end_sound = NULL; 02756 config->start_sound = NULL; 02757 config->firstpass = 0; 02758 } 02759 config->start_time = ast_tvnow(); 02760 config->feature_timer = featuredigittimeout; 02761 ast_debug(1, "Set time limit to %ld\n", config->feature_timer); 02762 } 02763 } 02764 if (f) 02765 ast_frfree(f); 02766 02767 } 02768 before_you_go: 02769 02770 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02771 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02772 if (bridge_cdr) { 02773 ast_cdr_discard(bridge_cdr); 02774 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02775 } 02776 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02777 } 02778 02779 if (config->end_bridge_callback) { 02780 config->end_bridge_callback(config->end_bridge_callback_data); 02781 } 02782 02783 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 02784 * if it were, then chan belongs to a different thread now, and might have been hung up long 02785 * ago. 02786 */ 02787 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02788 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02789 struct ast_cdr *swapper = NULL; 02790 char savelastapp[AST_MAX_EXTENSION]; 02791 char savelastdata[AST_MAX_EXTENSION]; 02792 char save_exten[AST_MAX_EXTENSION]; 02793 int save_prio; 02794 int found = 0; /* set if we find at least one match */ 02795 int spawn_error = 0; 02796 02797 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02798 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02799 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02800 ast_cdr_end(bridge_cdr); 02801 } 02802 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02803 dialplan code operate on it */ 02804 ast_channel_lock(chan); 02805 if (bridge_cdr) { 02806 swapper = chan->cdr; 02807 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02808 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02809 chan->cdr = bridge_cdr; 02810 } 02811 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02812 save_prio = chan->priority; 02813 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02814 chan->priority = 1; 02815 ast_channel_unlock(chan); 02816 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 02817 chan->priority++; 02818 } 02819 if (spawn_error && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num) || ast_check_hangup(chan))) { 02820 /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */ 02821 spawn_error = 0; 02822 } 02823 if (found && spawn_error) { 02824 /* Something bad happened, or a hangup has been requested. */ 02825 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02826 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02827 } 02828 /* swap it back */ 02829 ast_channel_lock(chan); 02830 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02831 chan->priority = save_prio; 02832 if (bridge_cdr) { 02833 if (chan->cdr == bridge_cdr) { 02834 chan->cdr = swapper; 02835 } else { 02836 bridge_cdr = NULL; 02837 } 02838 } 02839 if (!spawn_error) { 02840 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02841 } 02842 ast_channel_unlock(chan); 02843 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02844 if (bridge_cdr) { 02845 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02846 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02847 } 02848 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02849 } 02850 02851 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02852 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02853 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 02854 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02855 02856 /* we can post the bridge CDR at this point */ 02857 if (bridge_cdr) { 02858 ast_cdr_end(bridge_cdr); 02859 ast_cdr_detach(bridge_cdr); 02860 } 02861 02862 /* do a specialized reset on the beginning channel 02863 CDR's, if they still exist, so as not to mess up 02864 issues in future bridges; 02865 02866 Here are the rules of the game: 02867 1. The chan and peer channel pointers will not change 02868 during the life of the bridge. 02869 2. But, in transfers, the channel names will change. 02870 between the time the bridge is started, and the 02871 time the channel ends. 02872 Usually, when a channel changes names, it will 02873 also change CDR pointers. 02874 3. Usually, only one of the two channels (chan or peer) 02875 will change names. 02876 4. Usually, if a channel changes names during a bridge, 02877 it is because of a transfer. Usually, in these situations, 02878 it is normal to see 2 bridges running simultaneously, and 02879 it is not unusual to see the two channels that change 02880 swapped between bridges. 02881 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02882 to attend to; if the chan or peer changed names, 02883 we have the before and after attached CDR's. 02884 */ 02885 02886 if (new_chan_cdr) { 02887 struct ast_channel *chan_ptr = NULL; 02888 02889 if (strcasecmp(orig_channame, chan->name) != 0) { 02890 /* old channel */ 02891 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02892 if (chan_ptr) { 02893 if (!ast_bridged_channel(chan_ptr)) { 02894 struct ast_cdr *cur; 02895 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02896 if (cur == chan_cdr) { 02897 break; 02898 } 02899 } 02900 if (cur) 02901 ast_cdr_specialized_reset(chan_cdr,0); 02902 } 02903 ast_channel_unlock(chan_ptr); 02904 } 02905 /* new channel */ 02906 ast_cdr_specialized_reset(new_chan_cdr,0); 02907 } else { 02908 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02909 } 02910 } 02911 02912 { 02913 struct ast_channel *chan_ptr = NULL; 02914 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02915 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)) 02916 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02917 if (strcasecmp(orig_peername, peer->name) != 0) { 02918 /* old channel */ 02919 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02920 if (chan_ptr) { 02921 if (!ast_bridged_channel(chan_ptr)) { 02922 struct ast_cdr *cur; 02923 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02924 if (cur == peer_cdr) { 02925 break; 02926 } 02927 } 02928 if (cur) 02929 ast_cdr_specialized_reset(peer_cdr,0); 02930 } 02931 ast_channel_unlock(chan_ptr); 02932 } 02933 /* new channel */ 02934 if (new_peer_cdr) { 02935 ast_cdr_specialized_reset(new_peer_cdr, 0); 02936 } 02937 } else { 02938 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02939 } 02940 } 02941 02942 return res; 02943 }
| int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 4642 of file features.c.
References action_bridge(), ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application2(), bridge_exec(), do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), and parkinglots.
Referenced by main().
04643 { 04644 int res; 04645 04646 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); 04647 04648 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 04649 04650 if ((res = load_config())) 04651 return res; 04652 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); 04653 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 04654 res = ast_register_application2(parkedcall, park_exec, NULL, NULL, NULL); 04655 if (!res) 04656 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); 04657 if (!res) { 04658 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls"); 04659 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park); 04660 ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge); 04661 } 04662 04663 res |= ast_devstate_prov_add("Park", metermaidstate); 04664 04665 return res; 04666 }
| int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 4079 of file features.c.
References load_config().
Referenced by handle_features_reload().
04080 { 04081 int res; 04082 /* Release parking lot list */ 04083 //ASTOBJ_CONTAINER_MARKALL(&parkinglots); 04084 // TODO: I don't think any marking is necessary 04085 04086 /* Reload configuration */ 04087 res = load_config(); 04088 04089 //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy); 04090 return res; 04091 }
| struct ast_call_feature* ast_find_call_feature | ( | const char * | name | ) | [read] |
look for a call feature entry by its sname
| name | a string ptr, should match "automon", "blindxfer", "atxfer", etc. |
Definition at line 1884 of file features.c.
References FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), handle_request_info(), and load_config().
01885 { 01886 int x; 01887 for (x = 0; x < FEATURES_COUNT; x++) { 01888 if (!strcasecmp(name, builtin_features[x].sname)) 01889 return &builtin_features[x]; 01890 } 01891 return NULL; 01892 }
| 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. |
Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
| 0 | on success. | |
| -1 | on failure. |
Definition at line 894 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().
00895 { 00896 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00897 }
| int ast_park_call | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| int | timeout, | |||
| int * | extout | |||
| ) |
Park a call.
Park a call and read back parked location.
Definition at line 823 of file features.c.
References park_call_full(), and ast_park_call_args::timeout.
Referenced by iax_park_thread(), and sip_park_thread().
00824 { 00825 struct ast_park_call_args args = { 00826 .timeout = timeout, 00827 .extout = extout, 00828 }; 00829 00830 return park_call_full(chan, peer, &args); 00831 }
| const char* ast_parking_ext | ( | void | ) |
Determine system parking extension.
Definition at line 315 of file features.c.
References parking_ext.
Referenced by build_parkinglot(), builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), load_config(), mgcp_ss(), socket_process(), and ss_thread().
00316 { 00317 return parking_ext; 00318 }
| int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
| chan | channel that initiated pickup. |
Walk list of channels, checking it is not itself, channel is pbx one, check that the callgroup for both channels are the same and the channel is ringing. Answer calling channel, flag channel as answered on queue, masq channels together.
Definition at line 4475 of file features.c.
References ast_answer(), ast_channel_masquerade(), ast_channel_search_locked(), ast_channel_unlock, AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_queue_control(), ast_stream_and_wait(), ast_strlen_zero(), find_channel_by_group(), LOG_WARNING, ast_channel::name, pickupfailsound, and pickupsound.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), pickup_exec(), and ss_thread().
04476 { 04477 struct ast_channel *cur = ast_channel_search_locked(find_channel_by_group, chan); 04478 04479 if (cur) { 04480 int res = -1; 04481 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 04482 res = ast_answer(chan); 04483 if (res) 04484 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 04485 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 04486 if (res) 04487 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 04488 res = ast_channel_masquerade(cur, chan); 04489 if (res) 04490 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 04491 if (!ast_strlen_zero(pickupsound)) { 04492 ast_stream_and_wait(cur, pickupsound, ""); 04493 } 04494 ast_channel_unlock(cur); 04495 return res; 04496 } else { 04497 ast_debug(1, "No call pickup possible...\n"); 04498 if (!ast_strlen_zero(pickupfailsound)) { 04499 ast_stream_and_wait(chan, pickupfailsound, ""); 04500 } 04501 } 04502 return -1; 04503 }
| const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 320 of file features.c.
References pickup_ext.
Referenced by cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), mgcp_ss(), and ss_thread().
00321 { 00322 return pickup_ext; 00323 }
| void ast_rdlock_call_features | ( | void | ) |
Definition at line 1874 of file features.c.
References ast_rwlock_rdlock(), and features_lock.
Referenced by handle_request_info().
01875 { 01876 ast_rwlock_rdlock(&features_lock); 01877 }
| void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_list
register new feature into feature_set
Definition at line 1711 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
Referenced by load_config().
01712 { 01713 if (!feature) { 01714 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01715 return; 01716 } 01717 01718 AST_RWLIST_WRLOCK(&feature_list); 01719 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01720 AST_RWLIST_UNLOCK(&feature_list); 01721 01722 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 01723 }
| void ast_unlock_call_features | ( | void | ) |
Definition at line 1879 of file features.c.
References ast_rwlock_unlock(), and features_lock.
Referenced by handle_request_info().
01880 { 01881 ast_rwlock_unlock(&features_lock); 01882 }
| 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 1799 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
01800 { 01801 if (!feature) { 01802 return; 01803 } 01804 01805 AST_RWLIST_WRLOCK(&feature_list); 01806 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01807 AST_RWLIST_UNLOCK(&feature_list); 01808 01809 ast_free(feature); 01810 }
| static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1813 of file features.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_call_feature::feature_entry.
Referenced by load_config().
01814 { 01815 struct ast_call_feature *feature; 01816 01817 AST_RWLIST_WRLOCK(&feature_list); 01818 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 01819 ast_free(feature); 01820 } 01821 AST_RWLIST_UNLOCK(&feature_list); 01822 }
| static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 1839 of file features.c.
References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, and feature_group::features.
Referenced by load_config().
01840 { 01841 struct feature_group *fg; 01842 struct feature_group_exten *fge; 01843 01844 AST_RWLIST_WRLOCK(&feature_groups); 01845 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 01846 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 01847 ast_string_field_free_memory(fge); 01848 ast_free(fge); 01849 } 01850 01851 ast_string_field_free_memory(fg); 01852 ast_free(fg); 01853 } 01854 AST_RWLIST_UNLOCK(&feature_groups); 01855 }
| static void* bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
| data | thread bridge. |
Set Last Data for respective channels, reset cdr for channels bridge call, check if we're going back to dialplan if not hangup both legs of the call
Definition at line 412 of file features.c.
References ast_channel::appl, ast_bridge_call(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, LOG_VERBOSE, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.
Referenced by bridge_call_thread_launch().
00413 { 00414 struct ast_bridge_thread_obj *tobj = data; 00415 int res; 00416 00417 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00418 tobj->chan->data = tobj->peer->name; 00419 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00420 tobj->peer->data = tobj->chan->name; 00421 00422 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00423 00424 if (tobj->return_to_pbx) { 00425 if (!ast_check_hangup(tobj->peer)) { 00426 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 00427 res = ast_pbx_start(tobj->peer); 00428 if (res != AST_PBX_SUCCESS) 00429 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 00430 } else 00431 ast_hangup(tobj->peer); 00432 if (!ast_check_hangup(tobj->chan)) { 00433 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 00434 res = ast_pbx_start(tobj->chan); 00435 if (res != AST_PBX_SUCCESS) 00436 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 00437 } else 00438 ast_hangup(tobj->chan); 00439 } else { 00440 ast_hangup(tobj->chan); 00441 ast_hangup(tobj->peer); 00442 } 00443 00444 ast_free(tobj); 00445 00446 return NULL; 00447 }
| static void bridge_call_thread_launch | ( | void * | data | ) | [static] |
create thread for the parked call
| data | Create thread and attributes, call bridge_call_thread |
Definition at line 455 of file features.c.
References ast_pthread_create, bridge_call_thread(), and thread.
Referenced by action_bridge(), and builtin_atxfer().
00456 { 00457 pthread_t thread; 00458 pthread_attr_t attr; 00459 struct sched_param sched; 00460 00461 pthread_attr_init(&attr); 00462 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00463 ast_pthread_create(&thread, &attr, bridge_call_thread, data); 00464 pthread_attr_destroy(&attr); 00465 memset(&sched, 0, sizeof(sched)); 00466 pthread_setschedparam(thread, SCHED_RR, &sched); 00467 }
| static int bridge_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Bridge channels.
| chan | ||
| data | channel to bridge with. |
Split data, check we aren't bridging with ourself, check valid channel, answer call if not already, check compatible channels, setup bridge config now bridge call, if transfered party hangs up return to PBX extension.
Definition at line 4524 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_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, 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().
04525 { 04526 struct ast_channel *current_dest_chan, *final_dest_chan; 04527 char *tmp_data = NULL; 04528 struct ast_flags opts = { 0, }; 04529 struct ast_bridge_config bconfig = { { 0, }, }; 04530 04531 AST_DECLARE_APP_ARGS(args, 04532 AST_APP_ARG(dest_chan); 04533 AST_APP_ARG(options); 04534 ); 04535 04536 if (ast_strlen_zero(data)) { 04537 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 04538 return -1; 04539 } 04540 04541 tmp_data = ast_strdupa(data); 04542 AST_STANDARD_APP_ARGS(args, tmp_data); 04543 if (!ast_strlen_zero(args.options)) 04544 ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options); 04545 04546 /* avoid bridge with ourselves */ 04547 if (!strcmp(chan->name, args.dest_chan)) { 04548 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 04549 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04550 "Response: Failed\r\n" 04551 "Reason: Unable to bridge channel to itself\r\n" 04552 "Channel1: %s\r\n" 04553 "Channel2: %s\r\n", 04554 chan->name, args.dest_chan); 04555 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 04556 return 0; 04557 } 04558 04559 /* make sure we have a valid end point */ 04560 if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 04561 strlen(args.dest_chan)))) { 04562 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 04563 "cannot get its lock\n", args.dest_chan); 04564 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04565 "Response: Failed\r\n" 04566 "Reason: Cannot grab end point\r\n" 04567 "Channel1: %s\r\n" 04568 "Channel2: %s\r\n", chan->name, args.dest_chan); 04569 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 04570 return 0; 04571 } 04572 04573 /* answer the channel if needed */ 04574 if (current_dest_chan->_state != AST_STATE_UP) 04575 ast_answer(current_dest_chan); 04576 04577 /* try to allocate a place holder where current_dest_chan will be placed */ 04578 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04579 NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) { 04580 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 04581 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04582 "Response: Failed\r\n" 04583 "Reason: cannot create placeholder\r\n" 04584 "Channel1: %s\r\n" 04585 "Channel2: %s\r\n", chan->name, args.dest_chan); 04586 } 04587 do_bridge_masquerade(current_dest_chan, final_dest_chan); 04588 04589 ast_channel_unlock(current_dest_chan); 04590 04591 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 04592 /* try to make compatible, send error if we fail */ 04593 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 04594 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 04595 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04596 "Response: Failed\r\n" 04597 "Reason: Could not make channels compatible for bridge\r\n" 04598 "Channel1: %s\r\n" 04599 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 04600 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 04601 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 04602 return 0; 04603 } 04604 04605 /* Report that the bridge will be successfull */ 04606 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04607 "Response: Success\r\n" 04608 "Channel1: %s\r\n" 04609 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 04610 04611 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 04612 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 04613 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 04614 if (ast_waitstream(final_dest_chan, "") < 0) 04615 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 04616 } 04617 } 04618 04619 /* do the bridge */ 04620 ast_bridge_call(chan, final_dest_chan, &bconfig); 04621 04622 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 04623 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 04624 if (!ast_check_hangup(final_dest_chan)) { 04625 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 04626 final_dest_chan->context, final_dest_chan->exten, 04627 final_dest_chan->priority, final_dest_chan->name); 04628 04629 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 04630 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 04631 ast_hangup(final_dest_chan); 04632 } else 04633 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 04634 } else { 04635 ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name); 04636 ast_hangup(final_dest_chan); 04637 } 04638 04639 return 0; 04640 }
| static struct ast_parkinglot* build_parkinglot | ( | char * | name, | |
| struct ast_variable * | var | |||
| ) | [static, read] |
Build parkinglot from configuration and chain it in.
Definition at line 3554 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_parkinglot::mohclass, ast_variable::name, ast_variable::next, option_debug, parkcall, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglot_destroy(), parkinglot_unref(), parkinglots, ast_parkinglot::parkingtime, registrar, strdup, and ast_variable::value.
Referenced by load_config().
03555 { 03556 struct ast_parkinglot *parkinglot; 03557 struct ast_context *con = NULL; 03558 03559 struct ast_variable *confvar = var; 03560 int error = 0; 03561 int start = 0, end = 0; 03562 int oldparkinglot = 0; 03563 03564 parkinglot = find_parkinglot(name); 03565 if (parkinglot) 03566 oldparkinglot = 1; 03567 else 03568 parkinglot = create_parkinglot(name); 03569 03570 if (!parkinglot) 03571 return NULL; 03572 03573 ao2_lock(parkinglot); 03574 03575 if (option_debug) 03576 ast_log(LOG_DEBUG, "Building parking lot %s\n", name); 03577 03578 /* Do some config stuff */ 03579 while(confvar) { 03580 if (!strcasecmp(confvar->name, "context")) { 03581 ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con)); 03582 } else if (!strcasecmp(confvar->name, "parkingtime")) { 03583 if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) { 03584 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value); 03585 parkinglot->parkingtime = DEFAULT_PARK_TIME; 03586 } else 03587 parkinglot->parkingtime = parkinglot->parkingtime * 1000; 03588 } else if (!strcasecmp(confvar->name, "parkpos")) { 03589 if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) { 03590 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); 03591 error = 1; 03592 } else { 03593 parkinglot->parking_start = start; 03594 parkinglot->parking_stop = end; 03595 } 03596 } else if (!strcasecmp(confvar->name, "findslot")) { 03597 parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next")); 03598 } 03599 confvar = confvar->next; 03600 } 03601 /* make sure parkingtime is set if not specified */ 03602 if (parkinglot->parkingtime == 0) { 03603 parkinglot->parkingtime = DEFAULT_PARK_TIME; 03604 } 03605 03606 if (!var) { /* Default parking lot */ 03607 ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con)); 03608 ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial)); 03609 ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass)); 03610 } 03611 03612 /* Check for errors */ 03613 if (ast_strlen_zero(parkinglot->parking_con)) { 03614 ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name); 03615 error = 1; 03616 } 03617 03618 /* Create context */ 03619 if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) { 03620 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con); 03621 error = 1; 03622 } 03623 03624 /* Add a parking extension into the context */ 03625 if (!error && !oldparkinglot) { 03626 if (!ast_strlen_zero(ast_parking_ext())) { 03627 if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1) 03628 error = 1; 03629 } 03630 } 03631 03632 ao2_unlock(parkinglot); 03633 03634 if (error) { 03635 ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name); 03636 parkinglot_destroy(parkinglot); 03637 return NULL; 03638 } 03639 if (option_debug) 03640 ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end); 03641 03642 03643 /* Move it into the list, if it wasn't already there */ 03644 if (!oldparkinglot) { 03645 ao2_link(parkinglots, parkinglot); 03646 } 03647 parkinglot_unref(parkinglot); 03648 03649 return parkinglot; 03650 }
| 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 1396 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_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_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_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, ast_bridge_thread_obj::bconfig, bridge_call_thread_launch(), builtin_parkcall(), ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, ast_datastore::data, ast_bridge_config::end_bridge_callback_data_fixup, ast_channel::exten, f, feature_request_and_dial(), 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_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xferfailsound, and xfersound.
01397 { 01398 struct ast_channel *transferer; 01399 struct ast_channel *transferee; 01400 const char *transferer_real_context; 01401 char xferto[256] = ""; 01402 int res; 01403 int outstate=0; 01404 struct ast_channel *newchan; 01405 struct ast_channel *xferchan; 01406 struct ast_bridge_thread_obj *tobj; 01407 struct ast_bridge_config bconfig; 01408 struct ast_frame *f; 01409 int l; 01410 struct ast_datastore *features_datastore; 01411 struct ast_dial_features *dialfeatures = NULL; 01412 01413 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 01414 set_peers(&transferer, &transferee, peer, chan, sense); 01415 transferer_real_context = real_ctx(transferer, transferee); 01416 /* Start autoservice on chan while we talk to the originator */ 01417 ast_autoservice_start(transferee); 01418 ast_indicate(transferee, AST_CONTROL_HOLD); 01419 01420 /* Transfer */ 01421 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01422 if (res < 0) { 01423 finishup(transferee); 01424 return res; 01425 } 01426 if (res > 0) /* If they've typed a digit already, handle it */ 01427 xferto[0] = (char) res; 01428 01429 /* this is specific of atxfer */ 01430 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01431 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01432 finishup(transferee); 01433 return res; 01434 } 01435 if (res == 0) { 01436 ast_log(LOG_WARNING, "Did not read data.\n"); 01437 finishup(transferee); 01438 if (ast_stream_and_wait(transferer, "beeperr", "")) 01439 return -1; 01440 return AST_FEATURE_RETURN_SUCCESS; 01441 } 01442 01443 /* valid extension, res == 1 */ 01444 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01445 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 01446 finishup(transferee); 01447 if (ast_stream_and_wait(transferer, "beeperr", "")) 01448 return -1; 01449 return AST_FEATURE_RETURN_SUCCESS; 01450 } 01451 01452 /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of 01453 * the different variables for handling this properly with a builtin_atxfer */ 01454 if (!strcmp(xferto, ast_parking_ext())) { 01455 finishup(transferee); 01456 return builtin_parkcall(chan, peer, config, code, sense, data); 01457 } 01458 01459 l = strlen(xferto); 01460 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 01461 01462 /* If we are performing an attended transfer and we have two channels involved then 01463 copy sound file information to play upon attended transfer completion */ 01464 if (transferee) { 01465 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 01466 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 01467 01468 if (!ast_strlen_zero(chan1_attended_sound)) { 01469 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 01470 } 01471 if (!ast_strlen_zero(chan2_attended_sound)) { 01472 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 01473 } 01474 } 01475 01476 newchan = feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01477 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01478 01479 if (!ast_check_hangup(transferer)) { 01480 /* Transferer is up - old behaviour */ 01481 ast_indicate(transferer, -1); 01482 if (!newchan) { 01483 finishup(transferee); 01484 /* any reason besides user requested cancel and busy triggers the failed sound */ 01485 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 01486 ast_stream_and_wait(transferer, xferfailsound, "")) 01487 return -1; 01488 if (ast_stream_and_wait(transferer, xfersound, "")) 01489 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01490 return AST_FEATURE_RETURN_SUCCESS; 01491 } 01492 01493 if (check_compat(transferer, newchan)) { 01494 /* we do mean transferee here, NOT transferer */ 01495 finishup(transferee); 01496 return -1; 01497 } 01498 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 01499 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 01500 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 01501 res = ast_bridge_call(transferer, newchan, &bconfig); 01502 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 01503 ast_hangup(newchan); 01504 if (ast_stream_and_wait(transferer, xfersound, "")) 01505 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01506 finishup(transferee); 01507 transferer->_softhangup = 0; 01508 return AST_FEATURE_RETURN_SUCCESS; 01509 } 01510 if (check_compat(transferee, newchan)) { 01511 finishup(transferee); 01512 return -1; 01513 } 01514 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01515 01516 if ((ast_autoservice_stop(transferee) < 0) 01517 || (ast_waitfordigit(transferee, 100) < 0) 01518 || (ast_waitfordigit(newchan, 100) < 0) 01519 || ast_check_hangup(transferee) 01520 || ast_check_hangup(newchan)) { 01521 ast_hangup(newchan); 01522 return -1; 01523 } 01524 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01525 if (!xferchan) { 01526 ast_hangup(newchan); 01527 return -1; 01528 } 01529 /* Make formats okay */ 01530 xferchan->visible_indication = transferer->visible_indication; 01531 xferchan->readformat = transferee->readformat; 01532 xferchan->writeformat = transferee->writeformat; 01533 ast_channel_masquerade(xferchan, transferee); 01534 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01535 xferchan->_state = AST_STATE_UP; 01536 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01537 xferchan->_softhangup = 0; 01538 if ((f = ast_read(xferchan))) 01539 ast_frfree(f); 01540 newchan->_state = AST_STATE_UP; 01541 ast_clear_flag(newchan, AST_FLAGS_ALL); 01542 newchan->_softhangup = 0; 01543 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01544 ast_hangup(xferchan); 01545 ast_hangup(newchan); 01546 return -1; 01547 } 01548 01549 ast_channel_lock(newchan); 01550 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 01551 dialfeatures = features_datastore->data; 01552 } 01553 ast_channel_unlock(newchan); 01554 01555 if (dialfeatures) { 01556 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 01557 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 01558 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01559 dialfeatures = NULL; 01560 } 01561 01562 ast_channel_lock(xferchan); 01563 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 01564 dialfeatures = features_datastore->data; 01565 } 01566 ast_channel_unlock(xferchan); 01567 01568 if (dialfeatures) { 01569 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01570 } 01571 01572 tobj->chan = newchan; 01573 tobj->peer = xferchan; 01574 tobj->bconfig = *config; 01575 01576 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01577 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01578 } 01579 01580 if (ast_stream_and_wait(newchan, xfersound, "")) 01581 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01582 bridge_call_thread_launch(tobj); 01583 return -1; /* XXX meaning the channel is bridged ? */ 01584 } else if (!ast_check_hangup(transferee)) { 01585 /* act as blind transfer */ 01586 if (ast_autoservice_stop(transferee) < 0) { 01587 ast_hangup(newchan); 01588 return -1; 01589 } 01590 01591 if (!newchan) { 01592 unsigned int tries = 0; 01593 char *transferer_tech, *transferer_name = ast_strdupa(transferer->name); 01594 01595 transferer_tech = strsep(&transferer_name, "/"); 01596 transferer_name = strsep(&transferer_name, "-"); 01597 01598 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 01599 ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name); 01600 if (ast_stream_and_wait(transferee, "beeperr", "")) 01601 return -1; 01602 return AST_FEATURE_RETURN_SUCCESS; 01603 } 01604 01605 ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name); 01606 newchan = feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01607 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01608 while (!newchan && !atxferdropcall && tries < atxfercallbackretries) { 01609 /* Trying to transfer again */ 01610 ast_autoservice_start(transferee); 01611 ast_indicate(transferee, AST_CONTROL_HOLD); 01612 01613 newchan = feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01614 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01615 if (ast_autoservice_stop(transferee) < 0) { 01616 if (newchan) 01617 ast_hangup(newchan); 01618 return -1; 01619 } 01620 if (!newchan) { 01621 /* Transfer failed, sleeping */ 01622 ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay); 01623 ast_safe_sleep(transferee, atxferloopdelay); 01624 ast_debug(1, "Trying to callback...\n"); 01625 newchan = feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01626 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01627 } 01628 tries++; 01629 } 01630 } 01631 if (!newchan) 01632 return -1; 01633 01634 /* newchan is up, we should prepare transferee and bridge them */ 01635 if (check_compat(transferee, newchan)) { 01636 finishup(transferee); 01637 return -1; 01638 } 01639 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01640 01641 if ((ast_waitfordigit(transferee, 100) < 0) 01642 || (ast_waitfordigit(newchan, 100) < 0) 01643 || ast_check_hangup(transferee) 01644 || ast_check_hangup(newchan)) { 01645 ast_hangup(newchan); 01646 return -1; 01647 } 01648 01649 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01650 if (!xferchan) { 01651 ast_hangup(newchan); 01652 return -1; 01653 } 01654 /* Make formats okay */ 01655 xferchan->visible_indication = transferer->visible_indication; 01656 xferchan->readformat = transferee->readformat; 01657 xferchan->writeformat = transferee->writeformat; 01658 ast_channel_masquerade(xferchan, transferee); 01659 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01660 xferchan->_state = AST_STATE_UP; 01661 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01662 xferchan->_softhangup = 0; 01663 if ((f = ast_read(xferchan))) 01664 ast_frfree(f); 01665 newchan->_state = AST_STATE_UP; 01666 ast_clear_flag(newchan, AST_FLAGS_ALL); 01667 newchan->_softhangup = 0; 01668 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01669 ast_hangup(xferchan); 01670 ast_hangup(newchan); 01671 return -1; 01672 } 01673 tobj->chan = newchan; 01674 tobj->peer = xferchan; 01675 tobj->bconfig = *config; 01676 01677 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01678 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01679 } 01680 01681 if (ast_stream_and_wait(newchan, xfersound, "")) 01682 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01683 bridge_call_thread_launch(tobj); 01684 return -1; /* XXX meaning the channel is bridged ? */ 01685 } else { 01686 /* Transferee hung up */ 01687 finishup(transferee); 01688 return -1; 01689 } 01690 }
| 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 1105 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_stream_and_wait(), ast_strlen_zero(), ast_verb, 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.
01106 { 01107 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 01108 int x = 0; 01109 size_t len; 01110 struct ast_channel *caller_chan, *callee_chan; 01111 const char *mixmonitor_spy_type = "MixMonitor"; 01112 int count = 0; 01113 01114 if (!mixmonitor_ok) { 01115 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01116 return -1; 01117 } 01118 01119 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 01120 mixmonitor_ok = 0; 01121 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01122 return -1; 01123 } 01124 01125 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 01126 01127 if (!ast_strlen_zero(courtesytone)) { 01128 if (ast_autoservice_start(callee_chan)) 01129 return -1; 01130 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 01131 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01132 ast_autoservice_stop(callee_chan); 01133 return -1; 01134 } 01135 if (ast_autoservice_stop(callee_chan)) 01136 return -1; 01137 } 01138 01139 ast_channel_lock(callee_chan); 01140 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01141 ast_channel_unlock(callee_chan); 01142 01143 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 01144 if (count > 0) { 01145 01146 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 01147 01148 /* Make sure they are running */ 01149 ast_channel_lock(callee_chan); 01150 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01151 ast_channel_unlock(callee_chan); 01152 if (count > 0) { 01153 if (!stopmixmonitor_ok) { 01154 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01155 return -1; 01156 } 01157 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 01158 stopmixmonitor_ok = 0; 01159 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01160 return -1; 01161 } else { 01162 pbx_exec(callee_chan, stopmixmonitor_app, ""); 01163 return AST_FEATURE_RETURN_SUCCESS; 01164 } 01165 } 01166 01167 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 01168 } 01169 01170 if (caller_chan && callee_chan) { 01171 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 01172 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 01173 01174 if (!touch_format) 01175 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 01176 01177 if (!touch_monitor) 01178 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 01179 01180 if (touch_monitor) { 01181 len = strlen(touch_monitor) + 50; 01182 args = alloca(len); 01183 touch_filename = alloca(len); 01184 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 01185 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 01186 } else { 01187 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 01188 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 01189 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 01190 args = alloca(len); 01191 touch_filename = alloca(len); 01192 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 01193 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 01194 } 01195 01196 for( x = 0; x < strlen(args); x++) { 01197 if (args[x] == '/') 01198 args[x] = '-'; 01199 } 01200 01201 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 01202 01203 pbx_exec(callee_chan, mixmonitor_app, args); 01204 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01205 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01206 return AST_FEATURE_RETURN_SUCCESS; 01207 01208 } 01209 01210 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01211 return -1; 01212 01213 }
| 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 1012 of file features.c.
References AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strlen_zero(), ast_verb, 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.
01013 { 01014 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 01015 int x = 0; 01016 size_t len; 01017 struct ast_channel *caller_chan, *callee_chan; 01018 const char *automon_message_start = NULL; 01019 const char *automon_message_stop = NULL; 01020 01021 if (!monitor_ok) { 01022 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 01023 return -1; 01024 } 01025 01026 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 01027 monitor_ok = 0; 01028 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 01029 return -1; 01030 } 01031 01032 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 01033 if (caller_chan) { /* Find extra messages */ 01034 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 01035 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 01036 } 01037 01038 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 01039 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 01040 return -1; 01041 } 01042 } 01043 01044 if (callee_chan->monitor) { 01045 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 01046 if (!ast_strlen_zero(automon_message_stop)) { 01047 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 01048 } 01049 callee_chan->monitor->stop(callee_chan, 1); 01050 return AST_FEATURE_RETURN_SUCCESS; 01051 } 01052 01053 if (caller_chan && callee_chan) { 01054 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 01055 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 01056 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 01057 01058 if (!touch_format) 01059 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 01060 01061 if (!touch_monitor) 01062 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 01063 01064 if (!touch_monitor_prefix) 01065 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 01066 01067 if (touch_monitor) { 01068 len = strlen(touch_monitor) + 50; 01069 args = alloca(len); 01070 touch_filename = alloca(len); 01071 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 01072 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 01073 } else { 01074 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 01075 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 01076 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 01077 args = alloca(len); 01078 touch_filename = alloca(len); 01079 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 01080 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 01081 } 01082 01083 for(x = 0; x < strlen(args); x++) { 01084 if (args[x] == '/') 01085 args[x] = '-'; 01086 } 01087 01088 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 01089 01090 pbx_exec(callee_chan, monitor_app, args); 01091 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01092 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01093 01094 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 01095 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 01096 } 01097 01098 return AST_FEATURE_RETURN_SUCCESS; 01099 } 01100 01101 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01102 return -1; 01103 }
| 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 |
Place chan on hold, check if transferred to parkinglot extension, otherwise check extension exists and transfer caller.
| AST_FEATURE_RETURN_SUCCESS. | ||
| -1 | on failure. |
Definition at line 1265 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, 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.
01266 { 01267 struct ast_channel *transferer; 01268 struct ast_channel *transferee; 01269 const char *transferer_real_context; 01270 char xferto[256]; 01271 int res, parkstatus = 0; 01272 01273 set_peers(&transferer, &transferee, peer, chan, sense); 01274 transferer_real_context = real_ctx(transferer, transferee); 01275 /* Start autoservice on chan while we talk to the originator */ 01276 ast_autoservice_start(transferee); 01277 ast_indicate(transferee, AST_CONTROL_HOLD); 01278 01279 memset(xferto, 0, sizeof(xferto)); 01280 01281 /* Transfer */ 01282 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01283 if (res < 0) { 01284 finishup(transferee); 01285 return -1; /* error ? */ 01286 } 01287 if (res > 0) /* If they've typed a digit already, handle it */ 01288 xferto[0] = (char) res; 01289 01290 ast_stopstream(transferer); 01291 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01292 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01293 finishup(transferee); 01294 return res; 01295 } 01296 if (!strcmp(xferto, ast_parking_ext())) { 01297 res = finishup(transferee); 01298 if (res) 01299 res = -1; 01300 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) { /* success */ 01301 /* We return non-zero, but tell the PBX not to hang the channel when 01302 the thread dies -- We have to be careful now though. We are responsible for 01303 hanging up the channel, else it will never be hung up! */ 01304 01305 return 0; 01306 } else { 01307 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus); 01308 } 01309 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 01310 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01311 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 01312 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 01313 res=finishup(transferee); 01314 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 01315 transferer->cdr=ast_cdr_alloc(); 01316 if (transferer->cdr) { 01317 ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */ 01318 ast_cdr_start(transferer->cdr); 01319 } 01320 } 01321 if (transferer->cdr) { 01322 struct ast_cdr *swap = transferer->cdr; 01323 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 01324 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 01325 transferer->cdr->channel, transferer->cdr->dstchannel); 01326 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 01327 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel); 01328 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto); 01329 /* swap cdrs-- it will save us some time & work */ 01330 transferer->cdr = transferee->cdr; 01331 transferee->cdr = swap; 01332 } 01333 if (!transferee->pbx) { 01334 /* Doh! Use our handy async_goto functions */ 01335 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n" 01336 ,transferee->name, xferto, transferer_real_context); 01337 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 01338 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 01339 } else { 01340 /* Set the channel's new extension, since it exists, using transferer context */ 01341 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 01342 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name); 01343 set_c_e_p(transferee, transferer_real_context, xferto, 0); 01344 } 01345 check_goto_on_transfer(transferer); 01346 return res; 01347 } else { 01348 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 01349 } 01350 if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { 01351 finishup(transferee); 01352 return -1; 01353 } 01354 ast_stopstream(transferer); 01355 res = finishup(transferee); 01356 if (res) { 01357 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name); 01358 return res; 01359 } 01360 return AST_FEATURE_RETURN_SUCCESS; 01361 }
| 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 1215 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
01216 { 01217 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 01218 return AST_FEATURE_RETURN_HANGUP; 01219 }
| 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 942 of file features.c.
References ast_channel::_state, ast_answer(), ast_safe_sleep(), AST_STATE_UP, masq_park_call_announce(), and set_peers().
Referenced by builtin_atxfer().
00943 { 00944 struct ast_channel *parker; 00945 struct ast_channel *parkee; 00946 int res = 0; 00947 00948 set_peers(&parker, &parkee, peer, chan, sense); 00949 /* we used to set chan's exten and priority to "s" and 1 00950 here, but this generates (in some cases) an invalid 00951 extension, and if "s" exists, could errantly 00952 cause execution of extensions you don't expect. It 00953 makes more sense to let nature take its course 00954 when chan finishes, and let the pbx do its thing 00955 and hang up when the park is over. 00956 */ 00957 if (chan->_state != AST_STATE_UP) 00958 res = ast_answer(chan); 00959 if (!res) 00960 res = ast_safe_sleep(chan, 1000); 00961 00962 if (!res) { /* one direction used to call park_call.... */ 00963 res = masq_park_call_announce(parkee, parker, 0, NULL); 00964 /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ 00965 } 00966 00967 return res; 00968 }
| static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
| struct ast_flags * | features_caller, | |||
| char * | options, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 2964 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().
02965 { 02966 int i = 0; 02967 enum { 02968 OPT_CALLEE_REDIRECT = 't', 02969 OPT_CALLER_REDIRECT = 'T', 02970 OPT_CALLEE_AUTOMON = 'w', 02971 OPT_CALLER_AUTOMON = 'W', 02972 OPT_CALLEE_DISCONNECT = 'h', 02973 OPT_CALLER_DISCONNECT = 'H', 02974 OPT_CALLEE_PARKCALL = 'k', 02975 OPT_CALLER_PARKCALL = 'K', 02976 }; 02977 02978 memset(options, 0, len); 02979 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 02980 options[i++] = OPT_CALLER_REDIRECT; 02981 } 02982 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 02983 options[i++] = OPT_CALLER_AUTOMON; 02984 } 02985 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 02986 options[i++] = OPT_CALLER_DISCONNECT; 02987 } 02988 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 02989 options[i++] = OPT_CALLER_PARKCALL; 02990 } 02991 02992 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 02993 options[i++] = OPT_CALLEE_REDIRECT; 02994 } 02995 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 02996 options[i++] = OPT_CALLEE_AUTOMON; 02997 } 02998 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 02999 options[i++] = OPT_CALLEE_DISCONNECT; 03000 } 03001 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 03002 options[i++] = OPT_CALLEE_PARKCALL; 03003 } 03004 03005 return options; 03006 }
| 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 1370 of file features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by builtin_atxfer().
01371 { 01372 if (ast_channel_make_compatible(c, newchan) < 0) { 01373 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 01374 c->name, newchan->name); 01375 ast_hangup(newchan); 01376 return -1; 01377 } 01378 return 0; 01379 }
| 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 366 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_strlen_zero(), f, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.
Referenced by builtin_blindtransfer().
00367 { 00368 struct ast_channel *xferchan; 00369 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00370 char *x, *goto_on_transfer; 00371 struct ast_frame *f; 00372 00373 if (ast_strlen_zero(val)) 00374 return; 00375 00376 goto_on_transfer = ast_strdupa(val); 00377 00378 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name))) 00379 return; 00380 00381 for (x = goto_on_transfer; x && *x; x++) { 00382 if (*x == '^') 00383 *x = '|'; 00384 } 00385 /* Make formats okay */ 00386 xferchan->readformat = chan->readformat; 00387 xferchan->writeformat = chan->writeformat; 00388 ast_channel_masquerade(xferchan, chan); 00389 ast_parseable_goto(xferchan, goto_on_transfer); 00390 xferchan->_state = AST_STATE_UP; 00391 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00392 xferchan->_softhangup = 0; 00393 if ((f = ast_read(xferchan))) { 00394 ast_frfree(f); 00395 f = NULL; 00396 ast_pbx_start(xferchan); 00397 } else { 00398 ast_hangup(xferchan); 00399 } 00400 }
| static struct ast_parkinglot* create_parkinglot | ( | char * | name | ) | [static, read] |
Allocate parking lot structure.
Definition at line 3525 of file features.c.
References ao2_alloc, ast_copy_string(), AST_LIST_HEAD_INIT, ast_parkinglot::name, parkinglot_destroy(), and ast_parkinglot::parkings.
Referenced by build_parkinglot().
03526 { 03527 struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL; 03528 03529 if (!name) 03530 return NULL; 03531 03532 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 03533 if (!newlot) 03534 return NULL; 03535 03536 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 03537 AST_LIST_HEAD_INIT(&newlot->parkings); 03538 03539 return newlot; 03540 }
| static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 293 of file features.c.
References ast_free.
00294 { 00295 struct ast_dial_features *df = data; 00296 if (df) { 00297 ast_free(df); 00298 } 00299 }
| static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 280 of file features.c.
References ast_calloc.
00281 { 00282 struct ast_dial_features *df = data, *df_copy; 00283 00284 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00285 return NULL; 00286 } 00287 00288 memcpy(df_copy, df, sizeof(*df)); 00289 00290 return df_copy; 00291 }
| 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 4126 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(), ast_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
Referenced by action_bridge(), and bridge_exec().
04127 { 04128 ast_moh_stop(chan); 04129 ast_channel_lock(chan); 04130 ast_setstate(tmpchan, chan->_state); 04131 tmpchan->readformat = chan->readformat; 04132 tmpchan->writeformat = chan->writeformat; 04133 ast_channel_masquerade(tmpchan, chan); 04134 ast_channel_lock(tmpchan); 04135 ast_do_masquerade(tmpchan); 04136 /* when returning from bridge, the channel will continue at the next priority */ 04137 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 04138 ast_channel_unlock(tmpchan); 04139 ast_channel_unlock(chan); 04140 }
| static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
| ignore | unused var. |
Start inf loop, lock parking lot, check if any parked channels have gone above timeout if so, remove channel from parking lot and return it to the extension that parked it. Check if parked channel decided to hangup, wait until next FD via select().
Definition at line 3189 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().
03190 { 03191 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 03192 fd_set nrfds, nefds; /* args for the next select */ 03193 FD_ZERO(&rfds); 03194 FD_ZERO(&efds); 03195 03196 for (;;) { 03197 int res = 0; 03198 int ms = -1; /* select timeout, uninitialized */ 03199 int max = -1; /* max fd, none there yet */ 03200 struct ao2_iterator iter; 03201 struct ast_parkinglot *curlot; 03202 FD_ZERO(&nrfds); 03203 FD_ZERO(&nefds); 03204 iter = ao2_iterator_init(parkinglots, 0); 03205 03206 while ((curlot = ao2_iterator_next(&iter))) { 03207 res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max); 03208 ao2_ref(curlot, -1); 03209 } 03210 03211 rfds = nrfds; 03212 efds = nefds; 03213 { 03214 struct timeval wait = ast_samp2tv(ms, 1000); 03215 /* Wait for something to happen */ 03216 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL); 03217 } 03218 pthread_testcancel(); 03219 } 03220 return NULL; /* Never reached */ 03221 }
| 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 1903 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, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().
Referenced by load_config().
01904 { 01905 struct ast_app *app; 01906 struct ast_call_feature *feature = data; 01907 struct ast_channel *work, *idle; 01908 int res; 01909 01910 if (!feature) { /* shouldn't ever happen! */ 01911 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01912 return -1; 01913 } 01914 01915 if (sense == FEATURE_SENSE_CHAN) { 01916 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01917 return AST_FEATURE_RETURN_KEEPTRYING; 01918 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01919 work = chan; 01920 idle = peer; 01921 } else { 01922 work = peer; 01923 idle = chan; 01924 } 01925 } else { 01926 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01927 return AST_FEATURE_RETURN_KEEPTRYING; 01928 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01929 work = peer; 01930 idle = chan; 01931 } else { 01932 work = chan; 01933 idle = peer; 01934 } 01935 } 01936 01937 if (!(app = pbx_findapp(feature->app))) { 01938 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01939 return -2; 01940 } 01941 01942 ast_autoservice_start(idle); 01943 01944 if (!ast_strlen_zero(feature->moh_class)) 01945 ast_moh_start(idle, feature->moh_class, NULL); 01946 01947 res = pbx_exec(work, app, feature->app_args); 01948 01949 if (!ast_strlen_zero(feature->moh_class)) 01950 ast_moh_stop(idle); 01951 01952 ast_autoservice_stop(idle); 01953 01954 if (res) { 01955 return AST_FEATURE_RETURN_SUCCESSBREAK; 01956 } 01957 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01958 }
| static int 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 | Lock features list, browse for code, unlock list |
| res | on success. | |
| -1 | on failure. |
Definition at line 1996 of file features.c.
References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_STOREDIGITS, AST_FLAGS_ALL, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strlen_zero(), ast_test_flag, ast_verb, ast_call_feature::exten, feature_group_exten::exten, feature_group_exten::feature, FEATURE_SENSE_CHAN, feature_group::features, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, features_lock, find_dynamic_feature(), find_group(), ast_flags::flags, ast_channel::name, ast_call_feature::operation, pbx_builtin_getvar_helper(), S_OR, and ast_call_feature::sname.
Referenced by ast_bridge_call().
01997 { 01998 int x; 01999 struct ast_flags features; 02000 struct ast_call_feature *feature; 02001 struct feature_group *fg = NULL; 02002 struct feature_group_exten *fge; 02003 const char *peer_dynamic_features, *chan_dynamic_features; 02004 char dynamic_features_buf[128]; 02005 char *tmp, *tok; 02006 int res = AST_FEATURE_RETURN_PASSDIGITS; 02007 int feature_detected = 0; 02008 02009 if (sense == FEATURE_SENSE_CHAN) { 02010 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 02011 } 02012 else { 02013 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 02014 } 02015 02016 ast_channel_lock(peer); 02017 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 02018 ast_channel_unlock(peer); 02019 02020 ast_channel_lock(chan); 02021 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 02022 ast_channel_unlock(chan); 02023 02024 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,"")); 02025 02026 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); 02027 02028 ast_rwlock_rdlock(&features_lock); 02029 for (x = 0; x < FEATURES_COUNT; x++) { 02030 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 02031 !ast_strlen_zero(builtin_features[x].exten)) { 02032 /* Feature is up for consideration */ 02033 if (!strcmp(builtin_features[x].exten, code)) { 02034 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 02035 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 02036 feature_detected = 1; 02037 break; 02038 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 02039 if (res == AST_FEATURE_RETURN_PASSDIGITS) 02040 res = AST_FEATURE_RETURN_STOREDIGITS; 02041 } 02042 } 02043 } 02044 ast_rwlock_unlock(&features_lock); 02045 02046 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) 02047 return res; 02048 02049 tmp = dynamic_features_buf; 02050 02051 while ((tok = strsep(&tmp, "#"))) { 02052 AST_RWLIST_RDLOCK(&feature_groups); 02053 02054 fg = find_group(tok); 02055 02056 if (fg) { 02057 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 02058 if (strcasecmp(fge->exten, code)) 02059 continue; 02060 02061 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 02062 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 02063 AST_RWLIST_UNLOCK(&feature_groups); 02064 break; 02065 } 02066 res = AST_FEATURE_RETURN_PASSDIGITS; 02067 } 02068 if (fge) 02069 break; 02070 } 02071 02072 AST_RWLIST_UNLOCK(&feature_groups); 02073 02074 AST_RWLIST_RDLOCK(&feature_list); 02075 02076 if (!(feature = find_dynamic_feature(tok))) { 02077 AST_RWLIST_UNLOCK(&feature_list); 02078 continue; 02079 } 02080 02081 /* Feature is up for consideration */ 02082 if (!strcmp(feature->exten, code)) { 02083 ast_verb(3, " Feature Found: %s exten: %s\n",feature->sname, tok); 02084 res = feature->operation(chan, peer, config, code, sense, feature); 02085 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 02086 AST_RWLIST_UNLOCK(&feature_list); 02087 break; 02088 } 02089 res = AST_FEATURE_RETURN_PASSDIGITS; 02090 } else if (!strncmp(feature->exten, code, strlen(code))) 02091 res = AST_FEATURE_RETURN_STOREDIGITS; 02092 02093 AST_RWLIST_UNLOCK(&feature_list); 02094 } 02095 02096 return res; 02097 }
| static struct ast_channel * 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, read] |
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 2152 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(), ast_channel::call_forward, cause, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_frame::frametype, len(), LOG_NOTICE, ast_channel::name, pbx_builtin_setvar_helper(), and ast_frame::subclass.
Referenced by builtin_atxfer().
02153 { 02154 int state = 0; 02155 int cause = 0; 02156 int to; 02157 struct ast_channel *chan; 02158 struct ast_channel *monitor_chans[2]; 02159 struct ast_channel *active_channel; 02160 int res = 0, ready = 0; 02161 struct timeval started; 02162 int x, len = 0; 02163 char *disconnect_code = NULL, *dialed_code = NULL; 02164 02165 if (!(chan = ast_request(type, format, data, &cause))) { 02166 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 02167 switch(cause) { 02168 case AST_CAUSE_BUSY: 02169 state = AST_CONTROL_BUSY; 02170 break; 02171 case AST_CAUSE_CONGESTION: 02172 state = AST_CONTROL_CONGESTION; 02173 break; 02174 } 02175 goto done; 02176 } 02177 02178 ast_set_callerid(chan, cid_num, cid_name, cid_num); 02179 ast_string_field_set(chan, language, language); 02180 ast_channel_inherit_variables(caller, chan); 02181 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 02182 02183 if (ast_call(chan, data, timeout)) { 02184 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 02185 goto done; 02186 } 02187 02188 ast_indicate(caller, AST_CONTROL_RINGING); 02189 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 02190 ast_rwlock_rdlock(&features_lock); 02191 for (x = 0; x < FEATURES_COUNT; x++) { 02192 if (strcasecmp(builtin_features[x].sname, "disconnect")) 02193 continue; 02194 02195 disconnect_code = builtin_features[x].exten; 02196 len = strlen(disconnect_code) + 1; 02197 dialed_code = alloca(len); 02198 memset(dialed_code, 0, len); 02199 break; 02200 } 02201 ast_rwlock_unlock(&features_lock); 02202 x = 0; 02203 started = ast_tvnow(); 02204 to = timeout; 02205 02206 ast_poll_channel_add(caller, chan); 02207 02208 while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) { 02209 struct ast_frame *f = NULL; 02210 02211 monitor_chans[0] = caller; 02212 monitor_chans[1] = chan; 02213 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 02214 02215 /* see if the timeout has been violated */ 02216 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 02217 state = AST_CONTROL_UNHOLD; 02218 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 02219 break; /*doh! timeout*/ 02220 } 02221 02222 if (!active_channel) 02223 continue; 02224 02225 if (chan && (chan == active_channel)){ 02226 if (!ast_strlen_zero(chan->call_forward)) { 02227 if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) { 02228 return NULL; 02229 } 02230 continue; 02231 } 02232 f = ast_read(chan); 02233 if (f == NULL) { /*doh! where'd he go?*/ 02234 state = AST_CONTROL_HANGUP; 02235 res = 0; 02236 break; 02237 } 02238 02239 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 02240 if (f->subclass == AST_CONTROL_RINGING) { 02241 state = f->subclass; 02242 ast_verb(3, "%s is ringing\n", chan->name); 02243 ast_indicate(caller, AST_CONTROL_RINGING); 02244 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 02245 state = f->subclass; 02246 ast_verb(3, "%s is busy\n", chan->name); 02247 ast_indicate(caller, AST_CONTROL_BUSY); 02248 ast_frfree(f); 02249 f = NULL; 02250 break; 02251 } else if (f->subclass == AST_CONTROL_ANSWER) { 02252 /* This is what we are hoping for */ 02253 state = f->subclass; 02254 ast_frfree(f); 02255 f = NULL; 02256 ready=1; 02257 break; 02258 } else if (f->subclass != -1 && f->subclass != AST_CONTROL_PROGRESS) { 02259 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 02260 } 02261 /* else who cares */ 02262 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 02263 ast_write(caller, f); 02264 } 02265 02266 } else if (caller && (active_channel == caller)) { 02267 f = ast_read(caller); 02268 if (f == NULL) { /*doh! where'd he go?*/ 02269 if (!igncallerstate) { 02270 if (ast_check_hangup(caller) && !ast_check_hangup(chan)) { 02271 /* make this a blind transfer */ 02272 ready = 1; 02273 break; 02274 } 02275 state = AST_CONTROL_HANGUP; 02276 res = 0; 02277 break; 02278 } 02279 } else { 02280 02281 if (f->frametype == AST_FRAME_DTMF) { 02282 dialed_code[x++] = f->subclass; 02283 dialed_code[x] = '\0'; 02284 if (strlen(dialed_code) == len) { 02285 x = 0; 02286 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 02287 x = 0; 02288 dialed_code[x] = '\0'; 02289 } 02290 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 02291 /* Caller Canceled the call */ 02292 state = AST_CONTROL_UNHOLD; 02293 ast_frfree(f); 02294 f = NULL; 02295 break; 02296 } 02297 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 02298 ast_write(chan, f); 02299 } 02300 } 02301 } 02302 if (f) 02303 ast_frfree(f); 02304 } /* end while */ 02305 02306 ast_poll_channel_del(caller, chan); 02307 02308 done: 02309 ast_indicate(caller, -1); 02310 if (chan && ready) { 02311 if (chan->_state == AST_STATE_UP) 02312 state = AST_CONTROL_ANSWER; 02313 res = 0; 02314 } else if (chan) { 02315 res = -1; 02316 ast_hangup(chan); 02317 chan = NULL; 02318 } else { 02319 res = -1; 02320 } 02321 02322 if (outstate) 02323 *outstate = state; 02324 02325 return chan; 02326 }
| static int find_channel_by_group | ( | struct ast_channel * | c, | |
| void * | data | |||
| ) | [static] |
Definition at line 4455 of file features.c.
References ast_channel::_state, AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by ast_pickup_call().
04455 { 04456 struct ast_channel *chan = data; 04457 04458 return !c->pbx && 04459 /* Accessing 'chan' here is safe without locking, because there is no way for 04460 the channel do disappear from under us at this point. pickupgroup *could* 04461 change while we're here, but that isn't a problem. */ 04462 (c != chan) && 04463 (chan->pickupgroup & c->callgroup) && 04464 ((c->_state == AST_STATE_RINGING) || (c->_state == AST_STATE_RING)); 04465 }
| static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static, read] |
find a call feature by name
Definition at line 1825 of file features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by feature_interpret(), load_config(), and set_config_flags().
01826 { 01827 struct ast_call_feature *tmp; 01828 01829 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01830 if (!strcasecmp(tmp->sname, name)) { 01831 break; 01832 } 01833 } 01834 01835 return tmp; 01836 }
| static struct feature_group* find_group | ( | const char * | name | ) | [static, read] |
Find a group by name.
| name | feature name |
| feature | group on success. | |
| NULL | on failure. |
Definition at line 1863 of file features.c.
References AST_LIST_TRAVERSE, and feature_group::gname.
Referenced by feature_interpret().
01863 { 01864 struct feature_group *fg = NULL; 01865 01866 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 01867 if (!strcasecmp(fg->gname, name)) 01868 break; 01869 } 01870 01871 return fg; 01872 }
| struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) | [read] |
Find parkinglot by name.
Definition at line 3224 of file features.c.
References ao2_find, ast_copy_string(), ast_log(), ast_strlen_zero(), LOG_DEBUG, ast_parkinglot::name, OBJ_POINTER, option_debug, and parkinglots.
Referenced by build_parkinglot(), park_exec_full(), and park_space_reserve().
03225 { 03226 struct ast_parkinglot *parkinglot = NULL; 03227 struct ast_parkinglot tmp_parkinglot; 03228 03229 if (ast_strlen_zero(name)) 03230 return NULL; 03231 03232 ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name)); 03233 03234 parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER); 03235 03236 if (parkinglot && option_debug) 03237 ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name); 03238 03239 return parkinglot; 03240 }
| static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 493 of file features.c.
References ast_strlen_zero(), ast_channel::parkinglot, and pbx_builtin_getvar_helper().
Referenced by park_exec_full(), and park_space_reserve().
00494 { 00495 const char *temp, *parkinglot = NULL; 00496 00497 /* Check if the channel has a parking lot */ 00498 if (!ast_strlen_zero(chan->parkinglot)) 00499 parkinglot = chan->parkinglot; 00500 00501 /* Channel variables override everything */ 00502 00503 if ((temp = pbx_builtin_getvar_helper(chan, "PARKINGLOT"))) 00504 return temp; 00505 00506 return parkinglot; 00507 }
| static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1221 of file features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_atxfer(), and builtin_blindtransfer().
01222 { 01223 ast_indicate(chan, AST_CONTROL_UNHOLD); 01224 01225 return ast_autoservice_stop(chan); 01226 }
| 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 4019 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(), 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.
04020 { 04021 int i; 04022 struct ast_call_feature *feature; 04023 struct ao2_iterator iter; 04024 struct ast_parkinglot *curlot; 04025 #define HFS_FORMAT "%-25s %-7s %-7s\n" 04026 04027 switch (cmd) { 04028 04029 case CLI_INIT: 04030 e->command = "features show"; 04031 e->usage = 04032 "Usage: features show\n" 04033 " Lists configured features\n"; 04034 return NULL; 04035 case CLI_GENERATE: 04036 return NULL; 04037 } 04038 04039 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 04040 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 04041 04042 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 04043 04044 ast_rwlock_rdlock(&features_lock); 04045 for (i = 0; i < FEATURES_COUNT; i++) 04046 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 04047 ast_rwlock_unlock(&features_lock); 04048 04049 ast_cli(a->fd, "\n"); 04050 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 04051 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 04052 if (AST_RWLIST_EMPTY(&feature_list)) { 04053 ast_cli(a->fd, "(none)\n"); 04054 } else { 04055 AST_RWLIST_RDLOCK(&feature_list); 04056 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 04057 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 04058 } 04059 AST_RWLIST_UNLOCK(&feature_list); 04060 } 04061 04062 // loop through all the parking lots 04063 iter = ao2_iterator_init(parkinglots, 0); 04064 04065 while ((curlot = ao2_iterator_next(&iter))) { 04066 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 04067 ast_cli(a->fd, "------------\n"); 04068 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", parking_ext); 04069 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->parking_con); 04070 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop); 04071 ast_cli(a->fd,"\n"); 04072 ao2_ref(curlot, -1); 04073 } 04074 04075 04076 return CLI_SUCCESS; 04077 }
| static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 4093 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
04094 { 04095 switch (cmd) { 04096 case CLI_INIT: 04097 e->command = "features reload"; 04098 e->usage = 04099 "Usage: features reload\n" 04100 " Reloads configured call features from features.conf\n"; 04101 return NULL; 04102 case CLI_GENERATE: 04103 return NULL; 04104 } 04105 ast_features_reload(); 04106 04107 return CLI_SUCCESS; 04108 }
| 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 4276 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.
04277 { 04278 struct parkeduser *cur; 04279 int numparked = 0; 04280 struct ao2_iterator iter; 04281 struct ast_parkinglot *curlot; 04282 04283 switch (cmd) { 04284 case CLI_INIT: 04285 e->command = "parkedcalls show"; 04286 e->usage = 04287 "Usage: parkedcalls show\n" 04288 " List currently parked calls\n"; 04289 return NULL; 04290 case CLI_GENERATE: 04291 return NULL; 04292 } 04293 04294 if (a->argc > e->args) 04295 return CLI_SHOWUSAGE; 04296 04297 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 04298 , "Context", "Extension", "Pri", "Timeout"); 04299 04300 iter = ao2_iterator_init(parkinglots, 0); 04301 while ((curlot = ao2_iterator_next(&iter))) { 04302 int lotparked = 0; 04303 ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name); 04304 04305 AST_LIST_LOCK(&curlot->parkings); 04306 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 04307 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 04308 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 04309 ,cur->priority, 04310 (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) ); 04311 numparked++; 04312 numparked += lotparked; 04313 } 04314 AST_LIST_UNLOCK(&curlot->parkings); 04315 if (lotparked) 04316 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name); 04317 04318 ao2_ref(curlot, -1); 04319 } 04320 04321 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 04322 04323 return CLI_SUCCESS; 04324 }
| static int load_config | ( | void | ) | [static] |
Definition at line 3672 of file features.c.
References adsipark, ao2_lock(), ao2_unlock(), ast_call_feature::app, app, ast_call_feature::app_args, ARRAY_LEN, ast_add_extension2(), ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load2(), ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FEATURE_FLAG_ONPEER, AST_FEATURE_FLAG_ONSELF, ast_find_call_feature(), ast_log(), ast_parking_ext(), ast_register_feature(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_set_flag, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_unregister_groups(), ast_variable_browse(), ast_verb, atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_TIME, DEFAULT_PARKINGLOT, default_parkinglot, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_MOH_LEN, FEATURE_SNAME_LEN, featuredigittimeout, find_dynamic_feature(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_parkinglot::mohclass, ast_variable::name, ast_variable::next, notify_metermaids(), ast_call_feature::operation, option_debug, park_add_hints(), ast_parkinglot::parkaddhints, parkcall, ast_parkinglot::parkedcallhangup, ast_parkinglot::parkedcallrecording, ast_parkinglot::parkedcallreparking, ast_parkinglot::parkedcalltransfers, parkedplay, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, parking_ext, ast_parkinglot::parking_offset, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, ast_parkinglot::parkingtime, pickup_ext, pickupfailsound, pickupsound, register_group(), register_group_feature(), registrar, remap_feature(), ast_call_feature::sname, transferdigittimeout, unmap_features(), ast_variable::value, var, xferfailsound, and xfersound.
Referenced by ast_features_init(), and ast_features_reload().
03673 { 03674 int start = 0, end = 0; 03675 int res; 03676 int i; 03677 struct ast_context *con = NULL; 03678 struct ast_config *cfg = NULL; 03679 struct ast_variable *var = NULL; 03680 struct feature_group *fg = NULL; 03681 struct ast_flags config_flags = { 0 }; 03682 char old_parking_ext[AST_MAX_EXTENSION]; 03683 char old_parking_con[AST_MAX_EXTENSION] = ""; 03684 char *ctg; 03685 static const char *categories[] = { 03686 /* Categories in features.conf that are not 03687 * to be parsed as group categories 03688 */ 03689 "general", 03690 "featuremap", 03691 "applicationmap" 03692 }; 03693 03694 if (default_parkinglot) { 03695 strcpy(old_parking_con, default_parkinglot->parking_con); 03696 strcpy(old_parking_ext, parking_ext); 03697 } else { 03698 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 03699 if (default_parkinglot) { 03700 ao2_lock(default_parkinglot); 03701 default_parkinglot->parking_start = 701; 03702 default_parkinglot->parking_stop = 750; 03703 default_parkinglot->parking_offset = 0; 03704 default_parkinglot->parkfindnext = 0; 03705 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 03706 ao2_unlock(default_parkinglot); 03707 } 03708 } 03709 if (default_parkinglot) { 03710 if (option_debug) 03711 ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n"); 03712 } else { 03713 ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n"); 03714 return -1; 03715 } 03716 03717 03718 /* Reset to defaults */ 03719 strcpy(parking_ext, "700"); 03720 strcpy(pickup_ext, "*8"); 03721 courtesytone[0] = '\0'; 03722 strcpy(xfersound, "beep"); 03723 strcpy(xferfailsound, "pbx-invalid"); 03724 pickupsound[0] = '\0'; 03725 pickupfailsound[0] = '\0'; 03726 adsipark = 0; 03727 comebacktoorigin = 1; 03728 03729 default_parkinglot->parkaddhints = 0; 03730 default_parkinglot->parkedcalltransfers = 0; 03731 default_parkinglot->parkedcallreparking = 0; 03732 default_parkinglot->parkedcallrecording = 0; 03733 default_parkinglot->parkedcallhangup = 0; 03734 03735 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03736 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03737 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03738 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 03739 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 03740 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 03741 03742 cfg = ast_config_load2("features.conf", "features", config_flags); 03743 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { 03744 ast_log(LOG_WARNING,"Could not load features.conf\n"); 03745 return 0; 03746 } 03747 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 03748 if (!strcasecmp(var->name, "parkext")) { 03749 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 03750 } else if (!strcasecmp(var->name, "context")) { 03751 ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con)); 03752 } else if (!strcasecmp(var->name, "parkingtime")) { 03753 if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) { 03754 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 03755 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 03756 } else 03757 default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000; 03758 } else if (!strcasecmp(var->name, "parkpos")) { 03759 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 03760 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); 03761 } else if (default_parkinglot) { 03762 default_parkinglot->parking_start = start; 03763 default_parkinglot->parking_stop = end; 03764 } else { 03765 ast_log(LOG_WARNING, "No default parking lot!\n"); 03766 } 03767 } else if (!strcasecmp(var->name, "findslot")) { 03768 default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next")); 03769 } else if (!strcasecmp(var->name, "parkinghints")) { 03770 default_parkinglot->parkaddhints = ast_true(var->value); 03771 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 03772 if (!strcasecmp(var->value, "both")) 03773 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 03774 else if (!strcasecmp(var->value, "caller")) 03775 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 03776 else if (!strcasecmp(var->value, "callee")) 03777 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 03778 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 03779 if (!strcasecmp(var->value, "both")) 03780 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 03781 else if (!strcasecmp(var->value, "caller")) 03782 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 03783 else if (!strcasecmp(var->value, "callee")) 03784 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 03785 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 03786 if (!strcasecmp(var->value, "both")) 03787 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 03788 else if (!strcasecmp(var->value, "caller")) 03789 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 03790 else if (!strcasecmp(var->value, "callee")) 03791 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 03792 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 03793 if (!strcasecmp(var->value, "both")) 03794 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 03795 else if (!strcasecmp(var->value, "caller")) 03796 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 03797 else if (!strcasecmp(var->value, "callee")) 03798 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 03799 } else if (!strcasecmp(var->name, "adsipark")) { 03800 adsipark = ast_true(var->value); 03801 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03802 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03803 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03804 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03805 } else 03806 transferdigittimeout = transferdigittimeout * 1000; 03807 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03808 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03809 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03810 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03811 } 03812 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03813 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03814 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03815 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03816 } else 03817 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03818 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 03819 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 03820 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 03821 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 03822 } else 03823 atxferloopdelay *= 1000; 03824 } else if (!strcasecmp(var->name, "atxferdropcall")) { 03825 atxferdropcall = ast_true(var->value); 03826 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 03827 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 03828 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 03829 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 03830 } 03831 } else if (!strcasecmp(var->name, "courtesytone")) { 03832 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03833 } else if (!strcasecmp(var->name, "parkedplay")) { 03834 if (!strcasecmp(var->value, "both")) 03835 parkedplay = 2; 03836 else if (!strcasecmp(var->value, "parked")) 03837 parkedplay = 1; 03838 else 03839 parkedplay = 0; 03840 } else if (!strcasecmp(var->name, "xfersound")) { 03841 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03842 } else if (!strcasecmp(var->name, "xferfailsound")) { 03843 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03844 } else if (!strcasecmp(var->name, "pickupexten")) { 03845 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03846 } else if (!strcasecmp(var->name, "pickupsound")) { 03847 ast_copy_string(pickupsound, var->value, sizeof(pickupsound)); 03848 } else if (!strcasecmp(var->name, "pickupfailsound")) { 03849 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound)); 03850 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 03851 comebacktoorigin = ast_true(var->value); 03852 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03853 ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass)); 03854 } 03855 } 03856 03857 unmap_features(); 03858 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03859 if (remap_feature(var->name, var->value)) 03860 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03861 } 03862 03863 /* Map a key combination to an application*/ 03864 ast_unregister_features(); 03865 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03866 char *tmp_val = ast_strdupa(var->value); 03867 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 03868 struct ast_call_feature *feature; 03869 03870 /* strsep() sets the argument to NULL if match not found, and it 03871 * is safe to use it with a NULL argument, so we don't check 03872 * between calls. 03873 */ 03874 exten = strsep(&tmp_val,","); 03875 activatedby = strsep(&tmp_val,","); 03876 app = strsep(&tmp_val,","); 03877 app_args = strsep(&tmp_val,","); 03878 moh_class = strsep(&tmp_val,","); 03879 03880 activateon = strsep(&activatedby, "/"); 03881 03882 /*! \todo XXX var_name or app_args ? */ 03883 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03884 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03885 app, exten, activateon, var->name); 03886 continue; 03887 } 03888 03889 AST_RWLIST_RDLOCK(&feature_list); 03890 if ((feature = find_dynamic_feature(var->name))) { 03891 AST_RWLIST_UNLOCK(&feature_list); 03892 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03893 continue; 03894 } 03895 AST_RWLIST_UNLOCK(&feature_list); 03896 03897 if (!(feature = ast_calloc(1, sizeof(*feature)))) 03898 continue; 03899 03900 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03901 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 03902 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 03903 03904 if (app_args) 03905 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 03906 03907 if (moh_class) 03908 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 03909 03910 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 03911 feature->operation = feature_exec_app; 03912 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03913 03914 /* Allow caller and calle to be specified for backwards compatability */ 03915 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03916 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03917 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03918 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03919 else { 03920 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03921 " must be 'self', or 'peer'\n", var->name); 03922 continue; 03923 } 03924 03925 if (ast_strlen_zero(activatedby)) 03926 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03927 else if (!strcasecmp(activatedby, "caller")) 03928 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03929 else if (!strcasecmp(activatedby, "callee")) 03930 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03931 else if (!strcasecmp(activatedby, "both")) 03932 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03933 else { 03934 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03935 " must be 'caller', or 'callee', or 'both'\n", var->name); 03936 continue; 03937 } 03938 03939 ast_register_feature(feature); 03940 03941 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 03942 } 03943 03944 ast_unregister_groups(); 03945 AST_RWLIST_WRLOCK(&feature_groups); 03946 03947 ctg = NULL; 03948 while ((ctg = ast_category_browse(cfg, ctg))) { 03949 /* Is this a parkinglot definition ? */ 03950 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 03951 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 03952 if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) 03953 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 03954 else 03955 ast_debug(1, "Configured parking context %s\n", ctg); 03956 continue; 03957 } 03958 /* No, check if it's a group */ 03959 for (i = 0; i < ARRAY_LEN(categories); i++) { 03960 if (!strcasecmp(categories[i], ctg)) 03961 break; 03962 } 03963 03964 if (i < ARRAY_LEN(categories)) 03965 continue; 03966 03967 if (!(fg = register_group(ctg))) 03968 continue; 03969 03970 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 03971 struct ast_call_feature *feature; 03972 03973 AST_RWLIST_RDLOCK(&feature_list); 03974 if (!(feature = find_dynamic_feature(var->name)) && 03975 !(feature = ast_find_call_feature(var->name))) { 03976 AST_RWLIST_UNLOCK(&feature_list); 03977 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 03978 continue; 03979 } 03980 AST_RWLIST_UNLOCK(&feature_list); 03981 03982 register_group_feature(fg, var->value, feature); 03983 } 03984 } 03985 03986 AST_RWLIST_UNLOCK(&feature_groups); 03987 03988 ast_config_destroy(cfg); 03989 03990 /* Remove the old parking extension */ 03991 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03992 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0)) 03993 notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE); 03994 ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03995 } 03996 03997 if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) { 03998 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con); 03999 return -1; 04000 } 04001 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 04002 if (default_parkinglot->parkaddhints) 04003 park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop); 04004 if (!res) 04005 notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE); 04006 return res; 04007 04008 }
| 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 3009 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_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), AST_MAX_FDS, ast_pbx_start(), ast_read(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, buf, callback_dialoptions(), parkeduser::chan, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, ast_frame::frametype, free, ast_channel::generatordata, 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(), parkeduser::start, and ast_frame::subclass.
Referenced by do_parking_thread().
03010 { 03011 03012 struct parkeduser *pu; 03013 int res = 0; 03014 char parkingslot[AST_MAX_EXTENSION]; 03015 03016 /* Lock parking list */ 03017 AST_LIST_LOCK(&curlot->parkings); 03018 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 03019 struct ast_channel *chan = pu->chan; /* shorthand */ 03020 int tms; /* timeout for this item */ 03021 int x; /* fd index in channel */ 03022 struct ast_context *con; 03023 03024 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 03025 continue; 03026 } 03027 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 03028 if (tms > pu->parkingtime) { 03029 /* Stop music on hold */ 03030 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 03031 /* Get chan, exten from derived kludge */ 03032 if (pu->peername[0]) { 03033 char *peername = ast_strdupa(pu->peername); 03034 char *cp = strrchr(peername, '-'); 03035 char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 03036 int i; 03037 03038 if (cp) 03039 *cp = 0; 03040 ast_copy_string(peername_flat,peername,sizeof(peername_flat)); 03041 for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) { 03042 if (peername_flat[i] == '/') 03043 peername_flat[i]= '0'; 03044 } 03045 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar); 03046 if (!con) { 03047 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial); 03048 } 03049 if (con) { 03050 char returnexten[AST_MAX_EXTENSION]; 03051 struct ast_datastore *features_datastore; 03052 struct ast_dial_features *dialfeatures = NULL; 03053 03054 ast_channel_lock(chan); 03055 03056 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 03057 dialfeatures = features_datastore->data; 03058 03059 ast_channel_unlock(chan); 03060 03061 if (!strncmp(peername, "Parked/", 7)) { 03062 peername += 7; 03063 } 03064 03065 if (dialfeatures) { 03066 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 03067 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 03068 } else { /* Existing default */ 03069 ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name); 03070 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername); 03071 } 03072 03073 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar); 03074 } 03075 if (pu->options_specified == 1) { 03076 /* Park() was called with overriding return arguments, respect those arguments */ 03077 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 03078 } else { 03079 if (comebacktoorigin) { 03080 set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1); 03081 } else { 03082 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum); 03083 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 03084 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 03085 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 03086 } 03087 } 03088 } else { 03089 /* They've been waiting too long, send them back to where they came. Theoretically they 03090 should have their original extensions and such, but we copy to be on the safe side */ 03091 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 03092 } 03093 post_manager_event("ParkedCallTimeOut", pu); 03094 03095 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); 03096 /* Start up the PBX, or hang them up */ 03097 if (ast_pbx_start(chan)) { 03098 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name); 03099 ast_hangup(chan); 03100 } 03101 /* And take them out of the parking lot */ 03102 con = ast_context_find(pu->parkinglot->parking_con); 03103 if (con) { 03104 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03105 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n"); 03106 else 03107 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 03108 } else 03109 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 03110 AST_LIST_REMOVE_CURRENT(list); 03111 free(pu); 03112 } else { /* still within parking time, process descriptors */ 03113 for (x = 0; x < AST_MAX_FDS; x++) { 03114 struct ast_frame *f; 03115 03116 if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds))) 03117 continue; 03118 03119 if (FD_ISSET(chan->fds[x], efds)) 03120 ast_set_flag(chan, AST_FLAG_EXCEPTION); 03121 else 03122 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 03123 chan->fdno = x; 03124 03125 /* See if they need servicing */ 03126 f = ast_read(pu->chan); 03127 /* Hangup? */ 03128 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 03129 if (f) 03130 ast_frfree(f); 03131 post_manager_event("ParkedCallGiveUp", pu); 03132 03133 /* There's a problem, hang them up*/ 03134 ast_verb(2, "%s got tired of being parked\n", chan->name); 03135 ast_hangup(chan); 03136 /* And take them out of the parking lot */ 03137 con = ast_context_find(curlot->parking_con); 03138 if (con) { 03139 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03140 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 03141 else 03142 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 03143 } else 03144 ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name); 03145 AST_LIST_REMOVE_CURRENT(list); 03146 free(pu); 03147 break; 03148 } else { 03149 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 03150 ast_frfree(f); 03151 if (pu->moh_trys < 3 && !chan->generatordata) { 03152 ast_debug(1, "MOH on parked call stopped by outside source. Restarting on channel %s.\n", chan->name); 03153 ast_indicate_data(chan, AST_CONTROL_HOLD, 03154 S_OR(curlot->mohclass, NULL), 03155 (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0)); 03156 pu->moh_trys++; 03157 } 03158 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 03159 } 03160 } /* End for */ 03161 if (x >= AST_MAX_FDS) { 03162 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 03163 if (chan->fds[x] > -1) { 03164 FD_SET(chan->fds[x], nrfds); 03165 FD_SET(chan->fds[x], nefds); 03166 if (chan->fds[x] > *max) 03167 *max = chan->fds[x]; 03168 } 03169 } 03170 /* Keep track of our shortest wait */ 03171 if (tms < *ms || *ms < 0) 03172 *ms = tms; 03173 } 03174 } 03175 } 03176 AST_LIST_TRAVERSE_SAFE_END; 03177 AST_LIST_UNLOCK(&curlot->parkings); 03178 return res; 03179 }
| 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 4401 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(), and buf.
Referenced by ast_features_init().
04402 { 04403 const char *channel = astman_get_header(m, "Channel"); 04404 const char *channel2 = astman_get_header(m, "Channel2"); 04405 const char *timeout = astman_get_header(m, "Timeout"); 04406 char buf[BUFSIZ]; 04407 int to = 0; 04408 int res = 0; 04409 int parkExt = 0; 04410 struct ast_channel *ch1, *ch2; 04411 04412 if (ast_strlen_zero(channel)) { 04413 astman_send_error(s, m, "Channel not specified"); 04414 return 0; 04415 } 04416 04417 if (ast_strlen_zero(channel2)) { 04418 astman_send_error(s, m, "Channel2 not specified"); 04419 return 0; 04420 } 04421 04422 ch1 = ast_get_channel_by_name_locked(channel); 04423 if (!ch1) { 04424 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 04425 astman_send_error(s, m, buf); 04426 return 0; 04427 } 04428 04429 ch2 = ast_get_channel_by_name_locked(channel2); 04430 if (!ch2) { 04431 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 04432 astman_send_error(s, m, buf); 04433 ast_channel_unlock(ch1); 04434 return 0; 04435 } 04436 04437 if (!ast_strlen_zero(timeout)) { 04438 sscanf(timeout, "%30d", &to); 04439 } 04440 04441 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 04442 if (!res) { 04443 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 04444 astman_send_ack(s, m, "Park successful"); 04445 } else { 04446 astman_send_error(s, m, "Park failure"); 04447 } 04448 04449 ast_channel_unlock(ch1); 04450 ast_channel_unlock(ch2); 04451 04452 return 0; 04453 }
| 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 4340 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_OR, and parkeduser::start.
Referenced by ast_features_init().
04341 { 04342 struct parkeduser *cur; 04343 const char *id = astman_get_header(m, "ActionID"); 04344 char idText[256] = ""; 04345 struct ao2_iterator iter; 04346 struct ast_parkinglot *curlot; 04347 04348 if (!ast_strlen_zero(id)) 04349 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 04350 04351 astman_send_ack(s, m, "Parked calls will follow"); 04352 04353 iter = ao2_iterator_init(parkinglots, 0); 04354 while ((curlot = ao2_iterator_next(&iter))) { 04355 04356 AST_LIST_LOCK(&curlot->parkings); 04357 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 04358 astman_append(s, "Event: ParkedCall\r\n" 04359 "Exten: %d\r\n" 04360 "Channel: %s\r\n" 04361 "From: %s\r\n" 04362 "Timeout: %ld\r\n" 04363 "CallerIDNum: %s\r\n" 04364 "CallerIDName: %s\r\n" 04365 "%s" 04366 "\r\n", 04367 cur->parkingnum, cur->chan->name, cur->peername, 04368 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 04369 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 04370 S_OR(cur->chan->cid.cid_name, ""), 04371 idText); 04372 } 04373 AST_LIST_UNLOCK(&curlot->parkings); 04374 ao2_ref(curlot, -1); 04375 } 04376 04377 astman_append(s, 04378 "Event: ParkedCallsComplete\r\n" 04379 "%s" 04380 "\r\n",idText); 04381 04382 04383 return RESULT_SUCCESS; 04384 }
| 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 833 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_read(), AST_STATE_DOWN, ast_stream_and_wait(), 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_call_full(), 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().
00834 { 00835 struct ast_channel *chan; 00836 struct ast_frame *f; 00837 int park_status; 00838 struct ast_park_call_args park_args = {0,}; 00839 00840 if (!args) { 00841 args = &park_args; 00842 args->timeout = timeout; 00843 args->extout = extout; 00844 } 00845 00846 if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) { 00847 if (peer) 00848 ast_stream_and_wait(peer, "beeperr", ""); 00849 return AST_FEATURE_RETURN_PARKFAILED; 00850 } 00851 00852 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00853 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00854 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00855 return -1; 00856 } 00857 00858 /* Make formats okay */ 00859 chan->readformat = rchan->readformat; 00860 chan->writeformat = rchan->writeformat; 00861 ast_channel_masquerade(chan, rchan); 00862 00863 /* Setup the extensions and such */ 00864 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00865 00866 /* Setup the macro extension and such */ 00867 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext)); 00868 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten)); 00869 chan->macropriority = rchan->macropriority; 00870 00871 /* Make the masq execute */ 00872 if ((f = ast_read(chan))) 00873 ast_frfree(f); 00874 00875 if (peer == rchan) { 00876 peer = chan; 00877 } 00878 00879 if (peer && (!play_announcement && args == &park_args)) { 00880 args->orig_chan_name = ast_strdupa(peer->name); 00881 } 00882 00883 park_status = park_call_full(chan, peer, args); 00884 if (park_status == 1) { 00885 /* would be nice to play "invalid parking extension" */ 00886 ast_hangup(chan); 00887 return -1; 00888 } 00889 00890 return 0; 00891 }
| static int masq_park_call_announce | ( | struct ast_channel * | rchan, | |
| struct ast_channel * | peer, | |||
| int | timeout, | |||
| int * | extout | |||
| ) | [static] |
Definition at line 904 of file features.c.
References masq_park_call().
Referenced by builtin_blindtransfer(), and builtin_parkcall().
00905 { 00906 return masq_park_call(rchan, peer, timeout, extout, 1, NULL); 00907 }
| 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 899 of file features.c.
References masq_park_call().
Referenced by park_call_exec().
00900 { 00901 return masq_park_call(rchan, peer, 0, NULL, 1, args); 00902 }
| static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 519 of file features.c.
References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, and ast_exists_extension().
Referenced by ast_features_init().
00520 { 00521 char *context; 00522 char *exten; 00523 00524 context = ast_strdupa(data); 00525 00526 exten = strsep(&context, "@"); 00527 if (!context) 00528 return AST_DEVICE_INVALID; 00529 00530 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 00531 00532 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 00533 return AST_DEVICE_NOT_INUSE; 00534 00535 return AST_DEVICE_INUSE; 00536 }
| 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 510 of file features.c.
References ast_debug, ast_devstate2str(), and ast_devstate_changed().
Referenced by load_config(), manage_parkinglot(), park_call_full(), and park_exec_full().
00511 { 00512 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 00513 exten, context, ast_devstate2str(state)); 00514 00515 ast_devstate_changed(state, "park:%s@%s", exten, context); 00516 }
| 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 3659 of file features.c.
References ast_add_extension(), PRIORITY_HINT, and registrar.
Referenced by load_config().
03660 { 03661 int numext; 03662 char device[AST_MAX_EXTENSION]; 03663 char exten[10]; 03664 03665 for (numext = start; numext <= stop; numext++) { 03666 snprintf(exten, sizeof(exten), "%d", numext); 03667 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 03668 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 03669 } 03670 }
| static int park_call_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Park a call.
Definition at line 3249 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_strlen_zero(), ast_channel::exten, ast_flags::flags, ast_park_call_args::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().
03250 { 03251 /* Cache the original channel name in case we get masqueraded in the middle 03252 * of a park--it is still theoretically possible for a transfer to happen before 03253 * we get here, but it is _really_ unlikely */ 03254 char *orig_chan_name = ast_strdupa(chan->name); 03255 char orig_exten[AST_MAX_EXTENSION]; 03256 int orig_priority = chan->priority; 03257 03258 /* Data is unused at the moment but could contain a parking 03259 lot context eventually */ 03260 int res = 0; 03261 03262 char *parse = NULL; 03263 AST_DECLARE_APP_ARGS(app_args, 03264 AST_APP_ARG(timeout); 03265 AST_APP_ARG(return_con); 03266 AST_APP_ARG(return_ext); 03267 AST_APP_ARG(return_pri); 03268 AST_APP_ARG(options); 03269 ); 03270 03271 parse = ast_strdupa(data); 03272 AST_STANDARD_APP_ARGS(app_args, parse); 03273 03274 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 03275 03276 /* Setup the exten/priority to be s/1 since we don't know 03277 where this call should return */ 03278 strcpy(chan->exten, "s"); 03279 chan->priority = 1; 03280 03281 /* Answer if call is not up */ 03282 if (chan->_state != AST_STATE_UP) 03283 res = ast_answer(chan); 03284 03285 /* Sleep to allow VoIP streams to settle down */ 03286 if (!res) 03287 res = ast_safe_sleep(chan, 1000); 03288 03289 /* Park the call */ 03290 if (!res) { 03291 struct ast_park_call_args args = { 03292 .orig_chan_name = orig_chan_name, 03293 }; 03294 struct ast_flags flags = { 0 }; 03295 03296 if (parse) { 03297 if (!ast_strlen_zero(app_args.timeout)) { 03298 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) { 03299 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 03300 args.timeout = 0; 03301 } 03302 } 03303 if (!ast_strlen_zero(app_args.return_con)) { 03304 args.return_con = app_args.return_con; 03305 } 03306 if (!ast_strlen_zero(app_args.return_ext)) { 03307 args.return_ext = app_args.return_ext; 03308 } 03309 if (!ast_strlen_zero(app_args.return_pri)) { 03310 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) { 03311 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 03312 args.return_pri = 0; 03313 } 03314 } 03315 } 03316 03317 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 03318 args.flags = flags.flags; 03319 03320 res = masq_park_call_announce_args(chan, chan, &args); 03321 /* Continue on in the dialplan */ 03322 if (res == 1) { 03323 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 03324 chan->priority = orig_priority; 03325 res = 0; 03326 } else if (!res) { 03327 res = 1; 03328 } 03329 } 03330 03331 return res; 03332 }
| static int park_call_full | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_park_call_args * | args | |||
| ) | [static] |
Definition at line 678 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, 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().
00679 { 00680 struct ast_context *con; 00681 int parkingnum_copy; 00682 struct parkeduser *pu = args->pu; 00683 const char *event_from; 00684 00685 if (pu == NULL) 00686 pu = park_space_reserve(chan, peer, args); 00687 if (pu == NULL) 00688 return 1; /* Continue execution if possible */ 00689 00690 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum); 00691 00692 chan->appl = "Parked Call"; 00693 chan->data = NULL; 00694 00695 pu->chan = chan; 00696 00697 /* Put the parked channel on hold if we have two different channels */ 00698 if (chan != peer) { 00699 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 00700 ast_indicate(pu->chan, AST_CONTROL_RINGING); 00701 } else { 00702 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00703 S_OR(pu->parkinglot->mohclass, NULL), 00704 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 00705 } 00706 } 00707 00708 pu->start = ast_tvnow(); 00709 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime; 00710 parkingnum_copy = pu->parkingnum; 00711 if (args->extout) 00712 *(args->extout) = pu->parkingnum; 00713 00714 if (peer) { 00715 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels 00716 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking 00717 and we need the callback name to be that of transferer. Since local,1/2 have the same 00718 name we can be tricky and just grab the bridged channel from the other side of the local 00719 */ 00720 if (!strcasecmp(peer->tech->type, "Local")) { 00721 struct ast_channel *tmpchan, *base_peer; 00722 char other_side[AST_CHANNEL_NAME]; 00723 char *c; 00724 ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side)); 00725 if ((c = strrchr(other_side, ';'))) { 00726 *++c = '1'; 00727 } 00728 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) { 00729 if ((base_peer = ast_bridged_channel(tmpchan))) { 00730 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 00731 } 00732 ast_channel_unlock(tmpchan); 00733 } 00734 } else { 00735 ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername)); 00736 } 00737 } 00738 00739 /* Remember what had been dialed, so that if the parking 00740 expires, we try to come back to the same place */ 00741 00742 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri); 00743 00744 /* If extension has options specified, they override all other possibilities 00745 such as the returntoorigin flag and transferred context. Information on 00746 extension options is lost here, so we set a flag */ 00747 00748 ast_copy_string(pu->context, 00749 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 00750 sizeof(pu->context)); 00751 ast_copy_string(pu->exten, 00752 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 00753 sizeof(pu->exten)); 00754 pu->priority = args->return_pri ? args->return_pri : 00755 (chan->macropriority ? chan->macropriority : chan->priority); 00756 00757 /* If parking a channel directly, don't quiet yet get parking running on it. 00758 * All parking lot entries are put into the parking lot with notquiteyet on. */ 00759 if (peer != chan) 00760 pu->notquiteyet = 0; 00761 00762 /* Wake up the (presumably select()ing) thread */ 00763 pthread_kill(parking_thread, SIGURG); 00764 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)); 00765 00766 if (peer) { 00767 event_from = peer->name; 00768 } else { 00769 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 00770 } 00771 00772 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00773 "Exten: %s\r\n" 00774 "Channel: %s\r\n" 00775 "Parkinglot: %s\r\n" 00776 "From: %s\r\n" 00777 "Timeout: %ld\r\n" 00778 "CallerIDNum: %s\r\n" 00779 "CallerIDName: %s\r\n" 00780 "Uniqueid: %s\r\n", 00781 pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "", 00782 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00783 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00784 S_OR(pu->chan->cid.cid_name, "<unknown>"), 00785 pu->chan->uniqueid 00786 ); 00787 00788 if (peer && adsipark && ast_adsi_available(peer)) { 00789 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00790 ast_adsi_unload_session(peer); 00791 } 00792 00793 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar); 00794 if (!con) /* Still no context? Bad */ 00795 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con); 00796 if (con) { 00797 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar)) 00798 notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE); 00799 } 00800 00801 AST_LIST_UNLOCK(&pu->parkinglot->parkings); 00802 00803 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 00804 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) { 00805 /* 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. */ 00806 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00807 /* Tell the peer channel the number of the parking space */ 00808 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00809 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00810 } 00811 if (peer == chan) { /* pu->notquiteyet = 1 */ 00812 /* Wake up parking thread if we're really done */ 00813 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00814 S_OR(pu->parkinglot->mohclass, NULL), 00815 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 00816 pu->notquiteyet = 0; 00817 pthread_kill(parking_thread, SIGURG); 00818 } 00819 return 0; 00820 }
| static int park_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 3502 of file features.c.
References default_parkinglot, and park_exec_full().
Referenced by ast_features_init().
03503 { 03504 return park_exec_full(chan, data, default_parkinglot); 03505 }
| static int park_exec_full | ( | struct ast_channel * | chan, | |
| void * | data, | |||
| struct ast_parkinglot * | parkinglot | |||
| ) | [static] |
Pickup parked call.
Definition at line 3335 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(), ast_channel::cdr, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, courtesytone, ast_datastore::data, default_parkinglot, EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_dial_features::features_caller, find_parkinglot(), findparkinglotname(), ast_channel::language, LOG_WARNING, manager_event, ast_channel::name, notify_metermaids(), ast_parkinglot::parkedcallhangup, ast_parkinglot::parkedcallrecording, ast_parkinglot::parkedcallreparking, ast_parkinglot::parkedcalltransfers, parkedplay, ast_parkinglot::parking_con, parkeduser::parkingexten, parkeduser::parkingnum, ast_parkinglot::parkings, ast_channel::pbx, pbx_builtin_setvar_helper(), and S_OR.
Referenced by park_exec().
03336 { 03337 int res = 0; 03338 struct ast_channel *peer=NULL; 03339 struct parkeduser *pu; 03340 struct ast_context *con; 03341 int park = 0; 03342 struct ast_bridge_config config; 03343 03344 if (data) 03345 park = atoi((char *)data); 03346 03347 parkinglot = find_parkinglot(findparkinglotname(chan)); 03348 if (!parkinglot) 03349 parkinglot = default_parkinglot; 03350 03351 AST_LIST_LOCK(&parkinglot->parkings); 03352 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 03353 if (!data || pu->parkingnum == park) { 03354 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 03355 AST_LIST_UNLOCK(&parkinglot->parkings); 03356 return -1; 03357 } 03358 AST_LIST_REMOVE_CURRENT(list); 03359 break; 03360 } 03361 } 03362 AST_LIST_TRAVERSE_SAFE_END; 03363 AST_LIST_UNLOCK(&parkinglot->parkings); 03364 03365 if (pu) { 03366 peer = pu->chan; 03367 con = ast_context_find(parkinglot->parking_con); 03368 if (con) { 03369 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03370 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 03371 else 03372 notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE); 03373 } else 03374 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 03375 03376 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 03377 "Exten: %s\r\n" 03378 "Channel: %s\r\n" 03379 "From: %s\r\n" 03380 "CallerIDNum: %s\r\n" 03381 "CallerIDName: %s\r\n", 03382 pu->parkingexten, pu->chan->name, chan->name, 03383 S_OR(pu->chan->cid.cid_num, "<unknown>"), 03384 S_OR(pu->chan->cid.cid_name, "<unknown>") 03385 ); 03386 03387 ast_free(pu); 03388 } 03389 /* JK02: it helps to answer the channel if not already up */ 03390 if (chan->_state != AST_STATE_UP) 03391 ast_answer(chan); 03392 03393 //XXX Why do we unlock here ? 03394 // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain 03395 //ASTOBJ_UNLOCK(parkinglot); 03396 03397 if (peer) { 03398 struct ast_datastore *features_datastore; 03399 struct ast_dial_features *dialfeatures = NULL; 03400 03401 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 03402 03403 if (!ast_strlen_zero(courtesytone)) { 03404 int error = 0; 03405 ast_indicate(peer, AST_CONTROL_UNHOLD); 03406 if (parkedplay == 0) { 03407 error = ast_stream_and_wait(chan, courtesytone, ""); 03408 } else if (parkedplay == 1) { 03409 error = ast_stream_and_wait(peer, courtesytone, ""); 03410 } else if (parkedplay == 2) { 03411 if (!ast_streamfile(chan, courtesytone, chan->language) && 03412 !ast_streamfile(peer, courtesytone, chan->language)) { 03413 /*! \todo XXX we would like to wait on both! */ 03414 res = ast_waitstream(chan, ""); 03415 if (res >= 0) 03416 res = ast_waitstream(peer, ""); 03417 if (res < 0) 03418 error = 1; 03419 } 03420 } 03421 if (error) { 03422 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 03423 ast_hangup(peer); 03424 return -1; 03425 } 03426 } else 03427 ast_indicate(peer, AST_CONTROL_UNHOLD); 03428 03429 res = ast_channel_make_compatible(chan, peer); 03430 if (res < 0) { 03431 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 03432 ast_hangup(peer); 03433 return -1; 03434 } 03435 /* This runs sorta backwards, since we give the incoming channel control, as if it 03436 were the person called. */ 03437 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park); 03438 03439 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03440 ast_cdr_setdestchan(chan->cdr, peer->name); 03441 memset(&config, 0, sizeof(struct ast_bridge_config)); 03442 03443 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 03444 ast_channel_lock(peer); 03445 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 03446 dialfeatures = features_datastore->data; 03447 } 03448 ast_channel_unlock(peer); 03449 03450 /* When the datastores for both caller and callee are created, both the callee and caller channels 03451 * use the features_caller flag variable to represent themselves. With that said, the config.features_callee 03452 * flags should be copied from the datastore's caller feature flags regardless if peer was a callee 03453 * or caller. */ 03454 if (dialfeatures) { 03455 ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 03456 } 03457 03458 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03459 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 03460 } 03461 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03462 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 03463 } 03464 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03465 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 03466 } 03467 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03468 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 03469 } 03470 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03471 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 03472 } 03473 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03474 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 03475 } 03476 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03477 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 03478 } 03479 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03480 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 03481 } 03482 03483 res = ast_bridge_call(chan, peer, &config); 03484 03485 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03486 ast_cdr_setdestchan(chan->cdr, peer->name); 03487 03488 /* Simulate the PBX hanging up */ 03489 ast_hangup(peer); 03490 return -1; 03491 } else { 03492 /*! \todo XXX Play a message XXX */ 03493 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) 03494 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 03495 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 03496 res = -1; 03497 } 03498 03499 return -1; 03500 }
| static struct parkeduser* park_space_reserve | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_park_call_args * | args | |||
| ) | [static, read] |
Definition at line 566 of file features.c.
References ast_calloc, ast_channel_lock, ast_channel_unlock, ast_exists_extension(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strlen_zero(), ast_test_flag, default_parkinglot, find_parkinglot(), findparkinglotname(), free, LOG_DEBUG, LOG_WARNING, ast_parkinglot::name, parkeduser::notquiteyet, option_debug, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, ast_parkinglot::parking_offset, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, ast_parkinglot::parkings, pbx_builtin_getvar_helper(), and S_OR.
Referenced by masq_park_call(), and park_call_full().
00568 { 00569 struct parkeduser *pu; 00570 int i, parking_space = -1, parking_range; 00571 const char *parkinglotname = NULL; 00572 const char *parkingexten; 00573 struct ast_parkinglot *parkinglot = NULL; 00574 00575 if (peer) 00576 parkinglotname = findparkinglotname(peer); 00577 00578 if (parkinglotname) { 00579 if (option_debug) 00580 ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname); 00581 parkinglot = find_parkinglot(parkinglotname); 00582 } 00583 if (!parkinglot) { 00584 parkinglot = parkinglot_addref(default_parkinglot); 00585 } 00586 00587 if (option_debug) 00588 ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name); 00589 00590 /* Allocate memory for parking data */ 00591 if (!(pu = ast_calloc(1, sizeof(*pu)))) { 00592 parkinglot_unref(parkinglot); 00593 return NULL; 00594 } 00595 00596 /* Lock parking list */ 00597 AST_LIST_LOCK(&parkinglot->parkings); 00598 /* Check for channel variable PARKINGEXTEN */ 00599 ast_channel_lock(chan); 00600 parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"), "")); 00601 ast_channel_unlock(chan); 00602 if (!ast_strlen_zero(parkingexten)) { 00603 /*!\note The API forces us to specify a numeric parking slot, even 00604 * though the architecture would tend to support non-numeric extensions 00605 * (as are possible with SIP, for example). Hence, we enforce that 00606 * limitation here. If extout was not numeric, we could permit 00607 * arbitrary non-numeric extensions. 00608 */ 00609 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) { 00610 AST_LIST_UNLOCK(&parkinglot->parkings); 00611 parkinglot_unref(parkinglot); 00612 free(pu); 00613 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); 00614 return NULL; 00615 } 00616 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00617 00618 if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) { 00619 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con); 00620 AST_LIST_UNLOCK(&parkinglot->parkings); 00621 parkinglot_unref(parkinglot); 00622 ast_free(pu); 00623 return NULL; 00624 } 00625 } else { 00626 int start; 00627 struct parkeduser *cur = NULL; 00628 00629 /* Select parking space within range */ 00630 parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1; 00631 00632 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) { 00633 start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1); 00634 } else { 00635 start = parkinglot->parking_start; 00636 } 00637 00638 for (i = start; 1; i++) { 00639 if (i == parkinglot->parking_stop + 1) { 00640 i = parkinglot->parking_start - 1; 00641 break; 00642 } 00643 00644 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 00645 if (cur->parkingnum == i) { 00646 break; 00647 } 00648 } 00649 if (!cur) { 00650 parking_space = i; 00651 break; 00652 } 00653 } 00654 00655 if (i == start - 1 && cur) { 00656 ast_log(LOG_WARNING, "No more parking spaces\n"); 00657 ast_free(pu); 00658 AST_LIST_UNLOCK(&parkinglot->parkings); 00659 parkinglot_unref(parkinglot); 00660 return NULL; 00661 } 00662 /* Set pointer for next parking */ 00663 if (parkinglot->parkfindnext) 00664 parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1; 00665 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00666 } 00667 00668 pu->notquiteyet = 1; 00669 pu->parkingnum = parking_space; 00670 pu->parkinglot = parkinglot_addref(parkinglot); 00671 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list); 00672 parkinglot_unref(parkinglot); 00673 00674 return pu; 00675 }
| static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static, read] |
Definition at line 3516 of file features.c.
References ao2_ref, ast_log(), LOG_DEBUG, ast_parkinglot::name, and option_debug.
Referenced by park_space_reserve().
03517 { 03518 int refcount = ao2_ref(parkinglot, +1); 03519 if (option_debug > 2) 03520 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1); 03521 return parkinglot; 03522 }
| static int parkinglot_cmp_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 340 of file features.c.
References CMP_MATCH, CMP_STOP, and ast_parkinglot::name.
Referenced by ast_features_init().
00341 { 00342 struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg; 00343 00344 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0; 00345 }
| static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 3543 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().
03544 { 03545 struct ast_parkinglot *ruin = obj; 03546 struct ast_context *con; 03547 con = ast_context_find(ruin->parking_con); 03548 if (con) 03549 ast_context_destroy(con, registrar); 03550 ao2_unlink(parkinglots, ruin); 03551 }
| static int parkinglot_hash_cb | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 333 of file features.c.
References ast_str_case_hash(), and ast_parkinglot::name.
Referenced by ast_features_init().
00334 { 00335 const struct ast_parkinglot *parkinglot = obj; 00336 00337 return ast_str_case_hash(parkinglot->name); 00338 }
| 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 3509 of file features.c.
References ao2_ref, ast_log(), LOG_DEBUG, ast_parkinglot::name, and option_debug.
Referenced by build_parkinglot(), and park_space_reserve().
03510 { 03511 int refcount = ao2_ref(parkinglot, -1); 03512 if (option_debug > 2) 03513 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1); 03514 }
return the first unlocked cdr in a possible chain
Definition at line 2331 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
02332 { 02333 struct ast_cdr *cdr_orig = cdr; 02334 while (cdr) { 02335 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 02336 return cdr; 02337 cdr = cdr->next; 02338 } 02339 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 02340 }
| 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 973 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_stream_and_wait(), and LOG_WARNING.
Referenced by builtin_automonitor().
00974 { 00975 /* First play for caller, put other channel on auto service */ 00976 if (ast_autoservice_start(callee_chan)) 00977 return -1; 00978 if (ast_stream_and_wait(caller_chan, audiofile, "")) { 00979 ast_log(LOG_WARNING, "Failed to play automon message!\n"); 00980 ast_autoservice_stop(callee_chan); 00981 return -1; 00982 } 00983 if (ast_autoservice_stop(callee_chan)) 00984 return -1; 00985 /* Then play for callee, put other channel on auto service */ 00986 if (ast_autoservice_start(caller_chan)) 00987 return -1; 00988 if (ast_stream_and_wait(callee_chan, audiofile, "")) { 00989 ast_log(LOG_WARNING, "Failed to play automon message !\n"); 00990 ast_autoservice_stop(caller_chan); 00991 return -1; 00992 } 00993 if (ast_autoservice_stop(caller_chan)) 00994 return -1; 00995 return(0); 00996 }
| static void post_manager_event | ( | const char * | s, | |
| struct parkeduser * | pu | |||
| ) | [static] |
Output parking event to manager.
Definition at line 2946 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().
02947 { 02948 manager_event(EVENT_FLAG_CALL, s, 02949 "Exten: %s\r\n" 02950 "Channel: %s\r\n" 02951 "Parkinglot: %s\r\n" 02952 "CallerIDNum: %s\r\n" 02953 "CallerIDName: %s\r\n" 02954 "UniqueID: %s\r\n\r\n", 02955 pu->parkingexten, 02956 pu->chan->name, 02957 pu->parkinglot->name, 02958 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02959 S_OR(pu->chan->cid.cid_name, "<unknown>"), 02960 pu->chan->uniqueid 02961 ); 02962 }
| 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 1236 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().
01237 { 01238 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 01239 if (ast_strlen_zero(s)) { 01240 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 01241 } 01242 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 01243 s = transferer->macrocontext; 01244 } 01245 if (ast_strlen_zero(s)) { 01246 s = transferer->context; 01247 } 01248 return s; 01249 }
| static struct feature_group* register_group | ( | const char * | fgname | ) | [static, read] |
Add new feature group.
| fgname | feature group name. |
Add new feature group to the feature group list insert at head of list.
Definition at line 1732 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::gname, and LOG_NOTICE.
Referenced by load_config().
01733 { 01734 struct feature_group *fg; 01735 01736 if (!fgname) { 01737 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 01738 return NULL; 01739 } 01740 01741 if (!(fg = ast_calloc(1, sizeof(*fg)))) 01742 return NULL; 01743 01744 if (ast_string_field_init(fg, 128)) { 01745 ast_free(fg); 01746 return NULL; 01747 } 01748 01749 ast_string_field_set(fg, gname, fgname); 01750 01751 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 01752 01753 ast_verb(2, "Registered group '%s'\n", fg->gname); 01754 01755 return fg; 01756 }
| 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. |
Check fg and feature specified, add feature to list
Definition at line 1767 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, ast_call_feature::exten, feature_group_exten::feature, feature_group::features, feature_group::gname, LOG_NOTICE, S_OR, and ast_call_feature::sname.
Referenced by load_config().
01768 { 01769 struct feature_group_exten *fge; 01770 01771 if (!fg) { 01772 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 01773 return; 01774 } 01775 01776 if (!feature) { 01777 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 01778 return; 01779 } 01780 01781 if (!(fge = ast_calloc(1, sizeof(*fge)))) 01782 return; 01783 01784 if (ast_string_field_init(fge, 128)) { 01785 ast_free(fge); 01786 return; 01787 } 01788 01789 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 01790 01791 fge->feature = feature; 01792 01793 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 01794 01795 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 01796 feature->sname, fg->gname, exten); 01797 }
| static int remap_feature | ( | const char * | name, | |
| const char * | value | |||
| ) | [static] |
Definition at line 1970 of file features.c.
References ast_copy_string(), ast_rwlock_unlock(), ast_rwlock_wrlock(), FEATURES_COUNT, and features_lock.
Referenced by load_config().
01971 { 01972 int x, res = -1; 01973 01974 ast_rwlock_wrlock(&features_lock); 01975 for (x = 0; x < FEATURES_COUNT; x++) { 01976 if (strcasecmp(builtin_features[x].sname, name)) 01977 continue; 01978 01979 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01980 res = 0; 01981 break; 01982 } 01983 ast_rwlock_unlock(&features_lock); 01984 01985 return res; 01986 }
| static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
| const char * | features | |||
| ) | [static] |
Definition at line 2342 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(), ast_bridge_config::features_caller, and LOG_WARNING.
Referenced by ast_bridge_call().
02343 { 02344 const char *feature; 02345 02346 if (ast_strlen_zero(features)) { 02347 return; 02348 } 02349 02350 for (feature = features; *feature; feature++) { 02351 switch (*feature) { 02352 case 'T' : 02353 case 't' : 02354 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 02355 break; 02356 case 'K' : 02357 case 'k' : 02358 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 02359 break; 02360 case 'H' : 02361 case 'h' : 02362 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 02363 break; 02364 case 'W' : 02365 case 'w' : 02366 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 02367 break; 02368 default : 02369 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 02370 } 02371 } 02372 }
| 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 351 of file features.c.
References ast_copy_string(), ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by builtin_blindtransfer(), manage_parkinglot(), and masq_park_call().
00352 { 00353 ast_copy_string(chan->context, context, sizeof(chan->context)); 00354 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00355 chan->priority = pri; 00356 }
| static void set_config_flags | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config | |||
| ) | [static] |
Definition at line 2099 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_test_flag, ast_call_feature::feature_mask, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, features_lock, find_dynamic_feature(), and pbx_builtin_getvar_helper().
Referenced by ast_bridge_call().
02100 { 02101 int x; 02102 02103 ast_clear_flag(config, AST_FLAGS_ALL); 02104 02105 ast_rwlock_rdlock(&features_lock); 02106 for (x = 0; x < FEATURES_COUNT; x++) { 02107 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 02108 continue; 02109 02110 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 02111 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 02112 02113 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 02114 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 02115 } 02116 ast_rwlock_unlock(&features_lock); 02117 02118 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 02119 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 02120 02121 if (dynamic_features) { 02122 char *tmp = ast_strdupa(dynamic_features); 02123 char *tok; 02124 struct ast_call_feature *feature; 02125 02126 /* while we have a feature */ 02127 while ((tok = strsep(&tmp, "#"))) { 02128 AST_RWLIST_RDLOCK(&feature_list); 02129 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 02130 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 02131 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 02132 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 02133 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 02134 } 02135 AST_RWLIST_UNLOCK(&feature_list); 02136 } 02137 } 02138 } 02139 }
| 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 918 of file features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automixmonitor(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
00920 { 00921 if (sense == FEATURE_SENSE_PEER) { 00922 *caller = peer; 00923 *callee = chan; 00924 } else { 00925 *callee = peer; 00926 *caller = chan; 00927 } 00928 }
| static void unmap_features | ( | void | ) | [static] |
Definition at line 1960 of file features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), FEATURES_COUNT, and features_lock.
Referenced by load_config().
01961 { 01962 int x; 01963 01964 ast_rwlock_wrlock(&features_lock); 01965 for (x = 0; x < FEATURES_COUNT; x++) 01966 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01967 ast_rwlock_unlock(&features_lock); 01968 }
int adsipark [static] |
Definition at line 248 of file features.c.
Referenced by load_config(), and park_call_full().
char* app_bridge = "Bridge" [static] |
Definition at line 4505 of file features.c.
unsigned int atxfercallbackretries [static] |
Definition at line 257 of file features.c.
Referenced by builtin_atxfer(), and load_config().
unsigned int atxferdropcall [static] |
Definition at line 255 of file features.c.
Referenced by builtin_atxfer(), and load_config().
unsigned int atxferloopdelay [static] |
Definition at line 256 of file features.c.
Referenced by builtin_atxfer(), and load_config().
int atxfernoanswertimeout [static] |
Definition at line 254 of file features.c.
Referenced by builtin_atxfer(), and load_config().
struct ast_app_option bridge_exec_options[128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE } } [static] |
Definition at line 4513 of file features.c.
Referenced by bridge_exec().
struct ast_call_feature builtin_features[] [static] |
Definition at line 1697 of file features.c.
struct ast_cli_entry cli_features[] [static] |
{
AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
}
Definition at line 4326 of file features.c.
int comebacktoorigin = 1 [static] |
Definition at line 252 of file features.c.
Referenced by load_config(), and manage_parkinglot().
char courtesytone[256] [static] |
Courtesy tone
Definition at line 241 of file features.c.
Referenced by builtin_automixmonitor(), builtin_automonitor(), load_config(), and park_exec_full().
| struct ast_parkinglot* default_parkinglot |
Definition at line 238 of file features.c.
Referenced by load_config(), park_exec(), park_exec_full(), and park_space_reserve().
{
.type = "dial-features",
.destroy = dial_features_destroy,
.duplicate = dial_features_duplicate,
}
Definition at line 301 of file features.c.
int featuredigittimeout [static] |
Definition at line 251 of file features.c.
Referenced by ast_bridge_call(), and load_config().
ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static] |
Definition at line 1695 of file features.c.
Referenced by ast_rdlock_call_features(), ast_unlock_call_features(), feature_interpret(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
char mandescr_bridge[] [static] |
Definition at line 4110 of file features.c.
char mandescr_park[] [static] |
Definition at line 4386 of file features.c.
struct ast_app* mixmonitor_app = NULL [static] |
Definition at line 267 of file features.c.
Referenced by builtin_automixmonitor().
int mixmonitor_ok = 1 [static] |
Definition at line 268 of file features.c.
Referenced by builtin_automixmonitor().
struct ast_app* monitor_app = NULL [static] |
Definition at line 264 of file features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 265 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] |
Definition at line 3246 of file features.c.
Referenced by park_call_exec().
char* parkcall = PARK_APP_NAME [static] |
Definition at line 262 of file features.c.
Referenced by ast_features_init(), build_parkinglot(), and load_config().
char* parkedcall = "ParkedCall" [static] |
Definition at line 192 of file features.c.
Referenced by ast_features_init(), and park_call_full().
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 242 of file features.c.
Referenced by load_config(), and park_exec_full().
| char parking_ext[AST_MAX_EXTENSION] |
Extension you type to park the call
Definition at line 239 of file features.c.
Referenced by ast_parking_ext(), handle_feature_show(), and load_config().
pthread_t parking_thread [static] |
Definition at line 273 of file features.c.
Referenced by ast_features_init(), and 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 236 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 194 of file features.c.
Referenced by ast_pickup_ext(), and load_config().
char pickupfailsound[256] [static] |
Pickup failure sound
Definition at line 246 of file features.c.
Referenced by ast_pickup_call(), and load_config().
char pickupsound[256] [static] |
Pickup sound
Definition at line 245 of file features.c.
Referenced by ast_pickup_call(), and load_config().
char* registrar = "features" [static] |
Registrar for operations
Definition at line 259 of file features.c.
Referenced by build_parkinglot(), load_config(), manage_parkinglot(), park_add_hints(), park_call_full(), and parkinglot_destroy().
struct ast_app* stopmixmonitor_app = NULL [static] |
Definition at line 270 of file features.c.
Referenced by builtin_automixmonitor().
int stopmixmonitor_ok = 1 [static] |
Definition at line 271 of file features.c.
Referenced by builtin_automixmonitor().
int transferdigittimeout [static] |
Definition at line 250 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 244 of file features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), and load_config().
char xfersound[256] [static] |
Call transfer sound
Definition at line 243 of file features.c.
Referenced by action_bridge(), bridge_exec(), builtin_atxfer(), load_config(), and local_attended_transfer().
1.6.2