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