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