#include "asterisk.h"
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.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/global_datastores.h"
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | ast_dial_features |
struct | feature_list |
struct | parkeduser |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
#define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURE_RETURN_HANGUP -1 |
#define | FEATURE_RETURN_KEEPTRYING 24 |
#define | FEATURE_RETURN_PARKFAILED 25 |
#define | FEATURE_RETURN_PASSDIGITS 21 |
#define | FEATURE_RETURN_STOREDIGITS 22 |
#define | FEATURE_RETURN_SUCCESS 23 |
#define | FEATURE_RETURN_SUCCESSBREAK 0 |
#define | FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
#define | MAX_DIAL_FEATURE_OPTIONS 30 |
Enumerations | |
enum | { AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3), AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3) } |
enum | feature_interpret_op { FEATURE_INTERPRET_DETECT, FEATURE_INTERPRET_DO, FEATURE_INTERPRET_CHECK } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
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) |
int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
Bridge a call, optionally allowing redirection. | |
static void * | ast_bridge_call_thread (void *data) |
static void | ast_bridge_call_thread_launch (void *data) |
int | ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature) |
detect a feature before bridging | |
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 and read back parked location. | |
char * | ast_parking_ext (void) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
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 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_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
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) |
static void | check_goto_on_transfer (struct ast_channel *chan) |
static void | clear_dialed_interfaces (struct ast_channel *chan) |
static void | dial_features_destroy (void *data) |
static void * | dial_features_duplicate (void *data) |
static void * | do_parking_thread (void *ignore) |
Take care of parked calls and unpark them if needed. | |
static int | feature_check (struct ast_channel *chan, struct ast_flags *features, char *code) |
Check if a feature exists. | |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
exec an app by feature | |
static int | feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
Check the dynamic features. | |
static 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, feature_interpret_op operation, struct ast_call_feature *feature) |
Helper function for feature_interpret and ast_feature_detect. | |
static struct ast_channel * | feature_request_and_dial (struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language) |
static struct ast_call_feature * | find_dynamic_feature (const char *name) |
find a feature by name | |
static int | finishup (struct ast_channel *chan) |
static int | handle_parkedcalls (int fd, int argc, char *argv[]) |
static int | handle_showfeatures (int fd, int argc, char *argv[]) |
static int | load_config (void) |
static int | load_module (void) |
static int | manager_park (struct mansession *s, const struct message *m) |
static int | manager_parking_status (struct mansession *s, const struct message *m) |
Dump lot status. | |
static int | masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, const char *orig_chan_name) |
static int | masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name) |
static int | metermaidstate (const char *data) |
metermaids callback from devicestate.c | |
static void | notify_metermaids (char *exten, char *context) |
Notify metermaids that we've changed an extension. | |
static void | park_add_hints (char *context, int start, int stop) |
Add parking hints for all defined parking lots. | |
static int | park_call_exec (struct ast_channel *chan, void *data) |
Park a call. | |
static int | park_call_full (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name, struct parkeduser *pu) |
static int | park_exec (struct ast_channel *chan, void *data) |
Pickup parked call. | |
static struct parkeduser * | park_space_reserve (struct ast_channel *chan) |
static struct ast_cdr * | pick_unlocked_cdr (struct ast_cdr *cdr) |
static int | pickup_do (struct ast_channel *chan, struct ast_channel *target) |
static void | post_manager_event (const char *s, char *parkingexten, struct ast_channel *chan) |
static const char * | real_ctx (struct ast_channel *transferer, struct ast_channel *transferee) |
Find the context for the transfer. | |
static int | reload (void) |
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, priority and extension | |
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 int | unload_module (void) |
static void | unmap_features (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Call Features Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
static int | adsipark |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static int | atxfernoanswertimeout |
static struct ast_call_feature | builtin_features [] |
static struct ast_cli_entry | cli_features [] |
static struct ast_cli_entry | cli_show_features_deprecated |
static char | courtesytone [256] |
static char * | descrip |
static char * | descrip2 |
ast_datastore_info | dial_features_info |
static int | featuredigittimeout |
static ast_rwlock_t | features_lock = PTHREAD_RWLOCK_INITIALIZER |
static char | mandescr_park [] |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static int | parkaddhints = 0 |
static char * | parkcall = PARK_APP_NAME |
static char * | parkedcall = "ParkedCall" |
static int | parkedcallhangup |
static int | parkedcallrecording |
static int | parkedcallreparking |
static int | parkedcalltransfers |
static int | parkedplay = 0 |
static int | parkfindnext |
static char | parking_con [AST_MAX_EXTENSION] |
static char | parking_con_dial [AST_MAX_EXTENSION] |
static char | parking_ext [AST_MAX_EXTENSION] |
static ast_mutex_t | parking_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
static int | parking_offset |
static int | parking_start |
static int | parking_stop |
static pthread_t | parking_thread |
static struct parkeduser * | parkinglot |
static char | parkingretalertinfo [256] |
static char | parkingretcidname [256] |
static char | parkingretdahdiring [3] |
static int | parkingtime = DEFAULT_PARK_TIME |
static char | parkmohclass [MAX_MUSICCLASS] |
static char | pickup_ext [AST_MAX_EXTENSION] |
static char * | registrar = "res_features" |
static char | showfeatures_help [] |
static char | showparked_help [] |
static char * | synopsis = "Answer a parked call" |
static char * | synopsis2 = "Park yourself" |
static int | transferdigittimeout |
static char | xferfailsound [256] |
static char | xfersound [256] |
Definition in file res_features.c.
#define AST_MAX_WATCHERS 256 |
Definition at line 122 of file res_features.c.
#define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define DEFAULT_PARK_TIME 45000 |
Definition at line 117 of file res_features.c.
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURE_RETURN_HANGUP -1 |
Definition at line 125 of file res_features.c.
#define FEATURE_RETURN_KEEPTRYING 24 |
Definition at line 130 of file res_features.c.
#define FEATURE_RETURN_PARKFAILED 25 |
Definition at line 131 of file res_features.c.
#define FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 127 of file res_features.c.
#define FEATURE_RETURN_STOREDIGITS 22 |
Definition at line 128 of file res_features.c.
#define FEATURE_RETURN_SUCCESS 23 |
Definition at line 129 of file res_features.c.
#define FEATURE_RETURN_SUCCESSBREAK 0 |
Definition at line 126 of file res_features.c.
#define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Definition at line 1374 of file res_features.c.
Referenced by feature_interpret_helper(), feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().
#define MAX_DIAL_FEATURE_OPTIONS 30 |
anonymous enum |
AST_FEATURE_FLAG_NEEDSDTMF | |
AST_FEATURE_FLAG_ONPEER | |
AST_FEATURE_FLAG_ONSELF | |
AST_FEATURE_FLAG_BYCALLEE | |
AST_FEATURE_FLAG_BYCALLER | |
AST_FEATURE_FLAG_BYBOTH |
Definition at line 133 of file res_features.c.
00133 { 00134 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00135 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00136 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00137 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00138 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00139 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00140 };
enum feature_interpret_op |
Definition at line 142 of file res_features.c.
00142 { 00143 FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */ 00144 FEATURE_INTERPRET_DO, /* Used by feature_interpret */ 00145 FEATURE_INTERPRET_CHECK, /* Used by feature_check */ 00146 } feature_interpret_op;
static void __reg_module | ( | void | ) | [static] |
Definition at line 3802 of file res_features.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 3802 of file res_features.c.
static void add_features_datastores | ( | struct ast_channel * | caller, | |
struct ast_channel * | callee, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 2057 of file res_features.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, AST_FLAGS_ALL, ast_log(), config, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, and LOG_WARNING.
Referenced by ast_bridge_call().
02058 { 02059 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 02060 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 02061 02062 ast_channel_lock(caller); 02063 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 02064 ast_channel_unlock(caller); 02065 if (!ds_caller_features) { 02066 if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 02067 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 02068 return; 02069 } 02070 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 02071 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02072 ast_channel_datastore_free(ds_caller_features); 02073 return; 02074 } 02075 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 02076 caller_features->is_caller = 1; 02077 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 02078 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 02079 ds_caller_features->data = caller_features; 02080 ast_channel_lock(caller); 02081 ast_channel_datastore_add(caller, ds_caller_features); 02082 ast_channel_unlock(caller); 02083 } else { 02084 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 02085 * flags over from the atxfer to the caller */ 02086 return; 02087 } 02088 02089 ast_channel_lock(callee); 02090 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 02091 ast_channel_unlock(callee); 02092 if (!ds_callee_features) { 02093 if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 02094 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 02095 return; 02096 } 02097 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 02098 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02099 ast_channel_datastore_free(ds_callee_features); 02100 return; 02101 } 02102 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 02103 callee_features->is_caller = 0; 02104 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 02105 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 02106 ds_callee_features->data = callee_features; 02107 ast_channel_lock(callee); 02108 ast_channel_datastore_add(callee, ds_callee_features); 02109 ast_channel_unlock(callee); 02110 } 02111 02112 return; 02113 }
static int adsi_announce_park | ( | struct ast_channel * | chan, | |
char * | parkingexten | |||
) | [static] |
Definition at line 477 of file res_features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
00478 { 00479 int res; 00480 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00481 char tmp[256]; 00482 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00483 00484 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00485 message[0] = tmp; 00486 res = ast_adsi_load_session(chan, NULL, 0, 1); 00487 if (res == -1) 00488 return res; 00489 return ast_adsi_print(chan, message, justify, 1); 00490 }
int ast_bridge_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) |
Bridge a call, optionally allowing redirection.
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 2131 of file res_features.c.
References ast_channel::_state, ast_cdr::accountcode, ast_channel::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, ast_answer(), 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_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NOANSWER, ast_cdr_setaccount(), ast_cdr_setanswer(), ast_cdr_setcid(), ast_cdr_setdisposition(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), 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_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, 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_opt_transmit_silence, AST_OPTION_AUDIO_MODE, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, 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_verbose(), ast_write(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, clear_dialed_interfaces(), config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, ast_option_header::option, option_debug, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, VERBOSE_PREFIX_2, and ast_channel::visible_indication.
Referenced by app_exec(), ast_bridge_call_thread(), builtin_atxfer(), and park_exec().
02132 { 02133 /* Copy voice back and forth between the two channels. Give the peer 02134 the ability to transfer calls with '#<extension' syntax. */ 02135 struct ast_frame *f; 02136 struct ast_channel *who; 02137 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02138 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02139 char orig_channame[AST_MAX_EXTENSION]; 02140 char orig_peername[AST_MAX_EXTENSION]; 02141 02142 int res; 02143 int diff; 02144 int hasfeatures=0; 02145 int hadfeatures=0; 02146 int autoloopflag; 02147 int sendingdtmfdigit = 0; 02148 struct ast_option_header *aoh; 02149 struct ast_bridge_config backup_config; 02150 struct ast_cdr *bridge_cdr = NULL; 02151 struct ast_cdr *orig_peer_cdr = NULL; 02152 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 02153 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 02154 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02155 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02156 struct ast_silence_generator *silgen = NULL; 02157 02158 memset(&backup_config, 0, sizeof(backup_config)); 02159 02160 config->start_time = ast_tvnow(); 02161 02162 if (chan && peer) { 02163 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02164 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02165 } else if (chan) { 02166 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02167 } 02168 02169 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02170 add_features_datastores(chan, peer, config); 02171 02172 /* This is an interesting case. One example is if a ringing channel gets redirected to 02173 * an extension that picks up a parked call. This will make sure that the call taken 02174 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02175 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02176 ast_indicate(peer, AST_CONTROL_RINGING); 02177 } 02178 02179 if (monitor_ok) { 02180 const char *monitor_exec; 02181 struct ast_channel *src = NULL; 02182 if (!monitor_app) { 02183 if (!(monitor_app = pbx_findapp("Monitor"))) 02184 monitor_ok=0; 02185 } 02186 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02187 src = chan; 02188 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02189 src = peer; 02190 if (monitor_app && src) { 02191 char *tmp = ast_strdupa(monitor_exec); 02192 pbx_exec(src, monitor_app, tmp); 02193 } 02194 } 02195 02196 set_config_flags(chan, peer, config); 02197 config->firstpass = 1; 02198 02199 /* Answer if need be */ 02200 if (ast_answer(chan)) 02201 return -1; 02202 02203 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02204 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02205 orig_peer_cdr = peer_cdr; 02206 02207 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02208 02209 if (chan_cdr) { 02210 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02211 ast_cdr_update(chan); 02212 bridge_cdr = ast_cdr_dup(chan_cdr); 02213 /* rip any forked CDR's off of the chan_cdr and attach 02214 * them to the bridge_cdr instead */ 02215 bridge_cdr->next = chan_cdr->next; 02216 chan_cdr->next = NULL; 02217 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02218 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02219 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 02220 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02221 } 02222 ast_cdr_setaccount(peer, chan->accountcode); 02223 } else { 02224 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02225 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02226 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02227 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02228 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02229 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02230 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02231 ast_cdr_setcid(bridge_cdr, chan); 02232 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NOANSWER; 02233 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02234 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02235 /* Destination information */ 02236 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02237 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02238 if (peer_cdr) { 02239 bridge_cdr->start = peer_cdr->start; 02240 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02241 } else { 02242 ast_cdr_start(bridge_cdr); 02243 } 02244 } 02245 /* peer_cdr->answer will be set when a macro runs on the peer; 02246 in that case, the bridge answer will be delayed while the 02247 macro plays on the peer channel. The peer answered the call 02248 before the macro started playing. To the phone system, 02249 this is billable time for the call, even tho the caller 02250 hears nothing but ringing while the macro does its thing. */ 02251 02252 /* Another case where the peer cdr's time will be set, is when 02253 A self-parks by pickup up phone and dialing 700, then B 02254 picks up A by dialing its parking slot; there may be more 02255 practical paths that get the same result, tho... in which 02256 case you get the previous answer time from the Park... which 02257 is before the bridge's start time, so I added in the 02258 tvcmp check to the if below */ 02259 02260 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 02261 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 02262 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 02263 if (chan_cdr) { 02264 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 02265 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 02266 } 02267 } else { 02268 ast_cdr_answer(bridge_cdr); 02269 if (chan_cdr) { 02270 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02271 } 02272 } 02273 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 02274 if (chan_cdr) { 02275 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02276 } 02277 if (peer_cdr) { 02278 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02279 } 02280 } 02281 /* the DIALED flag may be set if a dialed channel is transfered 02282 * and then bridged to another channel. In order for the 02283 * bridge CDR to be written, the DIALED flag must not be 02284 * present. */ 02285 ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); 02286 } 02287 02288 /* If we are bridging a call, stop worrying about forwarding loops. We presume that if 02289 * a call is being bridged, that the humans in charge know what they're doing. If they 02290 * don't, well, what can we do about that? */ 02291 clear_dialed_interfaces(chan); 02292 clear_dialed_interfaces(peer); 02293 02294 for (;;) { 02295 struct ast_channel *other; /* used later */ 02296 02297 res = ast_channel_bridge(chan, peer, config, &f, &who); 02298 02299 /* When frame is not set, we are probably involved in a situation 02300 where we've timed out. 02301 When frame is set, we'll come thru this code twice; once for DTMF_BEGIN 02302 and also for DTMF_END. If we flow into the following 'if' for both, then 02303 our wait times are cut in half, as both will subtract from the 02304 feature_timer. Not good! 02305 */ 02306 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02307 /* Update time limit for next pass */ 02308 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 02309 if (res == AST_BRIDGE_RETRY) { 02310 /* The feature fully timed out but has not been updated. Skip 02311 * the potential round error from the diff calculation and 02312 * explicitly set to expired. */ 02313 config->feature_timer = -1; 02314 } else { 02315 config->feature_timer -= diff; 02316 } 02317 02318 if (hasfeatures) { 02319 /* Running on backup config, meaning a feature might be being 02320 activated, but that's no excuse to keep things going 02321 indefinitely! */ 02322 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 02323 if (option_debug) 02324 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 02325 config->feature_timer = 0; 02326 who = chan; 02327 if (f) 02328 ast_frfree(f); 02329 f = NULL; 02330 res = 0; 02331 } else if (config->feature_timer <= 0) { 02332 /* Not *really* out of time, just out of time for 02333 digits to come in for features. */ 02334 if (option_debug) 02335 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 02336 if (!ast_strlen_zero(peer_featurecode)) { 02337 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 02338 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02339 } 02340 if (!ast_strlen_zero(chan_featurecode)) { 02341 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 02342 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02343 } 02344 if (f) 02345 ast_frfree(f); 02346 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02347 if (!hasfeatures) { 02348 /* Restore original (possibly time modified) bridge config */ 02349 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02350 memset(&backup_config, 0, sizeof(backup_config)); 02351 } 02352 hadfeatures = hasfeatures; 02353 /* Continue as we were */ 02354 continue; 02355 } else if (!f) { 02356 /* The bridge returned without a frame and there is a feature in progress. 02357 * However, we don't think the feature has quite yet timed out, so just 02358 * go back into the bridge. */ 02359 continue; 02360 } 02361 } else { 02362 if (config->feature_timer <=0) { 02363 /* We ran out of time */ 02364 config->feature_timer = 0; 02365 who = chan; 02366 if (f) 02367 ast_frfree(f); 02368 f = NULL; 02369 res = 0; 02370 } 02371 } 02372 } 02373 if (res < 0) { 02374 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 02375 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02376 goto before_you_go; 02377 } 02378 02379 if (!f || (f->frametype == AST_FRAME_CONTROL && 02380 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02381 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 02382 res = -1; 02383 break; 02384 } 02385 /* many things should be sent to the 'other' channel */ 02386 other = (who == chan) ? peer : chan; 02387 if (f->frametype == AST_FRAME_CONTROL) { 02388 switch (f->subclass) { 02389 case AST_CONTROL_RINGING: 02390 case AST_CONTROL_FLASH: 02391 case -1: 02392 ast_indicate(other, f->subclass); 02393 break; 02394 case AST_CONTROL_HOLD: 02395 case AST_CONTROL_UNHOLD: 02396 ast_indicate_data(other, f->subclass, f->data, f->datalen); 02397 break; 02398 case AST_CONTROL_OPTION: 02399 aoh = f->data; 02400 /* Forward option Requests, but only ones we know are safe 02401 * These are ONLY sent by chan_iax2 and I'm not convinced that 02402 * they are useful. I haven't deleted them entirely because I 02403 * just am not sure of the ramifications of removing them. */ 02404 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02405 switch (ntohs(aoh->option)) { 02406 case AST_OPTION_TONE_VERIFY: 02407 case AST_OPTION_TDD: 02408 case AST_OPTION_RELAXDTMF: 02409 case AST_OPTION_AUDIO_MODE: 02410 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02411 f->datalen - sizeof(struct ast_option_header), 0); 02412 } 02413 } 02414 break; 02415 } 02416 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02417 struct ast_flags *cfg; 02418 char dtmfcode[2] = { f->subclass, }; 02419 size_t featurelen; 02420 02421 if (who == chan) { 02422 featurelen = strlen(chan_featurecode); 02423 cfg = &(config->features_caller); 02424 } else { 02425 featurelen = strlen(peer_featurecode); 02426 cfg = &(config->features_callee); 02427 } 02428 /* Take a peek if this (possibly) matches a feature. If not, just pass this 02429 * DTMF along untouched. If this is not the first digit of a multi-digit code 02430 * then we need to fall through and stream the characters if it matches */ 02431 if (featurelen == 0 02432 && feature_check(chan, cfg, &dtmfcode[0]) == FEATURE_RETURN_PASSDIGITS) { 02433 if (option_debug > 3) { 02434 ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n"); 02435 } 02436 ast_write(other, f); 02437 sendingdtmfdigit = 1; 02438 } else { 02439 /* If ast_opt_transmit_silence is set, then we need to make sure we are 02440 * transmitting something while we hold on to the DTMF waiting for a 02441 * feature. */ 02442 if (!silgen && ast_opt_transmit_silence) { 02443 silgen = ast_channel_start_silence_generator(other); 02444 } 02445 if (option_debug > 3) { 02446 ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n"); 02447 } 02448 } 02449 } else if (f->frametype == AST_FRAME_DTMF) { 02450 char *featurecode; 02451 int sense; 02452 02453 hadfeatures = hasfeatures; 02454 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02455 if (who == chan) { 02456 sense = FEATURE_SENSE_CHAN; 02457 featurecode = chan_featurecode; 02458 } else { 02459 sense = FEATURE_SENSE_PEER; 02460 featurecode = peer_featurecode; 02461 } 02462 02463 if (sendingdtmfdigit == 1) { 02464 /* We let the BEGIN go through happily, so let's not bother with the END, 02465 * since we already know it's not something we bother with */ 02466 ast_write(other, f); 02467 sendingdtmfdigit = 0; 02468 } else { 02469 /*! append the event to featurecode. we rely on the string being zero-filled, and 02470 * not overflowing it. 02471 * \todo XXX how do we guarantee the latter ? 02472 */ 02473 featurecode[strlen(featurecode)] = f->subclass; 02474 /* Get rid of the frame before we start doing "stuff" with the channels */ 02475 ast_frfree(f); 02476 f = NULL; 02477 if (silgen) { 02478 ast_channel_stop_silence_generator(other, silgen); 02479 silgen = NULL; 02480 } 02481 config->feature_timer = backup_config.feature_timer; 02482 res = feature_interpret(chan, peer, config, featurecode, sense); 02483 switch(res) { 02484 case FEATURE_RETURN_PASSDIGITS: 02485 ast_dtmf_stream(other, who, featurecode, 0); 02486 /* Fall through */ 02487 case FEATURE_RETURN_SUCCESS: 02488 memset(featurecode, 0, sizeof(chan_featurecode)); 02489 break; 02490 } 02491 if (res >= FEATURE_RETURN_PASSDIGITS) { 02492 res = 0; 02493 } else { 02494 break; 02495 } 02496 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02497 if (hadfeatures && !hasfeatures) { 02498 /* Restore backup */ 02499 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02500 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02501 } else if (hasfeatures) { 02502 if (!hadfeatures) { 02503 /* Backup configuration */ 02504 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02505 /* Setup temporary config options */ 02506 config->play_warning = 0; 02507 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02508 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02509 config->warning_freq = 0; 02510 config->warning_sound = NULL; 02511 config->end_sound = NULL; 02512 config->start_sound = NULL; 02513 config->firstpass = 0; 02514 } 02515 config->start_time = ast_tvnow(); 02516 config->feature_timer = featuredigittimeout; 02517 if (option_debug) { 02518 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 02519 } 02520 } 02521 } 02522 } 02523 if (f) 02524 ast_frfree(f); 02525 02526 } 02527 02528 before_you_go: 02529 /* Just in case something weird happened and we didn't clean up the silence generator... */ 02530 if (silgen) { 02531 ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen); 02532 silgen = NULL; 02533 } 02534 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02535 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02536 if (bridge_cdr) { 02537 ast_cdr_discard(bridge_cdr); 02538 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02539 } 02540 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02541 } 02542 02543 if (config->end_bridge_callback) { 02544 config->end_bridge_callback(config->end_bridge_callback_data); 02545 } 02546 02547 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02548 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02549 struct ast_cdr *swapper = NULL; 02550 char savelastapp[AST_MAX_EXTENSION]; 02551 char savelastdata[AST_MAX_EXTENSION]; 02552 char save_exten[AST_MAX_EXTENSION]; 02553 int save_prio, spawn_error = 0; 02554 02555 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02556 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02557 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02558 ast_cdr_end(bridge_cdr); 02559 } 02560 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02561 dialplan code operate on it */ 02562 ast_channel_lock(chan); 02563 if (bridge_cdr) { 02564 swapper = chan->cdr; 02565 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02566 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02567 chan->cdr = bridge_cdr; 02568 } 02569 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02570 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02571 save_prio = chan->priority; 02572 chan->priority = 1; 02573 ast_channel_unlock(chan); 02574 while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) { 02575 if ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) { 02576 /* Something bad happened, or a hangup has been requested. */ 02577 if (option_debug) 02578 ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02579 if (option_verbose > 1) 02580 ast_verbose( VERBOSE_PREFIX_2 "Spawn h extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02581 break; 02582 } 02583 chan->priority++; 02584 } 02585 /* swap it back */ 02586 ast_channel_lock(chan); 02587 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02588 chan->priority = save_prio; 02589 if (bridge_cdr) { 02590 if (chan->cdr == bridge_cdr) { 02591 chan->cdr = swapper; 02592 } else { 02593 bridge_cdr = NULL; 02594 } 02595 } 02596 if (chan->priority != 1 || !spawn_error) { 02597 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02598 } 02599 ast_channel_unlock(chan); 02600 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02601 if (bridge_cdr) { 02602 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02603 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02604 } 02605 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02606 } 02607 02608 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02609 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02610 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 02611 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02612 } 02613 02614 /* we can post the bridge CDR at this point */ 02615 if (bridge_cdr) { 02616 ast_cdr_end(bridge_cdr); 02617 ast_cdr_detach(bridge_cdr); 02618 } 02619 02620 /* do a specialized reset on the beginning channel 02621 CDR's, if they still exist, so as not to mess up 02622 issues in future bridges; 02623 02624 Here are the rules of the game: 02625 1. The chan and peer channel pointers will not change 02626 during the life of the bridge. 02627 2. But, in transfers, the channel names will change. 02628 between the time the bridge is started, and the 02629 time the channel ends. 02630 Usually, when a channel changes names, it will 02631 also change CDR pointers. 02632 3. Usually, only one of the two channels (chan or peer) 02633 will change names. 02634 4. Usually, if a channel changes names during a bridge, 02635 it is because of a transfer. Usually, in these situations, 02636 it is normal to see 2 bridges running simultaneously, and 02637 it is not unusual to see the two channels that change 02638 swapped between bridges. 02639 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02640 to attend to; if the chan or peer changed names, 02641 we have the before and after attached CDR's. 02642 */ 02643 02644 if (new_chan_cdr) { 02645 struct ast_channel *chan_ptr = NULL; 02646 02647 if (strcasecmp(orig_channame, chan->name) != 0) { 02648 /* old channel */ 02649 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02650 if (chan_ptr) { 02651 if (!ast_bridged_channel(chan_ptr)) { 02652 struct ast_cdr *cur; 02653 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02654 if (cur == chan_cdr) { 02655 break; 02656 } 02657 } 02658 if (cur) 02659 ast_cdr_specialized_reset(chan_cdr,0); 02660 } 02661 ast_channel_unlock(chan_ptr); 02662 } 02663 /* new channel */ 02664 ast_cdr_specialized_reset(new_chan_cdr,0); 02665 } else { 02666 ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr */ 02667 } 02668 } 02669 02670 { 02671 struct ast_channel *chan_ptr = NULL; 02672 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02673 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)) 02674 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02675 if (strcasecmp(orig_peername, peer->name) != 0) { 02676 /* old channel */ 02677 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02678 if (chan_ptr) { 02679 if (!ast_bridged_channel(chan_ptr)) { 02680 struct ast_cdr *cur; 02681 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02682 if (cur == peer_cdr) { 02683 break; 02684 } 02685 } 02686 if (cur) 02687 ast_cdr_specialized_reset(peer_cdr,0); 02688 } 02689 ast_channel_unlock(chan_ptr); 02690 } 02691 /* new channel */ 02692 if (new_peer_cdr) { 02693 ast_cdr_specialized_reset(new_peer_cdr, 0); 02694 } 02695 } else { 02696 ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr */ 02697 } 02698 } 02699 02700 return res; 02701 }
static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
Definition at line 446 of file res_features.c.
References ast_channel::appl, ast_bridge_call(), ast_hangup(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, free, ast_channel::name, and ast_bridge_thread_obj::peer.
Referenced by ast_bridge_call_thread_launch().
00447 { 00448 struct ast_bridge_thread_obj *tobj = data; 00449 00450 tobj->chan->appl = "Transferred Call"; 00451 tobj->chan->data = tobj->peer->name; 00452 tobj->peer->appl = "Transferred Call"; 00453 tobj->peer->data = tobj->chan->name; 00454 00455 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00456 ast_hangup(tobj->chan); 00457 ast_hangup(tobj->peer); 00458 bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */ 00459 free(tobj); 00460 return NULL; 00461 }
static void ast_bridge_call_thread_launch | ( | void * | data | ) | [static] |
Definition at line 463 of file res_features.c.
References ast_bridge_call_thread(), ast_pthread_create, and thread.
Referenced by builtin_atxfer().
00464 { 00465 pthread_t thread; 00466 pthread_attr_t attr; 00467 struct sched_param sched; 00468 00469 pthread_attr_init(&attr); 00470 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00471 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00472 pthread_attr_destroy(&attr); 00473 memset(&sched, 0, sizeof(sched)); 00474 pthread_setschedparam(thread, SCHED_RR, &sched); 00475 }
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 1665 of file res_features.c.
References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().
Referenced by detect_disconnect().
01665 { 01666 01667 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature); 01668 }
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 Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want |
Definition at line 792 of file res_features.c.
References masq_park_call().
Referenced by handle_exec(), manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().
00793 { 00794 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00795 }
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call and read back parked location.
Definition at line 731 of file res_features.c.
References park_call_full().
Referenced by iax_park_thread(), and sip_park_thread().
00732 { 00733 return park_call_full(chan, peer, timeout, extout, NULL, NULL); 00734 }
char* ast_parking_ext | ( | void | ) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
Definition at line 380 of file res_features.c.
Referenced by builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00381 { 00382 return parking_ext; 00383 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 3449 of file res_features.c.
References ast_channel::_state, ast_channel_unlock, ast_channel_walk_locked(), AST_FLAG_ZOMBIE, ast_log(), AST_STATE_RING, AST_STATE_RINGING, ast_test_flag, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, ast_channel::masq, ast_channel::name, option_debug, ast_channel::pbx, pickup_do(), and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), and ss_thread().
03450 { 03451 struct ast_channel *cur = NULL; 03452 int res = -1; 03453 03454 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 03455 if (!cur->pbx && 03456 (cur != chan) && 03457 (chan->pickupgroup & cur->callgroup) && 03458 ((cur->_state == AST_STATE_RINGING) || 03459 (cur->_state == AST_STATE_RING)) && 03460 !cur->masq && 03461 !ast_test_flag(cur, AST_FLAG_ZOMBIE)) { 03462 break; 03463 } 03464 ast_channel_unlock(cur); 03465 } 03466 if (cur) { 03467 res = pickup_do(chan, cur); 03468 if (res) { 03469 ast_log(LOG_WARNING, "pickup %s failed by %s\n", cur->name, chan->name); 03470 } 03471 ast_channel_unlock(cur); 03472 } else { 03473 if (option_debug) 03474 ast_log(LOG_DEBUG, "No call pickup possible... for %s\n", chan->name); 03475 } 03476 return res; 03477 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 385 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00386 { 00387 return pickup_ext; 00388 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_set
feature | an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call. |
Definition at line 1391 of file res_features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verbose(), ast_call_feature::feature_entry, LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.
01392 { 01393 if (!feature) { 01394 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01395 return; 01396 } 01397 01398 AST_RWLIST_WRLOCK(&feature_list); 01399 AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry); 01400 AST_RWLIST_UNLOCK(&feature_list); 01401 01402 if (option_verbose >= 2) { 01403 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 01404 } 01405 }
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 1408 of file res_features.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.
01409 { 01410 if (!feature) 01411 return; 01412 01413 AST_RWLIST_WRLOCK(&feature_list); 01414 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01415 AST_RWLIST_UNLOCK(&feature_list); 01416 01417 free(feature); 01418 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1421 of file res_features.c.
References AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.
01422 { 01423 struct ast_call_feature *feature; 01424 01425 AST_RWLIST_WRLOCK(&feature_list); 01426 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) { 01427 free(feature); 01428 } 01429 AST_RWLIST_UNLOCK(&feature_list); 01430 }
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 1107 of file res_features.c.
References 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_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_flags, AST_DIGIT_ANY, ast_do_masquerade(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAGS_ALL, ast_hangup(), ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_test_flag, ast_waitfordigit(), builtin_parkcall(), check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_datastore::data, dial_features_info, ast_channel::exten, feature_request_and_dial(), FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), ast_channel::language, LOG_DEBUG, LOG_WARNING, ast_channel::masq, ast_channel::name, ast_channel::nativeformats, option_debug, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_channel::visible_indication, and ast_channel::writeformat.
01108 { 01109 struct ast_channel *transferer;/* Party B */ 01110 struct ast_channel *transferee;/* Party A */ 01111 const char *transferer_real_context; 01112 char xferto[256] = ""; 01113 int res; 01114 int outstate=0; 01115 struct ast_channel *newchan; 01116 struct ast_channel *xferchan; 01117 struct ast_bridge_thread_obj *tobj; 01118 struct ast_bridge_config bconfig; 01119 int l; 01120 struct ast_datastore *features_datastore; 01121 struct ast_dial_features *dialfeatures = NULL; 01122 01123 if (option_debug) 01124 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 01125 set_peers(&transferer, &transferee, peer, chan, sense); 01126 transferer_real_context = real_ctx(transferer, transferee); 01127 01128 /* Start autoservice on transferee while we talk to the transferer */ 01129 ast_autoservice_start(transferee); 01130 ast_indicate(transferee, AST_CONTROL_HOLD); 01131 01132 /* Transfer */ 01133 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 01134 if (res < 0) { 01135 finishup(transferee); 01136 return -1; 01137 } 01138 if (res > 0) /* If they've typed a digit already, handle it */ 01139 xferto[0] = (char) res; 01140 01141 /* this is specific of atxfer */ 01142 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01143 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 01144 finishup(transferee); 01145 return -1; 01146 } 01147 l = strlen(xferto); 01148 if (res == 0) { 01149 if (l) { 01150 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 01151 xferto, transferer_real_context); 01152 } else { 01153 /* Does anyone care about this case? */ 01154 ast_log(LOG_WARNING, "No digits dialed for atxfer.\n"); 01155 } 01156 ast_stream_and_wait(transferer, "pbx-invalid", transferer->language, ""); 01157 finishup(transferee); 01158 return FEATURE_RETURN_SUCCESS; 01159 } 01160 01161 /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of 01162 * the different variables for handling this properly with a builtin_atxfer */ 01163 if (!strcmp(xferto, ast_parking_ext())) { 01164 finishup(transferee); 01165 return builtin_parkcall(chan, peer, config, code, sense, data); 01166 } 01167 01168 /* Append context to dialed transfer number. */ 01169 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); 01170 01171 /* Stop autoservice so we can monitor all parties involved in the transfer. */ 01172 if (ast_autoservice_stop(transferee) < 0) { 01173 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01174 return -1; 01175 } 01176 01177 /* Dial party C */ 01178 newchan = feature_request_and_dial(transferer, transferee, "Local", 01179 ast_best_codec(transferer->nativeformats), xferto, atxfernoanswertimeout, 01180 &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 01181 transferer->language); 01182 if (option_debug) { 01183 ast_log(LOG_DEBUG, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate); 01184 } 01185 01186 if (!ast_check_hangup(transferer)) { 01187 int hangup_dont = 0; 01188 01189 /* Transferer (party B) is up */ 01190 if (option_debug) { 01191 ast_log(LOG_DEBUG, "Actually doing an attended transfer.\n"); 01192 } 01193 01194 /* Start autoservice on transferee while the transferer deals with party C. */ 01195 ast_autoservice_start(transferee); 01196 01197 ast_indicate(transferer, -1); 01198 if (!newchan) { 01199 /* any reason besides user requested cancel and busy triggers the failed sound */ 01200 switch (outstate) { 01201 case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */ 01202 case AST_CONTROL_BUSY: 01203 case AST_CONTROL_CONGESTION: 01204 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) { 01205 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01206 } 01207 break; 01208 default: 01209 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) { 01210 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 01211 } 01212 break; 01213 } 01214 finishup(transferee); 01215 return FEATURE_RETURN_SUCCESS; 01216 } 01217 01218 if (check_compat(transferer, newchan)) { 01219 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) { 01220 ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); 01221 } 01222 /* we do mean transferee here, NOT transferer */ 01223 finishup(transferee); 01224 return FEATURE_RETURN_SUCCESS; 01225 } 01226 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 01227 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 01228 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 01229 01230 /* ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we don't 01231 want that to happen here because we're also in another bridge already 01232 */ 01233 if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) { 01234 hangup_dont = 1; 01235 } 01236 /* Let party B and party C talk as long as they want. */ 01237 ast_bridge_call(transferer, newchan, &bconfig); 01238 if (hangup_dont) { 01239 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); 01240 } 01241 01242 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 01243 ast_hangup(newchan); 01244 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) { 01245 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01246 } 01247 finishup(transferee); 01248 return FEATURE_RETURN_SUCCESS; 01249 } 01250 01251 /* Transferer (party B) is confirmed hung up at this point. */ 01252 if (check_compat(transferee, newchan)) { 01253 finishup(transferee); 01254 return -1; 01255 } 01256 01257 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01258 if ((ast_autoservice_stop(transferee) < 0) 01259 || (ast_waitfordigit(transferee, 100) < 0) 01260 || (ast_waitfordigit(newchan, 100) < 0) 01261 || ast_check_hangup(transferee) 01262 || ast_check_hangup(newchan)) { 01263 ast_hangup(newchan); 01264 return -1; 01265 } 01266 } else if (!ast_check_hangup(transferee)) { 01267 /* Transferer (party B) has hung up at this point. Doing blonde transfer. */ 01268 if (option_debug) { 01269 ast_log(LOG_DEBUG, "Actually doing a blonde transfer.\n"); 01270 } 01271 01272 if (!newchan) { 01273 /* No party C. */ 01274 return -1; 01275 } 01276 01277 /* newchan is up, we should prepare transferee and bridge them */ 01278 if (ast_check_hangup(newchan)) { 01279 ast_hangup(newchan); 01280 return -1; 01281 } 01282 if (check_compat(transferee, newchan)) { 01283 return -1; 01284 } 01285 } else { 01286 /* 01287 * Both the transferer and transferee have hungup. If newchan 01288 * is up, hang it up as it has no one to talk to. 01289 */ 01290 if (option_debug) { 01291 ast_log(LOG_DEBUG, "Everyone is hungup.\n"); 01292 } 01293 if (newchan) { 01294 ast_hangup(newchan); 01295 } 01296 return -1; 01297 } 01298 01299 /* Initiate the channel transfer of party A to party C. */ 01300 01301 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01302 if (!xferchan) { 01303 ast_hangup(newchan); 01304 return -1; 01305 } 01306 01307 /* Give party A a momentary ringback tone during transfer. */ 01308 xferchan->visible_indication = AST_CONTROL_RINGING; 01309 01310 /* Make formats okay */ 01311 xferchan->readformat = transferee->readformat; 01312 xferchan->writeformat = transferee->writeformat; 01313 01314 ast_channel_masquerade(xferchan, transferee); 01315 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01316 xferchan->_state = AST_STATE_UP; 01317 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01318 01319 /* Do the masquerade manually to make sure that is is completed. */ 01320 ast_channel_lock(xferchan); 01321 if (xferchan->masq) { 01322 ast_do_masquerade(xferchan); 01323 } 01324 ast_channel_unlock(xferchan); 01325 01326 newchan->_state = AST_STATE_UP; 01327 ast_clear_flag(newchan, AST_FLAGS_ALL); 01328 tobj = ast_calloc(1, sizeof(*tobj)); 01329 if (!tobj) { 01330 ast_hangup(xferchan); 01331 ast_hangup(newchan); 01332 return -1; 01333 } 01334 01335 ast_channel_lock(newchan); 01336 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 01337 dialfeatures = features_datastore->data; 01338 } 01339 ast_channel_unlock(newchan); 01340 01341 if (dialfeatures) { 01342 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 01343 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 01344 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01345 dialfeatures = NULL; 01346 } 01347 01348 ast_channel_lock(xferchan); 01349 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 01350 dialfeatures = features_datastore->data; 01351 } 01352 ast_channel_unlock(xferchan); 01353 01354 if (dialfeatures) { 01355 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01356 } 01357 01358 tobj->chan = newchan; 01359 tobj->peer = xferchan; 01360 tobj->bconfig = *config; 01361 01362 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01363 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01364 } 01365 01366 if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) 01367 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01368 ast_bridge_call_thread_launch(tobj); 01369 return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */ 01370 }
static int builtin_automonitor | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 852 of file res_features.c.
References ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FRAME_DTMF_END, ast_log(), ast_monitor_stop(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verbose(), ast_channel::cid, ast_callerid::cid_num, EVENT_FLAG_USER, FEATURE_RETURN_SUCCESS, ast_channel::language, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_event(), ast_channel::monitor, monitor_app, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), ast_channel::uniqueid, and VERBOSE_PREFIX_3.
00853 { 00854 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00855 int x = 0; 00856 size_t len; 00857 struct ast_channel *caller_chan, *callee_chan; 00858 00859 if (!monitor_ok) { 00860 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00861 return -1; 00862 } 00863 00864 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00865 monitor_ok = 0; 00866 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00867 return -1; 00868 } 00869 00870 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00871 00872 if (!ast_strlen_zero(courtesytone)) { 00873 if (ast_autoservice_start(callee_chan)) 00874 return -1; 00875 ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END); 00876 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) { 00877 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00878 ast_autoservice_stop(callee_chan); 00879 return -1; 00880 } 00881 if (ast_autoservice_stop(callee_chan)) 00882 return -1; 00883 } 00884 00885 if (callee_chan->monitor) { 00886 manager_event(EVENT_FLAG_USER, "UserEvent", 00887 "UserEvent: StopRec\r\n" 00888 "Uniqueid: %s\r\n", 00889 caller_chan->uniqueid); 00890 if (option_verbose > 3) 00891 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00892 ast_monitor_stop(callee_chan, 1); 00893 return FEATURE_RETURN_SUCCESS; 00894 } 00895 00896 if (caller_chan && callee_chan) { 00897 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00898 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00899 00900 if (!touch_format) 00901 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00902 00903 if (!touch_monitor) 00904 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00905 00906 if (touch_monitor) { 00907 len = strlen(touch_monitor) + 50; 00908 args = alloca(len); 00909 touch_filename = alloca(len); 00910 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00911 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename); 00912 } else { 00913 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00914 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00915 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00916 args = alloca(len); 00917 touch_filename = alloca(len); 00918 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00919 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename); 00920 } 00921 00922 for( x = 0; x < strlen(args); x++) { 00923 if (args[x] == '/') 00924 args[x] = '-'; 00925 } 00926 00927 manager_event(EVENT_FLAG_USER, "UserEvent", 00928 "UserEvent: Rec\r\n" 00929 "Uniqueid: %s\r\n" 00930 "FileName: %s\r\n", 00931 caller_chan->uniqueid, touch_filename); 00932 if (option_verbose > 3) 00933 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00934 00935 pbx_exec(callee_chan, monitor_app, args); 00936 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00937 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00938 00939 return FEATURE_RETURN_SUCCESS; 00940 } 00941 00942 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00943 return -1; 00944 }
static int builtin_blindtransfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 973 of file res_features.c.
References ast_app_dtget(), ast_async_goto(), ast_autoservice_ignore(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FRAME_DTMF_END, ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_verbose(), ast_channel::cdr, check_goto_on_transfer(), FEATURE_RETURN_PARKFAILED, FEATURE_RETURN_SUCCESS, finishup(), ast_channel::language, LOG_WARNING, masq_park_call_announce(), ast_channel::name, option_verbose, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.
00974 { 00975 struct ast_channel *transferer; 00976 struct ast_channel *transferee; 00977 const char *transferer_real_context; 00978 char xferto[256]; 00979 int res; 00980 const char *orig_chan_name; 00981 int parkstatus = 0; 00982 00983 set_peers(&transferer, &transferee, peer, chan, sense); 00984 orig_chan_name = ast_strdupa(transferer->name); 00985 transferer_real_context = real_ctx(transferer, transferee); 00986 /* Start autoservice on chan while we talk to the originator */ 00987 ast_autoservice_start(transferee); 00988 ast_autoservice_ignore(transferee, AST_FRAME_DTMF_END); 00989 ast_indicate(transferee, AST_CONTROL_HOLD); 00990 00991 memset(xferto, 0, sizeof(xferto)); 00992 00993 /* Transfer */ 00994 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00995 if (res < 0) { 00996 finishup(transferee); 00997 return -1; /* error ? */ 00998 } 00999 if (res > 0) /* If they've typed a digit already, handle it */ 01000 xferto[0] = (char) res; 01001 01002 ast_stopstream(transferer); 01003 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01004 if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ 01005 finishup(transferee); 01006 return -1; 01007 } 01008 if (res == 0) { 01009 if (xferto[0]) { 01010 ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", 01011 xferto, transferer_real_context); 01012 } else { 01013 /* Does anyone care about this case? */ 01014 ast_log(LOG_WARNING, "No digits dialed.\n"); 01015 } 01016 ast_stream_and_wait(transferer, "pbx-invalid", transferer->language, ""); 01017 finishup(transferee); 01018 return FEATURE_RETURN_SUCCESS; 01019 } 01020 01021 if (!strcmp(xferto, ast_parking_ext())) { 01022 res = finishup(transferee); 01023 if (res) { 01024 } else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name))) { /* success */ 01025 /* We return non-zero, but tell the PBX not to hang the channel when 01026 the thread dies -- We have to be careful now though. We are responsible for 01027 hanging up the channel, else it will never be hung up! */ 01028 return 0; 01029 } else { 01030 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus=%d\n", transferee->name, parkstatus); 01031 } 01032 ast_autoservice_start(transferee); 01033 } else { 01034 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 01035 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 01036 res=finishup(transferee); 01037 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 01038 transferer->cdr=ast_cdr_alloc(); 01039 if (transferer->cdr) { 01040 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 01041 ast_cdr_start(transferer->cdr); 01042 } 01043 } 01044 if (transferer->cdr) { 01045 struct ast_cdr *swap = transferer->cdr; 01046 /* swap cdrs-- it will save us some time & work */ 01047 transferer->cdr = transferee->cdr; 01048 transferee->cdr = swap; 01049 } 01050 if (!transferee->pbx) { 01051 /* Doh! Use our handy async_goto functions */ 01052 if (option_verbose > 2) 01053 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 01054 ,transferee->name, xferto, transferer_real_context); 01055 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 01056 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 01057 res = -1; 01058 } else { 01059 /* Set the channel's new extension, since it exists, using transferer context */ 01060 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 01061 set_c_e_p(transferee, transferer_real_context, xferto, 0); 01062 } 01063 check_goto_on_transfer(transferer); 01064 return res; 01065 } 01066 if (parkstatus != FEATURE_RETURN_PARKFAILED 01067 && ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) { 01068 finishup(transferee); 01069 return -1; 01070 } 01071 ast_stopstream(transferer); 01072 res = finishup(transferee); 01073 if (res) { 01074 if (option_verbose > 1) 01075 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 01076 return res; 01077 } 01078 return FEATURE_RETURN_SUCCESS; 01079 }
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 946 of file res_features.c.
References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.
00947 { 00948 if (option_verbose > 3) 00949 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00950 return FEATURE_RETURN_HANGUP; 00951 }
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
Definition at line 818 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_module_user::chan, masq_park_call_announce(), ast_channel::name, and set_peers().
Referenced by builtin_atxfer().
00819 { 00820 struct ast_channel *parker; 00821 struct ast_channel *parkee; 00822 int res = 0; 00823 struct ast_module_user *u; 00824 const char *orig_chan_name; 00825 00826 u = ast_module_user_add(chan); 00827 00828 set_peers(&parker, &parkee, peer, chan, sense); 00829 orig_chan_name = ast_strdupa(parker->name); 00830 /* we used to set chan's exten and priority to "s" and 1 00831 here, but this generates (in some cases) an invalid 00832 extension, and if "s" exists, could errantly 00833 cause execution of extensions you don't expect It 00834 makes more sense to let nature take its course 00835 when chan finishes, and let the pbx do its thing 00836 and hang up when the park is over. 00837 */ 00838 if (chan->_state != AST_STATE_UP) 00839 res = ast_answer(chan); 00840 if (!res) 00841 res = ast_safe_sleep(chan, 1000); 00842 00843 if (!res) { /* one direction used to call park_call.... */ 00844 res = masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name); 00845 /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ 00846 } 00847 00848 ast_module_user_remove(u); 00849 return res; 00850 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 2717 of file res_features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, and ast_test_flag.
Referenced by do_parking_thread().
02718 { 02719 int i = 0; 02720 enum { 02721 OPT_CALLEE_REDIRECT = 't', 02722 OPT_CALLER_REDIRECT = 'T', 02723 OPT_CALLEE_AUTOMON = 'w', 02724 OPT_CALLER_AUTOMON = 'W', 02725 OPT_CALLEE_DISCONNECT = 'h', 02726 OPT_CALLER_DISCONNECT = 'H', 02727 OPT_CALLEE_PARKCALL = 'k', 02728 OPT_CALLER_PARKCALL = 'K', 02729 }; 02730 02731 memset(options, 0, len); 02732 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 02733 options[i++] = OPT_CALLER_REDIRECT; 02734 } 02735 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 02736 options[i++] = OPT_CALLER_AUTOMON; 02737 } 02738 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 02739 options[i++] = OPT_CALLER_DISCONNECT; 02740 } 02741 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 02742 options[i++] = OPT_CALLER_PARKCALL; 02743 } 02744 02745 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 02746 options[i++] = OPT_CALLEE_REDIRECT; 02747 } 02748 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 02749 options[i++] = OPT_CALLEE_AUTOMON; 02750 } 02751 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 02752 options[i++] = OPT_CALLEE_DISCONNECT; 02753 } 02754 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 02755 options[i++] = OPT_CALLEE_PARKCALL; 02756 } 02757 02758 return options; 02759 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 1081 of file res_features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by builtin_atxfer().
01082 { 01083 if (ast_channel_make_compatible(c, newchan) < 0) { 01084 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 01085 c->name, newchan->name); 01086 ast_hangup(newchan); 01087 return -1; 01088 } 01089 return 0; 01090 }
static void check_goto_on_transfer | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 405 of file res_features.c.
References ast_channel::_state, ast_channel_alloc(), ast_channel_clear_softhangup(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_SOFTHANGUP_ALL, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), f, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.
Referenced by builtin_blindtransfer().
00406 { 00407 struct ast_channel *xferchan; 00408 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00409 char *x, *goto_on_transfer; 00410 struct ast_frame *f; 00411 00412 if (ast_strlen_zero(val)) 00413 return; 00414 00415 goto_on_transfer = ast_strdupa(val); 00416 00417 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name))) 00418 return; 00419 00420 for (x = goto_on_transfer; x && *x; x++) { 00421 if (*x == '^') 00422 *x = '|'; 00423 } 00424 /* Make formats okay */ 00425 xferchan->readformat = chan->readformat; 00426 xferchan->writeformat = chan->writeformat; 00427 ast_channel_masquerade(xferchan, chan); 00428 ast_parseable_goto(xferchan, goto_on_transfer); 00429 xferchan->_state = AST_STATE_UP; 00430 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00431 ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL); 00432 if ((f = ast_read(xferchan))) { 00433 ast_frfree(f); 00434 f = NULL; 00435 ast_pbx_start(xferchan); 00436 } else { 00437 ast_hangup(xferchan); 00438 } 00439 }
static void clear_dialed_interfaces | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 2115 of file res_features.c.
References ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_log(), dialed_interface_info, LOG_DEBUG, ast_channel::name, and option_debug.
Referenced by ast_bridge_call().
02116 { 02117 struct ast_datastore *di_datastore; 02118 02119 ast_channel_lock(chan); 02120 if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) { 02121 if (option_debug) { 02122 ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name); 02123 } 02124 if (!ast_channel_datastore_remove(chan, di_datastore)) { 02125 ast_channel_datastore_free(di_datastore); 02126 } 02127 } 02128 ast_channel_unlock(chan); 02129 }
static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 366 of file res_features.c.
References ast_free.
00367 { 00368 struct ast_dial_features *df = data; 00369 if (df) { 00370 ast_free(df); 00371 } 00372 }
static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 353 of file res_features.c.
References ast_calloc.
00354 { 00355 struct ast_dial_features *df = data, *df_copy; 00356 00357 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00358 return NULL; 00359 } 00360 00361 memcpy(df_copy, df, sizeof(*df)); 00362 00363 return df_copy; 00364 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
Definition at line 2762 of file res_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_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), ast_pbx_start(), ast_read(), ast_realloc, ast_set_flag, ast_strdup, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), callback_dialoptions(), parkeduser::chan, ast_channel::context, parkeduser::context, dahdi_chan_name, dahdi_chan_name_len, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, free, ast_channel::generatordata, LOG_DEBUG, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_channel::name, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, and VERBOSE_PREFIX_2.
Referenced by load_module().
02763 { 02764 /* results from previous poll, to be preserved across loops. */ 02765 struct pollfd *fds = NULL; 02766 int nfds = 0; 02767 struct timeval tv; 02768 02769 for (;;) { 02770 struct parkeduser *pu, *pl, *pt = NULL; 02771 int ms = -1; /* poll2 timeout, uninitialized */ 02772 struct pollfd *new_fds = NULL; 02773 int new_nfds = 0; 02774 02775 ast_mutex_lock(&parking_lock); 02776 pl = NULL; 02777 pu = parkinglot; 02778 /* navigate the list with prev-cur pointers to support removals */ 02779 while (pu) { 02780 struct ast_channel *chan = pu->chan; /* shorthand */ 02781 int tms; /* timeout for this item */ 02782 int x; /* fd index in channel */ 02783 struct ast_context *con; 02784 02785 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 02786 pl = pu; 02787 pu = pu->next; 02788 continue; 02789 } 02790 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 02791 if (tms > pu->parkingtime) { 02792 ast_indicate(chan, AST_CONTROL_UNHOLD); 02793 /* Get chan, exten from derived kludge */ 02794 if (pu->peername[0]) { 02795 /* Don't use ast_strdupa() inside an infinite loop */ 02796 char *dash, *peername = ast_strdup(pu->peername); 02797 if (!peername) { 02798 /* Skip for the time being. */ 02799 pl = pu; 02800 pu = pu->next; 02801 continue; 02802 } 02803 if ((dash = strrchr(peername, '-'))) { 02804 *dash = '\0'; 02805 } 02806 if (!(con = ast_context_find_or_create(NULL, parking_con_dial, registrar))) { 02807 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 02808 } else { 02809 char returnexten[AST_MAX_EXTENSION]; 02810 struct ast_datastore *features_datastore; 02811 struct ast_dial_features *dialfeatures = NULL; 02812 02813 ast_channel_lock(chan); 02814 02815 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) { 02816 dialfeatures = features_datastore->data; 02817 } 02818 02819 ast_channel_unlock(chan); 02820 02821 if (!strncmp(peername, "Parked/", 7)) { 02822 peername += 7; 02823 } 02824 02825 /* If dahdi channel, add a ring cadence DAHDI/NNr3 (if parkingretdahdiring defined) */ 02826 if (!ast_strlen_zero(parkingretdahdiring) && !strncasecmp(peername, dahdi_chan_name, *dahdi_chan_name_len)) 02827 strncat(peername, parkingretdahdiring, 2); 02828 if (dialfeatures) { 02829 char buf[MAX_DIAL_FEATURE_OPTIONS] = ""; 02830 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 02831 } else { /* Existing default */ 02832 ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name); 02833 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername); 02834 } 02835 02836 int parkdialprio = 1; 02837 char parkciddata[512]; 02838 char parkalertinfodata[512]; 02839 /* alter CALLERID(name) and add AlertInfo header if requested */ 02840 if (!ast_strlen_zero(parkingretcidname)) { 02841 snprintf(parkciddata, sizeof(parkciddata), "CALLERID(name)=%s", parkingretcidname); 02842 ast_add_extension2(con, 1, peername, parkdialprio++, NULL, NULL, "Set", strdup(parkciddata), ast_free_ptr, registrar); 02843 } 02844 if (!ast_strlen_zero(parkingretalertinfo)) { 02845 snprintf(parkalertinfodata, sizeof(parkalertinfodata), "Alert-Info: %s", parkingretalertinfo); 02846 ast_add_extension2(con, 1, peername, parkdialprio++, NULL, NULL, "SIPAddHeader", strdup(parkalertinfodata), ast_free_ptr, registrar); 02847 } 02848 ast_add_extension2(con, 1, peername, parkdialprio, NULL, NULL, "Dial", strdup(returnexten), ast_free_ptr, registrar); 02849 } 02850 set_c_e_p(chan, parking_con_dial, peername, 1); 02851 ast_free(peername); 02852 } else { 02853 /* They've been waiting too long, send them back to where they came. Theoretically they 02854 should have their original extensions and such, but we copy to be on the safe side */ 02855 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 02856 } 02857 02858 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 02859 02860 if (option_verbose > 1) { 02861 ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority); 02862 } 02863 /* Start up the PBX, or hang them up */ 02864 if (ast_pbx_start(chan)) { 02865 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 02866 ast_hangup(chan); 02867 } 02868 /* And take them out of the parking lot */ 02869 if (pl) { 02870 pl->next = pu->next; 02871 } else { 02872 parkinglot = pu->next; 02873 } 02874 pt = pu; 02875 pu = pu->next; 02876 con = ast_context_find(parking_con); 02877 if (con) { 02878 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) { 02879 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02880 } else { 02881 notify_metermaids(pt->parkingexten, parking_con); 02882 } 02883 } else { 02884 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02885 } 02886 free(pt); 02887 } else { /* still within parking time, process descriptors */ 02888 for (x = 0; x < AST_MAX_FDS; x++) { 02889 struct ast_frame *f; 02890 int y; 02891 02892 if (chan->fds[x] == -1) { 02893 continue; /* nothing on this descriptor */ 02894 } 02895 02896 for (y = 0; y < nfds; y++) { 02897 if (fds[y].fd == chan->fds[x]) { 02898 /* Found poll record! */ 02899 break; 02900 } 02901 } 02902 if (y == nfds) { 02903 /* Not found */ 02904 continue; 02905 } 02906 02907 if (!(fds[y].revents & (POLLIN | POLLERR | POLLPRI))) { 02908 /* Next x */ 02909 continue; 02910 } 02911 02912 if (fds[y].revents & POLLPRI) { 02913 ast_set_flag(chan, AST_FLAG_EXCEPTION); 02914 } else { 02915 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 02916 } 02917 chan->fdno = x; 02918 02919 /* See if they need servicing */ 02920 f = ast_read(chan); 02921 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 02922 if (f) { 02923 ast_frfree(f); 02924 } 02925 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 02926 02927 /* There's a problem, hang them up*/ 02928 if (option_verbose > 1) { 02929 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 02930 } 02931 /* And take them out of the parking lot */ 02932 if (pl) { 02933 pl->next = pu->next; 02934 } else { 02935 parkinglot = pu->next; 02936 } 02937 pt = pu; 02938 pu = pu->next; 02939 02940 ast_hangup(chan); 02941 con = ast_context_find(parking_con); 02942 if (con) { 02943 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) { 02944 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02945 } else { 02946 notify_metermaids(pt->parkingexten, parking_con); 02947 } 02948 } else { 02949 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02950 } 02951 free(pt); 02952 break; 02953 } else { 02954 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02955 ast_frfree(f); 02956 if (pu->moh_trys < 3 && !chan->generatordata) { 02957 if (option_debug) { 02958 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 02959 } 02960 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 02961 S_OR(parkmohclass, NULL), 02962 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 02963 pu->moh_trys++; 02964 } 02965 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 02966 } 02967 02968 } /* end for */ 02969 if (x >= AST_MAX_FDS) { 02970 std: for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */ 02971 if (chan->fds[x] > -1) { 02972 void *tmp = ast_realloc(new_fds, (new_nfds + 1) * sizeof(*new_fds)); 02973 if (!tmp) { 02974 continue; 02975 } 02976 new_fds = tmp; 02977 new_fds[new_nfds].fd = chan->fds[x]; 02978 new_fds[new_nfds].events = POLLIN | POLLERR | POLLPRI; 02979 new_fds[new_nfds].revents = 0; 02980 new_nfds++; 02981 } 02982 } 02983 /* Keep track of our shortest wait */ 02984 if (tms < ms || ms < 0) { 02985 ms = tms; 02986 } 02987 pl = pu; 02988 pu = pu->next; 02989 } 02990 } 02991 } /* end while */ 02992 ast_mutex_unlock(&parking_lock); 02993 ast_free(fds); 02994 fds = new_fds; 02995 nfds = new_nfds; 02996 new_fds = NULL; 02997 new_nfds = 0; 02998 02999 tv = ast_samp2tv(ms, 1000); 03000 /* Wait for something to happen */ 03001 ast_poll2(fds, nfds, (ms > -1) ? &tv : NULL); 03002 03003 pthread_testcancel(); 03004 } 03005 return NULL; /* Never reached */ 03006 }
static int feature_check | ( | struct ast_channel * | chan, | |
struct ast_flags * | features, | |||
char * | code | |||
) | [static] |
Check if a feature exists.
Definition at line 1671 of file res_features.c.
References ast_channel_lock, ast_channel_unlock, ast_strdupa, FEATURE_INTERPRET_CHECK, feature_interpret_helper(), pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
01671 { 01672 char *chan_dynamic_features; 01673 ast_channel_lock(chan); 01674 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 01675 ast_channel_unlock(chan); 01676 01677 return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL); 01678 }
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
Definition at line 1447 of file res_features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_FRAME_DTMF_END, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().
01448 { 01449 struct ast_app *app; 01450 struct ast_call_feature *feature = data; 01451 struct ast_channel *work, *idle; 01452 int res; 01453 01454 if (!feature) { /* shouldn't ever happen! */ 01455 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01456 return -1; 01457 } 01458 01459 if (sense == FEATURE_SENSE_CHAN) { 01460 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01461 return FEATURE_RETURN_KEEPTRYING; 01462 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01463 work = chan; 01464 idle = peer; 01465 } else { 01466 work = peer; 01467 idle = chan; 01468 } 01469 } else { 01470 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01471 return FEATURE_RETURN_KEEPTRYING; 01472 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01473 work = peer; 01474 idle = chan; 01475 } else { 01476 work = chan; 01477 idle = peer; 01478 } 01479 } 01480 01481 if (!(app = pbx_findapp(feature->app))) { 01482 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01483 return -2; 01484 } 01485 01486 ast_autoservice_start(idle); 01487 ast_autoservice_ignore(idle, AST_FRAME_DTMF_END); 01488 01489 if (!ast_strlen_zero(feature->moh_class)) 01490 ast_moh_start(idle, feature->moh_class, NULL); 01491 01492 res = pbx_exec(work, app, feature->app_args); 01493 01494 if (!ast_strlen_zero(feature->moh_class)) 01495 ast_moh_stop(idle); 01496 01497 ast_autoservice_stop(idle); 01498 01499 if (res) 01500 return FEATURE_RETURN_SUCCESSBREAK; 01501 01502 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01503 }
static int feature_interpret | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense | |||
) | [static] |
Check the dynamic features.
chan,peer,config,code,sense |
res | on success. | |
-1 | on failure. |
Definition at line 1634 of file res_features.c.
References ast_channel_lock, ast_channel_unlock, ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strdupa, config, FEATURE_INTERPRET_DO, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, LOG_DEBUG, ast_channel::name, option_debug, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
01634 { 01635 01636 char dynamic_features_buf[128]; 01637 const char *peer_dynamic_features, *chan_dynamic_features; 01638 struct ast_flags features; 01639 struct ast_call_feature feature; 01640 if (sense == FEATURE_SENSE_CHAN) { 01641 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01642 } 01643 else { 01644 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01645 } 01646 01647 ast_channel_lock(peer); 01648 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 01649 ast_channel_unlock(peer); 01650 01651 ast_channel_lock(chan); 01652 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 01653 ast_channel_unlock(chan); 01654 01655 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,"")); 01656 01657 if (option_debug > 2) { 01658 ast_log(LOG_DEBUG, "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); 01659 } 01660 01661 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature); 01662 }
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, | |||
feature_interpret_op | operation, | |||
struct ast_call_feature * | feature | |||
) | [static] |
Helper function for feature_interpret and ast_feature_detect.
chan,peer,config,code,sense,dynamic_features | char buf,feature flags,operation,feature |
res | on success. | |
-1 | on failure. |
Definition at line 1543 of file res_features.c.
References ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strlen_zero(), ast_test_flag, builtin_features, config, ast_call_feature::exten, exten, FEATURE_INTERPRET_CHECK, FEATURE_INTERPRET_DO, ast_call_feature::feature_mask, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_RETURN_SUCCESS, FEATURES_COUNT, features_lock, find_dynamic_feature(), ast_call_feature::fname, LOG_DEBUG, LOG_NOTICE, ast_call_feature::operation, option_debug, and ast_call_feature::sname.
Referenced by ast_feature_detect(), feature_check(), and feature_interpret().
01546 { 01547 int x; 01548 struct ast_call_feature *tmpfeature; 01549 char *tmp, *tok; 01550 int res = FEATURE_RETURN_PASSDIGITS; 01551 int feature_detected = 0; 01552 01553 if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) { 01554 return -1; /* can not run feature operation */ 01555 } 01556 01557 ast_rwlock_rdlock(&features_lock); 01558 for (x = 0; x < FEATURES_COUNT; x++) { 01559 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 01560 !ast_strlen_zero(builtin_features[x].exten)) { 01561 /* Feature is up for consideration */ 01562 if (!strcmp(builtin_features[x].exten, code)) { 01563 if (option_debug > 2) { 01564 ast_log(LOG_DEBUG, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 01565 } 01566 if (operation == FEATURE_INTERPRET_CHECK) { 01567 res = FEATURE_RETURN_SUCCESS; /* We found something */ 01568 } else if (operation == FEATURE_INTERPRET_DO) { 01569 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01570 } 01571 if (feature) { 01572 memcpy(feature, &builtin_features[x], sizeof(feature)); 01573 } 01574 01575 feature_detected = 1; 01576 break; 01577 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01578 if (res == FEATURE_RETURN_PASSDIGITS) { 01579 res = FEATURE_RETURN_STOREDIGITS; 01580 } 01581 } 01582 } 01583 } 01584 ast_rwlock_unlock(&features_lock); 01585 01586 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 01587 return res; 01588 } 01589 01590 tmp = dynamic_features_buf; 01591 01592 while ((tok = strsep(&tmp, "#"))) { 01593 AST_RWLIST_RDLOCK(&feature_list); 01594 if (!(tmpfeature = find_dynamic_feature(tok))) { 01595 AST_RWLIST_UNLOCK(&feature_list); 01596 continue; 01597 } 01598 01599 /* Feature is up for consideration */ 01600 if (!strcmp(tmpfeature->exten, code)) { 01601 if (option_debug > 2) { 01602 ast_log(LOG_NOTICE, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 01603 } 01604 if (operation == FEATURE_INTERPRET_CHECK) { 01605 res = FEATURE_RETURN_SUCCESS; /* We found something */ 01606 } else if (operation == FEATURE_INTERPRET_DO) { 01607 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 01608 } 01609 if (feature) { 01610 memcpy(feature, tmpfeature, sizeof(feature)); 01611 } 01612 if (res != FEATURE_RETURN_KEEPTRYING) { 01613 AST_RWLIST_UNLOCK(&feature_list); 01614 break; 01615 } 01616 res = FEATURE_RETURN_PASSDIGITS; 01617 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 01618 res = FEATURE_RETURN_STOREDIGITS; 01619 01620 AST_RWLIST_UNLOCK(&feature_list); 01621 } 01622 01623 return res; 01624 }
static struct ast_channel * feature_request_and_dial | ( | struct ast_channel * | caller, | |
struct ast_channel * | transferee, | |||
const char * | type, | |||
int | format, | |||
void * | data, | |||
int | timeout, | |||
int * | outstate, | |||
const char * | cid_num, | |||
const char * | cid_name, | |||
const char * | language | |||
) | [static] |
Definition at line 1756 of file res_features.c.
References ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_inherit_variables(), ast_channel_lock, ast_channel_unlock, ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_frisolate(), ast_hangup(), ast_indicate(), ast_is_deferrable_frame(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_queue_frame_head(), 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_verbose(), ast_waitfor_n(), ast_write(), builtin_features, ast_channel::call_forward, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_channel::hangupcause, len(), LOG_NOTICE, ast_channel::name, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.
Referenced by builtin_atxfer().
01760 { 01761 int state = 0; 01762 int cause = 0; 01763 int to; 01764 int caller_hungup; 01765 int transferee_hungup; 01766 struct ast_channel *chan; 01767 struct ast_channel *monitor_chans[3]; 01768 struct ast_channel *active_channel; 01769 int ready = 0; 01770 struct timeval started; 01771 int x, len = 0; 01772 char *disconnect_code = NULL, *dialed_code = NULL; 01773 struct ast_frame *f; 01774 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; 01775 01776 caller_hungup = ast_check_hangup(caller); 01777 01778 if (!(chan = ast_request(type, format, data, &cause))) { 01779 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01780 switch (cause) { 01781 case AST_CAUSE_BUSY: 01782 state = AST_CONTROL_BUSY; 01783 break; 01784 case AST_CAUSE_CONGESTION: 01785 state = AST_CONTROL_CONGESTION; 01786 break; 01787 default: 01788 state = 0; 01789 break; 01790 } 01791 goto done; 01792 } 01793 01794 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01795 ast_string_field_set(chan, language, language); 01796 ast_channel_inherit_variables(caller, chan); 01797 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01798 01799 if (ast_call(chan, data, timeout)) { 01800 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01801 switch (chan->hangupcause) { 01802 case AST_CAUSE_BUSY: 01803 state = AST_CONTROL_BUSY; 01804 break; 01805 case AST_CAUSE_CONGESTION: 01806 state = AST_CONTROL_CONGESTION; 01807 break; 01808 default: 01809 state = 0; 01810 break; 01811 } 01812 goto done; 01813 } 01814 01815 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01816 ast_rwlock_rdlock(&features_lock); 01817 for (x = 0; x < FEATURES_COUNT; x++) { 01818 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01819 continue; 01820 01821 disconnect_code = builtin_features[x].exten; 01822 len = strlen(disconnect_code) + 1; 01823 dialed_code = alloca(len); 01824 memset(dialed_code, 0, len); 01825 break; 01826 } 01827 ast_rwlock_unlock(&features_lock); 01828 x = 0; 01829 started = ast_tvnow(); 01830 to = timeout; 01831 AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); 01832 01833 if (caller_hungup) { 01834 /* Convert to a blonde transfer */ 01835 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01836 ast_indicate(transferee, AST_CONTROL_RINGING); 01837 } 01838 01839 transferee_hungup = 0; 01840 while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) { 01841 int num_chans = 0; 01842 01843 monitor_chans[num_chans++] = transferee; 01844 monitor_chans[num_chans++] = chan; 01845 if (!caller_hungup) { 01846 if (ast_check_hangup(caller)) { 01847 caller_hungup = 1; 01848 01849 #if defined(ATXFER_NULL_TECH) 01850 /* Change caller's name to ensure that it will remain unique. */ 01851 set_new_chan_name(caller); 01852 01853 /* 01854 * Get rid of caller's physical technology so it is free for 01855 * other calls. 01856 */ 01857 set_null_chan_tech(caller); 01858 #endif /* defined(ATXFER_NULL_TECH) */ 01859 01860 /* Convert to a blonde transfer */ 01861 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01862 ast_indicate(transferee, AST_CONTROL_RINGING); 01863 started = ast_tvnow(); 01864 to = timeout; 01865 } else { 01866 /* caller is not hungup so monitor it. */ 01867 monitor_chans[num_chans++] = caller; 01868 } 01869 } 01870 01871 /* see if the timeout has been violated */ 01872 if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01873 state = AST_CONTROL_UNHOLD; 01874 ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name); 01875 break; /*doh! timeout*/ 01876 } 01877 01878 active_channel = ast_waitfor_n(monitor_chans, num_chans, &to); 01879 if (!active_channel) 01880 continue; 01881 01882 f = NULL; 01883 if (transferee == active_channel) { 01884 struct ast_frame *dup_f; 01885 01886 f = ast_read(transferee); 01887 if (f == NULL) { /*doh! where'd he go?*/ 01888 transferee_hungup = 1; 01889 state = 0; 01890 break; 01891 } 01892 if (ast_is_deferrable_frame(f)) { 01893 dup_f = ast_frisolate(f); 01894 if (dup_f) { 01895 if (dup_f == f) { 01896 f = NULL; 01897 } 01898 AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); 01899 } 01900 } 01901 } else if (chan == active_channel) { 01902 if (!ast_strlen_zero(chan->call_forward)) { 01903 state = 0; 01904 chan = ast_call_forward(caller, chan, NULL, format, NULL, &state); 01905 if (!chan) { 01906 break; 01907 } 01908 continue; 01909 } 01910 f = ast_read(chan); 01911 if (f == NULL) { /*doh! where'd he go?*/ 01912 switch (chan->hangupcause) { 01913 case AST_CAUSE_BUSY: 01914 state = AST_CONTROL_BUSY; 01915 break; 01916 case AST_CAUSE_CONGESTION: 01917 state = AST_CONTROL_CONGESTION; 01918 break; 01919 default: 01920 state = 0; 01921 break; 01922 } 01923 break; 01924 } 01925 01926 if (f->frametype == AST_FRAME_CONTROL) { 01927 if (f->subclass == AST_CONTROL_RINGING) { 01928 if (option_verbose > 2) 01929 ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01930 ast_indicate(caller, AST_CONTROL_RINGING); 01931 } else if (f->subclass == AST_CONTROL_BUSY) { 01932 state = f->subclass; 01933 if (option_verbose > 2) 01934 ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01935 ast_indicate(caller, AST_CONTROL_BUSY); 01936 ast_frfree(f); 01937 break; 01938 } else if (f->subclass == AST_CONTROL_CONGESTION) { 01939 state = f->subclass; 01940 if (option_verbose > 2) 01941 ast_verbose(VERBOSE_PREFIX_3 "%s is congested\n", chan->name); 01942 ast_indicate(caller, AST_CONTROL_CONGESTION); 01943 ast_frfree(f); 01944 break; 01945 } else if (f->subclass == AST_CONTROL_ANSWER) { 01946 /* This is what we are hoping for */ 01947 state = f->subclass; 01948 ast_frfree(f); 01949 ready=1; 01950 break; 01951 } else if (f->subclass != -1 && f->subclass != AST_CONTROL_PROGRESS) { 01952 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01953 } 01954 /* else who cares */ 01955 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 01956 ast_write(caller, f); 01957 } 01958 } else if (caller == active_channel) { 01959 f = ast_read(caller); 01960 if (f) { 01961 if (f->frametype == AST_FRAME_DTMF) { 01962 dialed_code[x++] = f->subclass; 01963 dialed_code[x] = '\0'; 01964 if (strlen(dialed_code) == len) { 01965 x = 0; 01966 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01967 x = 0; 01968 dialed_code[x] = '\0'; 01969 } 01970 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01971 /* Caller Canceled the call */ 01972 state = AST_CONTROL_UNHOLD; 01973 ast_frfree(f); 01974 break; 01975 } 01976 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 01977 ast_write(chan, f); 01978 } 01979 } 01980 } 01981 if (f) 01982 ast_frfree(f); 01983 } /* end while */ 01984 01985 /* 01986 * We need to free all the deferred frames, but we only need to 01987 * queue the deferred frames if no hangup was received. 01988 */ 01989 ast_channel_lock(transferee); 01990 transferee_hungup = (transferee_hungup || ast_check_hangup(transferee)); 01991 while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { 01992 if (!transferee_hungup) { 01993 ast_queue_frame_head(transferee, f); 01994 } 01995 ast_frfree(f); 01996 } 01997 ast_channel_unlock(transferee); 01998 01999 done: 02000 ast_indicate(caller, -1); 02001 if (chan && (ready || chan->_state == AST_STATE_UP)) { 02002 state = AST_CONTROL_ANSWER; 02003 } else if (chan) { 02004 ast_hangup(chan); 02005 chan = NULL; 02006 } 02007 02008 if (outstate) 02009 *outstate = state; 02010 02011 return chan; 02012 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a feature by name
Definition at line 1433 of file res_features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by feature_interpret_helper(), and set_config_flags().
01434 { 01435 struct ast_call_feature *tmp; 01436 01437 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01438 if (!strcasecmp(tmp->sname, name)) { 01439 break; 01440 } 01441 } 01442 01443 return tmp; 01444 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 953 of file res_features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_atxfer(), and builtin_blindtransfer().
00954 { 00955 ast_indicate(chan, AST_CONTROL_UNHOLD); 00956 00957 return ast_autoservice_stop(chan); 00958 }
static int handle_parkedcalls | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 3275 of file res_features.c.
References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, ast_channel::name, parkeduser::next, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.
03276 { 03277 struct parkeduser *cur; 03278 int numparked = 0; 03279 03280 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 03281 , "Context", "Extension", "Pri", "Timeout"); 03282 03283 ast_mutex_lock(&parking_lock); 03284 03285 for (cur = parkinglot; cur; cur = cur->next) { 03286 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 03287 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 03288 ,cur->priority, (long) cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 03289 03290 numparked++; 03291 } 03292 ast_mutex_unlock(&parking_lock); 03293 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 03294 03295 03296 return RESULT_SUCCESS; 03297 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 3233 of file res_features.c.
References ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), builtin_features, ast_call_feature::default_exten, ast_call_feature::exten, exten, ast_call_feature::feature_entry, FEATURES_COUNT, features_lock, ast_call_feature::fname, format, RESULT_SUCCESS, and ast_call_feature::sname.
03234 { 03235 int i; 03236 struct ast_call_feature *feature; 03237 char format[] = "%-25s %-7s %-7s\n"; 03238 03239 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 03240 ast_cli(fd, format, "---------------", "-------", "-------"); 03241 03242 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 03243 03244 ast_rwlock_rdlock(&features_lock); 03245 for (i = 0; i < FEATURES_COUNT; i++) 03246 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 03247 ast_rwlock_unlock(&features_lock); 03248 03249 ast_cli(fd, "\n"); 03250 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 03251 ast_cli(fd, format, "---------------", "-------", "-------"); 03252 if (AST_RWLIST_EMPTY(&feature_list)) { 03253 ast_cli(fd, "(none)\n"); 03254 } else { 03255 AST_RWLIST_RDLOCK(&feature_list); 03256 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 03257 ast_cli(fd, format, feature->sname, "no def", feature->exten); 03258 } 03259 AST_RWLIST_UNLOCK(&feature_list); 03260 } 03261 ast_cli(fd, "\nCall parking\n"); 03262 ast_cli(fd, "------------\n"); 03263 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 03264 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 03265 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 03266 ast_cli(fd,"\n"); 03267 03268 return RESULT_SUCCESS; 03269 }
static int load_config | ( | void | ) | [static] |
Definition at line 3494 of file res_features.c.
References ast_config_load(), ast_copy_string(), AST_FEATURE_FLAG_BYBOTH, ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_strlen_zero(), ast_variable_browse(), DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_TRANSFER_DIGIT_TIMEOUT, LOG_WARNING, and var.
03495 { 03496 int start = 0, end = 0; 03497 int res; 03498 struct ast_context *con = NULL; 03499 struct ast_config *cfg = NULL; 03500 struct ast_variable *var = NULL; 03501 char old_parking_ext[AST_MAX_EXTENSION]; 03502 char old_parking_con[AST_MAX_EXTENSION] = ""; 03503 03504 if (!ast_strlen_zero(parking_con)) { 03505 strcpy(old_parking_ext, parking_ext); 03506 strcpy(old_parking_con, parking_con); 03507 } 03508 03509 /* Reset to defaults */ 03510 strcpy(parking_con, "parkedcalls"); 03511 strcpy(parking_con_dial, "park-dial"); 03512 strcpy(parking_ext, "700"); 03513 strcpy(pickup_ext, "*8"); 03514 strcpy(parkmohclass, "default"); 03515 courtesytone[0] = '\0'; 03516 strcpy(xfersound, "beep"); 03517 strcpy(xferfailsound, "beeperr"); 03518 parking_start = 701; 03519 parking_stop = 750; 03520 parkfindnext = 0; 03521 adsipark = 0; 03522 parkaddhints = 0; 03523 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 03524 parkedcallreparking = 0; 03525 parkedcallhangup = 0; 03526 parkedcallrecording = 0; 03527 03528 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03529 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03530 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03531 03532 cfg = ast_config_load("features.conf"); 03533 if (!cfg) { 03534 ast_log(LOG_WARNING,"Could not load features.conf\n"); 03535 return AST_MODULE_LOAD_DECLINE; 03536 } 03537 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 03538 if (!strcasecmp(var->name, "parkext")) { 03539 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 03540 } else if (!strcasecmp(var->name, "context")) { 03541 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 03542 } else if (!strcasecmp(var->name, "parkingtime")) { 03543 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || (parkingtime < 1)) { 03544 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 03545 parkingtime = DEFAULT_PARK_TIME; 03546 } else 03547 parkingtime = parkingtime * 1000; 03548 } else if (!strcasecmp(var->name, "parkpos")) { 03549 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 03550 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); 03551 } else { 03552 parking_start = start; 03553 parking_stop = end; 03554 } 03555 } else if (!strcasecmp(var->name, "findslot")) { 03556 parkfindnext = (!strcasecmp(var->value, "next")); 03557 } else if (!strcasecmp(var->name, "parkinghints")) { 03558 parkaddhints = ast_true(var->value); 03559 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 03560 if (!strcasecmp(var->value, "no")) 03561 parkedcalltransfers = 0; 03562 else if (!strcasecmp(var->value, "caller")) 03563 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 03564 else if (!strcasecmp(var->value, "callee")) 03565 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 03566 else if (!strcasecmp(var->value, "both")) 03567 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 03568 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 03569 if (!strcasecmp(var->value, "no")) 03570 parkedcallreparking = 0; 03571 else if (!strcasecmp(var->value, "caller")) 03572 parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 03573 else if (!strcasecmp(var->value, "callee")) 03574 parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 03575 else if (!strcasecmp(var->value, "both")) 03576 parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 03577 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 03578 if (!strcasecmp(var->value, "no")) 03579 parkedcallhangup = 0; 03580 else if (!strcasecmp(var->value, "caller")) 03581 parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 03582 else if (!strcasecmp(var->value, "callee")) 03583 parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 03584 else if (!strcasecmp(var->value, "both")) 03585 parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 03586 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 03587 if (!strcasecmp(var->value, "no")) 03588 parkedcallrecording = 0; 03589 else if (!strcasecmp(var->value, "caller")) 03590 parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 03591 else if (!strcasecmp(var->value, "callee")) 03592 parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 03593 else if (!strcasecmp(var->value, "both")) 03594 parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 03595 } else if (!strcasecmp(var->name, "adsipark")) { 03596 adsipark = ast_true(var->value); 03597 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03598 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03599 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03600 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03601 } else 03602 transferdigittimeout = transferdigittimeout * 1000; 03603 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03604 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03605 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03606 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03607 } 03608 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03609 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03610 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03611 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03612 } else 03613 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03614 } else if (!strcasecmp(var->name, "courtesytone")) { 03615 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03616 } else if (!strcasecmp(var->name, "parkedplay")) { 03617 if (!strcasecmp(var->value, "both")) 03618 parkedplay = 2; 03619 else if (!strcasecmp(var->value, "parked")) 03620 parkedplay = 1; 03621 else 03622 parkedplay = 0; 03623 } else if (!strcasecmp(var->name, "xfersound")) { 03624 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03625 } else if (!strcasecmp(var->name, "xferfailsound")) { 03626 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03627 } else if (!strcasecmp(var->name, "pickupexten")) { 03628 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03629 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03630 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 03631 } else if (!strcasecmp(var->name, "parkingretcidname")) { 03632 ast_copy_string(parkingretcidname, var->value, sizeof(parkingretcidname)); 03633 } else if (!strcasecmp(var->name, "parkingretdahdiring")) { 03634 ast_copy_string(parkingretdahdiring, var->value, sizeof(parkingretdahdiring)); 03635 } else if (!strcasecmp(var->name, "parkingretalertinfo")) { 03636 ast_copy_string(parkingretalertinfo, var->value, sizeof(parkingretalertinfo)); 03637 } 03638 } 03639 03640 unmap_features(); 03641 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03642 if (remap_feature(var->name, var->value)) 03643 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03644 } 03645 03646 /* Map a key combination to an application*/ 03647 ast_unregister_features(); 03648 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03649 char *tmp_val = ast_strdupa(var->value); 03650 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 03651 struct ast_call_feature *feature; 03652 03653 /* strsep() sets the argument to NULL if match not found, and it 03654 * is safe to use it with a NULL argument, so we don't check 03655 * between calls. 03656 */ 03657 exten = strsep(&tmp_val,","); 03658 activatedby = strsep(&tmp_val,","); 03659 app = strsep(&tmp_val,","); 03660 app_args = strsep(&tmp_val,","); 03661 moh_class = strsep(&tmp_val,","); 03662 03663 activateon = strsep(&activatedby, "/"); 03664 03665 /*! \todo XXX var_name or app_args ? */ 03666 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03667 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03668 app, exten, activateon, var->name); 03669 continue; 03670 } 03671 03672 AST_RWLIST_RDLOCK(&feature_list); 03673 if ((feature = find_dynamic_feature(var->name))) { 03674 AST_RWLIST_UNLOCK(&feature_list); 03675 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03676 continue; 03677 } 03678 AST_RWLIST_UNLOCK(&feature_list); 03679 03680 if (!(feature = ast_calloc(1, sizeof(*feature)))) 03681 continue; 03682 03683 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03684 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 03685 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 03686 03687 if (app_args) 03688 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 03689 03690 if (moh_class) 03691 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 03692 03693 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 03694 feature->operation = feature_exec_app; 03695 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03696 03697 /* Allow caller and calle to be specified for backwards compatability */ 03698 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03699 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03700 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03701 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03702 else { 03703 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03704 " must be 'self', or 'peer'\n", var->name); 03705 continue; 03706 } 03707 03708 if (ast_strlen_zero(activatedby)) 03709 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03710 else if (!strcasecmp(activatedby, "caller")) 03711 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03712 else if (!strcasecmp(activatedby, "callee")) 03713 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03714 else if (!strcasecmp(activatedby, "both")) 03715 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03716 else { 03717 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03718 " must be 'caller', or 'callee', or 'both'\n", var->name); 03719 continue; 03720 } 03721 03722 ast_register_feature(feature); 03723 03724 if (option_verbose >= 1) 03725 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 03726 } 03727 ast_config_destroy(cfg); 03728 03729 /* Remove the old parking extension */ 03730 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03731 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 03732 notify_metermaids(old_parking_ext, old_parking_con); 03733 if (option_debug) 03734 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03735 } 03736 03737 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 03738 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 03739 return -1; 03740 } 03741 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 03742 if (parkaddhints) 03743 park_add_hints(parking_con, parking_start, parking_stop); 03744 if (!res) 03745 notify_metermaids(ast_parking_ext(), parking_con); 03746 return res; 03747 03748 }
static int load_module | ( | void | ) | [static] |
Definition at line 3755 of file res_features.c.
References ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application(), cli_features, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), and park_exec().
03756 { 03757 int res; 03758 03759 memset(parking_ext, 0, sizeof(parking_ext)); 03760 memset(parking_con, 0, sizeof(parking_con)); 03761 03762 if ((res = load_config())) 03763 return res; 03764 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03765 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 03766 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 03767 if (!res) 03768 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 03769 if (!res) { 03770 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 03771 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 03772 "Park a channel", mandescr_park); 03773 } 03774 03775 res |= ast_devstate_prov_add("Park", metermaidstate); 03776 03777 return res; 03778 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 3366 of file res_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 s.
Referenced by load_module().
03367 { 03368 const char *channel = astman_get_header(m, "Channel"); 03369 const char *channel2 = astman_get_header(m, "Channel2"); 03370 const char *timeout = astman_get_header(m, "Timeout"); 03371 char buf[BUFSIZ]; 03372 int to = 0; 03373 int res = 0; 03374 int parkExt = 0; 03375 struct ast_channel *ch1, *ch2; 03376 03377 if (ast_strlen_zero(channel)) { 03378 astman_send_error(s, m, "Channel not specified"); 03379 return 0; 03380 } 03381 03382 if (ast_strlen_zero(channel2)) { 03383 astman_send_error(s, m, "Channel2 not specified"); 03384 return 0; 03385 } 03386 03387 ch1 = ast_get_channel_by_name_locked(channel); 03388 if (!ch1) { 03389 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 03390 astman_send_error(s, m, buf); 03391 return 0; 03392 } 03393 03394 ch2 = ast_get_channel_by_name_locked(channel2); 03395 if (!ch2) { 03396 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 03397 astman_send_error(s, m, buf); 03398 ast_channel_unlock(ch1); 03399 return 0; 03400 } 03401 03402 if (!ast_strlen_zero(timeout)) { 03403 sscanf(timeout, "%30d", &to); 03404 } 03405 03406 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 03407 if (!res) { 03408 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 03409 astman_send_ack(s, m, "Park successful"); 03410 } else { 03411 astman_send_error(s, m, "Park failure"); 03412 } 03413 03414 ast_channel_unlock(ch1); 03415 ast_channel_unlock(ch2); 03416 03417 return 0; 03418 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 3319 of file res_features.c.
References ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::name, parkeduser::next, parking_lock, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.
Referenced by load_module().
03320 { 03321 struct parkeduser *cur; 03322 const char *id = astman_get_header(m, "ActionID"); 03323 char idText[256] = ""; 03324 03325 if (!ast_strlen_zero(id)) 03326 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 03327 03328 astman_send_ack(s, m, "Parked calls will follow"); 03329 03330 ast_mutex_lock(&parking_lock); 03331 03332 for (cur = parkinglot; cur; cur = cur->next) { 03333 astman_append(s, "Event: ParkedCall\r\n" 03334 "Exten: %d\r\n" 03335 "Channel: %s\r\n" 03336 "From: %s\r\n" 03337 "Timeout: %ld\r\n" 03338 "CallerID: %s\r\n" 03339 "CallerIDName: %s\r\n" 03340 "%s" 03341 "\r\n", 03342 cur->parkingnum, cur->chan->name, cur->peername, 03343 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 03344 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 03345 S_OR(cur->chan->cid.cid_name, ""), 03346 idText); 03347 } 03348 03349 astman_append(s, 03350 "Event: ParkedCallsComplete\r\n" 03351 "%s" 03352 "\r\n",idText); 03353 03354 ast_mutex_unlock(&parking_lock); 03355 03356 return RESULT_SUCCESS; 03357 }
static int masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
int | play_announcement, | |||
const char * | orig_chan_name | |||
) | [static] |
Definition at line 736 of file res_features.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_copy_string(), ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), parkeduser::chan, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_PARKFAILED, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, ast_channel::name, park_call_full(), park_space_reserve(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.
Referenced by ast_masq_park_call(), and masq_park_call_announce().
00737 { 00738 struct ast_channel *chan; 00739 struct ast_frame *f; 00740 struct parkeduser *pu; 00741 int park_status; 00742 00743 if ((pu = park_space_reserve(rchan)) == NULL) { 00744 if (peer) 00745 ast_stream_and_wait(peer, "beeperr", peer->language, ""); 00746 return FEATURE_RETURN_PARKFAILED; 00747 } 00748 00749 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00750 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00751 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00752 return -1; 00753 } 00754 00755 /* Make formats okay */ 00756 chan->readformat = rchan->readformat; 00757 chan->writeformat = rchan->writeformat; 00758 ast_channel_masquerade(chan, rchan); 00759 00760 /* Setup the extensions and such */ 00761 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00762 00763 /* Setup the macro extension and such */ 00764 ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext)); 00765 ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten)); 00766 chan->macropriority = rchan->macropriority; 00767 00768 /* Make the masq execute */ 00769 if ((f = ast_read(chan))) { 00770 ast_frfree(f); 00771 } 00772 00773 if (peer == rchan) { 00774 peer = chan; 00775 } 00776 00777 if (peer && (!play_announcement || !orig_chan_name)) { 00778 /* chan is the channel being parked, peer is the effective park-er */ 00779 orig_chan_name = ast_strdupa(peer->name); 00780 } 00781 00782 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu); 00783 if (park_status == 1) { 00784 /* would be nice to play: "invalid parking extension" */ 00785 ast_hangup(chan); 00786 return -1; 00787 } 00788 00789 return 0; 00790 }
static int masq_park_call_announce | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
const char * | orig_chan_name | |||
) | [static] |
Definition at line 797 of file res_features.c.
References masq_park_call().
Referenced by builtin_blindtransfer(), builtin_parkcall(), and park_call_exec().
00798 { 00799 return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name); 00800 }
static int metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 504 of file res_features.c.
References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_log(), ast_strdupa, context, exten, LOG_DEBUG, and option_debug.
Referenced by load_module().
00505 { 00506 int res = AST_DEVICE_INVALID; 00507 char *context = ast_strdupa(data); 00508 char *exten; 00509 00510 exten = strsep(&context, "@"); 00511 if (!context) 00512 return res; 00513 00514 if (option_debug > 3) 00515 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context); 00516 00517 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00518 00519 if (!res) 00520 return AST_DEVICE_NOT_INUSE; 00521 else 00522 return AST_DEVICE_INUSE; 00523 }
static void notify_metermaids | ( | char * | exten, | |
char * | context | |||
) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 493 of file res_features.c.
References ast_device_state_changed(), ast_log(), LOG_DEBUG, and option_debug.
Referenced by do_parking_thread(), park_call_full(), and park_exec().
00494 { 00495 if (option_debug > 3) 00496 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context); 00497 00498 /* Send notification to devicestate subsystem */ 00499 ast_device_state_changed("park:%s@%s", exten, context); 00500 return; 00501 }
static void park_add_hints | ( | char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Add parking hints for all defined parking lots.
Definition at line 3480 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, and PRIORITY_HINT.
03481 { 03482 int numext; 03483 char device[AST_MAX_EXTENSION]; 03484 char exten[10]; 03485 03486 for (numext = start; numext <= stop; numext++) { 03487 snprintf(exten, sizeof(exten), "%d", numext); 03488 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 03489 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 03490 } 03491 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 3009 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_copy_string(), AST_MAX_EXTENSION, ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_module_user::chan, ast_channel::exten, masq_park_call_announce(), ast_channel::name, orig_exten(), and ast_channel::priority.
Referenced by load_module().
03010 { 03011 /* Cache the original channel name in case we get masqueraded in the middle 03012 * of a park--it is still theoretically possible for a transfer to happen before 03013 * we get here, but it is _really_ unlikely */ 03014 char *orig_chan_name = ast_strdupa(chan->name); 03015 char orig_exten[AST_MAX_EXTENSION]; 03016 int orig_priority = chan->priority; 03017 03018 /* Data is unused at the moment but could contain a parking 03019 lot context eventually */ 03020 int res = 0; 03021 struct ast_module_user *u; 03022 03023 u = ast_module_user_add(chan); 03024 03025 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 03026 03027 /* Setup the exten/priority to be s/1 since we don't know 03028 where this call should return */ 03029 strcpy(chan->exten, "s"); 03030 chan->priority = 1; 03031 /* Answer if call is not up */ 03032 if (chan->_state != AST_STATE_UP) 03033 res = ast_answer(chan); 03034 /* Sleep to allow VoIP streams to settle down */ 03035 if (!res) 03036 res = ast_safe_sleep(chan, 1000); 03037 /* Park the call */ 03038 if (!res) { 03039 res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name); 03040 /* Continue on in the dialplan */ 03041 if (res == 1) { 03042 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 03043 chan->priority = orig_priority; 03044 res = 0; 03045 } else if (!res) { 03046 res = 1; 03047 } 03048 } 03049 03050 ast_module_user_remove(u); 03051 03052 return res; 03053 }
static int park_call_full | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
const char * | orig_chan_name, | |||
struct parkeduser * | pu | |||
) | [static] |
Definition at line 596 of file res_features.c.
References adsi_announce_park(), 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_create(), ast_context_find(), AST_CONTROL_HOLD, ast_copy_string(), AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_get_channel_by_name_locked(), ast_indicate_data(), ast_log(), ast_say_digits(), ast_set_flag, ast_strlen_zero(), ast_tvnow(), ast_verbose(), 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, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, option_verbose, park_space_reserve(), parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, S_OR, parkeduser::start, strdup, ast_channel::tech, ast_channel_tech::type, and VERBOSE_PREFIX_2.
Referenced by ast_park_call(), and masq_park_call().
00597 { 00598 struct ast_context *con; 00599 int parkingnum_copy; 00600 const char *event_from; 00601 00602 /* Get a valid space if not already done */ 00603 if (pu == NULL) 00604 pu = park_space_reserve(chan); 00605 if (pu == NULL) 00606 return 1; /* Continue execution if possible */ 00607 00608 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum); 00609 00610 chan->appl = "Parked Call"; 00611 chan->data = NULL; 00612 00613 pu->chan = chan; 00614 00615 /* Put the parked channel on hold if we have two different channels */ 00616 if (chan != peer) { 00617 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00618 S_OR(parkmohclass, NULL), 00619 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00620 } 00621 00622 pu->start = ast_tvnow(); 00623 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00624 if (extout) 00625 *extout = pu->parkingnum; 00626 00627 if (peer) { 00628 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels 00629 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking 00630 and we need the callback name to be that of transferer. Since local,1/2 have the same 00631 name we can be tricky and just grab the bridged channel from the other side of the local 00632 */ 00633 if (!strcasecmp(peer->tech->type, "Local")) { 00634 struct ast_channel *tmpchan, *base_peer; 00635 char other_side[AST_CHANNEL_NAME]; 00636 char *c; 00637 ast_copy_string(other_side, S_OR(orig_chan_name, peer->name), sizeof(other_side)); 00638 if ((c = strrchr(other_side, ','))) { 00639 *++c = '1'; 00640 } 00641 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) { 00642 if ((base_peer = ast_bridged_channel(tmpchan))) { 00643 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 00644 } 00645 ast_channel_unlock(tmpchan); 00646 } 00647 } else { 00648 ast_copy_string(pu->peername, S_OR(orig_chan_name, peer->name), sizeof(pu->peername)); 00649 } 00650 } 00651 00652 /* Remember what had been dialed, so that if the parking 00653 expires, we try to come back to the same place */ 00654 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00655 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00656 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00657 parkingnum_copy = pu->parkingnum; 00658 00659 /* Mark channel as parked */ 00660 pbx_builtin_setvar_helper(pu->chan, "PARKED_CALL", "1"); 00661 00662 /* If parking a channel directly (peer == chan), don't quite yet get parking running on it. 00663 * All parking lot entires are put into the parking lot with notquiteyet on. */ 00664 if (peer != chan) 00665 pu->notquiteyet = 0; 00666 00667 if (option_verbose > 1) 00668 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); 00669 00670 if (peer) { 00671 event_from = peer->name; 00672 } else { 00673 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 00674 } 00675 00676 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00677 "Exten: %s\r\n" 00678 "Channel: %s\r\n" 00679 "From: %s\r\n" 00680 "Timeout: %ld\r\n" 00681 "CallerID: %s\r\n" 00682 "CallerIDName: %s\r\n", 00683 pu->parkingexten, pu->chan->name, event_from ? event_from : "", 00684 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00685 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00686 S_OR(pu->chan->cid.cid_name, "<unknown>") 00687 ); 00688 00689 if (peer && adsipark && ast_adsi_available(peer)) { 00690 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00691 ast_adsi_unload_session(peer); 00692 } 00693 00694 con = ast_context_find(parking_con); 00695 if (!con) 00696 con = ast_context_create(NULL, parking_con, registrar); 00697 if (!con) /* Still no context? Bad */ 00698 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00699 if (con) { 00700 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free_ptr, registrar)) { 00701 notify_metermaids(pu->parkingexten, parking_con); 00702 } 00703 } 00704 00705 /* Wake up the (presumably poll()ing) thread */ 00706 pthread_kill(parking_thread, SIGURG); 00707 00708 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 00709 if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) { 00710 /* Make sure we don't start saying digits to the channel being parked */ 00711 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00712 /* Tell the peer channel the number of the parking space */ 00713 ast_say_digits(peer, parkingnum_copy, "", peer->language); 00714 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00715 } 00716 00717 if (peer == chan) { /* pu->notquiteyet = 1 */ 00718 /* Wake up parking thread if we're really done */ 00719 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00720 S_OR(parkmohclass, NULL), 00721 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00722 pu->notquiteyet = 0; 00723 pthread_kill(parking_thread, SIGURG); 00724 } 00725 return 0; 00726 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Pickup parked call.
Definition at line 3056 of file res_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_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_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_datastore::data, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_caller, free, ast_channel::language, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.
Referenced by load_module().
03057 { 03058 int res = 0; 03059 struct ast_module_user *u; 03060 struct ast_channel *peer=NULL; 03061 struct parkeduser *pu, *pl=NULL; 03062 struct ast_context *con; 03063 03064 int park; 03065 struct ast_bridge_config config; 03066 03067 if (!data) { 03068 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 03069 return -1; 03070 } 03071 03072 u = ast_module_user_add(chan); 03073 03074 park = atoi((char *)data); 03075 ast_mutex_lock(&parking_lock); 03076 pu = parkinglot; 03077 while(pu) { 03078 if (pu->parkingnum == park && !pu->notquiteyet) { 03079 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 03080 ast_mutex_unlock(&parking_lock); 03081 ast_module_user_remove(u); 03082 return -1; 03083 } 03084 if (pl) 03085 pl->next = pu->next; 03086 else 03087 parkinglot = pu->next; 03088 break; 03089 } 03090 pl = pu; 03091 pu = pu->next; 03092 } 03093 ast_mutex_unlock(&parking_lock); 03094 if (pu) { 03095 peer = pu->chan; 03096 con = ast_context_find(parking_con); 03097 if (con) { 03098 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 03099 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 03100 else 03101 notify_metermaids(pu->parkingexten, parking_con); 03102 } else 03103 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 03104 03105 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 03106 "Exten: %s\r\n" 03107 "Channel: %s\r\n" 03108 "From: %s\r\n" 03109 "CallerID: %s\r\n" 03110 "CallerIDName: %s\r\n", 03111 pu->parkingexten, pu->chan->name, chan->name, 03112 S_OR(pu->chan->cid.cid_num, "<unknown>"), 03113 S_OR(pu->chan->cid.cid_name, "<unknown>") 03114 ); 03115 03116 free(pu); 03117 } 03118 /* JK02: it helps to answer the channel if not already up */ 03119 if (chan->_state != AST_STATE_UP) 03120 ast_answer(chan); 03121 03122 if (peer) { 03123 struct ast_datastore *features_datastore; 03124 struct ast_dial_features *dialfeatures = NULL; 03125 03126 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 03127 03128 if (!ast_strlen_zero(courtesytone)) { 03129 int error = 0; 03130 ast_indicate(peer, AST_CONTROL_UNHOLD); 03131 if (parkedplay == 0) { 03132 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 03133 } else if (parkedplay == 1) { 03134 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 03135 } else if (parkedplay == 2) { 03136 if (!ast_streamfile(chan, courtesytone, chan->language) && 03137 !ast_streamfile(peer, courtesytone, chan->language)) { 03138 /*! \todo XXX we would like to wait on both! */ 03139 res = ast_waitstream(chan, ""); 03140 if (res >= 0) 03141 res = ast_waitstream(peer, ""); 03142 if (res < 0) 03143 error = 1; 03144 } 03145 } 03146 if (error) { 03147 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 03148 ast_hangup(peer); 03149 ast_module_user_remove(u); 03150 return -1; 03151 } 03152 } else 03153 ast_indicate(peer, AST_CONTROL_UNHOLD); 03154 03155 res = ast_channel_make_compatible(chan, peer); 03156 if (res < 0) { 03157 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 03158 ast_hangup(peer); 03159 ast_module_user_remove(u); 03160 return -1; 03161 } 03162 /* This runs sorta backwards, since we give the incoming channel control, as if it 03163 were the person called. */ 03164 if (option_verbose > 2) 03165 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 03166 03167 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03168 ast_cdr_setdestchan(chan->cdr, peer->name); 03169 memset(&config, 0, sizeof(struct ast_bridge_config)); 03170 03171 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 03172 ast_channel_lock(peer); 03173 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 03174 dialfeatures = features_datastore->data; 03175 } 03176 ast_channel_unlock(peer); 03177 03178 /* When the datastores for both caller and callee are created, both the callee and caller channels 03179 * use the features_caller flag variable to represent themselves. With that said, the config.features_callee 03180 * flags should be copied from the datastore's caller feature flags regardless if peer was a callee 03181 * or caller. */ 03182 if (dialfeatures) { 03183 ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 03184 } 03185 03186 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03187 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 03188 } 03189 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03190 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 03191 } 03192 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03193 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 03194 } 03195 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03196 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 03197 } 03198 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03199 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 03200 } 03201 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03202 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 03203 } 03204 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03205 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 03206 } 03207 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03208 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 03209 } 03210 res = ast_bridge_call(chan, peer, &config); 03211 03212 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03213 ast_cdr_setdestchan(chan->cdr, peer->name); 03214 03215 /* Simulate the PBX hanging up */ 03216 ast_hangup(peer); 03217 ast_module_user_remove(u); 03218 return -1; 03219 } else { 03220 /*! \todo XXX Play a message XXX */ 03221 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 03222 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 03223 if (option_verbose > 2) 03224 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 03225 res = -1; 03226 } 03227 03228 ast_module_user_remove(u); 03229 03230 return -1; 03231 }
static struct parkeduser* park_space_reserve | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 525 of file res_features.c.
References ast_calloc, ast_exists_extension(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), parkeduser::chan, free, LOG_WARNING, parkeduser::next, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, and pbx_builtin_getvar_helper().
Referenced by masq_park_call(), and park_call_full().
00526 { 00527 struct parkeduser *pu, *cur; 00528 int i, parking_space = -1, parking_range; 00529 const char *parkingexten; 00530 00531 /* Allocate memory for parking data */ 00532 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00533 return NULL; 00534 00535 /* Lock parking lot */ 00536 ast_mutex_lock(&parking_lock); 00537 /* Check for channel variable PARKINGEXTEN */ 00538 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00539 if (!ast_strlen_zero(parkingexten)) { 00540 /*!\note The API forces us to specify a numeric parking slot, even 00541 * though the architecture would tend to support non-numeric extensions 00542 * (as are possible with SIP, for example). Hence, we enforce that 00543 * limitation here. If extout was not numeric, we could permit 00544 * arbitrary non-numeric extensions. 00545 */ 00546 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) { 00547 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); 00548 ast_mutex_unlock(&parking_lock); 00549 free(pu); 00550 return NULL; 00551 } 00552 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00553 00554 if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) { 00555 ast_mutex_unlock(&parking_lock); 00556 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00557 free(pu); 00558 return NULL; 00559 } 00560 } else { 00561 /* Select parking space within range */ 00562 parking_range = parking_stop - parking_start+1; 00563 for (i = 0; i < parking_range; i++) { 00564 parking_space = (i + parking_offset) % parking_range + parking_start; 00565 cur = parkinglot; 00566 while(cur) { 00567 if (cur->parkingnum == parking_space) 00568 break; 00569 cur = cur->next; 00570 } 00571 if (!cur) 00572 break; 00573 } 00574 00575 if (!(i < parking_range)) { 00576 ast_log(LOG_WARNING, "No more parking spaces\n"); 00577 ast_mutex_unlock(&parking_lock); 00578 free(pu); 00579 return NULL; 00580 } 00581 /* Set pointer for next parking */ 00582 if (parkfindnext) 00583 parking_offset = parking_space - parking_start + 1; 00584 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00585 } 00586 00587 pu->notquiteyet = 1; 00588 pu->parkingnum = parking_space; 00589 pu->next = parkinglot; 00590 parkinglot = pu; 00591 ast_mutex_unlock(&parking_lock); 00592 00593 return pu; 00594 }
Definition at line 2014 of file res_features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
02015 { 02016 struct ast_cdr *cdr_orig = cdr; 02017 while (cdr) { 02018 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 02019 return cdr; 02020 cdr = cdr->next; 02021 } 02022 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 02023 }
static int pickup_do | ( | struct ast_channel * | chan, | |
struct ast_channel * | target | |||
) | [static] |
Definition at line 3426 of file res_features.c.
References ast_answer(), ast_channel_masquerade(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), LOG_DEBUG, LOG_WARNING, ast_channel::name, and option_debug.
03427 { 03428 if (option_debug) 03429 ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name); 03430 03431 if (ast_answer(chan)) { 03432 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 03433 return -1; 03434 } 03435 03436 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 03437 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 03438 return -1; 03439 } 03440 03441 if (ast_channel_masquerade(target, chan)) { 03442 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); 03443 return -1; 03444 } 03445 03446 return 0; 03447 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 2703 of file res_features.c.
References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event(), ast_channel::name, and S_OR.
Referenced by do_parking_thread().
02704 { 02705 manager_event(EVENT_FLAG_CALL, s, 02706 "Exten: %s\r\n" 02707 "Channel: %s\r\n" 02708 "CallerID: %s\r\n" 02709 "CallerIDName: %s\r\n\r\n", 02710 parkingexten, 02711 chan->name, 02712 S_OR(chan->cid.cid_num, "<unknown>"), 02713 S_OR(chan->cid.cid_name, "<unknown>") 02714 ); 02715 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
Definition at line 961 of file res_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().
00962 { 00963 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00964 if (ast_strlen_zero(s)) 00965 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00966 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */ 00967 s = transferer->macrocontext; 00968 if (ast_strlen_zero(s)) 00969 s = transferer->context; 00970 return s; 00971 }
static int reload | ( | void | ) | [static] |
Definition at line 3750 of file res_features.c.
References load_config().
03751 { 03752 return load_config(); 03753 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1515 of file res_features.c.
References ast_copy_string(), ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, exten, FEATURES_COUNT, and features_lock.
01516 { 01517 int x, res = -1; 01518 01519 ast_rwlock_wrlock(&features_lock); 01520 for (x = 0; x < FEATURES_COUNT; x++) { 01521 if (strcasecmp(builtin_features[x].sname, name)) 01522 continue; 01523 01524 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01525 res = 0; 01526 break; 01527 } 01528 ast_rwlock_unlock(&features_lock); 01529 01530 return res; 01531 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 2025 of file res_features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), config, and LOG_WARNING.
Referenced by ast_bridge_call().
02026 { 02027 const char *feature; 02028 02029 if (ast_strlen_zero(features)) { 02030 return; 02031 } 02032 02033 for (feature = features; *feature; feature++) { 02034 switch (*feature) { 02035 case 'T' : 02036 case 't' : 02037 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 02038 break; 02039 case 'K' : 02040 case 'k' : 02041 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 02042 break; 02043 case 'H' : 02044 case 'h' : 02045 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 02046 break; 02047 case 'W' : 02048 case 'w' : 02049 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 02050 break; 02051 default : 02052 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 02053 } 02054 } 02055 }
static void set_c_e_p | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | ext, | |||
int | pri | |||
) | [static] |
store context, priority and extension
Definition at line 398 of file res_features.c.
References ast_copy_string(), ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by builtin_blindtransfer(), do_parking_thread(), and masq_park_call().
00399 { 00400 ast_copy_string(chan->context, context, sizeof(chan->context)); 00401 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00402 chan->priority = pri; 00403 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 1680 of file res_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, builtin_features, config, ast_call_feature::feature_mask, FEATURES_COUNT, features_lock, find_dynamic_feature(), and pbx_builtin_getvar_helper().
Referenced by ast_bridge_call().
01681 { 01682 int x; 01683 01684 ast_clear_flag(config, AST_FLAGS_ALL); 01685 01686 ast_rwlock_rdlock(&features_lock); 01687 for (x = 0; x < FEATURES_COUNT; x++) { 01688 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 01689 continue; 01690 01691 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01692 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01693 01694 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01695 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01696 } 01697 ast_rwlock_unlock(&features_lock); 01698 01699 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01700 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01701 01702 if (dynamic_features) { 01703 char *tmp = ast_strdupa(dynamic_features); 01704 char *tok; 01705 struct ast_call_feature *feature; 01706 01707 /* while we have a feature */ 01708 while ((tok = strsep(&tmp, "#"))) { 01709 AST_RWLIST_RDLOCK(&feature_list); 01710 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01711 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01712 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01713 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01714 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01715 } 01716 AST_RWLIST_UNLOCK(&feature_list); 01717 } 01718 } 01719 } 01720 }
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
Definition at line 805 of file res_features.c.
References parkeduser::chan, and FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
00807 { 00808 if (sense == FEATURE_SENSE_PEER) { 00809 *caller = peer; 00810 *callee = chan; 00811 } else { 00812 *callee = peer; 00813 *caller = chan; 00814 } 00815 }
static int unload_module | ( | void | ) | [static] |
Definition at line 3781 of file res_features.c.
References ast_cli_unregister_multiple(), ast_context_destroy(), ast_context_find(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), and cli_features.
03782 { 03783 struct ast_context *con; 03784 ast_module_user_hangup_all(); 03785 03786 ast_manager_unregister("ParkedCalls"); 03787 ast_manager_unregister("Park"); 03788 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03789 ast_unregister_application(parkcall); 03790 ast_devstate_prov_del("Park"); 03791 /* Delete park-dial context */ 03792 con = ast_context_find(parking_con_dial); 03793 if(con) 03794 ast_context_destroy(con, registrar); 03795 return ast_unregister_application(parkedcall); 03796 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1505 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, exten, FEATURES_COUNT, and features_lock.
01506 { 01507 int x; 01508 01509 ast_rwlock_wrlock(&features_lock); 01510 for (x = 0; x < FEATURES_COUNT; x++) 01511 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01512 ast_rwlock_unlock(&features_lock); 01513 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Call Features Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 3802 of file res_features.c.
int adsipark [static] |
Definition at line 177 of file res_features.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 3802 of file res_features.c.
int atxfernoanswertimeout [static] |
Definition at line 182 of file res_features.c.
struct ast_call_feature builtin_features[] [static] |
Definition at line 1378 of file res_features.c.
Referenced by feature_interpret_helper(), feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().
struct ast_cli_entry cli_features[] [static] |
Definition at line 3308 of file res_features.c.
struct ast_cli_entry cli_show_features_deprecated [static] |
Initial value:
{ { "show", "features", NULL }, handle_showfeatures, NULL, NULL }
Definition at line 3303 of file res_features.c.
char courtesytone[256] [static] |
Courtesy tone
Definition at line 165 of file res_features.c.
char* descrip [static] |
Initial value:
"ParkedCall(exten):" "Used to connect to a parked call. This application is always\n" "registered internally and does not need to be explicitly added\n" "into the dialplan, although you should include the 'parkedcalls'\n" "context.\n"
Definition at line 189 of file res_features.c.
char* descrip2 [static] |
Definition at line 199 of file res_features.c.
Initial value:
{ .type = "dial-features", .destroy = dial_features_destroy, .duplicate = dial_features_duplicate, }
Definition at line 374 of file res_features.c.
Referenced by add_features_datastores(), builtin_atxfer(), do_parking_thread(), and park_exec().
int featuredigittimeout [static] |
Definition at line 180 of file res_features.c.
ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static] |
Definition at line 1376 of file res_features.c.
Referenced by feature_interpret_helper(), feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().
char mandescr_park[] [static] |
Definition at line 3359 of file res_features.c.
struct ast_app* monitor_app = NULL [static] |
Definition at line 210 of file res_features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 211 of file res_features.c.
int parkaddhints = 0 [static] |
Add parking hints automatically
Definition at line 150 of file res_features.c.
char* parkcall = PARK_APP_NAME [static] |
Definition at line 195 of file res_features.c.
char* parkedcall = "ParkedCall" [static] |
Definition at line 148 of file res_features.c.
int parkedcallhangup [static] |
Who can DISCONNECT after picking up a parked call
Definition at line 162 of file res_features.c.
int parkedcallrecording [static] |
Who can AUTOMON after picking up a parked call
Definition at line 163 of file res_features.c.
int parkedcallreparking [static] |
Who can PARKCALL after picking up a parked call
Definition at line 161 of file res_features.c.
int parkedcalltransfers [static] |
Who can REDIRECT after picking up a parked a call
Definition at line 160 of file res_features.c.
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 166 of file res_features.c.
int parkfindnext [static] |
Definition at line 175 of file res_features.c.
char parking_con[AST_MAX_EXTENSION] [static] |
Context for which parking is made accessible
Definition at line 152 of file res_features.c.
char parking_con_dial[AST_MAX_EXTENSION] [static] |
Context for dialback for parking (KLUDGE)
Definition at line 153 of file res_features.c.
char parking_ext[AST_MAX_EXTENSION] [static] |
Extension you type to park the call
Definition at line 154 of file res_features.c.
ast_mutex_t parking_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static] |
protects all static variables above
Definition at line 230 of file res_features.c.
Referenced by do_parking_thread(), handle_parkedcalls(), manager_parking_status(), park_exec(), and park_space_reserve().
int parking_offset [static] |
Definition at line 174 of file res_features.c.
int parking_start [static] |
First available extension for parking
Definition at line 157 of file res_features.c.
int parking_stop [static] |
Last available extension for parking
Definition at line 158 of file res_features.c.
pthread_t parking_thread [static] |
Definition at line 232 of file res_features.c.
struct parkeduser* parkinglot [static] |
Definition at line 228 of file res_features.c.
Referenced by do_parking_thread(), handle_parkedcalls(), manager_parking_status(), park_exec(), and park_space_reserve().
char parkingretalertinfo[256] [static] |
Distinctive ring if chantech = SIP (adds a SIP AlertInfo header)
Definition at line 172 of file res_features.c.
char parkingretcidname[256] [static] |
Callerid name of returned parked call
Definition at line 170 of file res_features.c.
char parkingretdahdiring[3] [static] |
Distinctive ring if chantech = DAHDI
Definition at line 171 of file res_features.c.
int parkingtime = DEFAULT_PARK_TIME [static] |
No more than 45 seconds parked before you do something with them
Definition at line 151 of file res_features.c.
char parkmohclass[MAX_MUSICCLASS] [static] |
Music class used for parking
Definition at line 156 of file res_features.c.
char pickup_ext[AST_MAX_EXTENSION] [static] |
Call pickup extension
Definition at line 155 of file res_features.c.
char* registrar = "res_features" [static] |
Registrar for operations
Definition at line 184 of file res_features.c.
char showfeatures_help[] [static] |
Initial value:
"Usage: feature list\n" " Lists currently configured features.\n"
Definition at line 3271 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 3299 of file res_features.c.
char* synopsis = "Answer a parked call" [static] |
Definition at line 187 of file res_features.c.
char* synopsis2 = "Park yourself" [static] |
Definition at line 197 of file res_features.c.
int transferdigittimeout [static] |
Definition at line 179 of file res_features.c.
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 168 of file res_features.c.
char xfersound[256] [static] |
Call transfer sound
Definition at line 167 of file res_features.c.