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