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