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