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