#include "asterisk.h"
#include <pthread.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) } |
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 | |
static struct ast_channel * | ast_feature_request_and_dial (struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language) |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
int | ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout) |
Park a call and read back parked location. | |
char * | ast_parking_ext (void) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
static void | ast_unregister_features (void) |
Remove all features in the list. | |
static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Attended transfer (). | |
static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
support routing for one touch call parking | |
static char * | callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len) |
static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
static void | check_goto_on_transfer (struct ast_channel *chan) |
static void | cmd_atxfer (struct ast_channel *a, struct ast_channel *b, struct ast_bridge_config *conf, struct ast_channel *who, char *xferto) |
static void | dial_features_destroy (void *data) |
static void * | dial_features_duplicate (void *data) |
static int | do_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, int sense, const char *toExt, const char *toCont) |
Attended transfer implementation. | |
static void * | do_parking_thread (void *ignore) |
Take care of parked calls and unpark them if needed. | |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
exec an app by feature | |
static int | feature_interpret (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, int operation, struct ast_call_feature *feature) |
Helper function for feature_interpret and ast_feature_detect. | |
static struct ast_call_feature * | find_dynamic_feature (const char *name) |
find a 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 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 = "6989f2ec67f8497e38c12890500c525b" , .load = load_module, .unload = unload_module, .reload = reload, } |
static int | adsipark |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static int | atxfernoanswertimeout |
static struct ast_call_feature | builtin_features [] |
static struct ast_cli_entry | cli_features [] |
static struct ast_cli_entry | cli_show_features_deprecated |
static char | courtesytone [256] |
static char * | descrip |
static char * | descrip2 |
ast_datastore_info | dial_features_info |
static int | featuredigittimeout |
static ast_rwlock_t | features_lock = PTHREAD_RWLOCK_INITIALIZER |
static char | mandescr_park [] |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static int | parkaddhints = 0 |
static char * | parkcall = PARK_APP_NAME |
static char * | parkedcall = "ParkedCall" |
static int | parkedcallhangup |
static int | parkedcallrecording |
static int | parkedcallreparking |
static int | parkedcalltransfers |
static int | parkedplay = 0 |
static int | parkfindnext |
static char | parking_con [AST_MAX_EXTENSION] |
static char | parking_con_dial [AST_MAX_EXTENSION] |
static char | parking_ext [AST_MAX_EXTENSION] |
static ast_mutex_t | parking_lock = { PTHREAD_MUTEX_INITIALIZER , 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, 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 72 of file res_features.c.
#define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define DEFAULT_PARK_TIME 45000 |
Definition at line 67 of file res_features.c.
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURE_RETURN_HANGUP -1 |
Definition at line 75 of file res_features.c.
#define FEATURE_RETURN_KEEPTRYING 24 |
Definition at line 80 of file res_features.c.
#define FEATURE_RETURN_PARKFAILED 25 |
Definition at line 81 of file res_features.c.
#define FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 77 of file res_features.c.
#define FEATURE_RETURN_STOREDIGITS 22 |
Definition at line 78 of file res_features.c.
#define FEATURE_RETURN_SUCCESS 23 |
Definition at line 79 of file res_features.c.
#define FEATURE_RETURN_SUCCESSBREAK 0 |
Definition at line 76 of file res_features.c.
#define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Definition at line 1106 of file res_features.c.
Referenced by ast_feature_request_and_dial(), feature_interpret_helper(), 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 83 of file res_features.c.
00083 { 00084 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00085 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00086 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00087 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00088 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00089 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00090 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 3215 of file res_features.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 3215 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 1644 of file res_features.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, AST_FLAGS_ALL, ast_log(), config, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, and LOG_WARNING.
Referenced by ast_bridge_call().
01645 { 01646 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 01647 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 01648 01649 ast_channel_lock(caller); 01650 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 01651 ast_channel_unlock(caller); 01652 if (!ds_caller_features) { 01653 if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 01654 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 01655 return; 01656 } 01657 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 01658 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 01659 ast_channel_datastore_free(ds_caller_features); 01660 return; 01661 } 01662 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 01663 caller_features->is_caller = 1; 01664 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 01665 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 01666 ds_caller_features->data = caller_features; 01667 ast_channel_lock(caller); 01668 ast_channel_datastore_add(caller, ds_caller_features); 01669 ast_channel_unlock(caller); 01670 } else { 01671 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 01672 * flags over from the atxfer to the caller */ 01673 return; 01674 } 01675 01676 ast_channel_lock(callee); 01677 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 01678 ast_channel_unlock(callee); 01679 if (!ds_callee_features) { 01680 if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 01681 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 01682 return; 01683 } 01684 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 01685 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 01686 ast_channel_datastore_free(ds_callee_features); 01687 return; 01688 } 01689 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 01690 callee_features->is_caller = 0; 01691 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 01692 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 01693 ds_callee_features->data = callee_features; 01694 ast_channel_lock(callee); 01695 ast_channel_datastore_add(callee, ds_callee_features); 01696 ast_channel_unlock(callee); 01697 } 01698 01699 return; 01700 }
static int adsi_announce_park | ( | struct ast_channel * | chan, | |
char * | parkingexten | |||
) | [static] |
Definition at line 301 of file res_features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
00302 { 00303 int res; 00304 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00305 char tmp[256]; 00306 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00307 00308 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00309 message[0] = tmp; 00310 res = ast_adsi_load_session(chan, NULL, 0, 1); 00311 if (res == -1) 00312 return res; 00313 return ast_adsi_print(chan, message, justify, 1); 00314 }
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 1711 of file res_features.c.
References ast_channel::_state, ast_channel::accountcode, ast_cdr::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_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NOANSWER, 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_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_ATXFERCMD, 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_OPTION_FLAG_REQUEST, 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_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, cmd_atxfer(), config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_interpret(), FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, ast_option_header::option, option_debug, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, VERBOSE_PREFIX_2, and ast_channel::visible_indication.
Referenced by app_exec(), ast_bridge_call_thread(), do_atxfer(), and park_exec().
01712 { 01713 /* Copy voice back and forth between the two channels. Give the peer 01714 the ability to transfer calls with '#<extension' syntax. */ 01715 struct ast_frame *f; 01716 struct ast_channel *who; 01717 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01718 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01719 char orig_channame[AST_MAX_EXTENSION]; 01720 char orig_peername[AST_MAX_EXTENSION]; 01721 01722 int res; 01723 int diff; 01724 int hasfeatures=0; 01725 int hadfeatures=0; 01726 int autoloopflag; 01727 struct ast_option_header *aoh; 01728 struct ast_bridge_config backup_config; 01729 struct ast_cdr *bridge_cdr = NULL; 01730 struct ast_cdr *orig_peer_cdr = NULL; 01731 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 01732 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 01733 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01734 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01735 01736 memset(&backup_config, 0, sizeof(backup_config)); 01737 01738 config->start_time = ast_tvnow(); 01739 01740 if (chan && peer) { 01741 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01742 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01743 } else if (chan) { 01744 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01745 } 01746 01747 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 01748 add_features_datastores(chan, peer, config); 01749 01750 /* This is an interesting case. One example is if a ringing channel gets redirected to 01751 * an extension that picks up a parked call. This will make sure that the call taken 01752 * out of parking gets told that the channel it just got bridged to is still ringing. */ 01753 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 01754 ast_indicate(peer, AST_CONTROL_RINGING); 01755 } 01756 01757 if (monitor_ok) { 01758 const char *monitor_exec; 01759 struct ast_channel *src = NULL; 01760 if (!monitor_app) { 01761 if (!(monitor_app = pbx_findapp("Monitor"))) 01762 monitor_ok=0; 01763 } 01764 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01765 src = chan; 01766 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01767 src = peer; 01768 if (monitor_app && src) { 01769 char *tmp = ast_strdupa(monitor_exec); 01770 pbx_exec(src, monitor_app, tmp); 01771 } 01772 } 01773 01774 set_config_flags(chan, peer, config); 01775 config->firstpass = 1; 01776 01777 /* Answer if need be */ 01778 if (ast_answer(chan)) 01779 return -1; 01780 01781 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 01782 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 01783 orig_peer_cdr = peer_cdr; 01784 01785 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 01786 01787 if (chan_cdr) { 01788 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 01789 ast_cdr_update(chan); 01790 bridge_cdr = ast_cdr_dup(chan_cdr); 01791 /* rip any forked CDR's off of the chan_cdr and attach 01792 * them to the bridge_cdr instead */ 01793 bridge_cdr->next = chan_cdr->next; 01794 chan_cdr->next = NULL; 01795 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 01796 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 01797 if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) { 01798 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 01799 } 01800 } else { 01801 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 01802 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 01803 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 01804 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 01805 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 01806 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 01807 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 01808 ast_cdr_setcid(bridge_cdr, chan); 01809 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NOANSWER; 01810 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 01811 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 01812 /* Destination information */ 01813 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 01814 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 01815 if (peer_cdr) { 01816 bridge_cdr->start = peer_cdr->start; 01817 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 01818 } else { 01819 ast_cdr_start(bridge_cdr); 01820 } 01821 } 01822 /* peer_cdr->answer will be set when a macro runs on the peer; 01823 in that case, the bridge answer will be delayed while the 01824 macro plays on the peer channel. The peer answered the call 01825 before the macro started playing. To the phone system, 01826 this is billable time for the call, even tho the caller 01827 hears nothing but ringing while the macro does its thing. */ 01828 01829 /* Another case where the peer cdr's time will be set, is when 01830 A self-parks by pickup up phone and dialing 700, then B 01831 picks up A by dialing its parking slot; there may be more 01832 practical paths that get the same result, tho... in which 01833 case you get the previous answer time from the Park... which 01834 is before the bridge's start time, so I added in the 01835 tvcmp check to the if below */ 01836 01837 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 01838 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 01839 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 01840 if (chan_cdr) { 01841 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 01842 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 01843 } 01844 } else { 01845 ast_cdr_answer(bridge_cdr); 01846 if (chan_cdr) { 01847 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 01848 } 01849 } 01850 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 01851 if (chan_cdr) { 01852 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 01853 } 01854 if (peer_cdr) { 01855 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 01856 } 01857 } 01858 } 01859 01860 for (;;) { 01861 struct ast_channel *other; /* used later */ 01862 01863 res = ast_channel_bridge(chan, peer, config, &f, &who); 01864 01865 /* When frame is not set, we are probably involved in a situation 01866 where we've timed out. 01867 When frame is set, we'll come thru this code twice; once for DTMF_BEGIN 01868 and also for DTMF_END. If we flow into the following 'if' for both, then 01869 our wait times are cut in half, as both will subtract from the 01870 feature_timer. Not good! 01871 */ 01872 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 01873 /* Update time limit for next pass */ 01874 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01875 if (res == AST_BRIDGE_RETRY) { 01876 /* The feature fully timed out but has not been updated. Skip 01877 * the potential round error from the diff calculation and 01878 * explicitly set to expired. */ 01879 config->feature_timer = -1; 01880 } else { 01881 config->feature_timer -= diff; 01882 } 01883 01884 if (hasfeatures) { 01885 /* Running on backup config, meaning a feature might be being 01886 activated, but that's no excuse to keep things going 01887 indefinitely! */ 01888 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01889 if (option_debug) 01890 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01891 config->feature_timer = 0; 01892 who = chan; 01893 if (f) 01894 ast_frfree(f); 01895 f = NULL; 01896 res = 0; 01897 } else if (config->feature_timer <= 0) { 01898 /* Not *really* out of time, just out of time for 01899 digits to come in for features. */ 01900 if (option_debug) 01901 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01902 if (!ast_strlen_zero(peer_featurecode)) { 01903 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01904 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01905 } 01906 if (!ast_strlen_zero(chan_featurecode)) { 01907 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01908 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01909 } 01910 if (f) 01911 ast_frfree(f); 01912 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01913 if (!hasfeatures) { 01914 /* Restore original (possibly time modified) bridge config */ 01915 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01916 memset(&backup_config, 0, sizeof(backup_config)); 01917 } 01918 hadfeatures = hasfeatures; 01919 /* Continue as we were */ 01920 continue; 01921 } else if (!f) { 01922 /* The bridge returned without a frame and there is a feature in progress. 01923 * However, we don't think the feature has quite yet timed out, so just 01924 * go back into the bridge. */ 01925 continue; 01926 } 01927 } else { 01928 if (config->feature_timer <=0) { 01929 /* We ran out of time */ 01930 config->feature_timer = 0; 01931 who = chan; 01932 if (f) 01933 ast_frfree(f); 01934 f = NULL; 01935 res = 0; 01936 } 01937 } 01938 } 01939 if (res < 0) { 01940 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01941 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01942 goto before_you_go; 01943 } 01944 01945 if (!f || (f->frametype == AST_FRAME_CONTROL && 01946 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01947 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01948 res = -1; 01949 break; 01950 } 01951 /* many things should be sent to the 'other' channel */ 01952 other = (who == chan) ? peer : chan; 01953 if (f->frametype == AST_FRAME_CONTROL) { 01954 switch (f->subclass) { 01955 case AST_CONTROL_RINGING: 01956 case AST_CONTROL_FLASH: 01957 case -1: 01958 ast_indicate(other, f->subclass); 01959 break; 01960 case AST_CONTROL_HOLD: 01961 case AST_CONTROL_UNHOLD: 01962 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01963 break; 01964 case AST_CONTROL_OPTION: 01965 aoh = f->data; 01966 /* Forward option Requests */ 01967 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01968 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01969 f->datalen - sizeof(struct ast_option_header), 0); 01970 } 01971 break; 01972 case AST_CONTROL_ATXFERCMD: 01973 cmd_atxfer(chan, peer, config, who, f->data); 01974 break; 01975 } 01976 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01977 /* eat it */ 01978 } else if (f->frametype == AST_FRAME_DTMF) { 01979 char *featurecode; 01980 int sense; 01981 01982 hadfeatures = hasfeatures; 01983 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01984 if (who == chan) { 01985 sense = FEATURE_SENSE_CHAN; 01986 featurecode = chan_featurecode; 01987 } else { 01988 sense = FEATURE_SENSE_PEER; 01989 featurecode = peer_featurecode; 01990 } 01991 /*! append the event to featurecode. we rely on the string being zero-filled, and 01992 * not overflowing it. 01993 * \todo XXX how do we guarantee the latter ? 01994 */ 01995 featurecode[strlen(featurecode)] = f->subclass; 01996 /* Get rid of the frame before we start doing "stuff" with the channels */ 01997 ast_frfree(f); 01998 f = NULL; 01999 config->feature_timer = backup_config.feature_timer; 02000 res = feature_interpret(chan, peer, config, featurecode, sense); 02001 switch(res) { 02002 case FEATURE_RETURN_PASSDIGITS: 02003 ast_dtmf_stream(other, who, featurecode, 0); 02004 /* Fall through */ 02005 case FEATURE_RETURN_SUCCESS: 02006 memset(featurecode, 0, sizeof(chan_featurecode)); 02007 break; 02008 } 02009 if (res >= FEATURE_RETURN_PASSDIGITS) { 02010 res = 0; 02011 } else 02012 break; 02013 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02014 if (hadfeatures && !hasfeatures) { 02015 /* Restore backup */ 02016 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02017 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02018 } else if (hasfeatures) { 02019 if (!hadfeatures) { 02020 /* Backup configuration */ 02021 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02022 /* Setup temporary config options */ 02023 config->play_warning = 0; 02024 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02025 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02026 config->warning_freq = 0; 02027 config->warning_sound = NULL; 02028 config->end_sound = NULL; 02029 config->start_sound = NULL; 02030 config->firstpass = 0; 02031 } 02032 config->start_time = ast_tvnow(); 02033 config->feature_timer = featuredigittimeout; 02034 if (option_debug) 02035 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 02036 } 02037 } 02038 if (f) 02039 ast_frfree(f); 02040 02041 } 02042 before_you_go: 02043 02044 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02045 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02046 if (bridge_cdr) { 02047 ast_cdr_discard(bridge_cdr); 02048 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02049 } 02050 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02051 } 02052 02053 if (config->end_bridge_callback) { 02054 config->end_bridge_callback(config->end_bridge_callback_data); 02055 } 02056 02057 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02058 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02059 struct ast_cdr *swapper = NULL; 02060 char savelastapp[AST_MAX_EXTENSION]; 02061 char savelastdata[AST_MAX_EXTENSION]; 02062 char save_exten[AST_MAX_EXTENSION]; 02063 int save_prio, spawn_error = 0; 02064 02065 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02066 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02067 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02068 ast_cdr_end(bridge_cdr); 02069 } 02070 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02071 dialplan code operate on it */ 02072 ast_channel_lock(chan); 02073 if (bridge_cdr) { 02074 swapper = chan->cdr; 02075 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02076 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02077 chan->cdr = bridge_cdr; 02078 } 02079 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02080 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02081 save_prio = chan->priority; 02082 chan->priority = 1; 02083 ast_channel_unlock(chan); 02084 while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) { 02085 if ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) { 02086 /* Something bad happened, or a hangup has been requested. */ 02087 if (option_debug) 02088 ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02089 if (option_verbose > 1) 02090 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); 02091 break; 02092 } 02093 chan->priority++; 02094 } 02095 /* swap it back */ 02096 ast_channel_lock(chan); 02097 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02098 chan->priority = save_prio; 02099 if (bridge_cdr) { 02100 if (chan->cdr == bridge_cdr) { 02101 chan->cdr = swapper; 02102 } else { 02103 bridge_cdr = NULL; 02104 } 02105 } 02106 if (chan->priority != 1 || !spawn_error) { 02107 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02108 } 02109 ast_channel_unlock(chan); 02110 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02111 if (bridge_cdr) { 02112 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02113 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02114 } 02115 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02116 } 02117 02118 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02119 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02120 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 02121 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02122 } 02123 02124 /* we can post the bridge CDR at this point */ 02125 if (bridge_cdr) { 02126 ast_cdr_end(bridge_cdr); 02127 ast_cdr_detach(bridge_cdr); 02128 } 02129 02130 /* do a specialized reset on the beginning channel 02131 CDR's, if they still exist, so as not to mess up 02132 issues in future bridges; 02133 02134 Here are the rules of the game: 02135 1. The chan and peer channel pointers will not change 02136 during the life of the bridge. 02137 2. But, in transfers, the channel names will change. 02138 between the time the bridge is started, and the 02139 time the channel ends. 02140 Usually, when a channel changes names, it will 02141 also change CDR pointers. 02142 3. Usually, only one of the two channels (chan or peer) 02143 will change names. 02144 4. Usually, if a channel changes names during a bridge, 02145 it is because of a transfer. Usually, in these situations, 02146 it is normal to see 2 bridges running simultaneously, and 02147 it is not unusual to see the two channels that change 02148 swapped between bridges. 02149 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02150 to attend to; if the chan or peer changed names, 02151 we have the before and after attached CDR's. 02152 */ 02153 02154 if (new_chan_cdr) { 02155 struct ast_channel *chan_ptr = NULL; 02156 02157 if (strcasecmp(orig_channame, chan->name) != 0) { 02158 /* old channel */ 02159 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02160 if (chan_ptr) { 02161 if (!ast_bridged_channel(chan_ptr)) { 02162 struct ast_cdr *cur; 02163 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02164 if (cur == chan_cdr) { 02165 break; 02166 } 02167 } 02168 if (cur) 02169 ast_cdr_specialized_reset(chan_cdr,0); 02170 } 02171 ast_channel_unlock(chan_ptr); 02172 } 02173 /* new channel */ 02174 ast_cdr_specialized_reset(new_chan_cdr,0); 02175 } else { 02176 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02177 } 02178 } 02179 02180 { 02181 struct ast_channel *chan_ptr = NULL; 02182 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02183 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)) 02184 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02185 if (strcasecmp(orig_peername, peer->name) != 0) { 02186 /* old channel */ 02187 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02188 if (chan_ptr) { 02189 if (!ast_bridged_channel(chan_ptr)) { 02190 struct ast_cdr *cur; 02191 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02192 if (cur == peer_cdr) { 02193 break; 02194 } 02195 } 02196 if (cur) 02197 ast_cdr_specialized_reset(peer_cdr,0); 02198 } 02199 ast_channel_unlock(chan_ptr); 02200 } 02201 /* new channel */ 02202 ast_cdr_specialized_reset(new_peer_cdr,0); 02203 } else { 02204 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02205 } 02206 } 02207 02208 return res; 02209 }
static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
Definition at line 270 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().
00271 { 00272 struct ast_bridge_thread_obj *tobj = data; 00273 00274 tobj->chan->appl = "Transferred Call"; 00275 tobj->chan->data = tobj->peer->name; 00276 tobj->peer->appl = "Transferred Call"; 00277 tobj->peer->data = tobj->chan->name; 00278 00279 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00280 ast_hangup(tobj->chan); 00281 ast_hangup(tobj->peer); 00282 bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */ 00283 free(tobj); 00284 return NULL; 00285 }
static void ast_bridge_call_thread_launch | ( | void * | data | ) | [static] |
Definition at line 287 of file res_features.c.
References ast_bridge_call_thread(), ast_pthread_create, and thread.
Referenced by do_atxfer().
00288 { 00289 pthread_t thread; 00290 pthread_attr_t attr; 00291 struct sched_param sched; 00292 00293 pthread_attr_init(&attr); 00294 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00295 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00296 pthread_attr_destroy(&attr); 00297 memset(&sched, 0, sizeof(sched)); 00298 pthread_setschedparam(thread, SCHED_RR, &sched); 00299 }
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 1386 of file res_features.c.
References feature_interpret_helper().
Referenced by detect_disconnect().
01386 { 01387 01388 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 01389 }
static struct ast_channel * ast_feature_request_and_dial | ( | struct ast_channel * | caller, | |
const char * | type, | |||
int | format, | |||
void * | data, | |||
int | timeout, | |||
int * | outstate, | |||
const char * | cid_num, | |||
const char * | cid_name, | |||
const char * | language | |||
) | [static] |
Definition at line 1434 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_rwlock_rdlock, ast_rwlock_unlock, ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), ast_waitfor_n(), ast_write(), builtin_features, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, len(), LOG_NOTICE, ast_channel::name, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.
Referenced by do_atxfer().
01435 { 01436 int state = 0; 01437 int cause = 0; 01438 int to; 01439 struct ast_channel *chan; 01440 struct ast_channel *monitor_chans[2]; 01441 struct ast_channel *active_channel; 01442 int res = 0, ready = 0; 01443 01444 if ((chan = ast_request(type, format, data, &cause))) { 01445 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01446 ast_string_field_set(chan, language, language); 01447 ast_channel_inherit_variables(caller, chan); 01448 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01449 01450 if (!ast_call(chan, data, timeout)) { 01451 struct timeval started; 01452 int x, len = 0; 01453 char *disconnect_code = NULL, *dialed_code = NULL; 01454 01455 ast_indicate(caller, AST_CONTROL_RINGING); 01456 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01457 ast_rwlock_rdlock(&features_lock); 01458 for (x = 0; x < FEATURES_COUNT; x++) { 01459 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01460 continue; 01461 01462 disconnect_code = builtin_features[x].exten; 01463 len = strlen(disconnect_code) + 1; 01464 dialed_code = alloca(len); 01465 memset(dialed_code, 0, len); 01466 break; 01467 } 01468 ast_rwlock_unlock(&features_lock); 01469 x = 0; 01470 started = ast_tvnow(); 01471 to = timeout; 01472 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01473 struct ast_frame *f = NULL; 01474 01475 monitor_chans[0] = caller; 01476 monitor_chans[1] = chan; 01477 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01478 01479 /* see if the timeout has been violated */ 01480 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01481 state = AST_CONTROL_UNHOLD; 01482 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01483 break; /*doh! timeout*/ 01484 } 01485 01486 if (!active_channel) 01487 continue; 01488 01489 if (chan && (chan == active_channel)) { 01490 if (!ast_strlen_zero(chan->call_forward)) { 01491 if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) { 01492 return NULL; 01493 } 01494 continue; 01495 } 01496 f = ast_read(chan); 01497 if (f == NULL) { /*doh! where'd he go?*/ 01498 state = AST_CONTROL_HANGUP; 01499 res = 0; 01500 break; 01501 } 01502 01503 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01504 if (f->subclass == AST_CONTROL_RINGING) { 01505 state = f->subclass; 01506 if (option_verbose > 2) 01507 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01508 ast_indicate(caller, AST_CONTROL_RINGING); 01509 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01510 state = f->subclass; 01511 if (option_verbose > 2) 01512 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01513 ast_indicate(caller, AST_CONTROL_BUSY); 01514 ast_frfree(f); 01515 f = NULL; 01516 break; 01517 } else if (f->subclass == AST_CONTROL_ANSWER) { 01518 /* This is what we are hoping for */ 01519 state = f->subclass; 01520 ast_frfree(f); 01521 f = NULL; 01522 ready=1; 01523 break; 01524 } else if (f->subclass != -1 && f->subclass != AST_CONTROL_PROGRESS) { 01525 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01526 } 01527 /* else who cares */ 01528 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 01529 ast_write(caller, f); 01530 } 01531 01532 } else if (caller && (active_channel == caller)) { 01533 f = ast_read(caller); 01534 if (f == NULL) { /*doh! where'd he go?*/ 01535 if (caller->_softhangup && !chan->_softhangup) { 01536 /* make this a blind transfer */ 01537 ready = 1; 01538 break; 01539 } 01540 state = AST_CONTROL_HANGUP; 01541 res = 0; 01542 break; 01543 } 01544 01545 if (f->frametype == AST_FRAME_DTMF) { 01546 dialed_code[x++] = f->subclass; 01547 dialed_code[x] = '\0'; 01548 if (strlen(dialed_code) == len) { 01549 x = 0; 01550 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01551 x = 0; 01552 dialed_code[x] = '\0'; 01553 } 01554 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01555 /* Caller Canceled the call */ 01556 state = AST_CONTROL_UNHOLD; 01557 ast_frfree(f); 01558 f = NULL; 01559 break; 01560 } 01561 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 01562 ast_write(chan, f); 01563 } 01564 } 01565 if (f) 01566 ast_frfree(f); 01567 } /* end while */ 01568 } else 01569 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01570 } else { 01571 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01572 switch(cause) { 01573 case AST_CAUSE_BUSY: 01574 state = AST_CONTROL_BUSY; 01575 break; 01576 case AST_CAUSE_CONGESTION: 01577 state = AST_CONTROL_CONGESTION; 01578 break; 01579 } 01580 } 01581 01582 ast_indicate(caller, -1); 01583 if (chan && ready) { 01584 if (chan->_state == AST_STATE_UP) 01585 state = AST_CONTROL_ANSWER; 01586 res = 0; 01587 } else if(chan) { 01588 res = -1; 01589 ast_hangup(chan); 01590 chan = NULL; 01591 } else { 01592 res = -1; 01593 } 01594 01595 if (outstate) 01596 *outstate = state; 01597 01598 return chan; 01599 }
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 608 of file res_features.c.
References masq_park_call().
Referenced by handle_exec(), manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().
00609 { 00610 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00611 }
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call and read back parked location.
Definition at line 552 of file res_features.c.
References park_call_full().
Referenced by iax_park_thread(), and sip_park_thread().
00553 { 00554 return park_call_full(chan, peer, timeout, extout, NULL, NULL); 00555 }
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 207 of file res_features.c.
Referenced by builtin_blindtransfer(), do_atxfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00208 { 00209 return parking_ext; 00210 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2868 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), and ss_thread().
02869 { 02870 struct ast_channel *cur = NULL; 02871 int res = -1; 02872 02873 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02874 if (!cur->pbx && 02875 (cur != chan) && 02876 (chan->pickupgroup & cur->callgroup) && 02877 ((cur->_state == AST_STATE_RINGING) || 02878 (cur->_state == AST_STATE_RING))) { 02879 break; 02880 } 02881 ast_channel_unlock(cur); 02882 } 02883 if (cur) { 02884 if (option_debug) 02885 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02886 res = ast_answer(chan); 02887 if (res) 02888 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02889 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02890 if (res) 02891 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02892 res = ast_channel_masquerade(cur, chan); 02893 if (res) 02894 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02895 ast_channel_unlock(cur); 02896 } else { 02897 if (option_debug) 02898 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02899 } 02900 return res; 02901 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 212 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00213 { 00214 return pickup_ext; 00215 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_set
feature | an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call. |
Definition at line 1123 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.
01124 { 01125 if (!feature) { 01126 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01127 return; 01128 } 01129 01130 AST_RWLIST_WRLOCK(&feature_list); 01131 AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry); 01132 AST_RWLIST_UNLOCK(&feature_list); 01133 01134 if (option_verbose >= 2) { 01135 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 01136 } 01137 }
void ast_unregister_feature | ( | struct ast_call_feature * | feature | ) |
unregister feature from feature_set
feature | the ast_call_feature object which was registered before |
Definition at line 1140 of file res_features.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.
01141 { 01142 if (!feature) 01143 return; 01144 01145 AST_RWLIST_WRLOCK(&feature_list); 01146 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01147 AST_RWLIST_UNLOCK(&feature_list); 01148 01149 free(feature); 01150 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1153 of file res_features.c.
References AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.
01154 { 01155 struct ast_call_feature *feature; 01156 01157 AST_RWLIST_WRLOCK(&feature_list); 01158 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) { 01159 free(feature); 01160 } 01161 AST_RWLIST_UNLOCK(&feature_list); 01162 }
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 | ||
peer | ||
config | ||
code | ||
sense | ||
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 1100 of file res_features.c.
References config, and do_atxfer().
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 668 of file res_features.c.
References ast_autoservice_start(), ast_autoservice_stop(), 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, monitor_app, 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.
00669 { 00670 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00671 int x = 0; 00672 size_t len; 00673 struct ast_channel *caller_chan, *callee_chan; 00674 00675 if (!monitor_ok) { 00676 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00677 return -1; 00678 } 00679 00680 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00681 monitor_ok = 0; 00682 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00683 return -1; 00684 } 00685 00686 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00687 00688 if (!ast_strlen_zero(courtesytone)) { 00689 if (ast_autoservice_start(callee_chan)) 00690 return -1; 00691 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) { 00692 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00693 ast_autoservice_stop(callee_chan); 00694 return -1; 00695 } 00696 if (ast_autoservice_stop(callee_chan)) 00697 return -1; 00698 } 00699 00700 if (callee_chan->monitor) { 00701 if (option_verbose > 3) 00702 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00703 ast_monitor_stop(callee_chan, 1); 00704 return FEATURE_RETURN_SUCCESS; 00705 } 00706 00707 if (caller_chan && callee_chan) { 00708 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00709 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00710 00711 if (!touch_format) 00712 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00713 00714 if (!touch_monitor) 00715 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00716 00717 if (touch_monitor) { 00718 len = strlen(touch_monitor) + 50; 00719 args = alloca(len); 00720 touch_filename = alloca(len); 00721 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00722 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename); 00723 } else { 00724 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00725 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00726 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00727 args = alloca(len); 00728 touch_filename = alloca(len); 00729 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00730 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename); 00731 } 00732 00733 for( x = 0; x < strlen(args); x++) { 00734 if (args[x] == '/') 00735 args[x] = '-'; 00736 } 00737 00738 if (option_verbose > 3) 00739 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00740 00741 pbx_exec(callee_chan, monitor_app, args); 00742 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00743 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00744 00745 return FEATURE_RETURN_SUCCESS; 00746 } 00747 00748 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00749 return -1; 00750 }
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 779 of file res_features.c.
References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), AST_FLAG_BRIDGE_HANGUP_DONT, 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(), ast_channel::cid, ast_callerid::cid_num, 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.
00780 { 00781 struct ast_channel *transferer; 00782 struct ast_channel *transferee; 00783 const char *transferer_real_context; 00784 char xferto[256]; 00785 int res; 00786 const char *orig_chan_name; 00787 int parkstatus = 0; 00788 00789 set_peers(&transferer, &transferee, peer, chan, sense); 00790 orig_chan_name = ast_strdupa(transferer->name); 00791 transferer_real_context = real_ctx(transferer, transferee); 00792 /* Start autoservice on chan while we talk to the originator */ 00793 ast_autoservice_start(transferee); 00794 ast_indicate(transferee, AST_CONTROL_HOLD); 00795 00796 memset(xferto, 0, sizeof(xferto)); 00797 00798 /* Transfer */ 00799 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00800 if (res < 0) { 00801 finishup(transferee); 00802 return -1; /* error ? */ 00803 } 00804 if (res > 0) /* If they've typed a digit already, handle it */ 00805 xferto[0] = (char) res; 00806 00807 ast_stopstream(transferer); 00808 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00809 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00810 finishup(transferee); 00811 return res; 00812 } 00813 if (!strcmp(xferto, ast_parking_ext())) { 00814 res = finishup(transferee); 00815 if (res) 00816 res = -1; 00817 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name))) { /* success */ 00818 /* We return non-zero, but tell the PBX not to hang the channel when 00819 the thread dies -- We have to be careful now though. We are responsible for 00820 hanging up the channel, else it will never be hung up! */ 00821 return 0; 00822 } else { 00823 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus=%d\n", transferee->name, parkstatus); 00824 } 00825 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 00826 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00827 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 00828 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 00829 res=finishup(transferee); 00830 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 00831 transferer->cdr=ast_cdr_alloc(); 00832 if (transferer->cdr) { 00833 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 00834 ast_cdr_start(transferer->cdr); 00835 } 00836 } 00837 if (transferer->cdr) { 00838 struct ast_cdr *swap = transferer->cdr; 00839 /* swap cdrs-- it will save us some time & work */ 00840 transferer->cdr = transferee->cdr; 00841 transferee->cdr = swap; 00842 } 00843 if (!transferee->pbx) { 00844 /* Doh! Use our handy async_goto functions */ 00845 if (option_verbose > 2) 00846 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00847 ,transferee->name, xferto, transferer_real_context); 00848 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 00849 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00850 res = -1; 00851 } else { 00852 /* Set the channel's new extension, since it exists, using transferer context */ 00853 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 00854 set_c_e_p(transferee, transferer_real_context, xferto, 0); 00855 } 00856 check_goto_on_transfer(transferer); 00857 return res; 00858 } else { 00859 if (option_verbose > 2) 00860 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 00861 } 00862 if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) { 00863 finishup(transferee); 00864 return -1; 00865 } 00866 ast_stopstream(transferer); 00867 res = finishup(transferee); 00868 if (res) { 00869 if (option_verbose > 1) 00870 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00871 return res; 00872 } 00873 return FEATURE_RETURN_SUCCESS; 00874 }
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 752 of file res_features.c.
References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.
00753 { 00754 if (option_verbose > 3) 00755 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00756 return FEATURE_RETURN_HANGUP; 00757 }
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 634 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_module_user::chan, masq_park_call_announce(), ast_channel::name, and set_peers().
Referenced by do_atxfer().
00635 { 00636 struct ast_channel *parker; 00637 struct ast_channel *parkee; 00638 int res = 0; 00639 struct ast_module_user *u; 00640 const char *orig_chan_name; 00641 00642 u = ast_module_user_add(chan); 00643 00644 set_peers(&parker, &parkee, peer, chan, sense); 00645 orig_chan_name = ast_strdupa(parker->name); 00646 /* we used to set chan's exten and priority to "s" and 1 00647 here, but this generates (in some cases) an invalid 00648 extension, and if "s" exists, could errantly 00649 cause execution of extensions you don't expect It 00650 makes more sense to let nature take its course 00651 when chan finishes, and let the pbx do its thing 00652 and hang up when the park is over. 00653 */ 00654 if (chan->_state != AST_STATE_UP) 00655 res = ast_answer(chan); 00656 if (!res) 00657 res = ast_safe_sleep(chan, 1000); 00658 00659 if (!res) { /* one direction used to call park_call.... */ 00660 res = masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name); 00661 /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ 00662 } 00663 00664 ast_module_user_remove(u); 00665 return res; 00666 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 2225 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().
02226 { 02227 int i = 0; 02228 enum { 02229 OPT_CALLEE_REDIRECT = 't', 02230 OPT_CALLER_REDIRECT = 'T', 02231 OPT_CALLEE_AUTOMON = 'w', 02232 OPT_CALLER_AUTOMON = 'W', 02233 OPT_CALLEE_DISCONNECT = 'h', 02234 OPT_CALLER_DISCONNECT = 'H', 02235 OPT_CALLEE_PARKCALL = 'k', 02236 OPT_CALLER_PARKCALL = 'K', 02237 }; 02238 02239 memset(options, 0, len); 02240 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 02241 options[i++] = OPT_CALLER_REDIRECT; 02242 } 02243 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 02244 options[i++] = OPT_CALLER_AUTOMON; 02245 } 02246 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 02247 options[i++] = OPT_CALLER_DISCONNECT; 02248 } 02249 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 02250 options[i++] = OPT_CALLER_PARKCALL; 02251 } 02252 02253 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 02254 options[i++] = OPT_CALLEE_REDIRECT; 02255 } 02256 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 02257 options[i++] = OPT_CALLEE_AUTOMON; 02258 } 02259 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 02260 options[i++] = OPT_CALLEE_DISCONNECT; 02261 } 02262 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 02263 options[i++] = OPT_CALLEE_PARKCALL; 02264 } 02265 02266 return options; 02267 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 876 of file res_features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by do_atxfer().
00877 { 00878 if (ast_channel_make_compatible(c, newchan) < 0) { 00879 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 00880 c->name, newchan->name); 00881 ast_hangup(newchan); 00882 return -1; 00883 } 00884 return 0; 00885 }
static void check_goto_on_transfer | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 232 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_channel_alloc(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), f, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.
Referenced by builtin_blindtransfer().
00233 { 00234 struct ast_channel *xferchan; 00235 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00236 char *x, *goto_on_transfer; 00237 struct ast_frame *f; 00238 00239 if (ast_strlen_zero(val)) 00240 return; 00241 00242 goto_on_transfer = ast_strdupa(val); 00243 00244 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name))) 00245 return; 00246 00247 for (x = goto_on_transfer; x && *x; x++) { 00248 if (*x == '^') 00249 *x = '|'; 00250 } 00251 /* Make formats okay */ 00252 xferchan->readformat = chan->readformat; 00253 xferchan->writeformat = chan->writeformat; 00254 ast_channel_masquerade(xferchan, chan); 00255 ast_parseable_goto(xferchan, goto_on_transfer); 00256 xferchan->_state = AST_STATE_UP; 00257 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00258 xferchan->_softhangup = 0; 00259 if ((f = ast_read(xferchan))) { 00260 ast_frfree(f); 00261 f = NULL; 00262 ast_pbx_start(xferchan); 00263 } else { 00264 ast_hangup(xferchan); 00265 } 00266 }
static void cmd_atxfer | ( | struct ast_channel * | a, | |
struct ast_channel * | b, | |||
struct ast_bridge_config * | conf, | |||
struct ast_channel * | who, | |||
char * | xferto | |||
) | [static] |
Definition at line 1702 of file res_features.c.
References context, do_atxfer(), FEATURE_SENSE_CHAN, and FEATURE_SENSE_PEER.
Referenced by ast_bridge_call().
01703 { 01704 int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER; 01705 char *context = strchr(xferto, '@');; 01706 if (context) 01707 *context++ = '\0'; 01708 do_atxfer(a, b, conf, sense, xferto, context); 01709 }
static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 193 of file res_features.c.
References ast_free.
00194 { 00195 struct ast_dial_features *df = data; 00196 if (df) { 00197 ast_free(df); 00198 } 00199 }
static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 180 of file res_features.c.
References ast_calloc.
00181 { 00182 struct ast_dial_features *df = data, *df_copy; 00183 00184 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00185 return NULL; 00186 } 00187 00188 memcpy(df_copy, df, sizeof(*df)); 00189 00190 return df_copy; 00191 }
static int do_atxfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
int | sense, | |||
const char * | toExt, | |||
const char * | toCont | |||
) | [static] |
Attended transfer implementation.
chan | transfered user | |
peer | person transfering call | |
config | ||
sense | feature options | |
toExt | ||
toCont | This is the actual implementation of attended transfer, it can be activated as a regular feature or through the AMI. "toExt" is the extension to transfer to (default: ask for it on the transferer channel) "toCont" is the context to transfer to (default: the one in which the transferer is) |
Definition at line 902 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_copy_string(), AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_parking_ext(), ast_read(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_strlen_zero(), 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, config, ast_channel::context, ast_datastore::data, dial_features_info, ast_bridge_config::end_bridge_callback_data_fixup, ast_channel::exten, f, 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::name, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), S_OR, set_peers(), ast_channel::visible_indication, and ast_channel::writeformat.
Referenced by builtin_atxfer(), and cmd_atxfer().
00903 { 00904 struct ast_channel *transferer; 00905 struct ast_channel *transferee; 00906 const char *transferer_real_context; 00907 const char *transfer_context; 00908 char xferto[256] = ""; 00909 int res; 00910 int outstate=0; 00911 struct ast_channel *newchan; 00912 struct ast_channel *xferchan; 00913 struct ast_bridge_thread_obj *tobj; 00914 struct ast_bridge_config bconfig; 00915 struct ast_frame *f; 00916 int l; 00917 struct ast_datastore *features_datastore; 00918 struct ast_dial_features *dialfeatures = NULL; 00919 00920 if (option_debug) 00921 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 00922 set_peers(&transferer, &transferee, peer, chan, sense); 00923 transferer_real_context = real_ctx(transferer, transferee); 00924 transfer_context = S_OR(toCont, transferer_real_context); 00925 00926 /* Start autoservice on chan while we talk to the originator */ 00927 ast_autoservice_start(transferee); 00928 ast_indicate(transferee, AST_CONTROL_HOLD); 00929 00930 if (!ast_strlen_zero(toExt)) { 00931 ast_copy_string(xferto, toExt, sizeof(xferto)); 00932 } else { 00933 /* Ask for extension to transfer to on the transferer channel */ 00934 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00935 if (res < 0) { 00936 finishup(transferee); 00937 return res; 00938 } 00939 if (res > 0) /* If they've typed a digit already, handle it */ 00940 xferto[0] = (char) res; 00941 00942 /* this is specific of atxfer */ 00943 res = ast_app_dtget(transferer, transfer_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00944 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00945 finishup(transferee); 00946 return res; 00947 } 00948 if (res == 0) { 00949 ast_log(LOG_WARNING, "Did not read data.\n"); 00950 finishup(transferee); 00951 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00952 return -1; 00953 return FEATURE_RETURN_SUCCESS; 00954 } 00955 } 00956 00957 /* valid extension, res == 1 */ 00958 if (!ast_exists_extension(transferer, transfer_context, xferto, 1, transferer->cid.cid_num)) { 00959 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transfer_context); 00960 finishup(transferee); 00961 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00962 return -1; 00963 return FEATURE_RETURN_SUCCESS; 00964 } 00965 00966 /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of 00967 * the different variables for handling this properly with a builtin_atxfer */ 00968 if (!strcmp(xferto, ast_parking_ext())) { 00969 finishup(transferee); 00970 return builtin_parkcall(chan, peer, config, NULL, sense, NULL); 00971 } 00972 00973 l = strlen(xferto); 00974 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transfer_context); /* append context */ 00975 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), 00976 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language); 00977 ast_indicate(transferer, -1); 00978 if (!newchan) { 00979 finishup(transferee); 00980 /* any reason besides user requested cancel and busy triggers the failed sound */ 00981 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 00982 ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) 00983 return -1; 00984 return FEATURE_RETURN_SUCCESS; 00985 } 00986 00987 if (check_compat(transferer, newchan)) { 00988 /* we do mean transferee here, NOT transferer */ 00989 finishup(transferee); 00990 return -1; 00991 } 00992 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00993 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00994 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00995 res = ast_bridge_call(transferer, newchan, &bconfig); 00996 if (newchan->_softhangup || !transferer->_softhangup) { 00997 ast_hangup(newchan); 00998 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) 00999 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01000 finishup(transferee); 01001 transferer->_softhangup = 0; 01002 return FEATURE_RETURN_SUCCESS; 01003 } 01004 01005 if (check_compat(transferee, newchan)) { 01006 finishup(transferee); 01007 return -1; 01008 } 01009 01010 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01011 01012 if ((ast_autoservice_stop(transferee) < 0) 01013 || (ast_waitfordigit(transferee, 100) < 0) 01014 || (ast_waitfordigit(newchan, 100) < 0) 01015 || ast_check_hangup(transferee) 01016 || ast_check_hangup(newchan)) { 01017 ast_hangup(newchan); 01018 return -1; 01019 } 01020 01021 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01022 if (!xferchan) { 01023 ast_hangup(newchan); 01024 return -1; 01025 } 01026 /* Make formats okay */ 01027 xferchan->visible_indication = transferer->visible_indication; 01028 xferchan->readformat = transferee->readformat; 01029 xferchan->writeformat = transferee->writeformat; 01030 ast_channel_masquerade(xferchan, transferee); 01031 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01032 xferchan->_state = AST_STATE_UP; 01033 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01034 xferchan->_softhangup = 0; 01035 01036 if ((f = ast_read(xferchan))) 01037 ast_frfree(f); 01038 01039 newchan->_state = AST_STATE_UP; 01040 ast_clear_flag(newchan, AST_FLAGS_ALL); 01041 newchan->_softhangup = 0; 01042 01043 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj)); 01044 if (!tobj) { 01045 ast_hangup(xferchan); 01046 ast_hangup(newchan); 01047 return -1; 01048 } 01049 01050 ast_channel_lock(newchan); 01051 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 01052 dialfeatures = features_datastore->data; 01053 } 01054 ast_channel_unlock(newchan); 01055 01056 if (dialfeatures) { 01057 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 01058 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 01059 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01060 } 01061 01062 ast_channel_lock(xferchan); 01063 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 01064 dialfeatures = features_datastore->data; 01065 } 01066 ast_channel_unlock(xferchan); 01067 01068 if (dialfeatures) { 01069 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01070 } 01071 01072 tobj->chan = newchan; 01073 tobj->peer = xferchan; 01074 tobj->bconfig = *config; 01075 01076 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01077 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01078 } 01079 01080 if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) 01081 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01082 ast_bridge_call_thread_launch(tobj); 01083 return -1; /* XXX meaning the channel is bridged ? */ 01084 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
Definition at line 2270 of file res_features.c.
References ast_add_extension2(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_mutex_lock, ast_mutex_unlock, ast_pbx_start(), ast_read(), ast_samp2tv(), ast_select(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), callback_dialoptions(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_channel::name, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, and VERBOSE_PREFIX_2.
Referenced by load_module().
02271 { 02272 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 02273 FD_ZERO(&rfds); 02274 FD_ZERO(&efds); 02275 02276 for (;;) { 02277 struct parkeduser *pu, *pl, *pt = NULL; 02278 int ms = -1; /* select timeout, uninitialized */ 02279 int max = -1; /* max fd, none there yet */ 02280 fd_set nrfds, nefds; /* args for the next select */ 02281 FD_ZERO(&nrfds); 02282 FD_ZERO(&nefds); 02283 02284 ast_mutex_lock(&parking_lock); 02285 pl = NULL; 02286 pu = parkinglot; 02287 /* navigate the list with prev-cur pointers to support removals */ 02288 while (pu) { 02289 struct ast_channel *chan = pu->chan; /* shorthand */ 02290 int tms; /* timeout for this item */ 02291 int x; /* fd index in channel */ 02292 struct ast_context *con; 02293 02294 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 02295 pl = pu; 02296 pu = pu->next; 02297 continue; 02298 } 02299 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 02300 if (tms > pu->parkingtime) { 02301 ast_indicate(chan, AST_CONTROL_UNHOLD); 02302 /* Get chan, exten from derived kludge */ 02303 if (pu->peername[0]) { 02304 char *peername = ast_strdupa(pu->peername); 02305 char *cp = strrchr(peername, '-'); 02306 if (cp) 02307 *cp = 0; 02308 con = ast_context_find(parking_con_dial); 02309 if (!con) { 02310 con = ast_context_create(NULL, parking_con_dial, registrar); 02311 if (!con) 02312 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 02313 } 02314 if (con) { 02315 char returnexten[AST_MAX_EXTENSION]; 02316 struct ast_datastore *features_datastore; 02317 struct ast_dial_features *dialfeatures = NULL; 02318 02319 ast_channel_lock(chan); 02320 02321 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 02322 dialfeatures = features_datastore->data; 02323 02324 ast_channel_unlock(chan); 02325 02326 if (!strncmp(peername, "Parked/", 7)) { 02327 peername += 7; 02328 } 02329 02330 if (dialfeatures) { 02331 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 02332 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 02333 } else { /* Existing default */ 02334 ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name); 02335 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername); 02336 } 02337 02338 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free_ptr, registrar); 02339 } 02340 set_c_e_p(chan, parking_con_dial, peername, 1); 02341 } else { 02342 /* They've been waiting too long, send them back to where they came. Theoretically they 02343 should have their original extensions and such, but we copy to be on the safe side */ 02344 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 02345 } 02346 02347 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 02348 02349 if (option_verbose > 1) 02350 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); 02351 /* Start up the PBX, or hang them up */ 02352 if (ast_pbx_start(chan)) { 02353 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 02354 ast_hangup(chan); 02355 } 02356 /* And take them out of the parking lot */ 02357 if (pl) 02358 pl->next = pu->next; 02359 else 02360 parkinglot = pu->next; 02361 pt = pu; 02362 pu = pu->next; 02363 con = ast_context_find(parking_con); 02364 if (con) { 02365 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 02366 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02367 else 02368 notify_metermaids(pt->parkingexten, parking_con); 02369 } else 02370 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02371 free(pt); 02372 } else { /* still within parking time, process descriptors */ 02373 for (x = 0; x < AST_MAX_FDS; x++) { 02374 struct ast_frame *f; 02375 02376 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 02377 continue; /* nothing on this descriptor */ 02378 02379 if (FD_ISSET(chan->fds[x], &efds)) 02380 ast_set_flag(chan, AST_FLAG_EXCEPTION); 02381 else 02382 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 02383 chan->fdno = x; 02384 02385 /* See if they need servicing */ 02386 f = ast_read(chan); 02387 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 02388 if (f) 02389 ast_frfree(f); 02390 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 02391 02392 /* There's a problem, hang them up*/ 02393 if (option_verbose > 1) 02394 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 02395 ast_hangup(chan); 02396 /* And take them out of the parking lot */ 02397 if (pl) 02398 pl->next = pu->next; 02399 else 02400 parkinglot = pu->next; 02401 pt = pu; 02402 pu = pu->next; 02403 con = ast_context_find(parking_con); 02404 if (con) { 02405 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 02406 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02407 else { 02408 notify_metermaids(pt->parkingexten, parking_con); 02409 } 02410 } else 02411 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02412 free(pt); 02413 break; 02414 } else { 02415 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02416 ast_frfree(f); 02417 if (pu->moh_trys < 3 && !chan->generatordata) { 02418 if (option_debug) 02419 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 02420 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 02421 S_OR(parkmohclass, NULL), 02422 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 02423 pu->moh_trys++; 02424 } 02425 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 02426 } 02427 02428 } /* end for */ 02429 if (x >= AST_MAX_FDS) { 02430 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 02431 if (chan->fds[x] > -1) { 02432 FD_SET(chan->fds[x], &nrfds); 02433 FD_SET(chan->fds[x], &nefds); 02434 if (chan->fds[x] > max) 02435 max = chan->fds[x]; 02436 } 02437 } 02438 /* Keep track of our shortest wait */ 02439 if (tms < ms || ms < 0) 02440 ms = tms; 02441 pl = pu; 02442 pu = pu->next; 02443 } 02444 } 02445 } /* end while */ 02446 ast_mutex_unlock(&parking_lock); 02447 rfds = nrfds; 02448 efds = nefds; 02449 { 02450 struct timeval tv = ast_samp2tv(ms, 1000); 02451 /* Wait for something to happen */ 02452 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 02453 } 02454 pthread_testcancel(); 02455 } 02456 return NULL; /* Never reached */ 02457 }
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 1179 of file res_features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, ast_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().
01180 { 01181 struct ast_app *app; 01182 struct ast_call_feature *feature = data; 01183 struct ast_channel *work, *idle; 01184 int res; 01185 01186 if (!feature) { /* shouldn't ever happen! */ 01187 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01188 return -1; 01189 } 01190 01191 if (sense == FEATURE_SENSE_CHAN) { 01192 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01193 return FEATURE_RETURN_KEEPTRYING; 01194 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01195 work = chan; 01196 idle = peer; 01197 } else { 01198 work = peer; 01199 idle = chan; 01200 } 01201 } else { 01202 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01203 return FEATURE_RETURN_KEEPTRYING; 01204 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01205 work = peer; 01206 idle = chan; 01207 } else { 01208 work = chan; 01209 idle = peer; 01210 } 01211 } 01212 01213 if (!(app = pbx_findapp(feature->app))) { 01214 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01215 return -2; 01216 } 01217 01218 ast_autoservice_start(idle); 01219 01220 if (!ast_strlen_zero(feature->moh_class)) 01221 ast_moh_start(idle, feature->moh_class, NULL); 01222 01223 res = pbx_exec(work, app, feature->app_args); 01224 01225 if (!ast_strlen_zero(feature->moh_class)) 01226 ast_moh_stop(idle); 01227 01228 ast_autoservice_stop(idle); 01229 01230 if (res) 01231 return FEATURE_RETURN_SUCCESSBREAK; 01232 01233 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01234 }
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 1355 of file res_features.c.
References ast_channel_lock, ast_channel_unlock, ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strdupa, config, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, LOG_DEBUG, ast_channel::name, option_debug, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
01355 { 01356 01357 char dynamic_features_buf[128]; 01358 const char *peer_dynamic_features, *chan_dynamic_features; 01359 struct ast_flags features; 01360 struct ast_call_feature feature; 01361 if (sense == FEATURE_SENSE_CHAN) { 01362 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01363 } 01364 else { 01365 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01366 } 01367 01368 ast_channel_lock(peer); 01369 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 01370 ast_channel_unlock(peer); 01371 01372 ast_channel_lock(chan); 01373 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 01374 ast_channel_unlock(chan); 01375 01376 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,"")); 01377 01378 if (option_debug > 2) { 01379 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); 01380 } 01381 01382 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature); 01383 }
static int feature_interpret_helper | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
char * | dynamic_features_buf, | |||
struct ast_flags * | features, | |||
int | operation, | |||
struct ast_call_feature * | feature | |||
) | [static] |
Helper function for feature_interpret and ast_feature_detect.
chan,peer,config,code,sense,dynamic_features | char buf,feature flags,operation,feature |
res | on success. | |
-1 | on failure. |
Definition at line 1274 of file res_features.c.
References ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_strlen_zero(), ast_test_flag, builtin_features, config, ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, 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(), and feature_interpret().
01277 { 01278 int x; 01279 struct ast_call_feature *tmpfeature; 01280 char *tmp, *tok; 01281 int res = FEATURE_RETURN_PASSDIGITS; 01282 int feature_detected = 0; 01283 01284 if (!(peer && chan && config) && operation) { 01285 return -1; /* can not run feature operation */ 01286 } 01287 01288 ast_rwlock_rdlock(&features_lock); 01289 for (x = 0; x < FEATURES_COUNT; x++) { 01290 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 01291 !ast_strlen_zero(builtin_features[x].exten)) { 01292 /* Feature is up for consideration */ 01293 if (!strcmp(builtin_features[x].exten, code)) { 01294 if (option_debug > 2) { 01295 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); 01296 } 01297 if (operation) { 01298 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01299 } 01300 memcpy(feature, &builtin_features[x], sizeof(feature)); 01301 feature_detected = 1; 01302 break; 01303 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01304 if (res == FEATURE_RETURN_PASSDIGITS) 01305 res = FEATURE_RETURN_STOREDIGITS; 01306 } 01307 } 01308 } 01309 ast_rwlock_unlock(&features_lock); 01310 01311 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 01312 return res; 01313 } 01314 01315 tmp = dynamic_features_buf; 01316 01317 while ((tok = strsep(&tmp, "#"))) { 01318 AST_RWLIST_RDLOCK(&feature_list); 01319 if (!(tmpfeature = find_dynamic_feature(tok))) { 01320 AST_RWLIST_UNLOCK(&feature_list); 01321 continue; 01322 } 01323 01324 /* Feature is up for consideration */ 01325 if (!strcmp(tmpfeature->exten, code)) { 01326 if (option_debug > 2) { 01327 ast_log(LOG_NOTICE, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 01328 } 01329 if (operation) { 01330 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 01331 } 01332 memcpy(feature, tmpfeature, sizeof(feature)); 01333 if (res != FEATURE_RETURN_KEEPTRYING) { 01334 AST_RWLIST_UNLOCK(&feature_list); 01335 break; 01336 } 01337 res = FEATURE_RETURN_PASSDIGITS; 01338 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 01339 res = FEATURE_RETURN_STOREDIGITS; 01340 01341 AST_RWLIST_UNLOCK(&feature_list); 01342 } 01343 01344 return res; 01345 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a feature by name
Definition at line 1165 of file res_features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by feature_interpret_helper(), and set_config_flags().
01166 { 01167 struct ast_call_feature *tmp; 01168 01169 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01170 if (!strcasecmp(tmp->sname, name)) { 01171 break; 01172 } 01173 } 01174 01175 return tmp; 01176 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 759 of file res_features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_blindtransfer(), and do_atxfer().
00760 { 00761 ast_indicate(chan, AST_CONTROL_UNHOLD); 00762 00763 return ast_autoservice_stop(chan); 00764 }
static int handle_parkedcalls | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2722 of file res_features.c.
References ast_cli(), ast_mutex_lock, ast_mutex_unlock, parkeduser::chan, parkeduser::context, parkeduser::exten, ast_channel::name, parkeduser::next, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.
02723 { 02724 struct parkeduser *cur; 02725 int numparked = 0; 02726 02727 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 02728 , "Context", "Extension", "Pri", "Timeout"); 02729 02730 ast_mutex_lock(&parking_lock); 02731 02732 for (cur = parkinglot; cur; cur = cur->next) { 02733 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 02734 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 02735 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 02736 02737 numparked++; 02738 } 02739 ast_mutex_unlock(&parking_lock); 02740 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 02741 02742 02743 return RESULT_SUCCESS; 02744 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2680 of file res_features.c.
References ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, builtin_features, ast_call_feature::default_exten, ast_call_feature::exten, exten, ast_call_feature::feature_entry, FEATURES_COUNT, features_lock, ast_call_feature::fname, format, parking_con, parking_ext, parking_start, parking_stop, RESULT_SUCCESS, and ast_call_feature::sname.
02681 { 02682 int i; 02683 struct ast_call_feature *feature; 02684 char format[] = "%-25s %-7s %-7s\n"; 02685 02686 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 02687 ast_cli(fd, format, "---------------", "-------", "-------"); 02688 02689 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 02690 02691 ast_rwlock_rdlock(&features_lock); 02692 for (i = 0; i < FEATURES_COUNT; i++) 02693 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 02694 ast_rwlock_unlock(&features_lock); 02695 02696 ast_cli(fd, "\n"); 02697 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 02698 ast_cli(fd, format, "---------------", "-------", "-------"); 02699 if (AST_RWLIST_EMPTY(&feature_list)) { 02700 ast_cli(fd, "(none)\n"); 02701 } else { 02702 AST_RWLIST_RDLOCK(&feature_list); 02703 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 02704 ast_cli(fd, format, feature->sname, "no def", feature->exten); 02705 } 02706 AST_RWLIST_UNLOCK(&feature_list); 02707 } 02708 ast_cli(fd, "\nCall parking\n"); 02709 ast_cli(fd, "------------\n"); 02710 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 02711 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 02712 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 02713 ast_cli(fd,"\n"); 02714 02715 return RESULT_SUCCESS; 02716 }
static int load_config | ( | void | ) | [static] |
Definition at line 2918 of file res_features.c.
References adsipark, ast_config_load(), ast_copy_string(), AST_FEATURE_FLAG_BYBOTH, ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_strlen_zero(), ast_variable_browse(), atxfernoanswertimeout, courtesytone, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_WARNING, parkaddhints, parkedcallhangup, parkedcallrecording, parkedcallreparking, parkedcalltransfers, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkmohclass, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.
02919 { 02920 int start = 0, end = 0; 02921 int res; 02922 struct ast_context *con = NULL; 02923 struct ast_config *cfg = NULL; 02924 struct ast_variable *var = NULL; 02925 char old_parking_ext[AST_MAX_EXTENSION]; 02926 char old_parking_con[AST_MAX_EXTENSION] = ""; 02927 02928 if (!ast_strlen_zero(parking_con)) { 02929 strcpy(old_parking_ext, parking_ext); 02930 strcpy(old_parking_con, parking_con); 02931 } 02932 02933 /* Reset to defaults */ 02934 strcpy(parking_con, "parkedcalls"); 02935 strcpy(parking_con_dial, "park-dial"); 02936 strcpy(parking_ext, "700"); 02937 strcpy(pickup_ext, "*8"); 02938 strcpy(parkmohclass, "default"); 02939 courtesytone[0] = '\0'; 02940 strcpy(xfersound, "beep"); 02941 strcpy(xferfailsound, "pbx-invalid"); 02942 parking_start = 701; 02943 parking_stop = 750; 02944 parkfindnext = 0; 02945 adsipark = 0; 02946 parkaddhints = 0; 02947 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 02948 parkedcallreparking = 0; 02949 parkedcallhangup = 0; 02950 parkedcallrecording = 0; 02951 02952 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02953 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02954 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02955 02956 cfg = ast_config_load("features.conf"); 02957 if (!cfg) { 02958 ast_log(LOG_WARNING,"Could not load features.conf\n"); 02959 return AST_MODULE_LOAD_DECLINE; 02960 } 02961 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 02962 if (!strcasecmp(var->name, "parkext")) { 02963 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02964 } else if (!strcasecmp(var->name, "context")) { 02965 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02966 } else if (!strcasecmp(var->name, "parkingtime")) { 02967 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || (parkingtime < 1)) { 02968 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02969 parkingtime = DEFAULT_PARK_TIME; 02970 } else 02971 parkingtime = parkingtime * 1000; 02972 } else if (!strcasecmp(var->name, "parkpos")) { 02973 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 02974 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); 02975 } else { 02976 parking_start = start; 02977 parking_stop = end; 02978 } 02979 } else if (!strcasecmp(var->name, "findslot")) { 02980 parkfindnext = (!strcasecmp(var->value, "next")); 02981 } else if (!strcasecmp(var->name, "parkinghints")) { 02982 parkaddhints = ast_true(var->value); 02983 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 02984 if (!strcasecmp(var->value, "no")) 02985 parkedcalltransfers = 0; 02986 else if (!strcasecmp(var->value, "caller")) 02987 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 02988 else if (!strcasecmp(var->value, "callee")) 02989 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 02990 else if (!strcasecmp(var->value, "both")) 02991 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 02992 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 02993 if (!strcasecmp(var->value, "no")) 02994 parkedcallreparking = 0; 02995 else if (!strcasecmp(var->value, "caller")) 02996 parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 02997 else if (!strcasecmp(var->value, "callee")) 02998 parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 02999 else if (!strcasecmp(var->value, "both")) 03000 parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 03001 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 03002 if (!strcasecmp(var->value, "no")) 03003 parkedcallhangup = 0; 03004 else if (!strcasecmp(var->value, "caller")) 03005 parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 03006 else if (!strcasecmp(var->value, "callee")) 03007 parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 03008 else if (!strcasecmp(var->value, "both")) 03009 parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 03010 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 03011 if (!strcasecmp(var->value, "no")) 03012 parkedcallrecording = 0; 03013 else if (!strcasecmp(var->value, "caller")) 03014 parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 03015 else if (!strcasecmp(var->value, "callee")) 03016 parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 03017 else if (!strcasecmp(var->value, "both")) 03018 parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 03019 } else if (!strcasecmp(var->name, "adsipark")) { 03020 adsipark = ast_true(var->value); 03021 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03022 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03023 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03024 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03025 } else 03026 transferdigittimeout = transferdigittimeout * 1000; 03027 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03028 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03029 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03030 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03031 } 03032 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03033 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03034 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03035 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03036 } else 03037 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03038 } else if (!strcasecmp(var->name, "courtesytone")) { 03039 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03040 } else if (!strcasecmp(var->name, "parkedplay")) { 03041 if (!strcasecmp(var->value, "both")) 03042 parkedplay = 2; 03043 else if (!strcasecmp(var->value, "parked")) 03044 parkedplay = 1; 03045 else 03046 parkedplay = 0; 03047 } else if (!strcasecmp(var->name, "xfersound")) { 03048 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03049 } else if (!strcasecmp(var->name, "xferfailsound")) { 03050 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03051 } else if (!strcasecmp(var->name, "pickupexten")) { 03052 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03053 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03054 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 03055 } 03056 } 03057 03058 unmap_features(); 03059 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03060 if (remap_feature(var->name, var->value)) 03061 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03062 } 03063 03064 /* Map a key combination to an application*/ 03065 ast_unregister_features(); 03066 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03067 char *tmp_val = ast_strdupa(var->value); 03068 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 03069 struct ast_call_feature *feature; 03070 03071 /* strsep() sets the argument to NULL if match not found, and it 03072 * is safe to use it with a NULL argument, so we don't check 03073 * between calls. 03074 */ 03075 exten = strsep(&tmp_val,","); 03076 activatedby = strsep(&tmp_val,","); 03077 app = strsep(&tmp_val,","); 03078 app_args = strsep(&tmp_val,","); 03079 moh_class = strsep(&tmp_val,","); 03080 03081 activateon = strsep(&activatedby, "/"); 03082 03083 /*! \todo XXX var_name or app_args ? */ 03084 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03085 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03086 app, exten, activateon, var->name); 03087 continue; 03088 } 03089 03090 AST_RWLIST_RDLOCK(&feature_list); 03091 if ((feature = find_dynamic_feature(var->name))) { 03092 AST_RWLIST_UNLOCK(&feature_list); 03093 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03094 continue; 03095 } 03096 AST_RWLIST_UNLOCK(&feature_list); 03097 03098 if (!(feature = ast_calloc(1, sizeof(*feature)))) 03099 continue; 03100 03101 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03102 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 03103 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 03104 03105 if (app_args) 03106 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 03107 03108 if (moh_class) 03109 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 03110 03111 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 03112 feature->operation = feature_exec_app; 03113 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03114 03115 /* Allow caller and calle to be specified for backwards compatability */ 03116 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03117 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03118 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03119 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03120 else { 03121 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03122 " must be 'self', or 'peer'\n", var->name); 03123 continue; 03124 } 03125 03126 if (ast_strlen_zero(activatedby)) 03127 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03128 else if (!strcasecmp(activatedby, "caller")) 03129 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03130 else if (!strcasecmp(activatedby, "callee")) 03131 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03132 else if (!strcasecmp(activatedby, "both")) 03133 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03134 else { 03135 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03136 " must be 'caller', or 'callee', or 'both'\n", var->name); 03137 continue; 03138 } 03139 03140 ast_register_feature(feature); 03141 03142 if (option_verbose >= 1) 03143 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 03144 } 03145 ast_config_destroy(cfg); 03146 03147 /* Remove the old parking extension */ 03148 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03149 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 03150 notify_metermaids(old_parking_ext, old_parking_con); 03151 if (option_debug) 03152 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03153 } 03154 03155 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 03156 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 03157 return -1; 03158 } 03159 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 03160 if (parkaddhints) 03161 park_add_hints(parking_con, parking_start, parking_stop); 03162 if (!res) 03163 notify_metermaids(ast_parking_ext(), parking_con); 03164 return res; 03165 03166 }
static int load_module | ( | void | ) | [static] |
Definition at line 3173 of file res_features.c.
References ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application(), cli_features, descrip, descrip2, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), mandescr_park, metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, synopsis, and synopsis2.
03174 { 03175 int res; 03176 03177 memset(parking_ext, 0, sizeof(parking_ext)); 03178 memset(parking_con, 0, sizeof(parking_con)); 03179 03180 if ((res = load_config())) 03181 return res; 03182 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03183 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 03184 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 03185 if (!res) 03186 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 03187 if (!res) { 03188 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 03189 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 03190 "Park a channel", mandescr_park); 03191 } 03192 03193 res |= ast_devstate_prov_add("Park", metermaidstate); 03194 03195 return res; 03196 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2813 of file res_features.c.
References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and s.
Referenced by load_module().
02814 { 02815 const char *channel = astman_get_header(m, "Channel"); 02816 const char *channel2 = astman_get_header(m, "Channel2"); 02817 const char *timeout = astman_get_header(m, "Timeout"); 02818 char buf[BUFSIZ]; 02819 int to = 0; 02820 int res = 0; 02821 int parkExt = 0; 02822 struct ast_channel *ch1, *ch2; 02823 02824 if (ast_strlen_zero(channel)) { 02825 astman_send_error(s, m, "Channel not specified"); 02826 return 0; 02827 } 02828 02829 if (ast_strlen_zero(channel2)) { 02830 astman_send_error(s, m, "Channel2 not specified"); 02831 return 0; 02832 } 02833 02834 ch1 = ast_get_channel_by_name_locked(channel); 02835 if (!ch1) { 02836 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02837 astman_send_error(s, m, buf); 02838 return 0; 02839 } 02840 02841 ch2 = ast_get_channel_by_name_locked(channel2); 02842 if (!ch2) { 02843 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02844 astman_send_error(s, m, buf); 02845 ast_channel_unlock(ch1); 02846 return 0; 02847 } 02848 02849 if (!ast_strlen_zero(timeout)) { 02850 sscanf(timeout, "%30d", &to); 02851 } 02852 02853 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02854 if (!res) { 02855 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02856 astman_send_ack(s, m, "Park successful"); 02857 } else { 02858 astman_send_error(s, m, "Park failure"); 02859 } 02860 02861 ast_channel_unlock(ch1); 02862 ast_channel_unlock(ch2); 02863 02864 return 0; 02865 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 2766 of file res_features.c.
References ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::name, parkeduser::next, parking_lock, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.
Referenced by load_module().
02767 { 02768 struct parkeduser *cur; 02769 const char *id = astman_get_header(m, "ActionID"); 02770 char idText[256] = ""; 02771 02772 if (!ast_strlen_zero(id)) 02773 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 02774 02775 astman_send_ack(s, m, "Parked calls will follow"); 02776 02777 ast_mutex_lock(&parking_lock); 02778 02779 for (cur = parkinglot; cur; cur = cur->next) { 02780 astman_append(s, "Event: ParkedCall\r\n" 02781 "Exten: %d\r\n" 02782 "Channel: %s\r\n" 02783 "From: %s\r\n" 02784 "Timeout: %ld\r\n" 02785 "CallerID: %s\r\n" 02786 "CallerIDName: %s\r\n" 02787 "%s" 02788 "\r\n", 02789 cur->parkingnum, cur->chan->name, cur->peername, 02790 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 02791 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 02792 S_OR(cur->chan->cid.cid_name, ""), 02793 idText); 02794 } 02795 02796 astman_append(s, 02797 "Event: ParkedCallsComplete\r\n" 02798 "%s" 02799 "\r\n",idText); 02800 02801 ast_mutex_unlock(&parking_lock); 02802 02803 return RESULT_SUCCESS; 02804 }
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 557 of file res_features.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), parkeduser::chan, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_PARKFAILED, LOG_WARNING, ast_channel::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().
00558 { 00559 struct ast_channel *chan; 00560 struct ast_frame *f; 00561 struct parkeduser *pu; 00562 int park_status; 00563 00564 if ((pu = park_space_reserve(rchan)) == NULL) { 00565 if (peer) 00566 ast_stream_and_wait(peer, "beeperr", peer->language, ""); 00567 return FEATURE_RETURN_PARKFAILED; 00568 } 00569 00570 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00571 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00572 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00573 return -1; 00574 } 00575 00576 /* Make formats okay */ 00577 chan->readformat = rchan->readformat; 00578 chan->writeformat = rchan->writeformat; 00579 ast_channel_masquerade(chan, rchan); 00580 00581 /* Setup the extensions and such */ 00582 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00583 00584 /* Make the masq execute */ 00585 if ((f = ast_read(chan))) { 00586 ast_frfree(f); 00587 } 00588 00589 if (peer == rchan) { 00590 peer = chan; 00591 } 00592 00593 if (!play_announcement || !orig_chan_name) { 00594 /* chan is the channel being parked, peer is the effective park-er */ 00595 orig_chan_name = ast_strdupa(peer->name); 00596 } 00597 00598 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu); 00599 if (park_status == 1) { 00600 /* would be nice to play: "invalid parking extension" */ 00601 ast_hangup(chan); 00602 return -1; 00603 } 00604 00605 return 0; 00606 }
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 613 of file res_features.c.
References masq_park_call().
Referenced by builtin_blindtransfer(), builtin_parkcall(), and park_call_exec().
00614 { 00615 return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name); 00616 }
static int metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 328 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().
00329 { 00330 int res = AST_DEVICE_INVALID; 00331 char *context = ast_strdupa(data); 00332 char *exten; 00333 00334 exten = strsep(&context, "@"); 00335 if (!context) 00336 return res; 00337 00338 if (option_debug > 3) 00339 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context); 00340 00341 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00342 00343 if (!res) 00344 return AST_DEVICE_NOT_INUSE; 00345 else 00346 return AST_DEVICE_INUSE; 00347 }
static void notify_metermaids | ( | char * | exten, | |
char * | context | |||
) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 317 of file res_features.c.
References ast_device_state_changed(), ast_log(), LOG_DEBUG, and option_debug.
Referenced by do_parking_thread(), park_call_full(), and park_exec().
00318 { 00319 if (option_debug > 3) 00320 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context); 00321 00322 /* Send notification to devicestate subsystem */ 00323 ast_device_state_changed("park:%s@%s", exten, context); 00324 return; 00325 }
static void park_add_hints | ( | char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Add parking hints for all defined parking lots.
Definition at line 2904 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, PRIORITY_HINT, and registrar.
02905 { 02906 int numext; 02907 char device[AST_MAX_EXTENSION]; 02908 char exten[10]; 02909 02910 for (numext = start; numext <= stop; numext++) { 02911 snprintf(exten, sizeof(exten), "%d", numext); 02912 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 02913 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02914 } 02915 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 2460 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_copy_string(), AST_MAX_EXTENSION, ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_module_user::chan, ast_channel::exten, masq_park_call_announce(), ast_channel::name, orig_exten(), and ast_channel::priority.
Referenced by load_module().
02461 { 02462 /* Cache the original channel name in case we get masqueraded in the middle 02463 * of a park--it is still theoretically possible for a transfer to happen before 02464 * we get here, but it is _really_ unlikely */ 02465 char *orig_chan_name = ast_strdupa(chan->name); 02466 char orig_exten[AST_MAX_EXTENSION]; 02467 int orig_priority = chan->priority; 02468 02469 /* Data is unused at the moment but could contain a parking 02470 lot context eventually */ 02471 int res = 0; 02472 struct ast_module_user *u; 02473 02474 u = ast_module_user_add(chan); 02475 02476 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 02477 02478 /* Setup the exten/priority to be s/1 since we don't know 02479 where this call should return */ 02480 strcpy(chan->exten, "s"); 02481 chan->priority = 1; 02482 /* Answer if call is not up */ 02483 if (chan->_state != AST_STATE_UP) 02484 res = ast_answer(chan); 02485 /* Sleep to allow VoIP streams to settle down */ 02486 if (!res) 02487 res = ast_safe_sleep(chan, 1000); 02488 /* Park the call */ 02489 if (!res) { 02490 res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name); 02491 /* Continue on in the dialplan */ 02492 if (res == 1) { 02493 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 02494 chan->priority = orig_priority; 02495 res = 0; 02496 } else if (!res) { 02497 res = 1; 02498 } 02499 } 02500 02501 ast_module_user_remove(u); 02502 02503 return res; 02504 }
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 420 of file res_features.c.
References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_bridged_channel(), AST_CHANNEL_NAME, ast_channel_unlock, ast_clear_flag, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_copy_string(), AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_get_channel_by_name_locked(), ast_indicate_data(), ast_log(), ast_say_digits(), ast_set_flag, ast_strlen_zero(), ast_tvnow(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, option_verbose, park_space_reserve(), parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_getvar_helper(), 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().
00421 { 00422 struct ast_context *con; 00423 int parkingnum_copy; 00424 const char *event_from; 00425 00426 /* Get a valid space if not already done */ 00427 if (pu == NULL) 00428 pu = park_space_reserve(chan); 00429 if (pu == NULL) 00430 return 1; /* Continue execution if possible */ 00431 00432 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum); 00433 00434 chan->appl = "Parked Call"; 00435 chan->data = NULL; 00436 00437 pu->chan = chan; 00438 00439 /* Put the parked channel on hold if we have two different channels */ 00440 if (chan != peer) { 00441 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00442 S_OR(parkmohclass, NULL), 00443 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00444 } 00445 00446 pu->start = ast_tvnow(); 00447 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00448 if (extout) 00449 *extout = pu->parkingnum; 00450 00451 if (peer) { 00452 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels 00453 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking 00454 and we need the callback name to be that of transferer. Since local,1/2 have the same 00455 name we can be tricky and just grab the bridged channel from the other side of the local 00456 */ 00457 if (!strcasecmp(peer->tech->type, "Local")) { 00458 struct ast_channel *tmpchan, *base_peer; 00459 char other_side[AST_CHANNEL_NAME]; 00460 char *c; 00461 ast_copy_string(other_side, S_OR(orig_chan_name, peer->name), sizeof(other_side)); 00462 if ((c = strrchr(other_side, ','))) { 00463 *++c = '1'; 00464 } 00465 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) { 00466 if ((base_peer = ast_bridged_channel(tmpchan))) { 00467 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 00468 } 00469 ast_channel_unlock(tmpchan); 00470 } 00471 } else { 00472 ast_copy_string(pu->peername, S_OR(orig_chan_name, peer->name), sizeof(pu->peername)); 00473 } 00474 } 00475 00476 /* Remember what had been dialed, so that if the parking 00477 expires, we try to come back to the same place */ 00478 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00479 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00480 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00481 parkingnum_copy = pu->parkingnum; 00482 00483 /* If parking a channel directly (peer == chan), don't quite yet get parking running on it. 00484 * All parking lot entires are put into the parking lot with notquiteyet on. */ 00485 if (peer != chan) 00486 pu->notquiteyet = 0; 00487 00488 if (option_verbose > 1) 00489 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)); 00490 00491 if (peer) { 00492 event_from = peer->name; 00493 } else { 00494 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 00495 } 00496 00497 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00498 "Exten: %s\r\n" 00499 "Channel: %s\r\n" 00500 "From: %s\r\n" 00501 "Timeout: %ld\r\n" 00502 "CallerID: %s\r\n" 00503 "CallerIDName: %s\r\n", 00504 pu->parkingexten, pu->chan->name, event_from ? event_from : "", 00505 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00506 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00507 S_OR(pu->chan->cid.cid_name, "<unknown>") 00508 ); 00509 00510 if (peer && adsipark && ast_adsi_available(peer)) { 00511 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00512 ast_adsi_unload_session(peer); 00513 } 00514 00515 con = ast_context_find(parking_con); 00516 if (!con) 00517 con = ast_context_create(NULL, parking_con, registrar); 00518 if (!con) /* Still no context? Bad */ 00519 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00520 if (con) { 00521 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free_ptr, registrar)) { 00522 notify_metermaids(pu->parkingexten, parking_con); 00523 } 00524 } 00525 00526 /* Wake up the (presumably select()ing) thread */ 00527 pthread_kill(parking_thread, SIGURG); 00528 00529 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 00530 if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) { 00531 /* Make sure we don't start saying digits to the channel being parked */ 00532 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00533 /* Tell the peer channel the number of the parking space */ 00534 ast_say_digits(peer, parkingnum_copy, "", peer->language); 00535 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00536 } 00537 00538 if (peer == chan) { /* pu->notquiteyet = 1 */ 00539 /* Wake up parking thread if we're really done */ 00540 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00541 S_OR(parkmohclass, NULL), 00542 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00543 pu->notquiteyet = 0; 00544 pthread_kill(parking_thread, SIGURG); 00545 } 00546 return 0; 00547 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Pickup parked call.
Definition at line 2507 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, ast_copy_flags, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock, ast_mutex_unlock, ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, ast_datastore::data, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_callee, ast_dial_features::features_caller, free, ast_dial_features::is_caller, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), option_verbose, parkedcallhangup, parkedcallrecording, parkedcallreparking, parkedcalltransfers, parkedplay, parking_con, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.
Referenced by load_module().
02508 { 02509 int res = 0; 02510 struct ast_module_user *u; 02511 struct ast_channel *peer=NULL; 02512 struct parkeduser *pu, *pl=NULL; 02513 struct ast_context *con; 02514 02515 int park; 02516 struct ast_bridge_config config; 02517 02518 if (!data) { 02519 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 02520 return -1; 02521 } 02522 02523 u = ast_module_user_add(chan); 02524 02525 park = atoi((char *)data); 02526 ast_mutex_lock(&parking_lock); 02527 pu = parkinglot; 02528 while(pu) { 02529 if (pu->parkingnum == park) { 02530 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 02531 ast_mutex_unlock(&parking_lock); 02532 ast_module_user_remove(u); 02533 return -1; 02534 } 02535 if (pl) 02536 pl->next = pu->next; 02537 else 02538 parkinglot = pu->next; 02539 break; 02540 } 02541 pl = pu; 02542 pu = pu->next; 02543 } 02544 ast_mutex_unlock(&parking_lock); 02545 if (pu) { 02546 peer = pu->chan; 02547 con = ast_context_find(parking_con); 02548 if (con) { 02549 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 02550 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02551 else 02552 notify_metermaids(pu->parkingexten, parking_con); 02553 } else 02554 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02555 02556 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 02557 "Exten: %s\r\n" 02558 "Channel: %s\r\n" 02559 "From: %s\r\n" 02560 "CallerID: %s\r\n" 02561 "CallerIDName: %s\r\n", 02562 pu->parkingexten, pu->chan->name, chan->name, 02563 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02564 S_OR(pu->chan->cid.cid_name, "<unknown>") 02565 ); 02566 02567 free(pu); 02568 } 02569 /* JK02: it helps to answer the channel if not already up */ 02570 if (chan->_state != AST_STATE_UP) 02571 ast_answer(chan); 02572 02573 if (peer) { 02574 struct ast_datastore *features_datastore; 02575 struct ast_dial_features *dialfeatures = NULL; 02576 02577 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 02578 02579 if (!ast_strlen_zero(courtesytone)) { 02580 int error = 0; 02581 ast_indicate(peer, AST_CONTROL_UNHOLD); 02582 if (parkedplay == 0) { 02583 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 02584 } else if (parkedplay == 1) { 02585 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 02586 } else if (parkedplay == 2) { 02587 if (!ast_streamfile(chan, courtesytone, chan->language) && 02588 !ast_streamfile(peer, courtesytone, chan->language)) { 02589 /*! \todo XXX we would like to wait on both! */ 02590 res = ast_waitstream(chan, ""); 02591 if (res >= 0) 02592 res = ast_waitstream(peer, ""); 02593 if (res < 0) 02594 error = 1; 02595 } 02596 } 02597 if (error) { 02598 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02599 ast_hangup(peer); 02600 ast_module_user_remove(u); 02601 return -1; 02602 } 02603 } else 02604 ast_indicate(peer, AST_CONTROL_UNHOLD); 02605 02606 res = ast_channel_make_compatible(chan, peer); 02607 if (res < 0) { 02608 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 02609 ast_hangup(peer); 02610 ast_module_user_remove(u); 02611 return -1; 02612 } 02613 /* This runs sorta backwards, since we give the incoming channel control, as if it 02614 were the person called. */ 02615 if (option_verbose > 2) 02616 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 02617 02618 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02619 ast_cdr_setdestchan(chan->cdr, peer->name); 02620 memset(&config, 0, sizeof(struct ast_bridge_config)); 02621 02622 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 02623 ast_channel_lock(peer); 02624 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 02625 dialfeatures = features_datastore->data; 02626 } 02627 ast_channel_unlock(peer); 02628 02629 if (dialfeatures) { 02630 ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL); 02631 } 02632 02633 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 02634 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02635 } 02636 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 02637 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02638 } 02639 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 02640 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 02641 } 02642 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 02643 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 02644 } 02645 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 02646 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 02647 } 02648 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 02649 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 02650 } 02651 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 02652 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 02653 } 02654 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 02655 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 02656 } 02657 res = ast_bridge_call(chan, peer, &config); 02658 02659 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02660 ast_cdr_setdestchan(chan->cdr, peer->name); 02661 02662 /* Simulate the PBX hanging up */ 02663 ast_hangup(peer); 02664 ast_module_user_remove(u); 02665 return -1; 02666 } else { 02667 /*! \todo XXX Play a message XXX */ 02668 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 02669 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 02670 if (option_verbose > 2) 02671 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 02672 res = -1; 02673 } 02674 02675 ast_module_user_remove(u); 02676 02677 return -1; 02678 }
static struct parkeduser* park_space_reserve | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 349 of file res_features.c.
References ast_calloc, ast_exists_extension(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), parkeduser::chan, free, LOG_WARNING, parkeduser::next, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, and pbx_builtin_getvar_helper().
Referenced by masq_park_call(), and park_call_full().
00350 { 00351 struct parkeduser *pu, *cur; 00352 int i, parking_space = -1, parking_range; 00353 const char *parkingexten; 00354 00355 /* Allocate memory for parking data */ 00356 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00357 return NULL; 00358 00359 /* Lock parking lot */ 00360 ast_mutex_lock(&parking_lock); 00361 /* Check for channel variable PARKINGEXTEN */ 00362 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00363 if (!ast_strlen_zero(parkingexten)) { 00364 /*!\note The API forces us to specify a numeric parking slot, even 00365 * though the architecture would tend to support non-numeric extensions 00366 * (as are possible with SIP, for example). Hence, we enforce that 00367 * limitation here. If extout was not numeric, we could permit 00368 * arbitrary non-numeric extensions. 00369 */ 00370 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) { 00371 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); 00372 ast_mutex_unlock(&parking_lock); 00373 free(pu); 00374 return NULL; 00375 } 00376 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00377 00378 if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) { 00379 ast_mutex_unlock(&parking_lock); 00380 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00381 free(pu); 00382 return NULL; 00383 } 00384 } else { 00385 /* Select parking space within range */ 00386 parking_range = parking_stop - parking_start+1; 00387 for (i = 0; i < parking_range; i++) { 00388 parking_space = (i + parking_offset) % parking_range + parking_start; 00389 cur = parkinglot; 00390 while(cur) { 00391 if (cur->parkingnum == parking_space) 00392 break; 00393 cur = cur->next; 00394 } 00395 if (!cur) 00396 break; 00397 } 00398 00399 if (!(i < parking_range)) { 00400 ast_log(LOG_WARNING, "No more parking spaces\n"); 00401 ast_mutex_unlock(&parking_lock); 00402 free(pu); 00403 return NULL; 00404 } 00405 /* Set pointer for next parking */ 00406 if (parkfindnext) 00407 parking_offset = parking_space - parking_start + 1; 00408 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00409 } 00410 00411 pu->notquiteyet = 1; 00412 pu->parkingnum = parking_space; 00413 pu->next = parkinglot; 00414 parkinglot = pu; 00415 ast_mutex_unlock(&parking_lock); 00416 00417 return pu; 00418 }
Definition at line 1601 of file res_features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
01602 { 01603 struct ast_cdr *cdr_orig = cdr; 01604 while (cdr) { 01605 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 01606 return cdr; 01607 cdr = cdr->next; 01608 } 01609 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 01610 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 2211 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().
02212 { 02213 manager_event(EVENT_FLAG_CALL, s, 02214 "Exten: %s\r\n" 02215 "Channel: %s\r\n" 02216 "CallerID: %s\r\n" 02217 "CallerIDName: %s\r\n\r\n", 02218 parkingexten, 02219 chan->name, 02220 S_OR(chan->cid.cid_num, "<unknown>"), 02221 S_OR(chan->cid.cid_name, "<unknown>") 02222 ); 02223 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
Definition at line 767 of file res_features.c.
References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, pbx_builtin_getvar_helper(), and s.
Referenced by builtin_blindtransfer(), and do_atxfer().
00768 { 00769 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00770 if (ast_strlen_zero(s)) 00771 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00772 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */ 00773 s = transferer->macrocontext; 00774 if (ast_strlen_zero(s)) 00775 s = transferer->context; 00776 return s; 00777 }
static int reload | ( | void | ) | [static] |
Definition at line 3168 of file res_features.c.
References load_config().
03169 { 03170 return load_config(); 03171 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1246 of file res_features.c.
References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, exten, FEATURES_COUNT, and features_lock.
01247 { 01248 int x, res = -1; 01249 01250 ast_rwlock_wrlock(&features_lock); 01251 for (x = 0; x < FEATURES_COUNT; x++) { 01252 if (strcasecmp(builtin_features[x].sname, name)) 01253 continue; 01254 01255 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01256 res = 0; 01257 break; 01258 } 01259 ast_rwlock_unlock(&features_lock); 01260 01261 return res; 01262 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 1612 of file res_features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), config, and LOG_WARNING.
Referenced by ast_bridge_call().
01613 { 01614 const char *feature; 01615 01616 if (ast_strlen_zero(features)) { 01617 return; 01618 } 01619 01620 for (feature = features; *feature; feature++) { 01621 switch (*feature) { 01622 case 'T' : 01623 case 't' : 01624 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 01625 break; 01626 case 'K' : 01627 case 'k' : 01628 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 01629 break; 01630 case 'H' : 01631 case 'h' : 01632 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 01633 break; 01634 case 'W' : 01635 case 'w' : 01636 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 01637 break; 01638 default : 01639 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 01640 } 01641 } 01642 }
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 225 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().
00226 { 00227 ast_copy_string(chan->context, context, sizeof(chan->context)); 00228 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00229 chan->priority = pri; 00230 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 1391 of file res_features.c.
References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock, ast_rwlock_unlock, ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, config, ast_call_feature::feature_mask, FEATURES_COUNT, features_lock, find_dynamic_feature(), and pbx_builtin_getvar_helper().
Referenced by ast_bridge_call().
01392 { 01393 int x; 01394 01395 ast_clear_flag(config, AST_FLAGS_ALL); 01396 01397 ast_rwlock_rdlock(&features_lock); 01398 for (x = 0; x < FEATURES_COUNT; x++) { 01399 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 01400 continue; 01401 01402 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01403 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01404 01405 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01406 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01407 } 01408 ast_rwlock_unlock(&features_lock); 01409 01410 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01411 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01412 01413 if (dynamic_features) { 01414 char *tmp = ast_strdupa(dynamic_features); 01415 char *tok; 01416 struct ast_call_feature *feature; 01417 01418 /* while we have a feature */ 01419 while ((tok = strsep(&tmp, "#"))) { 01420 AST_RWLIST_RDLOCK(&feature_list); 01421 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01422 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01423 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01424 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01425 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01426 } 01427 AST_RWLIST_UNLOCK(&feature_list); 01428 } 01429 } 01430 } 01431 }
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 621 of file res_features.c.
References parkeduser::chan, and FEATURE_SENSE_PEER.
Referenced by builtin_automonitor(), builtin_blindtransfer(), builtin_parkcall(), and do_atxfer().
00623 { 00624 if (sense == FEATURE_SENSE_PEER) { 00625 *caller = peer; 00626 *callee = chan; 00627 } else { 00628 *callee = peer; 00629 *caller = chan; 00630 } 00631 }
static int unload_module | ( | void | ) | [static] |
Definition at line 3199 of file res_features.c.
References ast_cli_unregister_multiple(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), cli_features, parkcall, and parkedcall.
03200 { 03201 ast_module_user_hangup_all(); 03202 03203 ast_manager_unregister("ParkedCalls"); 03204 ast_manager_unregister("Park"); 03205 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03206 ast_unregister_application(parkcall); 03207 ast_devstate_prov_del("Park"); 03208 return ast_unregister_application(parkedcall); 03209 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1236 of file res_features.c.
References ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, exten, FEATURES_COUNT, and features_lock.
01237 { 01238 int x; 01239 01240 ast_rwlock_wrlock(&features_lock); 01241 for (x = 0; x < FEATURES_COUNT; x++) 01242 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01243 ast_rwlock_unlock(&features_lock); 01244 }
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 = "6989f2ec67f8497e38c12890500c525b" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 3215 of file res_features.c.
int adsipark [static] |
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 3215 of file res_features.c.
int atxfernoanswertimeout [static] |
struct ast_call_feature builtin_features[] [static] |
Definition at line 1110 of file res_features.c.
Referenced by ast_feature_request_and_dial(), feature_interpret_helper(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().
struct ast_cli_entry cli_features[] [static] |
Definition at line 2755 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 2750 of file res_features.c.
char courtesytone[256] [static] |
Courtesy tone
Definition at line 109 of file res_features.c.
Referenced by load_config(), and park_exec().
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 129 of file res_features.c.
char* descrip2 [static] |
Definition at line 139 of file res_features.c.
Initial value:
{ .type = "dial-features", .destroy = dial_features_destroy, .duplicate = dial_features_duplicate, }
Definition at line 201 of file res_features.c.
Referenced by add_features_datastores(), do_atxfer(), do_parking_thread(), and park_exec().
int featuredigittimeout [static] |
Definition at line 120 of file res_features.c.
ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static] |
Definition at line 1108 of file res_features.c.
Referenced by ast_feature_request_and_dial(), feature_interpret_helper(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().
char mandescr_park[] [static] |
struct ast_app* monitor_app = NULL [static] |
Definition at line 150 of file res_features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 151 of file res_features.c.
int parkaddhints = 0 [static] |
Add parking hints automatically
Definition at line 94 of file res_features.c.
Referenced by load_config().
char* parkcall = PARK_APP_NAME [static] |
char* parkedcall = "ParkedCall" [static] |
int parkedcallhangup [static] |
Who can DISCONNECT after picking up a parked call
Definition at line 106 of file res_features.c.
Referenced by load_config(), and park_exec().
int parkedcallrecording [static] |
Who can AUTOMON after picking up a parked call
Definition at line 107 of file res_features.c.
Referenced by load_config(), and park_exec().
int parkedcallreparking [static] |
Who can PARKCALL after picking up a parked call
Definition at line 105 of file res_features.c.
Referenced by load_config(), and park_exec().
int parkedcalltransfers [static] |
Who can REDIRECT after picking up a parked a call
Definition at line 104 of file res_features.c.
Referenced by load_config(), and park_exec().
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 110 of file res_features.c.
Referenced by park_exec().
int parkfindnext [static] |
char parking_con[AST_MAX_EXTENSION] [static] |
Context for which parking is made accessible
Definition at line 96 of file res_features.c.
Referenced by handle_showfeatures(), load_config(), load_module(), and park_exec().
char parking_con_dial[AST_MAX_EXTENSION] [static] |
Context for dialback for parking (KLUDGE)
Definition at line 97 of file res_features.c.
Referenced by load_config().
char parking_ext[AST_MAX_EXTENSION] [static] |
Extension you type to park the call
Definition at line 98 of file res_features.c.
Referenced by handle_showfeatures(), load_config(), and load_module().
ast_mutex_t parking_lock = { PTHREAD_MUTEX_INITIALIZER , 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INITIALIZER } [static] |
protects all static variables above
Definition at line 170 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 114 of file res_features.c.
int parking_start [static] |
First available extension for parking
Definition at line 101 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
int parking_stop [static] |
Last available extension for parking
Definition at line 102 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
pthread_t parking_thread [static] |
struct parkeduser* parkinglot [static] |
Definition at line 168 of file res_features.c.
Referenced by do_parking_thread(), handle_parkedcalls(), manager_parking_status(), park_exec(), and park_space_reserve().
int parkingtime = DEFAULT_PARK_TIME [static] |
No more than 45 seconds parked before you do something with them
Definition at line 95 of file res_features.c.
char parkmohclass[MAX_MUSICCLASS] [static] |
Music class used for parking
Definition at line 100 of file res_features.c.
Referenced by load_config().
char pickup_ext[AST_MAX_EXTENSION] [static] |
char* registrar = "res_features" [static] |
Registrar for operations
Definition at line 124 of file res_features.c.
char showfeatures_help[] [static] |
Initial value:
"Usage: feature list\n" " Lists currently configured features.\n"
Definition at line 2718 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 2746 of file res_features.c.
char* synopsis = "Answer a parked call" [static] |
Definition at line 127 of file res_features.c.
char* synopsis2 = "Park yourself" [static] |
Definition at line 137 of file res_features.c.
int transferdigittimeout [static] |
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 112 of file res_features.c.
Referenced by load_config().
char xfersound[256] [static] |