#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"
#include "asterisk/astobj2.h"

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