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