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