#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 1105 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 3207 of file res_features.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 3207 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 1639 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().
01640 { 01641 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 01642 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 01643 01644 ast_channel_lock(caller); 01645 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 01646 ast_channel_unlock(caller); 01647 if (!ds_caller_features) { 01648 if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 01649 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 01650 return; 01651 } 01652 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 01653 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 01654 ast_channel_datastore_free(ds_caller_features); 01655 return; 01656 } 01657 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 01658 caller_features->is_caller = 1; 01659 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 01660 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 01661 ds_caller_features->data = caller_features; 01662 ast_channel_lock(caller); 01663 ast_channel_datastore_add(caller, ds_caller_features); 01664 ast_channel_unlock(caller); 01665 } else { 01666 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 01667 * flags over from the atxfer to the caller */ 01668 return; 01669 } 01670 01671 ast_channel_lock(callee); 01672 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 01673 ast_channel_unlock(callee); 01674 if (!ds_callee_features) { 01675 if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 01676 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 01677 return; 01678 } 01679 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 01680 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 01681 ast_channel_datastore_free(ds_callee_features); 01682 return; 01683 } 01684 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 01685 callee_features->is_caller = 0; 01686 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 01687 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 01688 ds_callee_features->data = callee_features; 01689 ast_channel_lock(callee); 01690 ast_channel_datastore_add(callee, ds_callee_features); 01691 ast_channel_unlock(callee); 01692 } 01693 01694 return; 01695 }
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 1706 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().
01707 { 01708 /* Copy voice back and forth between the two channels. Give the peer 01709 the ability to transfer calls with '#<extension' syntax. */ 01710 struct ast_frame *f; 01711 struct ast_channel *who; 01712 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01713 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01714 char orig_channame[AST_MAX_EXTENSION]; 01715 char orig_peername[AST_MAX_EXTENSION]; 01716 01717 int res; 01718 int diff; 01719 int hasfeatures=0; 01720 int hadfeatures=0; 01721 int autoloopflag; 01722 struct ast_option_header *aoh; 01723 struct ast_bridge_config backup_config; 01724 struct ast_cdr *bridge_cdr = NULL; 01725 struct ast_cdr *orig_peer_cdr = NULL; 01726 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 01727 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 01728 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01729 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01730 01731 memset(&backup_config, 0, sizeof(backup_config)); 01732 01733 config->start_time = ast_tvnow(); 01734 01735 if (chan && peer) { 01736 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01737 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01738 } else if (chan) { 01739 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01740 } 01741 01742 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 01743 add_features_datastores(chan, peer, config); 01744 01745 /* This is an interesting case. One example is if a ringing channel gets redirected to 01746 * an extension that picks up a parked call. This will make sure that the call taken 01747 * out of parking gets told that the channel it just got bridged to is still ringing. */ 01748 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 01749 ast_indicate(peer, AST_CONTROL_RINGING); 01750 } 01751 01752 if (monitor_ok) { 01753 const char *monitor_exec; 01754 struct ast_channel *src = NULL; 01755 if (!monitor_app) { 01756 if (!(monitor_app = pbx_findapp("Monitor"))) 01757 monitor_ok=0; 01758 } 01759 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01760 src = chan; 01761 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01762 src = peer; 01763 if (monitor_app && src) { 01764 char *tmp = ast_strdupa(monitor_exec); 01765 pbx_exec(src, monitor_app, tmp); 01766 } 01767 } 01768 01769 set_config_flags(chan, peer, config); 01770 config->firstpass = 1; 01771 01772 /* Answer if need be */ 01773 if (ast_answer(chan)) 01774 return -1; 01775 01776 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 01777 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 01778 orig_peer_cdr = peer_cdr; 01779 01780 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 01781 01782 if (chan_cdr) { 01783 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 01784 ast_cdr_update(chan); 01785 bridge_cdr = ast_cdr_dup(chan_cdr); 01786 /* rip any forked CDR's off of the chan_cdr and attach 01787 * them to the bridge_cdr instead */ 01788 bridge_cdr->next = chan_cdr->next; 01789 chan_cdr->next = NULL; 01790 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 01791 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 01792 } else { 01793 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 01794 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 01795 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 01796 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 01797 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 01798 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 01799 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 01800 ast_cdr_setcid(bridge_cdr, chan); 01801 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NOANSWER; 01802 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 01803 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 01804 /* Destination information */ 01805 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 01806 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 01807 if (peer_cdr) { 01808 bridge_cdr->start = peer_cdr->start; 01809 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 01810 } else { 01811 ast_cdr_start(bridge_cdr); 01812 } 01813 } 01814 /* peer_cdr->answer will be set when a macro runs on the peer; 01815 in that case, the bridge answer will be delayed while the 01816 macro plays on the peer channel. The peer answered the call 01817 before the macro started playing. To the phone system, 01818 this is billable time for the call, even tho the caller 01819 hears nothing but ringing while the macro does its thing. */ 01820 01821 /* Another case where the peer cdr's time will be set, is when 01822 A self-parks by pickup up phone and dialing 700, then B 01823 picks up A by dialing its parking slot; there may be more 01824 practical paths that get the same result, tho... in which 01825 case you get the previous answer time from the Park... which 01826 is before the bridge's start time, so I added in the 01827 tvcmp check to the if below */ 01828 01829 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer->cdr->answer, bridge_cdr->start) >= 0) { 01830 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 01831 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 01832 if (chan_cdr) { 01833 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 01834 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 01835 } 01836 } else { 01837 ast_cdr_answer(bridge_cdr); 01838 if (chan_cdr) { 01839 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 01840 } 01841 } 01842 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 01843 if (chan_cdr) { 01844 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 01845 } 01846 if (peer_cdr) { 01847 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 01848 } 01849 } 01850 } 01851 01852 for (;;) { 01853 struct ast_channel *other; /* used later */ 01854 01855 res = ast_channel_bridge(chan, peer, config, &f, &who); 01856 01857 /* When frame is not set, we are probably involved in a situation 01858 where we've timed out. 01859 When frame is set, we'll come thru this code twice; once for DTMF_BEGIN 01860 and also for DTMF_END. If we flow into the following 'if' for both, then 01861 our wait times are cut in half, as both will subtract from the 01862 feature_timer. Not good! 01863 */ 01864 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 01865 /* Update time limit for next pass */ 01866 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01867 if (res == AST_BRIDGE_RETRY) { 01868 /* The feature fully timed out but has not been updated. Skip 01869 * the potential round error from the diff calculation and 01870 * explicitly set to expired. */ 01871 config->feature_timer = -1; 01872 } else { 01873 config->feature_timer -= diff; 01874 } 01875 01876 if (hasfeatures) { 01877 /* Running on backup config, meaning a feature might be being 01878 activated, but that's no excuse to keep things going 01879 indefinitely! */ 01880 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01881 if (option_debug) 01882 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01883 config->feature_timer = 0; 01884 who = chan; 01885 if (f) 01886 ast_frfree(f); 01887 f = NULL; 01888 res = 0; 01889 } else if (config->feature_timer <= 0) { 01890 /* Not *really* out of time, just out of time for 01891 digits to come in for features. */ 01892 if (option_debug) 01893 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01894 if (!ast_strlen_zero(peer_featurecode)) { 01895 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01896 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01897 } 01898 if (!ast_strlen_zero(chan_featurecode)) { 01899 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01900 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01901 } 01902 if (f) 01903 ast_frfree(f); 01904 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01905 if (!hasfeatures) { 01906 /* Restore original (possibly time modified) bridge config */ 01907 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01908 memset(&backup_config, 0, sizeof(backup_config)); 01909 } 01910 hadfeatures = hasfeatures; 01911 /* Continue as we were */ 01912 continue; 01913 } else if (!f) { 01914 /* The bridge returned without a frame and there is a feature in progress. 01915 * However, we don't think the feature has quite yet timed out, so just 01916 * go back into the bridge. */ 01917 continue; 01918 } 01919 } else { 01920 if (config->feature_timer <=0) { 01921 /* We ran out of time */ 01922 config->feature_timer = 0; 01923 who = chan; 01924 if (f) 01925 ast_frfree(f); 01926 f = NULL; 01927 res = 0; 01928 } 01929 } 01930 } 01931 if (res < 0) { 01932 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01933 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01934 goto before_you_go; 01935 } 01936 01937 if (!f || (f->frametype == AST_FRAME_CONTROL && 01938 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01939 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01940 res = -1; 01941 break; 01942 } 01943 /* many things should be sent to the 'other' channel */ 01944 other = (who == chan) ? peer : chan; 01945 if (f->frametype == AST_FRAME_CONTROL) { 01946 switch (f->subclass) { 01947 case AST_CONTROL_RINGING: 01948 case AST_CONTROL_FLASH: 01949 case -1: 01950 ast_indicate(other, f->subclass); 01951 break; 01952 case AST_CONTROL_HOLD: 01953 case AST_CONTROL_UNHOLD: 01954 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01955 break; 01956 case AST_CONTROL_OPTION: 01957 aoh = f->data; 01958 /* Forward option Requests */ 01959 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01960 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01961 f->datalen - sizeof(struct ast_option_header), 0); 01962 } 01963 break; 01964 case AST_CONTROL_ATXFERCMD: 01965 cmd_atxfer(chan, peer, config, who, f->data); 01966 break; 01967 } 01968 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01969 /* eat it */ 01970 } else if (f->frametype == AST_FRAME_DTMF) { 01971 char *featurecode; 01972 int sense; 01973 01974 hadfeatures = hasfeatures; 01975 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01976 if (who == chan) { 01977 sense = FEATURE_SENSE_CHAN; 01978 featurecode = chan_featurecode; 01979 } else { 01980 sense = FEATURE_SENSE_PEER; 01981 featurecode = peer_featurecode; 01982 } 01983 /*! append the event to featurecode. we rely on the string being zero-filled, and 01984 * not overflowing it. 01985 * \todo XXX how do we guarantee the latter ? 01986 */ 01987 featurecode[strlen(featurecode)] = f->subclass; 01988 /* Get rid of the frame before we start doing "stuff" with the channels */ 01989 ast_frfree(f); 01990 f = NULL; 01991 config->feature_timer = backup_config.feature_timer; 01992 res = feature_interpret(chan, peer, config, featurecode, sense); 01993 switch(res) { 01994 case FEATURE_RETURN_PASSDIGITS: 01995 ast_dtmf_stream(other, who, featurecode, 0); 01996 /* Fall through */ 01997 case FEATURE_RETURN_SUCCESS: 01998 memset(featurecode, 0, sizeof(chan_featurecode)); 01999 break; 02000 } 02001 if (res >= FEATURE_RETURN_PASSDIGITS) { 02002 res = 0; 02003 } else 02004 break; 02005 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02006 if (hadfeatures && !hasfeatures) { 02007 /* Restore backup */ 02008 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02009 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02010 } else if (hasfeatures) { 02011 if (!hadfeatures) { 02012 /* Backup configuration */ 02013 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02014 /* Setup temporary config options */ 02015 config->play_warning = 0; 02016 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02017 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02018 config->warning_freq = 0; 02019 config->warning_sound = NULL; 02020 config->end_sound = NULL; 02021 config->start_sound = NULL; 02022 config->firstpass = 0; 02023 } 02024 config->start_time = ast_tvnow(); 02025 config->feature_timer = featuredigittimeout; 02026 if (option_debug) 02027 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 02028 } 02029 } 02030 if (f) 02031 ast_frfree(f); 02032 02033 } 02034 before_you_go: 02035 02036 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02037 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02038 if (bridge_cdr) { 02039 ast_cdr_discard(bridge_cdr); 02040 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02041 } 02042 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02043 } 02044 02045 if (config->end_bridge_callback) { 02046 config->end_bridge_callback(config->end_bridge_callback_data); 02047 } 02048 02049 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02050 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02051 struct ast_cdr *swapper = NULL; 02052 char savelastapp[AST_MAX_EXTENSION]; 02053 char savelastdata[AST_MAX_EXTENSION]; 02054 char save_exten[AST_MAX_EXTENSION]; 02055 int save_prio, spawn_error = 0; 02056 02057 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02058 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02059 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02060 ast_cdr_end(bridge_cdr); 02061 } 02062 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02063 dialplan code operate on it */ 02064 ast_channel_lock(chan); 02065 if (bridge_cdr) { 02066 swapper = chan->cdr; 02067 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02068 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02069 chan->cdr = bridge_cdr; 02070 } 02071 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02072 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02073 save_prio = chan->priority; 02074 chan->priority = 1; 02075 ast_channel_unlock(chan); 02076 while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) { 02077 if ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) { 02078 /* Something bad happened, or a hangup has been requested. */ 02079 if (option_debug) 02080 ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02081 if (option_verbose > 1) 02082 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); 02083 break; 02084 } 02085 chan->priority++; 02086 } 02087 /* swap it back */ 02088 ast_channel_lock(chan); 02089 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02090 chan->priority = save_prio; 02091 if (bridge_cdr) { 02092 if (chan->cdr == bridge_cdr) { 02093 chan->cdr = swapper; 02094 } else { 02095 bridge_cdr = NULL; 02096 } 02097 } 02098 if (chan->priority != 1 || !spawn_error) { 02099 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02100 } 02101 ast_channel_unlock(chan); 02102 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02103 if (bridge_cdr) { 02104 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02105 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02106 } 02107 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02108 } 02109 02110 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02111 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02112 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 02113 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02114 } 02115 02116 /* we can post the bridge CDR at this point */ 02117 if (bridge_cdr) { 02118 ast_cdr_end(bridge_cdr); 02119 ast_cdr_detach(bridge_cdr); 02120 } 02121 02122 /* do a specialized reset on the beginning channel 02123 CDR's, if they still exist, so as not to mess up 02124 issues in future bridges; 02125 02126 Here are the rules of the game: 02127 1. The chan and peer channel pointers will not change 02128 during the life of the bridge. 02129 2. But, in transfers, the channel names will change. 02130 between the time the bridge is started, and the 02131 time the channel ends. 02132 Usually, when a channel changes names, it will 02133 also change CDR pointers. 02134 3. Usually, only one of the two channels (chan or peer) 02135 will change names. 02136 4. Usually, if a channel changes names during a bridge, 02137 it is because of a transfer. Usually, in these situations, 02138 it is normal to see 2 bridges running simultaneously, and 02139 it is not unusual to see the two channels that change 02140 swapped between bridges. 02141 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02142 to attend to; if the chan or peer changed names, 02143 we have the before and after attached CDR's. 02144 */ 02145 02146 if (new_chan_cdr) { 02147 struct ast_channel *chan_ptr = NULL; 02148 02149 if (strcasecmp(orig_channame, chan->name) != 0) { 02150 /* old channel */ 02151 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02152 if (chan_ptr) { 02153 if (!ast_bridged_channel(chan_ptr)) { 02154 struct ast_cdr *cur; 02155 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02156 if (cur == chan_cdr) { 02157 break; 02158 } 02159 } 02160 if (cur) 02161 ast_cdr_specialized_reset(chan_cdr,0); 02162 } 02163 ast_channel_unlock(chan_ptr); 02164 } 02165 /* new channel */ 02166 ast_cdr_specialized_reset(new_chan_cdr,0); 02167 } else { 02168 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02169 } 02170 } 02171 02172 { 02173 struct ast_channel *chan_ptr = NULL; 02174 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02175 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)) 02176 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02177 if (strcasecmp(orig_peername, peer->name) != 0) { 02178 /* old channel */ 02179 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02180 if (chan_ptr) { 02181 if (!ast_bridged_channel(chan_ptr)) { 02182 struct ast_cdr *cur; 02183 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02184 if (cur == peer_cdr) { 02185 break; 02186 } 02187 } 02188 if (cur) 02189 ast_cdr_specialized_reset(peer_cdr,0); 02190 } 02191 ast_channel_unlock(chan_ptr); 02192 } 02193 /* new channel */ 02194 ast_cdr_specialized_reset(new_peer_cdr,0); 02195 } else { 02196 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02197 } 02198 } 02199 02200 return res; 02201 }
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 1385 of file res_features.c.
References feature_interpret_helper().
Referenced by detect_disconnect().
01385 { 01386 01387 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 01388 }
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 1433 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_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, 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(), 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().
01434 { 01435 int state = 0; 01436 int cause = 0; 01437 int to; 01438 struct ast_channel *chan; 01439 struct ast_channel *monitor_chans[2]; 01440 struct ast_channel *active_channel; 01441 int res = 0, ready = 0; 01442 01443 if ((chan = ast_request(type, format, data, &cause))) { 01444 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01445 ast_string_field_set(chan, language, language); 01446 ast_channel_inherit_variables(caller, chan); 01447 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01448 01449 if (!ast_call(chan, data, timeout)) { 01450 struct timeval started; 01451 int x, len = 0; 01452 char *disconnect_code = NULL, *dialed_code = NULL; 01453 01454 ast_indicate(caller, AST_CONTROL_RINGING); 01455 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01456 ast_rwlock_rdlock(&features_lock); 01457 for (x = 0; x < FEATURES_COUNT; x++) { 01458 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01459 continue; 01460 01461 disconnect_code = builtin_features[x].exten; 01462 len = strlen(disconnect_code) + 1; 01463 dialed_code = alloca(len); 01464 memset(dialed_code, 0, len); 01465 break; 01466 } 01467 ast_rwlock_unlock(&features_lock); 01468 x = 0; 01469 started = ast_tvnow(); 01470 to = timeout; 01471 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01472 struct ast_frame *f = NULL; 01473 01474 monitor_chans[0] = caller; 01475 monitor_chans[1] = chan; 01476 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01477 01478 /* see if the timeout has been violated */ 01479 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01480 state = AST_CONTROL_UNHOLD; 01481 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01482 break; /*doh! timeout*/ 01483 } 01484 01485 if (!active_channel) 01486 continue; 01487 01488 if (chan && (chan == active_channel)) { 01489 if (!ast_strlen_zero(chan->call_forward)) { 01490 if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) { 01491 return NULL; 01492 } 01493 continue; 01494 } 01495 f = ast_read(chan); 01496 if (f == NULL) { /*doh! where'd he go?*/ 01497 state = AST_CONTROL_HANGUP; 01498 res = 0; 01499 break; 01500 } 01501 01502 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01503 if (f->subclass == AST_CONTROL_RINGING) { 01504 state = f->subclass; 01505 if (option_verbose > 2) 01506 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01507 ast_indicate(caller, AST_CONTROL_RINGING); 01508 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01509 state = f->subclass; 01510 if (option_verbose > 2) 01511 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01512 ast_indicate(caller, AST_CONTROL_BUSY); 01513 ast_frfree(f); 01514 f = NULL; 01515 break; 01516 } else if (f->subclass == AST_CONTROL_ANSWER) { 01517 /* This is what we are hoping for */ 01518 state = f->subclass; 01519 ast_frfree(f); 01520 f = NULL; 01521 ready=1; 01522 break; 01523 } else if (f->subclass != -1) { 01524 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01525 } 01526 /* else who cares */ 01527 } 01528 01529 } else if (caller && (active_channel == caller)) { 01530 f = ast_read(caller); 01531 if (f == NULL) { /*doh! where'd he go?*/ 01532 if (caller->_softhangup && !chan->_softhangup) { 01533 /* make this a blind transfer */ 01534 ready = 1; 01535 break; 01536 } 01537 state = AST_CONTROL_HANGUP; 01538 res = 0; 01539 break; 01540 } 01541 01542 if (f->frametype == AST_FRAME_DTMF) { 01543 dialed_code[x++] = f->subclass; 01544 dialed_code[x] = '\0'; 01545 if (strlen(dialed_code) == len) { 01546 x = 0; 01547 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01548 x = 0; 01549 dialed_code[x] = '\0'; 01550 } 01551 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01552 /* Caller Canceled the call */ 01553 state = AST_CONTROL_UNHOLD; 01554 ast_frfree(f); 01555 f = NULL; 01556 break; 01557 } 01558 } 01559 } 01560 if (f) 01561 ast_frfree(f); 01562 } /* end while */ 01563 } else 01564 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01565 } else { 01566 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01567 switch(cause) { 01568 case AST_CAUSE_BUSY: 01569 state = AST_CONTROL_BUSY; 01570 break; 01571 case AST_CAUSE_CONGESTION: 01572 state = AST_CONTROL_CONGESTION; 01573 break; 01574 } 01575 } 01576 01577 ast_indicate(caller, -1); 01578 if (chan && ready) { 01579 if (chan->_state == AST_STATE_UP) 01580 state = AST_CONTROL_ANSWER; 01581 res = 0; 01582 } else if(chan) { 01583 res = -1; 01584 ast_hangup(chan); 01585 chan = NULL; 01586 } else { 01587 res = -1; 01588 } 01589 01590 if (outstate) 01591 *outstate = state; 01592 01593 return chan; 01594 }
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 607 of file res_features.c.
References masq_park_call().
Referenced by handle_exec(), manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().
00608 { 00609 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00610 }
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 2860 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().
02861 { 02862 struct ast_channel *cur = NULL; 02863 int res = -1; 02864 02865 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02866 if (!cur->pbx && 02867 (cur != chan) && 02868 (chan->pickupgroup & cur->callgroup) && 02869 ((cur->_state == AST_STATE_RINGING) || 02870 (cur->_state == AST_STATE_RING))) { 02871 break; 02872 } 02873 ast_channel_unlock(cur); 02874 } 02875 if (cur) { 02876 if (option_debug) 02877 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02878 res = ast_answer(chan); 02879 if (res) 02880 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02881 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02882 if (res) 02883 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02884 res = ast_channel_masquerade(cur, chan); 02885 if (res) 02886 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02887 ast_channel_unlock(cur); 02888 } else { 02889 if (option_debug) 02890 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02891 } 02892 return res; 02893 }
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 1122 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.
01123 { 01124 if (!feature) { 01125 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01126 return; 01127 } 01128 01129 AST_RWLIST_WRLOCK(&feature_list); 01130 AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry); 01131 AST_RWLIST_UNLOCK(&feature_list); 01132 01133 if (option_verbose >= 2) { 01134 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 01135 } 01136 }
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 1139 of file res_features.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.
01140 { 01141 if (!feature) 01142 return; 01143 01144 AST_RWLIST_WRLOCK(&feature_list); 01145 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01146 AST_RWLIST_UNLOCK(&feature_list); 01147 01148 free(feature); 01149 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1152 of file res_features.c.
References AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.
01153 { 01154 struct ast_call_feature *feature; 01155 01156 AST_RWLIST_WRLOCK(&feature_list); 01157 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) { 01158 free(feature); 01159 } 01160 AST_RWLIST_UNLOCK(&feature_list); 01161 }
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 1099 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 667 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.
00668 { 00669 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00670 int x = 0; 00671 size_t len; 00672 struct ast_channel *caller_chan, *callee_chan; 00673 00674 if (!monitor_ok) { 00675 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00676 return -1; 00677 } 00678 00679 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00680 monitor_ok = 0; 00681 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00682 return -1; 00683 } 00684 00685 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00686 00687 if (!ast_strlen_zero(courtesytone)) { 00688 if (ast_autoservice_start(callee_chan)) 00689 return -1; 00690 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) { 00691 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00692 ast_autoservice_stop(callee_chan); 00693 return -1; 00694 } 00695 if (ast_autoservice_stop(callee_chan)) 00696 return -1; 00697 } 00698 00699 if (callee_chan->monitor) { 00700 if (option_verbose > 3) 00701 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00702 ast_monitor_stop(callee_chan, 1); 00703 return FEATURE_RETURN_SUCCESS; 00704 } 00705 00706 if (caller_chan && callee_chan) { 00707 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00708 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00709 00710 if (!touch_format) 00711 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00712 00713 if (!touch_monitor) 00714 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00715 00716 if (touch_monitor) { 00717 len = strlen(touch_monitor) + 50; 00718 args = alloca(len); 00719 touch_filename = alloca(len); 00720 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00721 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename); 00722 } else { 00723 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00724 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00725 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00726 args = alloca(len); 00727 touch_filename = alloca(len); 00728 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00729 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename); 00730 } 00731 00732 for( x = 0; x < strlen(args); x++) { 00733 if (args[x] == '/') 00734 args[x] = '-'; 00735 } 00736 00737 if (option_verbose > 3) 00738 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00739 00740 pbx_exec(callee_chan, monitor_app, args); 00741 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00742 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00743 00744 return FEATURE_RETURN_SUCCESS; 00745 } 00746 00747 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00748 return -1; 00749 }
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 778 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.
00779 { 00780 struct ast_channel *transferer; 00781 struct ast_channel *transferee; 00782 const char *transferer_real_context; 00783 char xferto[256]; 00784 int res; 00785 const char *orig_chan_name; 00786 int parkstatus = 0; 00787 00788 set_peers(&transferer, &transferee, peer, chan, sense); 00789 orig_chan_name = ast_strdupa(transferer->name); 00790 transferer_real_context = real_ctx(transferer, transferee); 00791 /* Start autoservice on chan while we talk to the originator */ 00792 ast_autoservice_start(transferee); 00793 ast_indicate(transferee, AST_CONTROL_HOLD); 00794 00795 memset(xferto, 0, sizeof(xferto)); 00796 00797 /* Transfer */ 00798 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00799 if (res < 0) { 00800 finishup(transferee); 00801 return -1; /* error ? */ 00802 } 00803 if (res > 0) /* If they've typed a digit already, handle it */ 00804 xferto[0] = (char) res; 00805 00806 ast_stopstream(transferer); 00807 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00808 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00809 finishup(transferee); 00810 return res; 00811 } 00812 if (!strcmp(xferto, ast_parking_ext())) { 00813 res = finishup(transferee); 00814 if (res) 00815 res = -1; 00816 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name))) { /* success */ 00817 /* We return non-zero, but tell the PBX not to hang the channel when 00818 the thread dies -- We have to be careful now though. We are responsible for 00819 hanging up the channel, else it will never be hung up! */ 00820 return 0; 00821 } else { 00822 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus=%d\n", transferee->name, parkstatus); 00823 } 00824 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 00825 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00826 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 00827 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 00828 res=finishup(transferee); 00829 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 00830 transferer->cdr=ast_cdr_alloc(); 00831 if (transferer->cdr) { 00832 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 00833 ast_cdr_start(transferer->cdr); 00834 } 00835 } 00836 if (transferer->cdr) { 00837 struct ast_cdr *swap = transferer->cdr; 00838 /* swap cdrs-- it will save us some time & work */ 00839 transferer->cdr = transferee->cdr; 00840 transferee->cdr = swap; 00841 } 00842 if (!transferee->pbx) { 00843 /* Doh! Use our handy async_goto functions */ 00844 if (option_verbose > 2) 00845 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00846 ,transferee->name, xferto, transferer_real_context); 00847 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 00848 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00849 res = -1; 00850 } else { 00851 /* Set the channel's new extension, since it exists, using transferer context */ 00852 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 00853 set_c_e_p(transferee, transferer_real_context, xferto, 0); 00854 } 00855 check_goto_on_transfer(transferer); 00856 return res; 00857 } else { 00858 if (option_verbose > 2) 00859 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 00860 } 00861 if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) { 00862 finishup(transferee); 00863 return -1; 00864 } 00865 ast_stopstream(transferer); 00866 res = finishup(transferee); 00867 if (res) { 00868 if (option_verbose > 1) 00869 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00870 return res; 00871 } 00872 return FEATURE_RETURN_SUCCESS; 00873 }
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 751 of file res_features.c.
References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.
00752 { 00753 if (option_verbose > 3) 00754 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00755 return FEATURE_RETURN_HANGUP; 00756 }
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 633 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().
00634 { 00635 struct ast_channel *parker; 00636 struct ast_channel *parkee; 00637 int res = 0; 00638 struct ast_module_user *u; 00639 const char *orig_chan_name; 00640 00641 u = ast_module_user_add(chan); 00642 00643 set_peers(&parker, &parkee, peer, chan, sense); 00644 orig_chan_name = ast_strdupa(parker->name); 00645 /* we used to set chan's exten and priority to "s" and 1 00646 here, but this generates (in some cases) an invalid 00647 extension, and if "s" exists, could errantly 00648 cause execution of extensions you don't expect It 00649 makes more sense to let nature take its course 00650 when chan finishes, and let the pbx do its thing 00651 and hang up when the park is over. 00652 */ 00653 if (chan->_state != AST_STATE_UP) 00654 res = ast_answer(chan); 00655 if (!res) 00656 res = ast_safe_sleep(chan, 1000); 00657 00658 if (!res) { /* one direction used to call park_call.... */ 00659 res = masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name); 00660 /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ 00661 } 00662 00663 ast_module_user_remove(u); 00664 return res; 00665 }
static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
struct ast_flags * | features_caller, | |||
char * | options, | |||
size_t | len | |||
) | [static] |
Definition at line 2217 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().
02218 { 02219 int i = 0; 02220 enum { 02221 OPT_CALLEE_REDIRECT = 't', 02222 OPT_CALLER_REDIRECT = 'T', 02223 OPT_CALLEE_AUTOMON = 'w', 02224 OPT_CALLER_AUTOMON = 'W', 02225 OPT_CALLEE_DISCONNECT = 'h', 02226 OPT_CALLER_DISCONNECT = 'H', 02227 OPT_CALLEE_PARKCALL = 'k', 02228 OPT_CALLER_PARKCALL = 'K', 02229 }; 02230 02231 memset(options, 0, len); 02232 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 02233 options[i++] = OPT_CALLER_REDIRECT; 02234 } 02235 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 02236 options[i++] = OPT_CALLER_AUTOMON; 02237 } 02238 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 02239 options[i++] = OPT_CALLER_DISCONNECT; 02240 } 02241 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 02242 options[i++] = OPT_CALLER_PARKCALL; 02243 } 02244 02245 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 02246 options[i++] = OPT_CALLEE_REDIRECT; 02247 } 02248 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 02249 options[i++] = OPT_CALLEE_AUTOMON; 02250 } 02251 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 02252 options[i++] = OPT_CALLEE_DISCONNECT; 02253 } 02254 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 02255 options[i++] = OPT_CALLEE_PARKCALL; 02256 } 02257 02258 return options; 02259 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 875 of file res_features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by do_atxfer().
00876 { 00877 if (ast_channel_make_compatible(c, newchan) < 0) { 00878 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 00879 c->name, newchan->name); 00880 ast_hangup(newchan); 00881 return -1; 00882 } 00883 return 0; 00884 }
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 1697 of file res_features.c.
References context, do_atxfer(), FEATURE_SENSE_CHAN, and FEATURE_SENSE_PEER.
Referenced by ast_bridge_call().
01698 { 01699 int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER; 01700 char *context = strchr(xferto, '@');; 01701 if (context) 01702 *context++ = '\0'; 01703 do_atxfer(a, b, conf, sense, xferto, context); 01704 }
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 901 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().
00902 { 00903 struct ast_channel *transferer; 00904 struct ast_channel *transferee; 00905 const char *transferer_real_context; 00906 const char *transfer_context; 00907 char xferto[256] = ""; 00908 int res; 00909 int outstate=0; 00910 struct ast_channel *newchan; 00911 struct ast_channel *xferchan; 00912 struct ast_bridge_thread_obj *tobj; 00913 struct ast_bridge_config bconfig; 00914 struct ast_frame *f; 00915 int l; 00916 struct ast_datastore *features_datastore; 00917 struct ast_dial_features *dialfeatures = NULL; 00918 00919 if (option_debug) 00920 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 00921 set_peers(&transferer, &transferee, peer, chan, sense); 00922 transferer_real_context = real_ctx(transferer, transferee); 00923 transfer_context = S_OR(toCont, transferer_real_context); 00924 00925 /* Start autoservice on chan while we talk to the originator */ 00926 ast_autoservice_start(transferee); 00927 ast_indicate(transferee, AST_CONTROL_HOLD); 00928 00929 if (!ast_strlen_zero(toExt)) { 00930 ast_copy_string(xferto, toExt, sizeof(xferto)); 00931 } else { 00932 /* Ask for extension to transfer to on the transferer channel */ 00933 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00934 if (res < 0) { 00935 finishup(transferee); 00936 return res; 00937 } 00938 if (res > 0) /* If they've typed a digit already, handle it */ 00939 xferto[0] = (char) res; 00940 00941 /* this is specific of atxfer */ 00942 res = ast_app_dtget(transferer, transfer_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00943 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00944 finishup(transferee); 00945 return res; 00946 } 00947 if (res == 0) { 00948 ast_log(LOG_WARNING, "Did not read data.\n"); 00949 finishup(transferee); 00950 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00951 return -1; 00952 return FEATURE_RETURN_SUCCESS; 00953 } 00954 } 00955 00956 /* valid extension, res == 1 */ 00957 if (!ast_exists_extension(transferer, transfer_context, xferto, 1, transferer->cid.cid_num)) { 00958 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transfer_context); 00959 finishup(transferee); 00960 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00961 return -1; 00962 return FEATURE_RETURN_SUCCESS; 00963 } 00964 00965 /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of 00966 * the different variables for handling this properly with a builtin_atxfer */ 00967 if (!strcmp(xferto, ast_parking_ext())) { 00968 finishup(transferee); 00969 return builtin_parkcall(chan, peer, config, NULL, sense, NULL); 00970 } 00971 00972 l = strlen(xferto); 00973 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transfer_context); /* append context */ 00974 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), 00975 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language); 00976 ast_indicate(transferer, -1); 00977 if (!newchan) { 00978 finishup(transferee); 00979 /* any reason besides user requested cancel and busy triggers the failed sound */ 00980 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 00981 ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) 00982 return -1; 00983 return FEATURE_RETURN_SUCCESS; 00984 } 00985 00986 if (check_compat(transferer, newchan)) { 00987 /* we do mean transferee here, NOT transferer */ 00988 finishup(transferee); 00989 return -1; 00990 } 00991 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00992 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00993 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00994 res = ast_bridge_call(transferer, newchan, &bconfig); 00995 if (newchan->_softhangup || !transferer->_softhangup) { 00996 ast_hangup(newchan); 00997 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) 00998 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00999 finishup(transferee); 01000 transferer->_softhangup = 0; 01001 return FEATURE_RETURN_SUCCESS; 01002 } 01003 01004 if (check_compat(transferee, newchan)) { 01005 finishup(transferee); 01006 return -1; 01007 } 01008 01009 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01010 01011 if ((ast_autoservice_stop(transferee) < 0) 01012 || (ast_waitfordigit(transferee, 100) < 0) 01013 || (ast_waitfordigit(newchan, 100) < 0) 01014 || ast_check_hangup(transferee) 01015 || ast_check_hangup(newchan)) { 01016 ast_hangup(newchan); 01017 return -1; 01018 } 01019 01020 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 01021 if (!xferchan) { 01022 ast_hangup(newchan); 01023 return -1; 01024 } 01025 /* Make formats okay */ 01026 xferchan->visible_indication = transferer->visible_indication; 01027 xferchan->readformat = transferee->readformat; 01028 xferchan->writeformat = transferee->writeformat; 01029 ast_channel_masquerade(xferchan, transferee); 01030 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01031 xferchan->_state = AST_STATE_UP; 01032 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01033 xferchan->_softhangup = 0; 01034 01035 if ((f = ast_read(xferchan))) 01036 ast_frfree(f); 01037 01038 newchan->_state = AST_STATE_UP; 01039 ast_clear_flag(newchan, AST_FLAGS_ALL); 01040 newchan->_softhangup = 0; 01041 01042 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj)); 01043 if (!tobj) { 01044 ast_hangup(xferchan); 01045 ast_hangup(newchan); 01046 return -1; 01047 } 01048 01049 ast_channel_lock(newchan); 01050 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 01051 dialfeatures = features_datastore->data; 01052 } 01053 ast_channel_unlock(newchan); 01054 01055 if (dialfeatures) { 01056 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 01057 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 01058 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01059 } 01060 01061 ast_channel_lock(xferchan); 01062 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 01063 dialfeatures = features_datastore->data; 01064 } 01065 ast_channel_unlock(xferchan); 01066 01067 if (dialfeatures) { 01068 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01069 } 01070 01071 tobj->chan = newchan; 01072 tobj->peer = xferchan; 01073 tobj->bconfig = *config; 01074 01075 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01076 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01077 } 01078 01079 if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) 01080 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01081 ast_bridge_call_thread_launch(tobj); 01082 return -1; /* XXX meaning the channel is bridged ? */ 01083 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
Definition at line 2262 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().
02263 { 02264 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 02265 FD_ZERO(&rfds); 02266 FD_ZERO(&efds); 02267 02268 for (;;) { 02269 struct parkeduser *pu, *pl, *pt = NULL; 02270 int ms = -1; /* select timeout, uninitialized */ 02271 int max = -1; /* max fd, none there yet */ 02272 fd_set nrfds, nefds; /* args for the next select */ 02273 FD_ZERO(&nrfds); 02274 FD_ZERO(&nefds); 02275 02276 ast_mutex_lock(&parking_lock); 02277 pl = NULL; 02278 pu = parkinglot; 02279 /* navigate the list with prev-cur pointers to support removals */ 02280 while (pu) { 02281 struct ast_channel *chan = pu->chan; /* shorthand */ 02282 int tms; /* timeout for this item */ 02283 int x; /* fd index in channel */ 02284 struct ast_context *con; 02285 02286 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 02287 pl = pu; 02288 pu = pu->next; 02289 continue; 02290 } 02291 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 02292 if (tms > pu->parkingtime) { 02293 ast_indicate(chan, AST_CONTROL_UNHOLD); 02294 /* Get chan, exten from derived kludge */ 02295 if (pu->peername[0]) { 02296 char *peername = ast_strdupa(pu->peername); 02297 char *cp = strrchr(peername, '-'); 02298 if (cp) 02299 *cp = 0; 02300 con = ast_context_find(parking_con_dial); 02301 if (!con) { 02302 con = ast_context_create(NULL, parking_con_dial, registrar); 02303 if (!con) 02304 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 02305 } 02306 if (con) { 02307 char returnexten[AST_MAX_EXTENSION]; 02308 struct ast_datastore *features_datastore; 02309 struct ast_dial_features *dialfeatures = NULL; 02310 02311 ast_channel_lock(chan); 02312 02313 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 02314 dialfeatures = features_datastore->data; 02315 02316 ast_channel_unlock(chan); 02317 02318 if (!strncmp(peername, "Parked/", 7)) { 02319 peername += 7; 02320 } 02321 02322 if (dialfeatures) { 02323 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 02324 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 02325 } else { /* Existing default */ 02326 ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name); 02327 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername); 02328 } 02329 02330 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free_ptr, registrar); 02331 } 02332 set_c_e_p(chan, parking_con_dial, peername, 1); 02333 } else { 02334 /* They've been waiting too long, send them back to where they came. Theoretically they 02335 should have their original extensions and such, but we copy to be on the safe side */ 02336 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 02337 } 02338 02339 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 02340 02341 if (option_verbose > 1) 02342 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); 02343 /* Start up the PBX, or hang them up */ 02344 if (ast_pbx_start(chan)) { 02345 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 02346 ast_hangup(chan); 02347 } 02348 /* And take them out of the parking lot */ 02349 if (pl) 02350 pl->next = pu->next; 02351 else 02352 parkinglot = pu->next; 02353 pt = pu; 02354 pu = pu->next; 02355 con = ast_context_find(parking_con); 02356 if (con) { 02357 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 02358 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02359 else 02360 notify_metermaids(pt->parkingexten, parking_con); 02361 } else 02362 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02363 free(pt); 02364 } else { /* still within parking time, process descriptors */ 02365 for (x = 0; x < AST_MAX_FDS; x++) { 02366 struct ast_frame *f; 02367 02368 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 02369 continue; /* nothing on this descriptor */ 02370 02371 if (FD_ISSET(chan->fds[x], &efds)) 02372 ast_set_flag(chan, AST_FLAG_EXCEPTION); 02373 else 02374 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 02375 chan->fdno = x; 02376 02377 /* See if they need servicing */ 02378 f = ast_read(chan); 02379 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 02380 if (f) 02381 ast_frfree(f); 02382 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 02383 02384 /* There's a problem, hang them up*/ 02385 if (option_verbose > 1) 02386 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 02387 ast_hangup(chan); 02388 /* And take them out of the parking lot */ 02389 if (pl) 02390 pl->next = pu->next; 02391 else 02392 parkinglot = pu->next; 02393 pt = pu; 02394 pu = pu->next; 02395 con = ast_context_find(parking_con); 02396 if (con) { 02397 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 02398 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02399 else { 02400 notify_metermaids(pt->parkingexten, parking_con); 02401 } 02402 } else 02403 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02404 free(pt); 02405 break; 02406 } else { 02407 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02408 ast_frfree(f); 02409 if (pu->moh_trys < 3 && !chan->generatordata) { 02410 if (option_debug) 02411 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 02412 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 02413 S_OR(parkmohclass, NULL), 02414 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 02415 pu->moh_trys++; 02416 } 02417 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 02418 } 02419 02420 } /* end for */ 02421 if (x >= AST_MAX_FDS) { 02422 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 02423 if (chan->fds[x] > -1) { 02424 FD_SET(chan->fds[x], &nrfds); 02425 FD_SET(chan->fds[x], &nefds); 02426 if (chan->fds[x] > max) 02427 max = chan->fds[x]; 02428 } 02429 } 02430 /* Keep track of our shortest wait */ 02431 if (tms < ms || ms < 0) 02432 ms = tms; 02433 pl = pu; 02434 pu = pu->next; 02435 } 02436 } 02437 } /* end while */ 02438 ast_mutex_unlock(&parking_lock); 02439 rfds = nrfds; 02440 efds = nefds; 02441 { 02442 struct timeval tv = ast_samp2tv(ms, 1000); 02443 /* Wait for something to happen */ 02444 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 02445 } 02446 pthread_testcancel(); 02447 } 02448 return NULL; /* Never reached */ 02449 }
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 1178 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().
01179 { 01180 struct ast_app *app; 01181 struct ast_call_feature *feature = data; 01182 struct ast_channel *work, *idle; 01183 int res; 01184 01185 if (!feature) { /* shouldn't ever happen! */ 01186 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01187 return -1; 01188 } 01189 01190 if (sense == FEATURE_SENSE_CHAN) { 01191 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01192 return FEATURE_RETURN_KEEPTRYING; 01193 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01194 work = chan; 01195 idle = peer; 01196 } else { 01197 work = peer; 01198 idle = chan; 01199 } 01200 } else { 01201 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01202 return FEATURE_RETURN_KEEPTRYING; 01203 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01204 work = peer; 01205 idle = chan; 01206 } else { 01207 work = chan; 01208 idle = peer; 01209 } 01210 } 01211 01212 if (!(app = pbx_findapp(feature->app))) { 01213 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01214 return -2; 01215 } 01216 01217 ast_autoservice_start(idle); 01218 01219 if (!ast_strlen_zero(feature->moh_class)) 01220 ast_moh_start(idle, feature->moh_class, NULL); 01221 01222 res = pbx_exec(work, app, feature->app_args); 01223 01224 if (!ast_strlen_zero(feature->moh_class)) 01225 ast_moh_stop(idle); 01226 01227 ast_autoservice_stop(idle); 01228 01229 if (res) 01230 return FEATURE_RETURN_SUCCESSBREAK; 01231 01232 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01233 }
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 1354 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().
01354 { 01355 01356 char dynamic_features_buf[128]; 01357 const char *peer_dynamic_features, *chan_dynamic_features; 01358 struct ast_flags features; 01359 struct ast_call_feature feature; 01360 if (sense == FEATURE_SENSE_CHAN) { 01361 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01362 } 01363 else { 01364 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01365 } 01366 01367 ast_channel_lock(peer); 01368 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 01369 ast_channel_unlock(peer); 01370 01371 ast_channel_lock(chan); 01372 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 01373 ast_channel_unlock(chan); 01374 01375 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,"")); 01376 01377 if (option_debug > 2) { 01378 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); 01379 } 01380 01381 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature); 01382 }
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 1273 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().
01276 { 01277 int x; 01278 struct ast_call_feature *tmpfeature; 01279 char *tmp, *tok; 01280 int res = FEATURE_RETURN_PASSDIGITS; 01281 int feature_detected = 0; 01282 01283 if (!(peer && chan && config) && operation) { 01284 return -1; /* can not run feature operation */ 01285 } 01286 01287 ast_rwlock_rdlock(&features_lock); 01288 for (x = 0; x < FEATURES_COUNT; x++) { 01289 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 01290 !ast_strlen_zero(builtin_features[x].exten)) { 01291 /* Feature is up for consideration */ 01292 if (!strcmp(builtin_features[x].exten, code)) { 01293 if (option_debug > 2) { 01294 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); 01295 } 01296 if (operation) { 01297 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01298 } 01299 memcpy(feature, &builtin_features[x], sizeof(feature)); 01300 feature_detected = 1; 01301 break; 01302 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01303 if (res == FEATURE_RETURN_PASSDIGITS) 01304 res = FEATURE_RETURN_STOREDIGITS; 01305 } 01306 } 01307 } 01308 ast_rwlock_unlock(&features_lock); 01309 01310 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 01311 return res; 01312 } 01313 01314 tmp = dynamic_features_buf; 01315 01316 while ((tok = strsep(&tmp, "#"))) { 01317 AST_RWLIST_RDLOCK(&feature_list); 01318 if (!(tmpfeature = find_dynamic_feature(tok))) { 01319 AST_RWLIST_UNLOCK(&feature_list); 01320 continue; 01321 } 01322 01323 /* Feature is up for consideration */ 01324 if (!strcmp(tmpfeature->exten, code)) { 01325 if (option_debug > 2) { 01326 ast_log(LOG_NOTICE, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 01327 } 01328 if (operation) { 01329 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 01330 } 01331 memcpy(feature, tmpfeature, sizeof(feature)); 01332 if (res != FEATURE_RETURN_KEEPTRYING) { 01333 AST_RWLIST_UNLOCK(&feature_list); 01334 break; 01335 } 01336 res = FEATURE_RETURN_PASSDIGITS; 01337 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 01338 res = FEATURE_RETURN_STOREDIGITS; 01339 01340 AST_RWLIST_UNLOCK(&feature_list); 01341 } 01342 01343 return res; 01344 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a feature by name
Definition at line 1164 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().
01165 { 01166 struct ast_call_feature *tmp; 01167 01168 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01169 if (!strcasecmp(tmp->sname, name)) { 01170 break; 01171 } 01172 } 01173 01174 return tmp; 01175 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 758 of file res_features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_blindtransfer(), and do_atxfer().
00759 { 00760 ast_indicate(chan, AST_CONTROL_UNHOLD); 00761 00762 return ast_autoservice_stop(chan); 00763 }
static int handle_parkedcalls | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2714 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.
02715 { 02716 struct parkeduser *cur; 02717 int numparked = 0; 02718 02719 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 02720 , "Context", "Extension", "Pri", "Timeout"); 02721 02722 ast_mutex_lock(&parking_lock); 02723 02724 for (cur = parkinglot; cur; cur = cur->next) { 02725 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 02726 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 02727 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 02728 02729 numparked++; 02730 } 02731 ast_mutex_unlock(&parking_lock); 02732 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 02733 02734 02735 return RESULT_SUCCESS; 02736 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2672 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.
02673 { 02674 int i; 02675 struct ast_call_feature *feature; 02676 char format[] = "%-25s %-7s %-7s\n"; 02677 02678 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 02679 ast_cli(fd, format, "---------------", "-------", "-------"); 02680 02681 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 02682 02683 ast_rwlock_rdlock(&features_lock); 02684 for (i = 0; i < FEATURES_COUNT; i++) 02685 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 02686 ast_rwlock_unlock(&features_lock); 02687 02688 ast_cli(fd, "\n"); 02689 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 02690 ast_cli(fd, format, "---------------", "-------", "-------"); 02691 if (AST_RWLIST_EMPTY(&feature_list)) { 02692 ast_cli(fd, "(none)\n"); 02693 } else { 02694 AST_RWLIST_RDLOCK(&feature_list); 02695 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 02696 ast_cli(fd, format, feature->sname, "no def", feature->exten); 02697 } 02698 AST_RWLIST_UNLOCK(&feature_list); 02699 } 02700 ast_cli(fd, "\nCall parking\n"); 02701 ast_cli(fd, "------------\n"); 02702 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 02703 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 02704 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 02705 ast_cli(fd,"\n"); 02706 02707 return RESULT_SUCCESS; 02708 }
static int load_config | ( | void | ) | [static] |
Definition at line 2910 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.
02911 { 02912 int start = 0, end = 0; 02913 int res; 02914 struct ast_context *con = NULL; 02915 struct ast_config *cfg = NULL; 02916 struct ast_variable *var = NULL; 02917 char old_parking_ext[AST_MAX_EXTENSION]; 02918 char old_parking_con[AST_MAX_EXTENSION] = ""; 02919 02920 if (!ast_strlen_zero(parking_con)) { 02921 strcpy(old_parking_ext, parking_ext); 02922 strcpy(old_parking_con, parking_con); 02923 } 02924 02925 /* Reset to defaults */ 02926 strcpy(parking_con, "parkedcalls"); 02927 strcpy(parking_con_dial, "park-dial"); 02928 strcpy(parking_ext, "700"); 02929 strcpy(pickup_ext, "*8"); 02930 strcpy(parkmohclass, "default"); 02931 courtesytone[0] = '\0'; 02932 strcpy(xfersound, "beep"); 02933 strcpy(xferfailsound, "pbx-invalid"); 02934 parking_start = 701; 02935 parking_stop = 750; 02936 parkfindnext = 0; 02937 adsipark = 0; 02938 parkaddhints = 0; 02939 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 02940 parkedcallreparking = 0; 02941 parkedcallhangup = 0; 02942 parkedcallrecording = 0; 02943 02944 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02945 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02946 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02947 02948 cfg = ast_config_load("features.conf"); 02949 if (!cfg) { 02950 ast_log(LOG_WARNING,"Could not load features.conf\n"); 02951 return AST_MODULE_LOAD_DECLINE; 02952 } 02953 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 02954 if (!strcasecmp(var->name, "parkext")) { 02955 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02956 } else if (!strcasecmp(var->name, "context")) { 02957 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02958 } else if (!strcasecmp(var->name, "parkingtime")) { 02959 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || (parkingtime < 1)) { 02960 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02961 parkingtime = DEFAULT_PARK_TIME; 02962 } else 02963 parkingtime = parkingtime * 1000; 02964 } else if (!strcasecmp(var->name, "parkpos")) { 02965 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 02966 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); 02967 } else { 02968 parking_start = start; 02969 parking_stop = end; 02970 } 02971 } else if (!strcasecmp(var->name, "findslot")) { 02972 parkfindnext = (!strcasecmp(var->value, "next")); 02973 } else if (!strcasecmp(var->name, "parkinghints")) { 02974 parkaddhints = ast_true(var->value); 02975 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 02976 if (!strcasecmp(var->value, "no")) 02977 parkedcalltransfers = 0; 02978 else if (!strcasecmp(var->value, "caller")) 02979 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 02980 else if (!strcasecmp(var->value, "callee")) 02981 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 02982 else if (!strcasecmp(var->value, "both")) 02983 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 02984 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 02985 if (!strcasecmp(var->value, "no")) 02986 parkedcallreparking = 0; 02987 else if (!strcasecmp(var->value, "caller")) 02988 parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 02989 else if (!strcasecmp(var->value, "callee")) 02990 parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 02991 else if (!strcasecmp(var->value, "both")) 02992 parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 02993 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 02994 if (!strcasecmp(var->value, "no")) 02995 parkedcallhangup = 0; 02996 else if (!strcasecmp(var->value, "caller")) 02997 parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 02998 else if (!strcasecmp(var->value, "callee")) 02999 parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 03000 else if (!strcasecmp(var->value, "both")) 03001 parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 03002 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 03003 if (!strcasecmp(var->value, "no")) 03004 parkedcallrecording = 0; 03005 else if (!strcasecmp(var->value, "caller")) 03006 parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 03007 else if (!strcasecmp(var->value, "callee")) 03008 parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 03009 else if (!strcasecmp(var->value, "both")) 03010 parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 03011 } else if (!strcasecmp(var->name, "adsipark")) { 03012 adsipark = ast_true(var->value); 03013 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03014 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03015 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03016 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03017 } else 03018 transferdigittimeout = transferdigittimeout * 1000; 03019 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03020 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03021 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03022 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03023 } 03024 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03025 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03026 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03027 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03028 } else 03029 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03030 } else if (!strcasecmp(var->name, "courtesytone")) { 03031 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03032 } else if (!strcasecmp(var->name, "parkedplay")) { 03033 if (!strcasecmp(var->value, "both")) 03034 parkedplay = 2; 03035 else if (!strcasecmp(var->value, "parked")) 03036 parkedplay = 1; 03037 else 03038 parkedplay = 0; 03039 } else if (!strcasecmp(var->name, "xfersound")) { 03040 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03041 } else if (!strcasecmp(var->name, "xferfailsound")) { 03042 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03043 } else if (!strcasecmp(var->name, "pickupexten")) { 03044 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03045 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03046 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 03047 } 03048 } 03049 03050 unmap_features(); 03051 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03052 if (remap_feature(var->name, var->value)) 03053 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03054 } 03055 03056 /* Map a key combination to an application*/ 03057 ast_unregister_features(); 03058 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03059 char *tmp_val = ast_strdupa(var->value); 03060 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 03061 struct ast_call_feature *feature; 03062 03063 /* strsep() sets the argument to NULL if match not found, and it 03064 * is safe to use it with a NULL argument, so we don't check 03065 * between calls. 03066 */ 03067 exten = strsep(&tmp_val,","); 03068 activatedby = strsep(&tmp_val,","); 03069 app = strsep(&tmp_val,","); 03070 app_args = strsep(&tmp_val,","); 03071 moh_class = strsep(&tmp_val,","); 03072 03073 activateon = strsep(&activatedby, "/"); 03074 03075 /*! \todo XXX var_name or app_args ? */ 03076 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03077 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03078 app, exten, activateon, var->name); 03079 continue; 03080 } 03081 03082 AST_RWLIST_RDLOCK(&feature_list); 03083 if ((feature = find_dynamic_feature(var->name))) { 03084 AST_RWLIST_UNLOCK(&feature_list); 03085 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03086 continue; 03087 } 03088 AST_RWLIST_UNLOCK(&feature_list); 03089 03090 if (!(feature = ast_calloc(1, sizeof(*feature)))) 03091 continue; 03092 03093 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03094 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 03095 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 03096 03097 if (app_args) 03098 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 03099 03100 if (moh_class) 03101 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 03102 03103 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 03104 feature->operation = feature_exec_app; 03105 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03106 03107 /* Allow caller and calle to be specified for backwards compatability */ 03108 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03109 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03110 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03111 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03112 else { 03113 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03114 " must be 'self', or 'peer'\n", var->name); 03115 continue; 03116 } 03117 03118 if (ast_strlen_zero(activatedby)) 03119 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03120 else if (!strcasecmp(activatedby, "caller")) 03121 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03122 else if (!strcasecmp(activatedby, "callee")) 03123 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03124 else if (!strcasecmp(activatedby, "both")) 03125 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03126 else { 03127 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03128 " must be 'caller', or 'callee', or 'both'\n", var->name); 03129 continue; 03130 } 03131 03132 ast_register_feature(feature); 03133 03134 if (option_verbose >= 1) 03135 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 03136 } 03137 ast_config_destroy(cfg); 03138 03139 /* Remove the old parking extension */ 03140 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03141 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 03142 notify_metermaids(old_parking_ext, old_parking_con); 03143 if (option_debug) 03144 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03145 } 03146 03147 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 03148 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 03149 return -1; 03150 } 03151 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 03152 if (parkaddhints) 03153 park_add_hints(parking_con, parking_start, parking_stop); 03154 if (!res) 03155 notify_metermaids(ast_parking_ext(), parking_con); 03156 return res; 03157 03158 }
static int load_module | ( | void | ) | [static] |
Definition at line 3165 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.
03166 { 03167 int res; 03168 03169 memset(parking_ext, 0, sizeof(parking_ext)); 03170 memset(parking_con, 0, sizeof(parking_con)); 03171 03172 if ((res = load_config())) 03173 return res; 03174 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03175 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 03176 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 03177 if (!res) 03178 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 03179 if (!res) { 03180 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 03181 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 03182 "Park a channel", mandescr_park); 03183 } 03184 03185 res |= ast_devstate_prov_add("Park", metermaidstate); 03186 03187 return res; 03188 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2805 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().
02806 { 02807 const char *channel = astman_get_header(m, "Channel"); 02808 const char *channel2 = astman_get_header(m, "Channel2"); 02809 const char *timeout = astman_get_header(m, "Timeout"); 02810 char buf[BUFSIZ]; 02811 int to = 0; 02812 int res = 0; 02813 int parkExt = 0; 02814 struct ast_channel *ch1, *ch2; 02815 02816 if (ast_strlen_zero(channel)) { 02817 astman_send_error(s, m, "Channel not specified"); 02818 return 0; 02819 } 02820 02821 if (ast_strlen_zero(channel2)) { 02822 astman_send_error(s, m, "Channel2 not specified"); 02823 return 0; 02824 } 02825 02826 ch1 = ast_get_channel_by_name_locked(channel); 02827 if (!ch1) { 02828 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02829 astman_send_error(s, m, buf); 02830 return 0; 02831 } 02832 02833 ch2 = ast_get_channel_by_name_locked(channel2); 02834 if (!ch2) { 02835 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02836 astman_send_error(s, m, buf); 02837 ast_channel_unlock(ch1); 02838 return 0; 02839 } 02840 02841 if (!ast_strlen_zero(timeout)) { 02842 sscanf(timeout, "%30d", &to); 02843 } 02844 02845 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02846 if (!res) { 02847 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02848 astman_send_ack(s, m, "Park successful"); 02849 } else { 02850 astman_send_error(s, m, "Park failure"); 02851 } 02852 02853 ast_channel_unlock(ch1); 02854 ast_channel_unlock(ch2); 02855 02856 return 0; 02857 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 2758 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().
02759 { 02760 struct parkeduser *cur; 02761 const char *id = astman_get_header(m, "ActionID"); 02762 char idText[256] = ""; 02763 02764 if (!ast_strlen_zero(id)) 02765 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 02766 02767 astman_send_ack(s, m, "Parked calls will follow"); 02768 02769 ast_mutex_lock(&parking_lock); 02770 02771 for (cur = parkinglot; cur; cur = cur->next) { 02772 astman_append(s, "Event: ParkedCall\r\n" 02773 "Exten: %d\r\n" 02774 "Channel: %s\r\n" 02775 "From: %s\r\n" 02776 "Timeout: %ld\r\n" 02777 "CallerID: %s\r\n" 02778 "CallerIDName: %s\r\n" 02779 "%s" 02780 "\r\n", 02781 cur->parkingnum, cur->chan->name, cur->peername, 02782 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 02783 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 02784 S_OR(cur->chan->cid.cid_name, ""), 02785 idText); 02786 } 02787 02788 astman_append(s, 02789 "Event: ParkedCallsComplete\r\n" 02790 "%s" 02791 "\r\n",idText); 02792 02793 ast_mutex_unlock(&parking_lock); 02794 02795 return RESULT_SUCCESS; 02796 }
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 orig_chan_name = ast_strdupa(chan->name); 00595 } 00596 00597 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu); 00598 if (park_status == 1) { 00599 /* would be nice to play: "invalid parking extension" */ 00600 ast_hangup(chan); 00601 return -1; 00602 } 00603 00604 return 0; 00605 }
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 612 of file res_features.c.
References masq_park_call().
Referenced by builtin_blindtransfer(), builtin_parkcall(), and park_call_exec().
00613 { 00614 return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name); 00615 }
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 2896 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, PRIORITY_HINT, and registrar.
02897 { 02898 int numext; 02899 char device[AST_MAX_EXTENSION]; 02900 char exten[10]; 02901 02902 for (numext = start; numext <= stop; numext++) { 02903 snprintf(exten, sizeof(exten), "%d", numext); 02904 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 02905 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02906 } 02907 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 2452 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().
02453 { 02454 /* Cache the original channel name in case we get masqueraded in the middle 02455 * of a park--it is still theoretically possible for a transfer to happen before 02456 * we get here, but it is _really_ unlikely */ 02457 char *orig_chan_name = ast_strdupa(chan->name); 02458 char orig_exten[AST_MAX_EXTENSION]; 02459 int orig_priority = chan->priority; 02460 02461 /* Data is unused at the moment but could contain a parking 02462 lot context eventually */ 02463 int res = 0; 02464 struct ast_module_user *u; 02465 02466 u = ast_module_user_add(chan); 02467 02468 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 02469 02470 /* Setup the exten/priority to be s/1 since we don't know 02471 where this call should return */ 02472 strcpy(chan->exten, "s"); 02473 chan->priority = 1; 02474 /* Answer if call is not up */ 02475 if (chan->_state != AST_STATE_UP) 02476 res = ast_answer(chan); 02477 /* Sleep to allow VoIP streams to settle down */ 02478 if (!res) 02479 res = ast_safe_sleep(chan, 1000); 02480 /* Park the call */ 02481 if (!res) { 02482 res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name); 02483 /* Continue on in the dialplan */ 02484 if (res == 1) { 02485 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 02486 chan->priority = orig_priority; 02487 res = 0; 02488 } else if (!res) { 02489 res = 1; 02490 } 02491 } 02492 02493 ast_module_user_remove(u); 02494 02495 return res; 02496 }
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 2499 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().
02500 { 02501 int res = 0; 02502 struct ast_module_user *u; 02503 struct ast_channel *peer=NULL; 02504 struct parkeduser *pu, *pl=NULL; 02505 struct ast_context *con; 02506 02507 int park; 02508 struct ast_bridge_config config; 02509 02510 if (!data) { 02511 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 02512 return -1; 02513 } 02514 02515 u = ast_module_user_add(chan); 02516 02517 park = atoi((char *)data); 02518 ast_mutex_lock(&parking_lock); 02519 pu = parkinglot; 02520 while(pu) { 02521 if (pu->parkingnum == park) { 02522 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 02523 ast_mutex_unlock(&parking_lock); 02524 ast_module_user_remove(u); 02525 return -1; 02526 } 02527 if (pl) 02528 pl->next = pu->next; 02529 else 02530 parkinglot = pu->next; 02531 break; 02532 } 02533 pl = pu; 02534 pu = pu->next; 02535 } 02536 ast_mutex_unlock(&parking_lock); 02537 if (pu) { 02538 peer = pu->chan; 02539 con = ast_context_find(parking_con); 02540 if (con) { 02541 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 02542 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02543 else 02544 notify_metermaids(pu->parkingexten, parking_con); 02545 } else 02546 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02547 02548 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 02549 "Exten: %s\r\n" 02550 "Channel: %s\r\n" 02551 "From: %s\r\n" 02552 "CallerID: %s\r\n" 02553 "CallerIDName: %s\r\n", 02554 pu->parkingexten, pu->chan->name, chan->name, 02555 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02556 S_OR(pu->chan->cid.cid_name, "<unknown>") 02557 ); 02558 02559 free(pu); 02560 } 02561 /* JK02: it helps to answer the channel if not already up */ 02562 if (chan->_state != AST_STATE_UP) 02563 ast_answer(chan); 02564 02565 if (peer) { 02566 struct ast_datastore *features_datastore; 02567 struct ast_dial_features *dialfeatures = NULL; 02568 02569 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 02570 02571 if (!ast_strlen_zero(courtesytone)) { 02572 int error = 0; 02573 ast_indicate(peer, AST_CONTROL_UNHOLD); 02574 if (parkedplay == 0) { 02575 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 02576 } else if (parkedplay == 1) { 02577 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 02578 } else if (parkedplay == 2) { 02579 if (!ast_streamfile(chan, courtesytone, chan->language) && 02580 !ast_streamfile(peer, courtesytone, chan->language)) { 02581 /*! \todo XXX we would like to wait on both! */ 02582 res = ast_waitstream(chan, ""); 02583 if (res >= 0) 02584 res = ast_waitstream(peer, ""); 02585 if (res < 0) 02586 error = 1; 02587 } 02588 } 02589 if (error) { 02590 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02591 ast_hangup(peer); 02592 ast_module_user_remove(u); 02593 return -1; 02594 } 02595 } else 02596 ast_indicate(peer, AST_CONTROL_UNHOLD); 02597 02598 res = ast_channel_make_compatible(chan, peer); 02599 if (res < 0) { 02600 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 02601 ast_hangup(peer); 02602 ast_module_user_remove(u); 02603 return -1; 02604 } 02605 /* This runs sorta backwards, since we give the incoming channel control, as if it 02606 were the person called. */ 02607 if (option_verbose > 2) 02608 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 02609 02610 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02611 ast_cdr_setdestchan(chan->cdr, peer->name); 02612 memset(&config, 0, sizeof(struct ast_bridge_config)); 02613 02614 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 02615 ast_channel_lock(peer); 02616 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 02617 dialfeatures = features_datastore->data; 02618 } 02619 ast_channel_unlock(peer); 02620 02621 if (dialfeatures) { 02622 ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL); 02623 } 02624 02625 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 02626 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02627 } 02628 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 02629 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02630 } 02631 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 02632 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 02633 } 02634 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 02635 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 02636 } 02637 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 02638 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 02639 } 02640 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 02641 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 02642 } 02643 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 02644 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 02645 } 02646 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 02647 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 02648 } 02649 res = ast_bridge_call(chan, peer, &config); 02650 02651 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02652 ast_cdr_setdestchan(chan->cdr, peer->name); 02653 02654 /* Simulate the PBX hanging up */ 02655 ast_hangup(peer); 02656 ast_module_user_remove(u); 02657 return -1; 02658 } else { 02659 /*! \todo XXX Play a message XXX */ 02660 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 02661 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 02662 if (option_verbose > 2) 02663 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 02664 res = -1; 02665 } 02666 02667 ast_module_user_remove(u); 02668 02669 return -1; 02670 }
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 1596 of file res_features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
01597 { 01598 struct ast_cdr *cdr_orig = cdr; 01599 while (cdr) { 01600 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 01601 return cdr; 01602 cdr = cdr->next; 01603 } 01604 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 01605 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 2203 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().
02204 { 02205 manager_event(EVENT_FLAG_CALL, s, 02206 "Exten: %s\r\n" 02207 "Channel: %s\r\n" 02208 "CallerID: %s\r\n" 02209 "CallerIDName: %s\r\n\r\n", 02210 parkingexten, 02211 chan->name, 02212 S_OR(chan->cid.cid_num, "<unknown>"), 02213 S_OR(chan->cid.cid_name, "<unknown>") 02214 ); 02215 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
Definition at line 766 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().
00767 { 00768 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00769 if (ast_strlen_zero(s)) 00770 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00771 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */ 00772 s = transferer->macrocontext; 00773 if (ast_strlen_zero(s)) 00774 s = transferer->context; 00775 return s; 00776 }
static int reload | ( | void | ) | [static] |
Definition at line 3160 of file res_features.c.
References load_config().
03161 { 03162 return load_config(); 03163 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1245 of file res_features.c.
References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, exten, FEATURES_COUNT, and features_lock.
01246 { 01247 int x, res = -1; 01248 01249 ast_rwlock_wrlock(&features_lock); 01250 for (x = 0; x < FEATURES_COUNT; x++) { 01251 if (strcasecmp(builtin_features[x].sname, name)) 01252 continue; 01253 01254 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01255 res = 0; 01256 break; 01257 } 01258 ast_rwlock_unlock(&features_lock); 01259 01260 return res; 01261 }
static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
const char * | features | |||
) | [static] |
Definition at line 1607 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().
01608 { 01609 const char *feature; 01610 01611 if (ast_strlen_zero(features)) { 01612 return; 01613 } 01614 01615 for (feature = features; *feature; feature++) { 01616 switch (*feature) { 01617 case 'T' : 01618 case 't' : 01619 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 01620 break; 01621 case 'K' : 01622 case 'k' : 01623 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 01624 break; 01625 case 'H' : 01626 case 'h' : 01627 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 01628 break; 01629 case 'W' : 01630 case 'w' : 01631 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 01632 break; 01633 default : 01634 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 01635 } 01636 } 01637 }
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 1390 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().
01391 { 01392 int x; 01393 01394 ast_clear_flag(config, AST_FLAGS_ALL); 01395 01396 ast_rwlock_rdlock(&features_lock); 01397 for (x = 0; x < FEATURES_COUNT; x++) { 01398 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 01399 continue; 01400 01401 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01402 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01403 01404 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01405 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01406 } 01407 ast_rwlock_unlock(&features_lock); 01408 01409 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01410 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01411 01412 if (dynamic_features) { 01413 char *tmp = ast_strdupa(dynamic_features); 01414 char *tok; 01415 struct ast_call_feature *feature; 01416 01417 /* while we have a feature */ 01418 while ((tok = strsep(&tmp, "#"))) { 01419 AST_RWLIST_RDLOCK(&feature_list); 01420 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01421 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01422 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01423 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01424 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01425 } 01426 AST_RWLIST_UNLOCK(&feature_list); 01427 } 01428 } 01429 } 01430 }
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 620 of file res_features.c.
References parkeduser::chan, and FEATURE_SENSE_PEER.
Referenced by builtin_automonitor(), builtin_blindtransfer(), builtin_parkcall(), and do_atxfer().
00622 { 00623 if (sense == FEATURE_SENSE_PEER) { 00624 *caller = peer; 00625 *callee = chan; 00626 } else { 00627 *callee = peer; 00628 *caller = chan; 00629 } 00630 }
static int unload_module | ( | void | ) | [static] |
Definition at line 3191 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.
03192 { 03193 ast_module_user_hangup_all(); 03194 03195 ast_manager_unregister("ParkedCalls"); 03196 ast_manager_unregister("Park"); 03197 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03198 ast_unregister_application(parkcall); 03199 ast_devstate_prov_del("Park"); 03200 return ast_unregister_application(parkedcall); 03201 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1235 of file res_features.c.
References ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, exten, FEATURES_COUNT, and features_lock.
01236 { 01237 int x; 01238 01239 ast_rwlock_wrlock(&features_lock); 01240 for (x = 0; x < FEATURES_COUNT; x++) 01241 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01242 ast_rwlock_unlock(&features_lock); 01243 }
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 3207 of file res_features.c.
int adsipark [static] |
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 3207 of file res_features.c.
int atxfernoanswertimeout [static] |
struct ast_call_feature builtin_features[] [static] |
Definition at line 1109 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 2747 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 2742 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 1107 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 2710 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 2738 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] |