#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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
static int | adsipark |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static int | atxfernoanswertimeout |
static struct ast_call_feature | builtin_features [] |
static struct ast_cli_entry | cli_features [] |
static struct ast_cli_entry | cli_show_features_deprecated |
static char | courtesytone [256] |
static char * | descrip |
static char * | descrip2 |
ast_datastore_info | dial_features_info |
static int | featuredigittimeout |
static ast_rwlock_t | features_lock = PTHREAD_RWLOCK_INITIALIZER |
static char | mandescr_park [] |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static int | parkaddhints = 0 |
static char * | parkcall = PARK_APP_NAME |
static char * | parkedcall = "ParkedCall" |
static int | parkedcallhangup |
static int | parkedcallrecording |
static int | parkedcallreparking |
static int | parkedcalltransfers |
static int | parkedplay = 0 |
static int | parkfindnext |
static char | parking_con [AST_MAX_EXTENSION] |
static char | parking_con_dial [AST_MAX_EXTENSION] |
static char | parking_ext [AST_MAX_EXTENSION] |
static ast_mutex_t | parking_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
static int | parking_offset |
static int | parking_start |
static int | parking_stop |
static pthread_t | parking_thread |
static struct parkeduser * | parkinglot |
static 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 3211 of file res_features.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 3211 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 1643 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().
01644 { 01645 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 01646 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 01647 01648 ast_channel_lock(caller); 01649 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 01650 ast_channel_unlock(caller); 01651 if (!ds_caller_features) { 01652 if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 01653 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 01654 return; 01655 } 01656 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 01657 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 01658 ast_channel_datastore_free(ds_caller_features); 01659 return; 01660 } 01661 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 01662 caller_features->is_caller = 1; 01663 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 01664 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 01665 ds_caller_features->data = caller_features; 01666 ast_channel_lock(caller); 01667 ast_channel_datastore_add(caller, ds_caller_features); 01668 ast_channel_unlock(caller); 01669 } else { 01670 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 01671 * flags over from the atxfer to the caller */ 01672 return; 01673 } 01674 01675 ast_channel_lock(callee); 01676 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 01677 ast_channel_unlock(callee); 01678 if (!ds_callee_features) { 01679 if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { 01680 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 01681 return; 01682 } 01683 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 01684 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 01685 ast_channel_datastore_free(ds_callee_features); 01686 return; 01687 } 01688 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 01689 callee_features->is_caller = 0; 01690 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 01691 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 01692 ds_callee_features->data = callee_features; 01693 ast_channel_lock(callee); 01694 ast_channel_datastore_add(callee, ds_callee_features); 01695 ast_channel_unlock(callee); 01696 } 01697 01698 return; 01699 }
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 1710 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().
01711 { 01712 /* Copy voice back and forth between the two channels. Give the peer 01713 the ability to transfer calls with '#<extension' syntax. */ 01714 struct ast_frame *f; 01715 struct ast_channel *who; 01716 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01717 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01718 char orig_channame[AST_MAX_EXTENSION]; 01719 char orig_peername[AST_MAX_EXTENSION]; 01720 01721 int res; 01722 int diff; 01723 int hasfeatures=0; 01724 int hadfeatures=0; 01725 int autoloopflag; 01726 struct ast_option_header *aoh; 01727 struct ast_bridge_config backup_config; 01728 struct ast_cdr *bridge_cdr = NULL; 01729 struct ast_cdr *orig_peer_cdr = NULL; 01730 struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */ 01731 struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ 01732 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01733 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01734 01735 memset(&backup_config, 0, sizeof(backup_config)); 01736 01737 config->start_time = ast_tvnow(); 01738 01739 if (chan && peer) { 01740 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01741 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01742 } else if (chan) { 01743 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01744 } 01745 01746 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 01747 add_features_datastores(chan, peer, config); 01748 01749 /* This is an interesting case. One example is if a ringing channel gets redirected to 01750 * an extension that picks up a parked call. This will make sure that the call taken 01751 * out of parking gets told that the channel it just got bridged to is still ringing. */ 01752 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 01753 ast_indicate(peer, AST_CONTROL_RINGING); 01754 } 01755 01756 if (monitor_ok) { 01757 const char *monitor_exec; 01758 struct ast_channel *src = NULL; 01759 if (!monitor_app) { 01760 if (!(monitor_app = pbx_findapp("Monitor"))) 01761 monitor_ok=0; 01762 } 01763 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01764 src = chan; 01765 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01766 src = peer; 01767 if (monitor_app && src) { 01768 char *tmp = ast_strdupa(monitor_exec); 01769 pbx_exec(src, monitor_app, tmp); 01770 } 01771 } 01772 01773 set_config_flags(chan, peer, config); 01774 config->firstpass = 1; 01775 01776 /* Answer if need be */ 01777 if (ast_answer(chan)) 01778 return -1; 01779 01780 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 01781 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 01782 orig_peer_cdr = peer_cdr; 01783 01784 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 01785 01786 if (chan_cdr) { 01787 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 01788 ast_cdr_update(chan); 01789 bridge_cdr = ast_cdr_dup(chan_cdr); 01790 /* rip any forked CDR's off of the chan_cdr and attach 01791 * them to the bridge_cdr instead */ 01792 bridge_cdr->next = chan_cdr->next; 01793 chan_cdr->next = NULL; 01794 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 01795 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 01796 } else { 01797 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 01798 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 01799 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 01800 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 01801 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 01802 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 01803 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 01804 ast_cdr_setcid(bridge_cdr, chan); 01805 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NOANSWER; 01806 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 01807 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 01808 /* Destination information */ 01809 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 01810 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 01811 if (peer_cdr) { 01812 bridge_cdr->start = peer_cdr->start; 01813 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 01814 } else { 01815 ast_cdr_start(bridge_cdr); 01816 } 01817 } 01818 /* peer_cdr->answer will be set when a macro runs on the peer; 01819 in that case, the bridge answer will be delayed while the 01820 macro plays on the peer channel. The peer answered the call 01821 before the macro started playing. To the phone system, 01822 this is billable time for the call, even tho the caller 01823 hears nothing but ringing while the macro does its thing. */ 01824 01825 /* Another case where the peer cdr's time will be set, is when 01826 A self-parks by pickup up phone and dialing 700, then B 01827 picks up A by dialing its parking slot; there may be more 01828 practical paths that get the same result, tho... in which 01829 case you get the previous answer time from the Park... which 01830 is before the bridge's start time, so I added in the 01831 tvcmp check to the if below */ 01832 01833 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 01834 ast_cdr_setanswer(bridge_cdr, peer_cdr->answer); 01835 ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition); 01836 if (chan_cdr) { 01837 ast_cdr_setanswer(chan_cdr, peer_cdr->answer); 01838 ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition); 01839 } 01840 } else { 01841 ast_cdr_answer(bridge_cdr); 01842 if (chan_cdr) { 01843 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 01844 } 01845 } 01846 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 01847 if (chan_cdr) { 01848 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 01849 } 01850 if (peer_cdr) { 01851 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 01852 } 01853 } 01854 } 01855 01856 for (;;) { 01857 struct ast_channel *other; /* used later */ 01858 01859 res = ast_channel_bridge(chan, peer, config, &f, &who); 01860 01861 /* When frame is not set, we are probably involved in a situation 01862 where we've timed out. 01863 When frame is set, we'll come thru this code twice; once for DTMF_BEGIN 01864 and also for DTMF_END. If we flow into the following 'if' for both, then 01865 our wait times are cut in half, as both will subtract from the 01866 feature_timer. Not good! 01867 */ 01868 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 01869 /* Update time limit for next pass */ 01870 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01871 if (res == AST_BRIDGE_RETRY) { 01872 /* The feature fully timed out but has not been updated. Skip 01873 * the potential round error from the diff calculation and 01874 * explicitly set to expired. */ 01875 config->feature_timer = -1; 01876 } else { 01877 config->feature_timer -= diff; 01878 } 01879 01880 if (hasfeatures) { 01881 /* Running on backup config, meaning a feature might be being 01882 activated, but that's no excuse to keep things going 01883 indefinitely! */ 01884 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01885 if (option_debug) 01886 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01887 config->feature_timer = 0; 01888 who = chan; 01889 if (f) 01890 ast_frfree(f); 01891 f = NULL; 01892 res = 0; 01893 } else if (config->feature_timer <= 0) { 01894 /* Not *really* out of time, just out of time for 01895 digits to come in for features. */ 01896 if (option_debug) 01897 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01898 if (!ast_strlen_zero(peer_featurecode)) { 01899 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01900 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01901 } 01902 if (!ast_strlen_zero(chan_featurecode)) { 01903 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01904 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01905 } 01906 if (f) 01907 ast_frfree(f); 01908 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01909 if (!hasfeatures) { 01910 /* Restore original (possibly time modified) bridge config */ 01911 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01912 memset(&backup_config, 0, sizeof(backup_config)); 01913 } 01914 hadfeatures = hasfeatures; 01915 /* Continue as we were */ 01916 continue; 01917 } else if (!f) { 01918 /* The bridge returned without a frame and there is a feature in progress. 01919 * However, we don't think the feature has quite yet timed out, so just 01920 * go back into the bridge. */ 01921 continue; 01922 } 01923 } else { 01924 if (config->feature_timer <=0) { 01925 /* We ran out of time */ 01926 config->feature_timer = 0; 01927 who = chan; 01928 if (f) 01929 ast_frfree(f); 01930 f = NULL; 01931 res = 0; 01932 } 01933 } 01934 } 01935 if (res < 0) { 01936 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01937 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01938 goto before_you_go; 01939 } 01940 01941 if (!f || (f->frametype == AST_FRAME_CONTROL && 01942 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01943 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01944 res = -1; 01945 break; 01946 } 01947 /* many things should be sent to the 'other' channel */ 01948 other = (who == chan) ? peer : chan; 01949 if (f->frametype == AST_FRAME_CONTROL) { 01950 switch (f->subclass) { 01951 case AST_CONTROL_RINGING: 01952 case AST_CONTROL_FLASH: 01953 case -1: 01954 ast_indicate(other, f->subclass); 01955 break; 01956 case AST_CONTROL_HOLD: 01957 case AST_CONTROL_UNHOLD: 01958 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01959 break; 01960 case AST_CONTROL_OPTION: 01961 aoh = f->data; 01962 /* Forward option Requests */ 01963 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01964 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01965 f->datalen - sizeof(struct ast_option_header), 0); 01966 } 01967 break; 01968 case AST_CONTROL_ATXFERCMD: 01969 cmd_atxfer(chan, peer, config, who, f->data); 01970 break; 01971 } 01972 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01973 /* eat it */ 01974 } else if (f->frametype == AST_FRAME_DTMF) { 01975 char *featurecode; 01976 int sense; 01977 01978 hadfeatures = hasfeatures; 01979 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01980 if (who == chan) { 01981 sense = FEATURE_SENSE_CHAN; 01982 featurecode = chan_featurecode; 01983 } else { 01984 sense = FEATURE_SENSE_PEER; 01985 featurecode = peer_featurecode; 01986 } 01987 /*! append the event to featurecode. we rely on the string being zero-filled, and 01988 * not overflowing it. 01989 * \todo XXX how do we guarantee the latter ? 01990 */ 01991 featurecode[strlen(featurecode)] = f->subclass; 01992 /* Get rid of the frame before we start doing "stuff" with the channels */ 01993 ast_frfree(f); 01994 f = NULL; 01995 config->feature_timer = backup_config.feature_timer; 01996 res = feature_interpret(chan, peer, config, featurecode, sense); 01997 switch(res) { 01998 case FEATURE_RETURN_PASSDIGITS: 01999 ast_dtmf_stream(other, who, featurecode, 0); 02000 /* Fall through */ 02001 case FEATURE_RETURN_SUCCESS: 02002 memset(featurecode, 0, sizeof(chan_featurecode)); 02003 break; 02004 } 02005 if (res >= FEATURE_RETURN_PASSDIGITS) { 02006 res = 0; 02007 } else 02008 break; 02009 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02010 if (hadfeatures && !hasfeatures) { 02011 /* Restore backup */ 02012 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 02013 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 02014 } else if (hasfeatures) { 02015 if (!hadfeatures) { 02016 /* Backup configuration */ 02017 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 02018 /* Setup temporary config options */ 02019 config->play_warning = 0; 02020 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 02021 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 02022 config->warning_freq = 0; 02023 config->warning_sound = NULL; 02024 config->end_sound = NULL; 02025 config->start_sound = NULL; 02026 config->firstpass = 0; 02027 } 02028 config->start_time = ast_tvnow(); 02029 config->feature_timer = featuredigittimeout; 02030 if (option_debug) 02031 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 02032 } 02033 } 02034 if (f) 02035 ast_frfree(f); 02036 02037 } 02038 before_you_go: 02039 02040 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 02041 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 02042 if (bridge_cdr) { 02043 ast_cdr_discard(bridge_cdr); 02044 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 02045 } 02046 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 02047 } 02048 02049 if (config->end_bridge_callback) { 02050 config->end_bridge_callback(config->end_bridge_callback_data); 02051 } 02052 02053 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 02054 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 02055 struct ast_cdr *swapper = NULL; 02056 char savelastapp[AST_MAX_EXTENSION]; 02057 char savelastdata[AST_MAX_EXTENSION]; 02058 char save_exten[AST_MAX_EXTENSION]; 02059 int save_prio, spawn_error = 0; 02060 02061 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 02062 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 02063 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 02064 ast_cdr_end(bridge_cdr); 02065 } 02066 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 02067 dialplan code operate on it */ 02068 ast_channel_lock(chan); 02069 if (bridge_cdr) { 02070 swapper = chan->cdr; 02071 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 02072 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 02073 chan->cdr = bridge_cdr; 02074 } 02075 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 02076 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 02077 save_prio = chan->priority; 02078 chan->priority = 1; 02079 ast_channel_unlock(chan); 02080 while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) { 02081 if ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) { 02082 /* Something bad happened, or a hangup has been requested. */ 02083 if (option_debug) 02084 ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 02085 if (option_verbose > 1) 02086 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); 02087 break; 02088 } 02089 chan->priority++; 02090 } 02091 /* swap it back */ 02092 ast_channel_lock(chan); 02093 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 02094 chan->priority = save_prio; 02095 if (bridge_cdr) { 02096 if (chan->cdr == bridge_cdr) { 02097 chan->cdr = swapper; 02098 } else { 02099 bridge_cdr = NULL; 02100 } 02101 } 02102 if (chan->priority != 1 || !spawn_error) { 02103 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 02104 } 02105 ast_channel_unlock(chan); 02106 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 02107 if (bridge_cdr) { 02108 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 02109 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 02110 } 02111 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 02112 } 02113 02114 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 02115 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02116 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 02117 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 02118 } 02119 02120 /* we can post the bridge CDR at this point */ 02121 if (bridge_cdr) { 02122 ast_cdr_end(bridge_cdr); 02123 ast_cdr_detach(bridge_cdr); 02124 } 02125 02126 /* do a specialized reset on the beginning channel 02127 CDR's, if they still exist, so as not to mess up 02128 issues in future bridges; 02129 02130 Here are the rules of the game: 02131 1. The chan and peer channel pointers will not change 02132 during the life of the bridge. 02133 2. But, in transfers, the channel names will change. 02134 between the time the bridge is started, and the 02135 time the channel ends. 02136 Usually, when a channel changes names, it will 02137 also change CDR pointers. 02138 3. Usually, only one of the two channels (chan or peer) 02139 will change names. 02140 4. Usually, if a channel changes names during a bridge, 02141 it is because of a transfer. Usually, in these situations, 02142 it is normal to see 2 bridges running simultaneously, and 02143 it is not unusual to see the two channels that change 02144 swapped between bridges. 02145 5. After a bridge occurs, we have 2 or 3 channels' CDRs 02146 to attend to; if the chan or peer changed names, 02147 we have the before and after attached CDR's. 02148 */ 02149 02150 if (new_chan_cdr) { 02151 struct ast_channel *chan_ptr = NULL; 02152 02153 if (strcasecmp(orig_channame, chan->name) != 0) { 02154 /* old channel */ 02155 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 02156 if (chan_ptr) { 02157 if (!ast_bridged_channel(chan_ptr)) { 02158 struct ast_cdr *cur; 02159 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02160 if (cur == chan_cdr) { 02161 break; 02162 } 02163 } 02164 if (cur) 02165 ast_cdr_specialized_reset(chan_cdr,0); 02166 } 02167 ast_channel_unlock(chan_ptr); 02168 } 02169 /* new channel */ 02170 ast_cdr_specialized_reset(new_chan_cdr,0); 02171 } else { 02172 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 02173 } 02174 } 02175 02176 { 02177 struct ast_channel *chan_ptr = NULL; 02178 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02179 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)) 02180 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 02181 if (strcasecmp(orig_peername, peer->name) != 0) { 02182 /* old channel */ 02183 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 02184 if (chan_ptr) { 02185 if (!ast_bridged_channel(chan_ptr)) { 02186 struct ast_cdr *cur; 02187 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 02188 if (cur == peer_cdr) { 02189 break; 02190 } 02191 } 02192 if (cur) 02193 ast_cdr_specialized_reset(peer_cdr,0); 02194 } 02195 ast_channel_unlock(chan_ptr); 02196 } 02197 /* new channel */ 02198 ast_cdr_specialized_reset(new_peer_cdr,0); 02199 } else { 02200 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 02201 } 02202 } 02203 02204 return res; 02205 }
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_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), ast_waitfor_n(), ast_write(), builtin_features, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, len(), LOG_NOTICE, ast_channel::name, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.
Referenced by do_atxfer().
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 && f->subclass != AST_CONTROL_PROGRESS) { 01524 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01525 } 01526 /* else who cares */ 01527 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 01528 ast_write(caller, f); 01529 } 01530 01531 } else if (caller && (active_channel == caller)) { 01532 f = ast_read(caller); 01533 if (f == NULL) { /*doh! where'd he go?*/ 01534 if (caller->_softhangup && !chan->_softhangup) { 01535 /* make this a blind transfer */ 01536 ready = 1; 01537 break; 01538 } 01539 state = AST_CONTROL_HANGUP; 01540 res = 0; 01541 break; 01542 } 01543 01544 if (f->frametype == AST_FRAME_DTMF) { 01545 dialed_code[x++] = f->subclass; 01546 dialed_code[x] = '\0'; 01547 if (strlen(dialed_code) == len) { 01548 x = 0; 01549 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01550 x = 0; 01551 dialed_code[x] = '\0'; 01552 } 01553 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01554 /* Caller Canceled the call */ 01555 state = AST_CONTROL_UNHOLD; 01556 ast_frfree(f); 01557 f = NULL; 01558 break; 01559 } 01560 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 01561 ast_write(chan, f); 01562 } 01563 } 01564 if (f) 01565 ast_frfree(f); 01566 } /* end while */ 01567 } else 01568 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01569 } else { 01570 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01571 switch(cause) { 01572 case AST_CAUSE_BUSY: 01573 state = AST_CONTROL_BUSY; 01574 break; 01575 case AST_CAUSE_CONGESTION: 01576 state = AST_CONTROL_CONGESTION; 01577 break; 01578 } 01579 } 01580 01581 ast_indicate(caller, -1); 01582 if (chan && ready) { 01583 if (chan->_state == AST_STATE_UP) 01584 state = AST_CONTROL_ANSWER; 01585 res = 0; 01586 } else if(chan) { 01587 res = -1; 01588 ast_hangup(chan); 01589 chan = NULL; 01590 } else { 01591 res = -1; 01592 } 01593 01594 if (outstate) 01595 *outstate = state; 01596 01597 return chan; 01598 }
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 2864 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().
02865 { 02866 struct ast_channel *cur = NULL; 02867 int res = -1; 02868 02869 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02870 if (!cur->pbx && 02871 (cur != chan) && 02872 (chan->pickupgroup & cur->callgroup) && 02873 ((cur->_state == AST_STATE_RINGING) || 02874 (cur->_state == AST_STATE_RING))) { 02875 break; 02876 } 02877 ast_channel_unlock(cur); 02878 } 02879 if (cur) { 02880 if (option_debug) 02881 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02882 res = ast_answer(chan); 02883 if (res) 02884 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02885 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02886 if (res) 02887 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02888 res = ast_channel_masquerade(cur, chan); 02889 if (res) 02890 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02891 ast_channel_unlock(cur); 02892 } else { 02893 if (option_debug) 02894 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02895 } 02896 return res; 02897 }
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 2221 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().
02222 { 02223 int i = 0; 02224 enum { 02225 OPT_CALLEE_REDIRECT = 't', 02226 OPT_CALLER_REDIRECT = 'T', 02227 OPT_CALLEE_AUTOMON = 'w', 02228 OPT_CALLER_AUTOMON = 'W', 02229 OPT_CALLEE_DISCONNECT = 'h', 02230 OPT_CALLER_DISCONNECT = 'H', 02231 OPT_CALLEE_PARKCALL = 'k', 02232 OPT_CALLER_PARKCALL = 'K', 02233 }; 02234 02235 memset(options, 0, len); 02236 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 02237 options[i++] = OPT_CALLER_REDIRECT; 02238 } 02239 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 02240 options[i++] = OPT_CALLER_AUTOMON; 02241 } 02242 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 02243 options[i++] = OPT_CALLER_DISCONNECT; 02244 } 02245 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 02246 options[i++] = OPT_CALLER_PARKCALL; 02247 } 02248 02249 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 02250 options[i++] = OPT_CALLEE_REDIRECT; 02251 } 02252 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 02253 options[i++] = OPT_CALLEE_AUTOMON; 02254 } 02255 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 02256 options[i++] = OPT_CALLEE_DISCONNECT; 02257 } 02258 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 02259 options[i++] = OPT_CALLEE_PARKCALL; 02260 } 02261 02262 return options; 02263 }
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 1701 of file res_features.c.
References context, do_atxfer(), FEATURE_SENSE_CHAN, and FEATURE_SENSE_PEER.
Referenced by ast_bridge_call().
01702 { 01703 int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER; 01704 char *context = strchr(xferto, '@');; 01705 if (context) 01706 *context++ = '\0'; 01707 do_atxfer(a, b, conf, sense, xferto, context); 01708 }
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 2266 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().
02267 { 02268 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 02269 FD_ZERO(&rfds); 02270 FD_ZERO(&efds); 02271 02272 for (;;) { 02273 struct parkeduser *pu, *pl, *pt = NULL; 02274 int ms = -1; /* select timeout, uninitialized */ 02275 int max = -1; /* max fd, none there yet */ 02276 fd_set nrfds, nefds; /* args for the next select */ 02277 FD_ZERO(&nrfds); 02278 FD_ZERO(&nefds); 02279 02280 ast_mutex_lock(&parking_lock); 02281 pl = NULL; 02282 pu = parkinglot; 02283 /* navigate the list with prev-cur pointers to support removals */ 02284 while (pu) { 02285 struct ast_channel *chan = pu->chan; /* shorthand */ 02286 int tms; /* timeout for this item */ 02287 int x; /* fd index in channel */ 02288 struct ast_context *con; 02289 02290 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 02291 pl = pu; 02292 pu = pu->next; 02293 continue; 02294 } 02295 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 02296 if (tms > pu->parkingtime) { 02297 ast_indicate(chan, AST_CONTROL_UNHOLD); 02298 /* Get chan, exten from derived kludge */ 02299 if (pu->peername[0]) { 02300 char *peername = ast_strdupa(pu->peername); 02301 char *cp = strrchr(peername, '-'); 02302 if (cp) 02303 *cp = 0; 02304 con = ast_context_find(parking_con_dial); 02305 if (!con) { 02306 con = ast_context_create(NULL, parking_con_dial, registrar); 02307 if (!con) 02308 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 02309 } 02310 if (con) { 02311 char returnexten[AST_MAX_EXTENSION]; 02312 struct ast_datastore *features_datastore; 02313 struct ast_dial_features *dialfeatures = NULL; 02314 02315 ast_channel_lock(chan); 02316 02317 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 02318 dialfeatures = features_datastore->data; 02319 02320 ast_channel_unlock(chan); 02321 02322 if (!strncmp(peername, "Parked/", 7)) { 02323 peername += 7; 02324 } 02325 02326 if (dialfeatures) { 02327 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 02328 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 02329 } else { /* Existing default */ 02330 ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name); 02331 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername); 02332 } 02333 02334 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free_ptr, registrar); 02335 } 02336 set_c_e_p(chan, parking_con_dial, peername, 1); 02337 } else { 02338 /* They've been waiting too long, send them back to where they came. Theoretically they 02339 should have their original extensions and such, but we copy to be on the safe side */ 02340 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 02341 } 02342 02343 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 02344 02345 if (option_verbose > 1) 02346 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); 02347 /* Start up the PBX, or hang them up */ 02348 if (ast_pbx_start(chan)) { 02349 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 02350 ast_hangup(chan); 02351 } 02352 /* And take them out of the parking lot */ 02353 if (pl) 02354 pl->next = pu->next; 02355 else 02356 parkinglot = pu->next; 02357 pt = pu; 02358 pu = pu->next; 02359 con = ast_context_find(parking_con); 02360 if (con) { 02361 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 02362 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02363 else 02364 notify_metermaids(pt->parkingexten, parking_con); 02365 } else 02366 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02367 free(pt); 02368 } else { /* still within parking time, process descriptors */ 02369 for (x = 0; x < AST_MAX_FDS; x++) { 02370 struct ast_frame *f; 02371 02372 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 02373 continue; /* nothing on this descriptor */ 02374 02375 if (FD_ISSET(chan->fds[x], &efds)) 02376 ast_set_flag(chan, AST_FLAG_EXCEPTION); 02377 else 02378 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 02379 chan->fdno = x; 02380 02381 /* See if they need servicing */ 02382 f = ast_read(chan); 02383 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 02384 if (f) 02385 ast_frfree(f); 02386 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 02387 02388 /* There's a problem, hang them up*/ 02389 if (option_verbose > 1) 02390 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 02391 ast_hangup(chan); 02392 /* And take them out of the parking lot */ 02393 if (pl) 02394 pl->next = pu->next; 02395 else 02396 parkinglot = pu->next; 02397 pt = pu; 02398 pu = pu->next; 02399 con = ast_context_find(parking_con); 02400 if (con) { 02401 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 02402 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02403 else { 02404 notify_metermaids(pt->parkingexten, parking_con); 02405 } 02406 } else 02407 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02408 free(pt); 02409 break; 02410 } else { 02411 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02412 ast_frfree(f); 02413 if (pu->moh_trys < 3 && !chan->generatordata) { 02414 if (option_debug) 02415 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 02416 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 02417 S_OR(parkmohclass, NULL), 02418 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 02419 pu->moh_trys++; 02420 } 02421 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 02422 } 02423 02424 } /* end for */ 02425 if (x >= AST_MAX_FDS) { 02426 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 02427 if (chan->fds[x] > -1) { 02428 FD_SET(chan->fds[x], &nrfds); 02429 FD_SET(chan->fds[x], &nefds); 02430 if (chan->fds[x] > max) 02431 max = chan->fds[x]; 02432 } 02433 } 02434 /* Keep track of our shortest wait */ 02435 if (tms < ms || ms < 0) 02436 ms = tms; 02437 pl = pu; 02438 pu = pu->next; 02439 } 02440 } 02441 } /* end while */ 02442 ast_mutex_unlock(&parking_lock); 02443 rfds = nrfds; 02444 efds = nefds; 02445 { 02446 struct timeval tv = ast_samp2tv(ms, 1000); 02447 /* Wait for something to happen */ 02448 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 02449 } 02450 pthread_testcancel(); 02451 } 02452 return NULL; /* Never reached */ 02453 }
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 2718 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.
02719 { 02720 struct parkeduser *cur; 02721 int numparked = 0; 02722 02723 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 02724 , "Context", "Extension", "Pri", "Timeout"); 02725 02726 ast_mutex_lock(&parking_lock); 02727 02728 for (cur = parkinglot; cur; cur = cur->next) { 02729 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 02730 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 02731 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 02732 02733 numparked++; 02734 } 02735 ast_mutex_unlock(&parking_lock); 02736 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 02737 02738 02739 return RESULT_SUCCESS; 02740 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2676 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.
02677 { 02678 int i; 02679 struct ast_call_feature *feature; 02680 char format[] = "%-25s %-7s %-7s\n"; 02681 02682 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 02683 ast_cli(fd, format, "---------------", "-------", "-------"); 02684 02685 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 02686 02687 ast_rwlock_rdlock(&features_lock); 02688 for (i = 0; i < FEATURES_COUNT; i++) 02689 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 02690 ast_rwlock_unlock(&features_lock); 02691 02692 ast_cli(fd, "\n"); 02693 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 02694 ast_cli(fd, format, "---------------", "-------", "-------"); 02695 if (AST_RWLIST_EMPTY(&feature_list)) { 02696 ast_cli(fd, "(none)\n"); 02697 } else { 02698 AST_RWLIST_RDLOCK(&feature_list); 02699 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 02700 ast_cli(fd, format, feature->sname, "no def", feature->exten); 02701 } 02702 AST_RWLIST_UNLOCK(&feature_list); 02703 } 02704 ast_cli(fd, "\nCall parking\n"); 02705 ast_cli(fd, "------------\n"); 02706 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 02707 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 02708 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 02709 ast_cli(fd,"\n"); 02710 02711 return RESULT_SUCCESS; 02712 }
static int load_config | ( | void | ) | [static] |
Definition at line 2914 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.
02915 { 02916 int start = 0, end = 0; 02917 int res; 02918 struct ast_context *con = NULL; 02919 struct ast_config *cfg = NULL; 02920 struct ast_variable *var = NULL; 02921 char old_parking_ext[AST_MAX_EXTENSION]; 02922 char old_parking_con[AST_MAX_EXTENSION] = ""; 02923 02924 if (!ast_strlen_zero(parking_con)) { 02925 strcpy(old_parking_ext, parking_ext); 02926 strcpy(old_parking_con, parking_con); 02927 } 02928 02929 /* Reset to defaults */ 02930 strcpy(parking_con, "parkedcalls"); 02931 strcpy(parking_con_dial, "park-dial"); 02932 strcpy(parking_ext, "700"); 02933 strcpy(pickup_ext, "*8"); 02934 strcpy(parkmohclass, "default"); 02935 courtesytone[0] = '\0'; 02936 strcpy(xfersound, "beep"); 02937 strcpy(xferfailsound, "pbx-invalid"); 02938 parking_start = 701; 02939 parking_stop = 750; 02940 parkfindnext = 0; 02941 adsipark = 0; 02942 parkaddhints = 0; 02943 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 02944 parkedcallreparking = 0; 02945 parkedcallhangup = 0; 02946 parkedcallrecording = 0; 02947 02948 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02949 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02950 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02951 02952 cfg = ast_config_load("features.conf"); 02953 if (!cfg) { 02954 ast_log(LOG_WARNING,"Could not load features.conf\n"); 02955 return AST_MODULE_LOAD_DECLINE; 02956 } 02957 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 02958 if (!strcasecmp(var->name, "parkext")) { 02959 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02960 } else if (!strcasecmp(var->name, "context")) { 02961 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02962 } else if (!strcasecmp(var->name, "parkingtime")) { 02963 if ((sscanf(var->value, "%30d", &parkingtime) != 1) || (parkingtime < 1)) { 02964 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02965 parkingtime = DEFAULT_PARK_TIME; 02966 } else 02967 parkingtime = parkingtime * 1000; 02968 } else if (!strcasecmp(var->name, "parkpos")) { 02969 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 02970 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); 02971 } else { 02972 parking_start = start; 02973 parking_stop = end; 02974 } 02975 } else if (!strcasecmp(var->name, "findslot")) { 02976 parkfindnext = (!strcasecmp(var->value, "next")); 02977 } else if (!strcasecmp(var->name, "parkinghints")) { 02978 parkaddhints = ast_true(var->value); 02979 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 02980 if (!strcasecmp(var->value, "no")) 02981 parkedcalltransfers = 0; 02982 else if (!strcasecmp(var->value, "caller")) 02983 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 02984 else if (!strcasecmp(var->value, "callee")) 02985 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 02986 else if (!strcasecmp(var->value, "both")) 02987 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 02988 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 02989 if (!strcasecmp(var->value, "no")) 02990 parkedcallreparking = 0; 02991 else if (!strcasecmp(var->value, "caller")) 02992 parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 02993 else if (!strcasecmp(var->value, "callee")) 02994 parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 02995 else if (!strcasecmp(var->value, "both")) 02996 parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 02997 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 02998 if (!strcasecmp(var->value, "no")) 02999 parkedcallhangup = 0; 03000 else if (!strcasecmp(var->value, "caller")) 03001 parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 03002 else if (!strcasecmp(var->value, "callee")) 03003 parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 03004 else if (!strcasecmp(var->value, "both")) 03005 parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 03006 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 03007 if (!strcasecmp(var->value, "no")) 03008 parkedcallrecording = 0; 03009 else if (!strcasecmp(var->value, "caller")) 03010 parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 03011 else if (!strcasecmp(var->value, "callee")) 03012 parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 03013 else if (!strcasecmp(var->value, "both")) 03014 parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 03015 } else if (!strcasecmp(var->name, "adsipark")) { 03016 adsipark = ast_true(var->value); 03017 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03018 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03019 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03020 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03021 } else 03022 transferdigittimeout = transferdigittimeout * 1000; 03023 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03024 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03025 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03026 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03027 } 03028 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03029 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03030 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03031 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03032 } else 03033 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03034 } else if (!strcasecmp(var->name, "courtesytone")) { 03035 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03036 } else if (!strcasecmp(var->name, "parkedplay")) { 03037 if (!strcasecmp(var->value, "both")) 03038 parkedplay = 2; 03039 else if (!strcasecmp(var->value, "parked")) 03040 parkedplay = 1; 03041 else 03042 parkedplay = 0; 03043 } else if (!strcasecmp(var->name, "xfersound")) { 03044 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03045 } else if (!strcasecmp(var->name, "xferfailsound")) { 03046 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03047 } else if (!strcasecmp(var->name, "pickupexten")) { 03048 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03049 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03050 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 03051 } 03052 } 03053 03054 unmap_features(); 03055 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03056 if (remap_feature(var->name, var->value)) 03057 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03058 } 03059 03060 /* Map a key combination to an application*/ 03061 ast_unregister_features(); 03062 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03063 char *tmp_val = ast_strdupa(var->value); 03064 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 03065 struct ast_call_feature *feature; 03066 03067 /* strsep() sets the argument to NULL if match not found, and it 03068 * is safe to use it with a NULL argument, so we don't check 03069 * between calls. 03070 */ 03071 exten = strsep(&tmp_val,","); 03072 activatedby = strsep(&tmp_val,","); 03073 app = strsep(&tmp_val,","); 03074 app_args = strsep(&tmp_val,","); 03075 moh_class = strsep(&tmp_val,","); 03076 03077 activateon = strsep(&activatedby, "/"); 03078 03079 /*! \todo XXX var_name or app_args ? */ 03080 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03081 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03082 app, exten, activateon, var->name); 03083 continue; 03084 } 03085 03086 AST_RWLIST_RDLOCK(&feature_list); 03087 if ((feature = find_dynamic_feature(var->name))) { 03088 AST_RWLIST_UNLOCK(&feature_list); 03089 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03090 continue; 03091 } 03092 AST_RWLIST_UNLOCK(&feature_list); 03093 03094 if (!(feature = ast_calloc(1, sizeof(*feature)))) 03095 continue; 03096 03097 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03098 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 03099 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 03100 03101 if (app_args) 03102 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 03103 03104 if (moh_class) 03105 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 03106 03107 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 03108 feature->operation = feature_exec_app; 03109 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03110 03111 /* Allow caller and calle to be specified for backwards compatability */ 03112 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03113 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03114 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03115 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03116 else { 03117 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03118 " must be 'self', or 'peer'\n", var->name); 03119 continue; 03120 } 03121 03122 if (ast_strlen_zero(activatedby)) 03123 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03124 else if (!strcasecmp(activatedby, "caller")) 03125 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03126 else if (!strcasecmp(activatedby, "callee")) 03127 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03128 else if (!strcasecmp(activatedby, "both")) 03129 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03130 else { 03131 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03132 " must be 'caller', or 'callee', or 'both'\n", var->name); 03133 continue; 03134 } 03135 03136 ast_register_feature(feature); 03137 03138 if (option_verbose >= 1) 03139 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 03140 } 03141 ast_config_destroy(cfg); 03142 03143 /* Remove the old parking extension */ 03144 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03145 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 03146 notify_metermaids(old_parking_ext, old_parking_con); 03147 if (option_debug) 03148 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03149 } 03150 03151 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 03152 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 03153 return -1; 03154 } 03155 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 03156 if (parkaddhints) 03157 park_add_hints(parking_con, parking_start, parking_stop); 03158 if (!res) 03159 notify_metermaids(ast_parking_ext(), parking_con); 03160 return res; 03161 03162 }
static int load_module | ( | void | ) | [static] |
Definition at line 3169 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.
03170 { 03171 int res; 03172 03173 memset(parking_ext, 0, sizeof(parking_ext)); 03174 memset(parking_con, 0, sizeof(parking_con)); 03175 03176 if ((res = load_config())) 03177 return res; 03178 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03179 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 03180 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 03181 if (!res) 03182 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 03183 if (!res) { 03184 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 03185 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 03186 "Park a channel", mandescr_park); 03187 } 03188 03189 res |= ast_devstate_prov_add("Park", metermaidstate); 03190 03191 return res; 03192 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2809 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().
02810 { 02811 const char *channel = astman_get_header(m, "Channel"); 02812 const char *channel2 = astman_get_header(m, "Channel2"); 02813 const char *timeout = astman_get_header(m, "Timeout"); 02814 char buf[BUFSIZ]; 02815 int to = 0; 02816 int res = 0; 02817 int parkExt = 0; 02818 struct ast_channel *ch1, *ch2; 02819 02820 if (ast_strlen_zero(channel)) { 02821 astman_send_error(s, m, "Channel not specified"); 02822 return 0; 02823 } 02824 02825 if (ast_strlen_zero(channel2)) { 02826 astman_send_error(s, m, "Channel2 not specified"); 02827 return 0; 02828 } 02829 02830 ch1 = ast_get_channel_by_name_locked(channel); 02831 if (!ch1) { 02832 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02833 astman_send_error(s, m, buf); 02834 return 0; 02835 } 02836 02837 ch2 = ast_get_channel_by_name_locked(channel2); 02838 if (!ch2) { 02839 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02840 astman_send_error(s, m, buf); 02841 ast_channel_unlock(ch1); 02842 return 0; 02843 } 02844 02845 if (!ast_strlen_zero(timeout)) { 02846 sscanf(timeout, "%30d", &to); 02847 } 02848 02849 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02850 if (!res) { 02851 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02852 astman_send_ack(s, m, "Park successful"); 02853 } else { 02854 astman_send_error(s, m, "Park failure"); 02855 } 02856 02857 ast_channel_unlock(ch1); 02858 ast_channel_unlock(ch2); 02859 02860 return 0; 02861 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 2762 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().
02763 { 02764 struct parkeduser *cur; 02765 const char *id = astman_get_header(m, "ActionID"); 02766 char idText[256] = ""; 02767 02768 if (!ast_strlen_zero(id)) 02769 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 02770 02771 astman_send_ack(s, m, "Parked calls will follow"); 02772 02773 ast_mutex_lock(&parking_lock); 02774 02775 for (cur = parkinglot; cur; cur = cur->next) { 02776 astman_append(s, "Event: ParkedCall\r\n" 02777 "Exten: %d\r\n" 02778 "Channel: %s\r\n" 02779 "From: %s\r\n" 02780 "Timeout: %ld\r\n" 02781 "CallerID: %s\r\n" 02782 "CallerIDName: %s\r\n" 02783 "%s" 02784 "\r\n", 02785 cur->parkingnum, cur->chan->name, cur->peername, 02786 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 02787 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 02788 S_OR(cur->chan->cid.cid_name, ""), 02789 idText); 02790 } 02791 02792 astman_append(s, 02793 "Event: ParkedCallsComplete\r\n" 02794 "%s" 02795 "\r\n",idText); 02796 02797 ast_mutex_unlock(&parking_lock); 02798 02799 return RESULT_SUCCESS; 02800 }
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 2900 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, PRIORITY_HINT, and registrar.
02901 { 02902 int numext; 02903 char device[AST_MAX_EXTENSION]; 02904 char exten[10]; 02905 02906 for (numext = start; numext <= stop; numext++) { 02907 snprintf(exten, sizeof(exten), "%d", numext); 02908 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 02909 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02910 } 02911 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 2456 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().
02457 { 02458 /* Cache the original channel name in case we get masqueraded in the middle 02459 * of a park--it is still theoretically possible for a transfer to happen before 02460 * we get here, but it is _really_ unlikely */ 02461 char *orig_chan_name = ast_strdupa(chan->name); 02462 char orig_exten[AST_MAX_EXTENSION]; 02463 int orig_priority = chan->priority; 02464 02465 /* Data is unused at the moment but could contain a parking 02466 lot context eventually */ 02467 int res = 0; 02468 struct ast_module_user *u; 02469 02470 u = ast_module_user_add(chan); 02471 02472 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 02473 02474 /* Setup the exten/priority to be s/1 since we don't know 02475 where this call should return */ 02476 strcpy(chan->exten, "s"); 02477 chan->priority = 1; 02478 /* Answer if call is not up */ 02479 if (chan->_state != AST_STATE_UP) 02480 res = ast_answer(chan); 02481 /* Sleep to allow VoIP streams to settle down */ 02482 if (!res) 02483 res = ast_safe_sleep(chan, 1000); 02484 /* Park the call */ 02485 if (!res) { 02486 res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name); 02487 /* Continue on in the dialplan */ 02488 if (res == 1) { 02489 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 02490 chan->priority = orig_priority; 02491 res = 0; 02492 } else if (!res) { 02493 res = 1; 02494 } 02495 } 02496 02497 ast_module_user_remove(u); 02498 02499 return res; 02500 }
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 2503 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().
02504 { 02505 int res = 0; 02506 struct ast_module_user *u; 02507 struct ast_channel *peer=NULL; 02508 struct parkeduser *pu, *pl=NULL; 02509 struct ast_context *con; 02510 02511 int park; 02512 struct ast_bridge_config config; 02513 02514 if (!data) { 02515 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 02516 return -1; 02517 } 02518 02519 u = ast_module_user_add(chan); 02520 02521 park = atoi((char *)data); 02522 ast_mutex_lock(&parking_lock); 02523 pu = parkinglot; 02524 while(pu) { 02525 if (pu->parkingnum == park) { 02526 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 02527 ast_mutex_unlock(&parking_lock); 02528 ast_module_user_remove(u); 02529 return -1; 02530 } 02531 if (pl) 02532 pl->next = pu->next; 02533 else 02534 parkinglot = pu->next; 02535 break; 02536 } 02537 pl = pu; 02538 pu = pu->next; 02539 } 02540 ast_mutex_unlock(&parking_lock); 02541 if (pu) { 02542 peer = pu->chan; 02543 con = ast_context_find(parking_con); 02544 if (con) { 02545 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 02546 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02547 else 02548 notify_metermaids(pu->parkingexten, parking_con); 02549 } else 02550 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02551 02552 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 02553 "Exten: %s\r\n" 02554 "Channel: %s\r\n" 02555 "From: %s\r\n" 02556 "CallerID: %s\r\n" 02557 "CallerIDName: %s\r\n", 02558 pu->parkingexten, pu->chan->name, chan->name, 02559 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02560 S_OR(pu->chan->cid.cid_name, "<unknown>") 02561 ); 02562 02563 free(pu); 02564 } 02565 /* JK02: it helps to answer the channel if not already up */ 02566 if (chan->_state != AST_STATE_UP) 02567 ast_answer(chan); 02568 02569 if (peer) { 02570 struct ast_datastore *features_datastore; 02571 struct ast_dial_features *dialfeatures = NULL; 02572 02573 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 02574 02575 if (!ast_strlen_zero(courtesytone)) { 02576 int error = 0; 02577 ast_indicate(peer, AST_CONTROL_UNHOLD); 02578 if (parkedplay == 0) { 02579 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 02580 } else if (parkedplay == 1) { 02581 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 02582 } else if (parkedplay == 2) { 02583 if (!ast_streamfile(chan, courtesytone, chan->language) && 02584 !ast_streamfile(peer, courtesytone, chan->language)) { 02585 /*! \todo XXX we would like to wait on both! */ 02586 res = ast_waitstream(chan, ""); 02587 if (res >= 0) 02588 res = ast_waitstream(peer, ""); 02589 if (res < 0) 02590 error = 1; 02591 } 02592 } 02593 if (error) { 02594 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02595 ast_hangup(peer); 02596 ast_module_user_remove(u); 02597 return -1; 02598 } 02599 } else 02600 ast_indicate(peer, AST_CONTROL_UNHOLD); 02601 02602 res = ast_channel_make_compatible(chan, peer); 02603 if (res < 0) { 02604 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 02605 ast_hangup(peer); 02606 ast_module_user_remove(u); 02607 return -1; 02608 } 02609 /* This runs sorta backwards, since we give the incoming channel control, as if it 02610 were the person called. */ 02611 if (option_verbose > 2) 02612 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 02613 02614 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02615 ast_cdr_setdestchan(chan->cdr, peer->name); 02616 memset(&config, 0, sizeof(struct ast_bridge_config)); 02617 02618 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 02619 ast_channel_lock(peer); 02620 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 02621 dialfeatures = features_datastore->data; 02622 } 02623 ast_channel_unlock(peer); 02624 02625 if (dialfeatures) { 02626 ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL); 02627 } 02628 02629 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 02630 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02631 } 02632 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 02633 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02634 } 02635 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 02636 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 02637 } 02638 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 02639 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 02640 } 02641 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 02642 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 02643 } 02644 if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 02645 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 02646 } 02647 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 02648 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 02649 } 02650 if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 02651 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 02652 } 02653 res = ast_bridge_call(chan, peer, &config); 02654 02655 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02656 ast_cdr_setdestchan(chan->cdr, peer->name); 02657 02658 /* Simulate the PBX hanging up */ 02659 ast_hangup(peer); 02660 ast_module_user_remove(u); 02661 return -1; 02662 } else { 02663 /*! \todo XXX Play a message XXX */ 02664 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 02665 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 02666 if (option_verbose > 2) 02667 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 02668 res = -1; 02669 } 02670 02671 ast_module_user_remove(u); 02672 02673 return -1; 02674 }
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 1600 of file res_features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
01601 { 01602 struct ast_cdr *cdr_orig = cdr; 01603 while (cdr) { 01604 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 01605 return cdr; 01606 cdr = cdr->next; 01607 } 01608 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 01609 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 2207 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().
02208 { 02209 manager_event(EVENT_FLAG_CALL, s, 02210 "Exten: %s\r\n" 02211 "Channel: %s\r\n" 02212 "CallerID: %s\r\n" 02213 "CallerIDName: %s\r\n\r\n", 02214 parkingexten, 02215 chan->name, 02216 S_OR(chan->cid.cid_num, "<unknown>"), 02217 S_OR(chan->cid.cid_name, "<unknown>") 02218 ); 02219 }
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 3164 of file res_features.c.
References load_config().
03165 { 03166 return load_config(); 03167 }
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 1611 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().
01612 { 01613 const char *feature; 01614 01615 if (ast_strlen_zero(features)) { 01616 return; 01617 } 01618 01619 for (feature = features; *feature; feature++) { 01620 switch (*feature) { 01621 case 'T' : 01622 case 't' : 01623 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 01624 break; 01625 case 'K' : 01626 case 'k' : 01627 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 01628 break; 01629 case 'H' : 01630 case 'h' : 01631 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 01632 break; 01633 case 'W' : 01634 case 'w' : 01635 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 01636 break; 01637 default : 01638 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 01639 } 01640 } 01641 }
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 3195 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.
03196 { 03197 ast_module_user_hangup_all(); 03198 03199 ast_manager_unregister("ParkedCalls"); 03200 ast_manager_unregister("Park"); 03201 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03202 ast_unregister_application(parkcall); 03203 ast_devstate_prov_del("Park"); 03204 return ast_unregister_application(parkedcall); 03205 }
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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 3211 of file res_features.c.
int adsipark [static] |
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 3211 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 2751 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 2746 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 = ((ast_mutex_t) 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 2714 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 2742 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] |