Thu Jan 28 17:36:11 2010

Asterisk developer's documentation


res_features.c File Reference

Routines implementing call features as call pickup, parking and transfer. More...

#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_channelast_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_featurefind_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 parkeduserpark_space_reserve (struct ast_channel *chan)
static struct ast_cdrpick_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 = "6989f2ec67f8497e38c12890500c525b" , .load = load_module, .unload = unload_module, .reload = reload, }
static int adsipark
static const struct ast_module_infoast_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_appmonitor_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 = { PTHREAD_MUTEX_INITIALIZER , 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INITIALIZER }
static int parking_offset
static int parking_start
static int parking_stop
static pthread_t parking_thread
static struct parkeduserparkinglot
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]


Detailed Description

Routines implementing call features as call pickup, parking and transfer.

Author:
Mark Spencer <markster@digium.com>

Definition in file res_features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 72 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

Definition at line 69 of file res_features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 70 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 67 of file res_features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 68 of file res_features.c.

Referenced by load_config().

#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 1106 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

Definition at line 73 of file res_features.c.

Referenced by do_parking_thread().


Enumeration Type Documentation

anonymous enum

Enumerator:
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 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 3215 of file res_features.c.

static void __unreg_module ( void   )  [static]

Definition at line 3215 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 1644 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().

01645 {
01646    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
01647    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
01648 
01649    ast_channel_lock(caller);
01650    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
01651    ast_channel_unlock(caller);
01652    if (!ds_caller_features) {
01653       if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
01654          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
01655          return;
01656       }
01657       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
01658          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
01659          ast_channel_datastore_free(ds_caller_features);
01660          return;
01661       }
01662       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
01663       caller_features->is_caller = 1;
01664       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
01665       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
01666       ds_caller_features->data = caller_features;
01667       ast_channel_lock(caller);
01668       ast_channel_datastore_add(caller, ds_caller_features);
01669       ast_channel_unlock(caller);
01670    } else {
01671       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
01672        * flags over from the atxfer to the caller */
01673       return;
01674    }
01675 
01676    ast_channel_lock(callee);
01677    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
01678    ast_channel_unlock(callee);
01679    if (!ds_callee_features) {
01680       if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
01681          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
01682          return;
01683       }
01684       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
01685          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
01686          ast_channel_datastore_free(ds_callee_features);
01687          return;
01688       }
01689       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
01690       callee_features->is_caller = 0;
01691       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
01692       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
01693       ds_callee_features->data = callee_features;
01694       ast_channel_lock(callee);
01695       ast_channel_datastore_add(callee, ds_callee_features);
01696       ast_channel_unlock(callee);
01697    }
01698 
01699    return;
01700 }

static int adsi_announce_park ( struct ast_channel chan,
char *  parkingexten 
) [static]

Definition at line 301 of file res_features.c.

References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.

Referenced by park_call_full().

00302 {
00303    int res;
00304    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00305    char tmp[256];
00306    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00307 
00308    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00309    message[0] = tmp;
00310    res = ast_adsi_load_session(chan, NULL, 0, 1);
00311    if (res == -1)
00312       return res;
00313    return ast_adsi_print(chan, message, justify, 1);
00314 }

int ast_bridge_call ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config 
)

Bridge a call, optionally allowing redirection.

append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.

Todo:
XXX how do we guarantee the latter ?

Definition at line 1711 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().

01712 {
01713    /* Copy voice back and forth between the two channels.  Give the peer
01714       the ability to transfer calls with '#<extension' syntax. */
01715    struct ast_frame *f;
01716    struct ast_channel *who;
01717    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01718    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01719    char orig_channame[AST_MAX_EXTENSION];
01720    char orig_peername[AST_MAX_EXTENSION];
01721 
01722    int res;
01723    int diff;
01724    int hasfeatures=0;
01725    int hadfeatures=0;
01726    int autoloopflag;
01727    struct ast_option_header *aoh;
01728    struct ast_bridge_config backup_config;
01729    struct ast_cdr *bridge_cdr = NULL;
01730    struct ast_cdr *orig_peer_cdr = NULL;
01731    struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */
01732    struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */
01733    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
01734    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
01735 
01736    memset(&backup_config, 0, sizeof(backup_config));
01737 
01738    config->start_time = ast_tvnow();
01739 
01740    if (chan && peer) {
01741       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01742       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01743    } else if (chan) {
01744       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01745    }
01746 
01747    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
01748    add_features_datastores(chan, peer, config);
01749 
01750    /* This is an interesting case.  One example is if a ringing channel gets redirected to
01751     * an extension that picks up a parked call.  This will make sure that the call taken
01752     * out of parking gets told that the channel it just got bridged to is still ringing. */
01753    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
01754       ast_indicate(peer, AST_CONTROL_RINGING);
01755    }
01756 
01757    if (monitor_ok) {
01758       const char *monitor_exec;
01759       struct ast_channel *src = NULL;
01760       if (!monitor_app) { 
01761          if (!(monitor_app = pbx_findapp("Monitor")))
01762             monitor_ok=0;
01763       }
01764       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01765          src = chan;
01766       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01767          src = peer;
01768       if (monitor_app && src) {
01769          char *tmp = ast_strdupa(monitor_exec);
01770          pbx_exec(src, monitor_app, tmp);
01771       }
01772    }
01773 
01774    set_config_flags(chan, peer, config);
01775    config->firstpass = 1;
01776 
01777    /* Answer if need be */
01778    if (ast_answer(chan))
01779       return -1;
01780 
01781    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
01782    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
01783    orig_peer_cdr = peer_cdr;
01784    
01785    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
01786          
01787       if (chan_cdr) {
01788          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
01789          ast_cdr_update(chan);
01790          bridge_cdr = ast_cdr_dup(chan_cdr);
01791          /* rip any forked CDR's off of the chan_cdr and attach
01792           * them to the bridge_cdr instead */
01793          bridge_cdr->next = chan_cdr->next;
01794          chan_cdr->next = NULL;
01795          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
01796          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
01797          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
01798             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
01799          }
01800       } else {
01801          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
01802          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
01803          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
01804          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
01805          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
01806          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
01807          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
01808          ast_cdr_setcid(bridge_cdr, chan);
01809          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
01810          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
01811          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
01812          /* Destination information */
01813          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
01814          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
01815          if (peer_cdr) {
01816             bridge_cdr->start = peer_cdr->start;
01817             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
01818          } else {
01819             ast_cdr_start(bridge_cdr);
01820          }
01821       }
01822       /* peer_cdr->answer will be set when a macro runs on the peer;
01823          in that case, the bridge answer will be delayed while the
01824          macro plays on the peer channel. The peer answered the call
01825          before the macro started playing. To the phone system,
01826          this is billable time for the call, even tho the caller
01827          hears nothing but ringing while the macro does its thing. */
01828 
01829       /* Another case where the peer cdr's time will be set, is when
01830          A self-parks by pickup up phone and dialing 700, then B
01831          picks up A by dialing its parking slot; there may be more 
01832          practical paths that get the same result, tho... in which
01833          case you get the previous answer time from the Park... which
01834          is before the bridge's start time, so I added in the 
01835          tvcmp check to the if below */
01836 
01837       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
01838          ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
01839          ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
01840          if (chan_cdr) {
01841             ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
01842             ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
01843          }
01844       } else {
01845          ast_cdr_answer(bridge_cdr);
01846          if (chan_cdr) {
01847             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
01848          }
01849       }
01850       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
01851          if (chan_cdr) {
01852             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
01853          }
01854          if (peer_cdr) {
01855             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
01856          }
01857       }
01858    }
01859 
01860    for (;;) {
01861       struct ast_channel *other; /* used later */
01862 
01863       res = ast_channel_bridge(chan, peer, config, &f, &who);
01864       
01865       /* When frame is not set, we are probably involved in a situation
01866          where we've timed out.
01867          When frame is set, we'll come thru this code twice; once for DTMF_BEGIN
01868          and also for DTMF_END. If we flow into the following 'if' for both, then 
01869          our wait times are cut in half, as both will subtract from the
01870          feature_timer. Not good!
01871       */
01872       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
01873          /* Update time limit for next pass */
01874          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01875          if (res == AST_BRIDGE_RETRY) {
01876             /* The feature fully timed out but has not been updated. Skip
01877              * the potential round error from the diff calculation and
01878              * explicitly set to expired. */
01879             config->feature_timer = -1;
01880          } else {
01881             config->feature_timer -= diff;
01882          }
01883 
01884          if (hasfeatures) {
01885             /* Running on backup config, meaning a feature might be being
01886                activated, but that's no excuse to keep things going 
01887                indefinitely! */
01888             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01889                if (option_debug)
01890                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01891                config->feature_timer = 0;
01892                who = chan;
01893                if (f)
01894                   ast_frfree(f);
01895                f = NULL;
01896                res = 0;
01897             } else if (config->feature_timer <= 0) {
01898                /* Not *really* out of time, just out of time for
01899                   digits to come in for features. */
01900                if (option_debug)
01901                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01902                if (!ast_strlen_zero(peer_featurecode)) {
01903                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01904                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01905                }
01906                if (!ast_strlen_zero(chan_featurecode)) {
01907                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01908                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01909                }
01910                if (f)
01911                   ast_frfree(f);
01912                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01913                if (!hasfeatures) {
01914                   /* Restore original (possibly time modified) bridge config */
01915                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01916                   memset(&backup_config, 0, sizeof(backup_config));
01917                }
01918                hadfeatures = hasfeatures;
01919                /* Continue as we were */
01920                continue;
01921             } else if (!f) {
01922                /* The bridge returned without a frame and there is a feature in progress.
01923                 * However, we don't think the feature has quite yet timed out, so just
01924                 * go back into the bridge. */
01925                continue;
01926             }
01927          } else {
01928             if (config->feature_timer <=0) {
01929                /* We ran out of time */
01930                config->feature_timer = 0;
01931                who = chan;
01932                if (f)
01933                   ast_frfree(f);
01934                f = NULL;
01935                res = 0;
01936             }
01937          }
01938       }
01939       if (res < 0) {
01940          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01941             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01942          goto before_you_go;
01943       }
01944       
01945       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01946             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01947                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01948          res = -1;
01949          break;
01950       }
01951       /* many things should be sent to the 'other' channel */
01952       other = (who == chan) ? peer : chan;
01953       if (f->frametype == AST_FRAME_CONTROL) {
01954          switch (f->subclass) {
01955          case AST_CONTROL_RINGING:
01956          case AST_CONTROL_FLASH:
01957          case -1:
01958             ast_indicate(other, f->subclass);
01959             break;
01960          case AST_CONTROL_HOLD:
01961          case AST_CONTROL_UNHOLD:
01962             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01963             break;
01964          case AST_CONTROL_OPTION:
01965             aoh = f->data;
01966             /* Forward option Requests */
01967             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01968                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01969                   f->datalen - sizeof(struct ast_option_header), 0);
01970             }
01971             break;
01972          case AST_CONTROL_ATXFERCMD:
01973             cmd_atxfer(chan, peer, config, who, f->data);
01974             break;
01975          }
01976       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01977          /* eat it */
01978       } else if (f->frametype == AST_FRAME_DTMF) {
01979          char *featurecode;
01980          int sense;
01981 
01982          hadfeatures = hasfeatures;
01983          /* This cannot overrun because the longest feature is one shorter than our buffer */
01984          if (who == chan) {
01985             sense = FEATURE_SENSE_CHAN;
01986             featurecode = chan_featurecode;
01987          } else  {
01988             sense = FEATURE_SENSE_PEER;
01989             featurecode = peer_featurecode;
01990          }
01991          /*! append the event to featurecode. we rely on the string being zero-filled, and
01992           * not overflowing it. 
01993           * \todo XXX how do we guarantee the latter ?
01994           */
01995          featurecode[strlen(featurecode)] = f->subclass;
01996          /* Get rid of the frame before we start doing "stuff" with the channels */
01997          ast_frfree(f);
01998          f = NULL;
01999          config->feature_timer = backup_config.feature_timer;
02000          res = feature_interpret(chan, peer, config, featurecode, sense);
02001          switch(res) {
02002          case FEATURE_RETURN_PASSDIGITS:
02003             ast_dtmf_stream(other, who, featurecode, 0);
02004             /* Fall through */
02005          case FEATURE_RETURN_SUCCESS:
02006             memset(featurecode, 0, sizeof(chan_featurecode));
02007             break;
02008          }
02009          if (res >= FEATURE_RETURN_PASSDIGITS) {
02010             res = 0;
02011          } else 
02012             break;
02013          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02014          if (hadfeatures && !hasfeatures) {
02015             /* Restore backup */
02016             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02017             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02018          } else if (hasfeatures) {
02019             if (!hadfeatures) {
02020                /* Backup configuration */
02021                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02022                /* Setup temporary config options */
02023                config->play_warning = 0;
02024                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02025                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02026                config->warning_freq = 0;
02027                config->warning_sound = NULL;
02028                config->end_sound = NULL;
02029                config->start_sound = NULL;
02030                config->firstpass = 0;
02031             }
02032             config->start_time = ast_tvnow();
02033             config->feature_timer = featuredigittimeout;
02034             if (option_debug)
02035                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
02036          }
02037       }
02038       if (f)
02039          ast_frfree(f);
02040 
02041    }
02042   before_you_go:
02043 
02044    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02045       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
02046       if (bridge_cdr) {
02047          ast_cdr_discard(bridge_cdr);
02048          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
02049       }
02050       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
02051    }
02052 
02053    if (config->end_bridge_callback) {
02054       config->end_bridge_callback(config->end_bridge_callback_data);
02055    }
02056 
02057    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 
02058        ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02059       struct ast_cdr *swapper = NULL;
02060       char savelastapp[AST_MAX_EXTENSION];
02061       char savelastdata[AST_MAX_EXTENSION];
02062       char save_exten[AST_MAX_EXTENSION];
02063       int  save_prio, spawn_error = 0;
02064       
02065       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02066       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02067       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02068          ast_cdr_end(bridge_cdr);
02069       }
02070       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
02071          dialplan code operate on it */
02072       ast_channel_lock(chan);
02073       if (bridge_cdr) {
02074          swapper = chan->cdr;
02075          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02076          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02077          chan->cdr = bridge_cdr;
02078       }
02079       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02080       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02081       save_prio = chan->priority;
02082       chan->priority = 1;
02083       ast_channel_unlock(chan);
02084       while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
02085          if ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) {
02086             /* Something bad happened, or a hangup has been requested. */
02087             if (option_debug)
02088                ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02089             if (option_verbose > 1)
02090                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);
02091             break;
02092          }
02093          chan->priority++;
02094       }
02095       /* swap it back */
02096       ast_channel_lock(chan);
02097       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02098       chan->priority = save_prio;
02099       if (bridge_cdr) {
02100          if (chan->cdr == bridge_cdr) {
02101             chan->cdr = swapper;
02102          } else {
02103             bridge_cdr = NULL;
02104          }
02105       }
02106       if (chan->priority != 1 || !spawn_error) {
02107          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02108       }
02109       ast_channel_unlock(chan);
02110       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
02111       if (bridge_cdr) {
02112          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02113          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02114       }
02115       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02116    }
02117    
02118    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
02119    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02120    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
02121       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02122    }
02123 
02124    /* we can post the bridge CDR at this point */
02125    if (bridge_cdr) {
02126       ast_cdr_end(bridge_cdr);
02127       ast_cdr_detach(bridge_cdr);
02128    }
02129    
02130    /* do a specialized reset on the beginning channel
02131       CDR's, if they still exist, so as not to mess up
02132       issues in future bridges;
02133       
02134       Here are the rules of the game:
02135       1. The chan and peer channel pointers will not change
02136          during the life of the bridge.
02137       2. But, in transfers, the channel names will change.
02138          between the time the bridge is started, and the
02139          time the channel ends. 
02140          Usually, when a channel changes names, it will
02141          also change CDR pointers.
02142       3. Usually, only one of the two channels (chan or peer)
02143          will change names.
02144       4. Usually, if a channel changes names during a bridge,
02145          it is because of a transfer. Usually, in these situations,
02146          it is normal to see 2 bridges running simultaneously, and
02147          it is not unusual to see the two channels that change
02148          swapped between bridges.
02149       5. After a bridge occurs, we have 2 or 3 channels' CDRs
02150          to attend to; if the chan or peer changed names,
02151          we have the before and after attached CDR's.
02152    */
02153    
02154    if (new_chan_cdr) {
02155       struct ast_channel *chan_ptr = NULL;
02156       
02157       if (strcasecmp(orig_channame, chan->name) != 0) { 
02158          /* old channel */
02159          chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02160          if (chan_ptr) {
02161             if (!ast_bridged_channel(chan_ptr)) {
02162                struct ast_cdr *cur;
02163                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02164                   if (cur == chan_cdr) {
02165                      break;
02166                   }
02167                }
02168                if (cur)
02169                   ast_cdr_specialized_reset(chan_cdr,0);
02170             }
02171             ast_channel_unlock(chan_ptr);
02172          }
02173          /* new channel */
02174          ast_cdr_specialized_reset(new_chan_cdr,0);
02175       } else {
02176          ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr  */
02177       }
02178    }
02179 
02180    {
02181       struct ast_channel *chan_ptr = NULL;
02182       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02183       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))
02184          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
02185       if (strcasecmp(orig_peername, peer->name) != 0) { 
02186          /* old channel */
02187          chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02188          if (chan_ptr) {
02189             if (!ast_bridged_channel(chan_ptr)) {
02190                struct ast_cdr *cur;
02191                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02192                   if (cur == peer_cdr) {
02193                      break;
02194                   }
02195                }
02196                if (cur)
02197                   ast_cdr_specialized_reset(peer_cdr,0);
02198             }
02199             ast_channel_unlock(chan_ptr);
02200          }
02201          /* new channel */
02202          ast_cdr_specialized_reset(new_peer_cdr,0);
02203       } else {
02204          ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr  */
02205       }
02206    }
02207    
02208    return res;
02209 }

static void* ast_bridge_call_thread ( void *  data  )  [static]

Definition at line 270 of file res_features.c.

References ast_channel::appl, ast_bridge_call(), ast_hangup(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, free, ast_channel::name, and ast_bridge_thread_obj::peer.

Referenced by ast_bridge_call_thread_launch().

00271 {
00272    struct ast_bridge_thread_obj *tobj = data;
00273 
00274    tobj->chan->appl = "Transferred Call";
00275    tobj->chan->data = tobj->peer->name;
00276    tobj->peer->appl = "Transferred Call";
00277    tobj->peer->data = tobj->chan->name;
00278 
00279    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00280    ast_hangup(tobj->chan);
00281    ast_hangup(tobj->peer);
00282    bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
00283    free(tobj);
00284    return NULL;
00285 }

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 287 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by do_atxfer().

00288 {
00289    pthread_t thread;
00290    pthread_attr_t attr;
00291    struct sched_param sched;
00292 
00293    pthread_attr_init(&attr);
00294    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00295    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00296    pthread_attr_destroy(&attr);
00297    memset(&sched, 0, sizeof(sched));
00298    pthread_setschedparam(thread, SCHED_RR, &sched);
00299 }

int ast_feature_detect ( struct ast_channel chan,
struct ast_flags features,
char *  code,
struct ast_call_feature feature 
)

detect a feature before bridging

Parameters:
chan 
ast_flags ptr
char ptr of input code
Return values:
ast_call_feature ptr to be set if found
Returns:
result, was feature found or not

Definition at line 1386 of file res_features.c.

References feature_interpret_helper().

Referenced by detect_disconnect().

01386                                                                                                                            {
01387 
01388    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01389 }

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]

Todo:
XXX Check - this is very similar to the code in channel.c

Definition at line 1434 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().

01435 {
01436    int state = 0;
01437    int cause = 0;
01438    int to;
01439    struct ast_channel *chan;
01440    struct ast_channel *monitor_chans[2];
01441    struct ast_channel *active_channel;
01442    int res = 0, ready = 0;
01443    
01444    if ((chan = ast_request(type, format, data, &cause))) {
01445       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01446       ast_string_field_set(chan, language, language);
01447       ast_channel_inherit_variables(caller, chan); 
01448       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01449          
01450       if (!ast_call(chan, data, timeout)) {
01451          struct timeval started;
01452          int x, len = 0;
01453          char *disconnect_code = NULL, *dialed_code = NULL;
01454 
01455          ast_indicate(caller, AST_CONTROL_RINGING);
01456          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01457          ast_rwlock_rdlock(&features_lock);
01458          for (x = 0; x < FEATURES_COUNT; x++) {
01459             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01460                continue;
01461 
01462             disconnect_code = builtin_features[x].exten;
01463             len = strlen(disconnect_code) + 1;
01464             dialed_code = alloca(len);
01465             memset(dialed_code, 0, len);
01466             break;
01467          }
01468          ast_rwlock_unlock(&features_lock);
01469          x = 0;
01470          started = ast_tvnow();
01471          to = timeout;
01472          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01473             struct ast_frame *f = NULL;
01474 
01475             monitor_chans[0] = caller;
01476             monitor_chans[1] = chan;
01477             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01478 
01479             /* see if the timeout has been violated */
01480             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01481                state = AST_CONTROL_UNHOLD;
01482                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01483                break; /*doh! timeout*/
01484             }
01485 
01486             if (!active_channel)
01487                continue;
01488 
01489             if (chan && (chan == active_channel)) {
01490                if (!ast_strlen_zero(chan->call_forward)) {
01491                   if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) {
01492                      return NULL;
01493                   }
01494                   continue;
01495                }
01496                f = ast_read(chan);
01497                if (f == NULL) { /*doh! where'd he go?*/
01498                   state = AST_CONTROL_HANGUP;
01499                   res = 0;
01500                   break;
01501                }
01502                
01503                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01504                   if (f->subclass == AST_CONTROL_RINGING) {
01505                      state = f->subclass;
01506                      if (option_verbose > 2)
01507                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01508                      ast_indicate(caller, AST_CONTROL_RINGING);
01509                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01510                      state = f->subclass;
01511                      if (option_verbose > 2)
01512                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01513                      ast_indicate(caller, AST_CONTROL_BUSY);
01514                      ast_frfree(f);
01515                      f = NULL;
01516                      break;
01517                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01518                      /* This is what we are hoping for */
01519                      state = f->subclass;
01520                      ast_frfree(f);
01521                      f = NULL;
01522                      ready=1;
01523                      break;
01524                   } else if (f->subclass != -1 && f->subclass != AST_CONTROL_PROGRESS) {
01525                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01526                   }
01527                   /* else who cares */
01528                } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
01529                   ast_write(caller, f);
01530                }
01531 
01532             } else if (caller && (active_channel == caller)) {
01533                f = ast_read(caller);
01534                if (f == NULL) { /*doh! where'd he go?*/
01535                   if (caller->_softhangup && !chan->_softhangup) {
01536                      /* make this a blind transfer */
01537                      ready = 1;
01538                      break;
01539                   }
01540                   state = AST_CONTROL_HANGUP;
01541                   res = 0;
01542                   break;
01543                }
01544                
01545                if (f->frametype == AST_FRAME_DTMF) {
01546                   dialed_code[x++] = f->subclass;
01547                   dialed_code[x] = '\0';
01548                   if (strlen(dialed_code) == len) {
01549                      x = 0;
01550                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01551                      x = 0;
01552                      dialed_code[x] = '\0';
01553                   }
01554                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01555                      /* Caller Canceled the call */
01556                      state = AST_CONTROL_UNHOLD;
01557                      ast_frfree(f);
01558                      f = NULL;
01559                      break;
01560                   }
01561                } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
01562                   ast_write(chan, f);
01563                }
01564             }
01565             if (f)
01566                ast_frfree(f);
01567          } /* end while */
01568       } else
01569          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01570    } else {
01571       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01572       switch(cause) {
01573       case AST_CAUSE_BUSY:
01574          state = AST_CONTROL_BUSY;
01575          break;
01576       case AST_CAUSE_CONGESTION:
01577          state = AST_CONTROL_CONGESTION;
01578          break;
01579       }
01580    }
01581    
01582    ast_indicate(caller, -1);
01583    if (chan && ready) {
01584       if (chan->_state == AST_STATE_UP) 
01585          state = AST_CONTROL_ANSWER;
01586       res = 0;
01587    } else if(chan) {
01588       res = -1;
01589       ast_hangup(chan);
01590       chan = NULL;
01591    } else {
01592       res = -1;
01593    }
01594    
01595    if (outstate)
01596       *outstate = state;
01597 
01598    return chan;
01599 }

int ast_masq_park_call ( struct ast_channel rchan,
struct ast_channel host,
int  timeout,
int *  extout 
)

Park a call via a masqueraded channel.

Parameters:
rchan the real channel to be parked
host the channel to have the parking read to Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want

Definition at line 608 of file res_features.c.

References masq_park_call().

Referenced by handle_exec(), manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().

00609 {
00610    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00611 }

int ast_park_call ( struct ast_channel chan,
struct ast_channel peer,
int  timeout,
int *  extout 
)

Park a call and read back parked location.

Note:
We put the user in the parking list, then wake up the parking thread to be sure it looks after these channels too

Definition at line 552 of file res_features.c.

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00553 {
00554    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00555 }

char* ast_parking_ext ( void   ) 

Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.

Definition at line 207 of file res_features.c.

Referenced by builtin_blindtransfer(), do_atxfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().

00208 {
00209    return parking_ext;
00210 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2868 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().

02869 {
02870    struct ast_channel *cur = NULL;
02871    int res = -1;
02872 
02873    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02874       if (!cur->pbx && 
02875          (cur != chan) &&
02876          (chan->pickupgroup & cur->callgroup) &&
02877          ((cur->_state == AST_STATE_RINGING) ||
02878           (cur->_state == AST_STATE_RING))) {
02879             break;
02880       }
02881       ast_channel_unlock(cur);
02882    }
02883    if (cur) {
02884       if (option_debug)
02885          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02886       res = ast_answer(chan);
02887       if (res)
02888          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02889       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02890       if (res)
02891          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02892       res = ast_channel_masquerade(cur, chan);
02893       if (res)
02894          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02895       ast_channel_unlock(cur);
02896    } else   {
02897       if (option_debug)
02898          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02899    }
02900    return res;
02901 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 212 of file res_features.c.

Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().

00213 {
00214    return pickup_ext;
00215 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_set

Parameters:
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 1123 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.

01124 {
01125    if (!feature) {
01126       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01127          return;
01128    }
01129   
01130    AST_RWLIST_WRLOCK(&feature_list);
01131    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01132    AST_RWLIST_UNLOCK(&feature_list);
01133 
01134    if (option_verbose >= 2) {
01135       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01136    }
01137 }

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 1140 of file res_features.c.

References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.

01141 {
01142    if (!feature)
01143       return;
01144 
01145    AST_RWLIST_WRLOCK(&feature_list);
01146    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01147    AST_RWLIST_UNLOCK(&feature_list);
01148    
01149    free(feature);
01150 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1153 of file res_features.c.

References AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.

01154 {
01155    struct ast_call_feature *feature;
01156 
01157    AST_RWLIST_WRLOCK(&feature_list);
01158    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01159       free(feature);
01160    }
01161    AST_RWLIST_UNLOCK(&feature_list);
01162 }

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 ().

Parameters:
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.
Returns:
-1 means what failure/success both?

Definition at line 1100 of file res_features.c.

References config, and do_atxfer().

01101 {
01102    return do_atxfer(chan, peer, config, sense, NULL, NULL);
01103 }

static int builtin_automonitor ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense,
void *  data 
) [static]

Definition at line 668 of file res_features.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_monitor_stop(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verbose(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, ast_channel::language, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::monitor, monitor_app, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3.

00669 {
00670    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00671    int x = 0;
00672    size_t len;
00673    struct ast_channel *caller_chan, *callee_chan;
00674 
00675    if (!monitor_ok) {
00676       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00677       return -1;
00678    }
00679 
00680    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00681       monitor_ok = 0;
00682       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00683       return -1;
00684    }
00685 
00686    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00687 
00688    if (!ast_strlen_zero(courtesytone)) {
00689       if (ast_autoservice_start(callee_chan))
00690          return -1;
00691       if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00692          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00693          ast_autoservice_stop(callee_chan);
00694          return -1;
00695       }
00696       if (ast_autoservice_stop(callee_chan))
00697          return -1;
00698    }
00699    
00700    if (callee_chan->monitor) {
00701       if (option_verbose > 3)
00702          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00703       ast_monitor_stop(callee_chan, 1);
00704       return FEATURE_RETURN_SUCCESS;
00705    }
00706 
00707    if (caller_chan && callee_chan) {
00708       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00709       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00710 
00711       if (!touch_format)
00712          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00713 
00714       if (!touch_monitor)
00715          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00716    
00717       if (touch_monitor) {
00718          len = strlen(touch_monitor) + 50;
00719          args = alloca(len);
00720          touch_filename = alloca(len);
00721          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00722          snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00723       } else {
00724          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00725          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00726          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00727          args = alloca(len);
00728          touch_filename = alloca(len);
00729          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00730          snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00731       }
00732 
00733       for( x = 0; x < strlen(args); x++) {
00734          if (args[x] == '/')
00735             args[x] = '-';
00736       }
00737       
00738       if (option_verbose > 3)
00739          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00740 
00741       pbx_exec(callee_chan, monitor_app, args);
00742       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00743       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00744    
00745       return FEATURE_RETURN_SUCCESS;
00746    }
00747    
00748    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00749    return -1;
00750 }

static int builtin_blindtransfer ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense,
void *  data 
) [static]

Definition at line 779 of file res_features.c.

References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), AST_FLAG_BRIDGE_HANGUP_DONT, ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_verbose(), ast_channel::cdr, check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_PARKFAILED, FEATURE_RETURN_SUCCESS, finishup(), ast_channel::language, LOG_WARNING, masq_park_call_announce(), ast_channel::name, option_verbose, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.

00780 {
00781    struct ast_channel *transferer;
00782    struct ast_channel *transferee;
00783    const char *transferer_real_context;
00784    char xferto[256];
00785    int res;
00786    const char *orig_chan_name;
00787    int parkstatus = 0;
00788 
00789    set_peers(&transferer, &transferee, peer, chan, sense);
00790    orig_chan_name = ast_strdupa(transferer->name);
00791    transferer_real_context = real_ctx(transferer, transferee);
00792    /* Start autoservice on chan while we talk to the originator */
00793    ast_autoservice_start(transferee);
00794    ast_indicate(transferee, AST_CONTROL_HOLD);
00795 
00796    memset(xferto, 0, sizeof(xferto));
00797 
00798    /* Transfer */
00799    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00800    if (res < 0) {
00801       finishup(transferee);
00802       return -1; /* error ? */
00803    }
00804    if (res > 0)   /* If they've typed a digit already, handle it */
00805       xferto[0] = (char) res;
00806 
00807    ast_stopstream(transferer);
00808    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00809    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00810       finishup(transferee);
00811       return res;
00812    }
00813    if (!strcmp(xferto, ast_parking_ext())) {
00814       res = finishup(transferee);
00815       if (res)
00816          res = -1;
00817       else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name))) {  /* success */
00818          /* We return non-zero, but tell the PBX not to hang the channel when
00819             the thread dies -- We have to be careful now though.  We are responsible for 
00820             hanging up the channel, else it will never be hung up! */
00821          return 0;
00822       } else {
00823          ast_log(LOG_WARNING, "Unable to park call %s, parkstatus=%d\n", transferee->name, parkstatus);
00824       }
00825       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
00826    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00827       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
00828       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
00829       res=finishup(transferee);
00830       if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
00831          transferer->cdr=ast_cdr_alloc();
00832          if (transferer->cdr) {
00833             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
00834             ast_cdr_start(transferer->cdr);
00835          }
00836       }
00837       if (transferer->cdr) {
00838          struct ast_cdr *swap = transferer->cdr;
00839          /* swap cdrs-- it will save us some time & work */
00840          transferer->cdr = transferee->cdr;
00841          transferee->cdr = swap;
00842       }
00843       if (!transferee->pbx) {
00844          /* Doh!  Use our handy async_goto functions */
00845          if (option_verbose > 2) 
00846             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00847                         ,transferee->name, xferto, transferer_real_context);
00848          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00849             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00850          res = -1;
00851       } else {
00852          /* Set the channel's new extension, since it exists, using transferer context */
00853          ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
00854          set_c_e_p(transferee, transferer_real_context, xferto, 0);
00855       }
00856       check_goto_on_transfer(transferer);
00857       return res;
00858    } else {
00859       if (option_verbose > 2) 
00860          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00861    }
00862    if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00863       finishup(transferee);
00864       return -1;
00865    }
00866    ast_stopstream(transferer);
00867    res = finishup(transferee);
00868    if (res) {
00869       if (option_verbose > 1)
00870          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00871       return res;
00872    }
00873    return FEATURE_RETURN_SUCCESS;
00874 }

static int builtin_disconnect ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense,
void *  data 
) [static]

Definition at line 752 of file res_features.c.

References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.

00753 {
00754    if (option_verbose > 3)
00755       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00756    return FEATURE_RETURN_HANGUP;
00757 }

static int builtin_parkcall ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense,
void *  data 
) [static]

support routing for one touch call parking

Definition at line 634 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_module_user::chan, masq_park_call_announce(), ast_channel::name, and set_peers().

Referenced by do_atxfer().

00635 {
00636    struct ast_channel *parker;
00637    struct ast_channel *parkee;
00638    int res = 0;
00639    struct ast_module_user *u;
00640    const char *orig_chan_name;
00641 
00642    u = ast_module_user_add(chan);
00643 
00644    set_peers(&parker, &parkee, peer, chan, sense);
00645    orig_chan_name = ast_strdupa(parker->name);
00646    /* we used to set chan's exten and priority to "s" and 1
00647       here, but this generates (in some cases) an invalid
00648       extension, and if "s" exists, could errantly
00649       cause execution of extensions you don't expect It
00650       makes more sense to let nature take its course
00651       when chan finishes, and let the pbx do its thing
00652       and hang up when the park is over.
00653    */
00654    if (chan->_state != AST_STATE_UP)
00655       res = ast_answer(chan);
00656    if (!res)
00657       res = ast_safe_sleep(chan, 1000);
00658 
00659    if (!res) { /* one direction used to call park_call.... */
00660       res = masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name);
00661       /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
00662    }
00663 
00664    ast_module_user_remove(u);
00665    return res;
00666 }

static char* callback_dialoptions ( struct ast_flags features_callee,
struct ast_flags features_caller,
char *  options,
size_t  len 
) [static]

Definition at line 2225 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().

02226 {
02227    int i = 0;
02228    enum {
02229       OPT_CALLEE_REDIRECT   = 't',
02230       OPT_CALLER_REDIRECT   = 'T',
02231       OPT_CALLEE_AUTOMON    = 'w',
02232       OPT_CALLER_AUTOMON    = 'W',
02233       OPT_CALLEE_DISCONNECT = 'h',
02234       OPT_CALLER_DISCONNECT = 'H',
02235       OPT_CALLEE_PARKCALL   = 'k',
02236       OPT_CALLER_PARKCALL   = 'K',
02237    };
02238 
02239    memset(options, 0, len);
02240    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02241       options[i++] = OPT_CALLER_REDIRECT;
02242    }
02243    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02244       options[i++] = OPT_CALLER_AUTOMON;
02245    }
02246    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02247       options[i++] = OPT_CALLER_DISCONNECT;
02248    }
02249    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02250       options[i++] = OPT_CALLER_PARKCALL;
02251    }
02252 
02253    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02254       options[i++] = OPT_CALLEE_REDIRECT;
02255    }
02256    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02257       options[i++] = OPT_CALLEE_AUTOMON;
02258    }
02259    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02260       options[i++] = OPT_CALLEE_DISCONNECT;
02261    }
02262    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02263       options[i++] = OPT_CALLEE_PARKCALL;
02264    }
02265 
02266    return options;
02267 }

static int check_compat ( struct ast_channel c,
struct ast_channel newchan 
) [static]

Definition at line 876 of file res_features.c.

References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.

Referenced by do_atxfer().

00877 {
00878    if (ast_channel_make_compatible(c, newchan) < 0) {
00879       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00880          c->name, newchan->name);
00881       ast_hangup(newchan);
00882       return -1;
00883    }
00884    return 0;
00885 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Definition at line 232 of file res_features.c.

References ast_channel::_softhangup, ast_channel::_state, ast_channel_alloc(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), f, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.

Referenced by builtin_blindtransfer().

00233 {
00234    struct ast_channel *xferchan;
00235    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00236    char *x, *goto_on_transfer;
00237    struct ast_frame *f;
00238 
00239    if (ast_strlen_zero(val))
00240       return;
00241 
00242    goto_on_transfer = ast_strdupa(val);
00243 
00244    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name)))
00245       return;
00246 
00247    for (x = goto_on_transfer; x && *x; x++) {
00248       if (*x == '^')
00249          *x = '|';
00250    }
00251    /* Make formats okay */
00252    xferchan->readformat = chan->readformat;
00253    xferchan->writeformat = chan->writeformat;
00254    ast_channel_masquerade(xferchan, chan);
00255    ast_parseable_goto(xferchan, goto_on_transfer);
00256    xferchan->_state = AST_STATE_UP;
00257    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00258    xferchan->_softhangup = 0;
00259    if ((f = ast_read(xferchan))) {
00260       ast_frfree(f);
00261       f = NULL;
00262       ast_pbx_start(xferchan);
00263    } else {
00264       ast_hangup(xferchan);
00265    }
00266 }

static void cmd_atxfer ( struct ast_channel a,
struct ast_channel b,
struct ast_bridge_config conf,
struct ast_channel who,
char *  xferto 
) [static]

Definition at line 1702 of file res_features.c.

References context, do_atxfer(), FEATURE_SENSE_CHAN, and FEATURE_SENSE_PEER.

Referenced by ast_bridge_call().

01703 {
01704    int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER;
01705    char *context = strchr(xferto, '@');;
01706    if (context)
01707       *context++ = '\0';
01708    do_atxfer(a, b, conf, sense, xferto, context);
01709 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 193 of file res_features.c.

References ast_free.

00194 {
00195    struct ast_dial_features *df = data;
00196    if (df) {
00197       ast_free(df);
00198    }
00199 }

static void* dial_features_duplicate ( void *  data  )  [static]

Definition at line 180 of file res_features.c.

References ast_calloc.

00181 {
00182    struct ast_dial_features *df = data, *df_copy;
00183 
00184    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00185       return NULL;
00186    }
00187 
00188    memcpy(df_copy, df, sizeof(*df));
00189 
00190    return df_copy;
00191 }

static int do_atxfer ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
int  sense,
const char *  toExt,
const char *  toCont 
) [static]

Attended transfer implementation.

Parameters:
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)
Returns:
-1 on failure

Definition at line 902 of file res_features.c.

References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_copy_string(), AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_parking_ext(), ast_read(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), ast_bridge_thread_obj::bconfig, builtin_parkcall(), ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_datastore::data, dial_features_info, ast_bridge_config::end_bridge_callback_data_fixup, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), ast_channel::language, LOG_DEBUG, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), S_OR, set_peers(), ast_channel::visible_indication, and ast_channel::writeformat.

Referenced by builtin_atxfer(), and cmd_atxfer().

00903 {
00904    struct ast_channel *transferer;
00905    struct ast_channel *transferee;
00906    const char *transferer_real_context;
00907    const char *transfer_context;
00908    char xferto[256] = "";
00909    int res;
00910    int outstate=0;
00911    struct ast_channel *newchan;
00912    struct ast_channel *xferchan;
00913    struct ast_bridge_thread_obj *tobj;
00914    struct ast_bridge_config bconfig;
00915    struct ast_frame *f;
00916    int l;
00917    struct ast_datastore *features_datastore;
00918    struct ast_dial_features *dialfeatures = NULL;
00919 
00920    if (option_debug)
00921       ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00922    set_peers(&transferer, &transferee, peer, chan, sense);
00923    transferer_real_context = real_ctx(transferer, transferee);
00924    transfer_context = S_OR(toCont, transferer_real_context);
00925 
00926    /* Start autoservice on chan while we talk to the originator */
00927    ast_autoservice_start(transferee);
00928    ast_indicate(transferee, AST_CONTROL_HOLD);
00929 
00930    if (!ast_strlen_zero(toExt)) {
00931       ast_copy_string(xferto, toExt, sizeof(xferto));
00932    } else {
00933       /* Ask for extension to transfer to on the transferer channel */
00934       res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00935       if (res < 0) {
00936          finishup(transferee);
00937          return res;
00938       }
00939       if (res > 0) /* If they've typed a digit already, handle it */
00940          xferto[0] = (char) res;
00941 
00942       /* this is specific of atxfer */
00943       res = ast_app_dtget(transferer, transfer_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00944       if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00945          finishup(transferee);
00946          return res;
00947       }
00948       if (res == 0) {
00949          ast_log(LOG_WARNING, "Did not read data.\n");
00950          finishup(transferee);
00951          if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00952             return -1;
00953          return FEATURE_RETURN_SUCCESS;
00954       }
00955    }
00956 
00957    /* valid extension, res == 1 */
00958    if (!ast_exists_extension(transferer, transfer_context, xferto, 1, transferer->cid.cid_num)) {
00959       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transfer_context);
00960       finishup(transferee);
00961       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00962          return -1;
00963       return FEATURE_RETURN_SUCCESS;
00964    }
00965 
00966    /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of
00967     * the different variables for handling this properly with a builtin_atxfer */
00968    if (!strcmp(xferto, ast_parking_ext())) {
00969       finishup(transferee);
00970       return builtin_parkcall(chan, peer, config, NULL, sense, NULL);
00971    }
00972 
00973    l = strlen(xferto);
00974    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transfer_context); /* append context */
00975    newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00976       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
00977    ast_indicate(transferer, -1);
00978    if (!newchan) {
00979       finishup(transferee);
00980       /* any reason besides user requested cancel and busy triggers the failed sound */
00981       if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00982             ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
00983          return -1;
00984       return FEATURE_RETURN_SUCCESS;
00985    }
00986 
00987    if (check_compat(transferer, newchan)) {
00988       /* we do mean transferee here, NOT transferer */
00989       finishup(transferee);
00990       return -1;
00991    }
00992    memset(&bconfig,0,sizeof(struct ast_bridge_config));
00993    ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00994    ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00995    res = ast_bridge_call(transferer, newchan, &bconfig);
00996    if (newchan->_softhangup || !transferer->_softhangup) {
00997       ast_hangup(newchan);
00998       if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
00999          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01000       finishup(transferee);
01001       transferer->_softhangup = 0;
01002       return FEATURE_RETURN_SUCCESS;
01003    }
01004 
01005    if (check_compat(transferee, newchan)) {
01006       finishup(transferee);
01007       return -1;
01008    }
01009 
01010    ast_indicate(transferee, AST_CONTROL_UNHOLD);
01011 
01012    if ((ast_autoservice_stop(transferee) < 0)
01013       || (ast_waitfordigit(transferee, 100) < 0)
01014       || (ast_waitfordigit(newchan, 100) < 0) 
01015       || ast_check_hangup(transferee) 
01016       || ast_check_hangup(newchan)) {
01017       ast_hangup(newchan);
01018       return -1;
01019    }
01020 
01021    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01022    if (!xferchan) {
01023       ast_hangup(newchan);
01024       return -1;
01025    }
01026    /* Make formats okay */
01027    xferchan->visible_indication = transferer->visible_indication;
01028    xferchan->readformat = transferee->readformat;
01029    xferchan->writeformat = transferee->writeformat;
01030    ast_channel_masquerade(xferchan, transferee);
01031    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01032    xferchan->_state = AST_STATE_UP;
01033    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
01034    xferchan->_softhangup = 0;
01035 
01036    if ((f = ast_read(xferchan)))
01037       ast_frfree(f);
01038 
01039    newchan->_state = AST_STATE_UP;
01040    ast_clear_flag(newchan, AST_FLAGS_ALL);   
01041    newchan->_softhangup = 0;
01042 
01043    tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
01044    if (!tobj) {
01045       ast_hangup(xferchan);
01046       ast_hangup(newchan);
01047       return -1;
01048    }
01049 
01050    ast_channel_lock(newchan);
01051    if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
01052       dialfeatures = features_datastore->data;
01053    }
01054    ast_channel_unlock(newchan);
01055 
01056    if (dialfeatures) {
01057       /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
01058          I don't currently understand, the abilities of newchan seem to be stored on the caller side */
01059       ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01060    }
01061 
01062    ast_channel_lock(xferchan);
01063    if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
01064       dialfeatures = features_datastore->data;
01065    }
01066    ast_channel_unlock(xferchan);
01067 
01068    if (dialfeatures) {
01069       ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01070    }
01071 
01072    tobj->chan = newchan;
01073    tobj->peer = xferchan;
01074    tobj->bconfig = *config;
01075 
01076    if (tobj->bconfig.end_bridge_callback_data_fixup) {
01077       tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01078    }
01079 
01080    if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
01081       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01082    ast_bridge_call_thread_launch(tobj);
01083    return -1;  /* XXX meaning the channel is bridged ? */
01084 }

static void* do_parking_thread ( void *  ignore  )  [static]

Take care of parked calls and unpark them if needed.

Todo:
XXX Maybe we could do something with packets, like dial "0" for operator or something XXX

Todo:
XXX Ick: jumping into an else statement??? XXX

Definition at line 2270 of file res_features.c.

References ast_add_extension2(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_mutex_lock, ast_mutex_unlock, ast_pbx_start(), ast_read(), ast_samp2tv(), ast_select(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), callback_dialoptions(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_channel::name, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, and VERBOSE_PREFIX_2.

Referenced by load_module().

02271 {
02272    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
02273    FD_ZERO(&rfds);
02274    FD_ZERO(&efds);
02275 
02276    for (;;) {
02277       struct parkeduser *pu, *pl, *pt = NULL;
02278       int ms = -1;   /* select timeout, uninitialized */
02279       int max = -1;  /* max fd, none there yet */
02280       fd_set nrfds, nefds; /* args for the next select */
02281       FD_ZERO(&nrfds);
02282       FD_ZERO(&nefds);
02283 
02284       ast_mutex_lock(&parking_lock);
02285       pl = NULL;
02286       pu = parkinglot;
02287       /* navigate the list with prev-cur pointers to support removals */
02288       while (pu) {
02289          struct ast_channel *chan = pu->chan;   /* shorthand */
02290          int tms;        /* timeout for this item */
02291          int x;          /* fd index in channel */
02292          struct ast_context *con;
02293 
02294          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
02295             pl = pu;
02296             pu = pu->next;
02297             continue;
02298          }
02299          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
02300          if (tms > pu->parkingtime) {
02301             ast_indicate(chan, AST_CONTROL_UNHOLD);
02302             /* Get chan, exten from derived kludge */
02303             if (pu->peername[0]) {
02304                char *peername = ast_strdupa(pu->peername);
02305                char *cp = strrchr(peername, '-');
02306                if (cp) 
02307                   *cp = 0;
02308                con = ast_context_find(parking_con_dial);
02309                if (!con) {
02310                   con = ast_context_create(NULL, parking_con_dial, registrar);
02311                   if (!con)
02312                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
02313                }
02314                if (con) {
02315                   char returnexten[AST_MAX_EXTENSION];
02316                   struct ast_datastore *features_datastore;
02317                   struct ast_dial_features *dialfeatures = NULL;
02318 
02319                   ast_channel_lock(chan);
02320 
02321                   if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
02322                      dialfeatures = features_datastore->data;
02323 
02324                   ast_channel_unlock(chan);
02325 
02326                   if (!strncmp(peername, "Parked/", 7)) {
02327                      peername += 7;
02328                   }
02329 
02330                   if (dialfeatures) {
02331                      char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
02332                      snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
02333                   } else { /* Existing default */
02334                      ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name);
02335                      snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
02336                   }
02337 
02338                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free_ptr, registrar);
02339                }
02340                set_c_e_p(chan, parking_con_dial, peername, 1);
02341             } else {
02342                /* They've been waiting too long, send them back to where they came.  Theoretically they
02343                   should have their original extensions and such, but we copy to be on the safe side */
02344                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
02345             }
02346 
02347             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
02348 
02349             if (option_verbose > 1) 
02350                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);
02351             /* Start up the PBX, or hang them up */
02352             if (ast_pbx_start(chan))  {
02353                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
02354                ast_hangup(chan);
02355             }
02356             /* And take them out of the parking lot */
02357             if (pl) 
02358                pl->next = pu->next;
02359             else
02360                parkinglot = pu->next;
02361             pt = pu;
02362             pu = pu->next;
02363             con = ast_context_find(parking_con);
02364             if (con) {
02365                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
02366                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02367                else
02368                   notify_metermaids(pt->parkingexten, parking_con);
02369             } else
02370                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02371             free(pt);
02372          } else { /* still within parking time, process descriptors */
02373             for (x = 0; x < AST_MAX_FDS; x++) {
02374                struct ast_frame *f;
02375 
02376                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
02377                   continue;   /* nothing on this descriptor */
02378 
02379                if (FD_ISSET(chan->fds[x], &efds))
02380                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
02381                else
02382                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
02383                chan->fdno = x;
02384 
02385                /* See if they need servicing */
02386                f = ast_read(chan);
02387                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
02388                   if (f)
02389                      ast_frfree(f);
02390                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
02391 
02392                   /* There's a problem, hang them up*/
02393                   if (option_verbose > 1) 
02394                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
02395                   ast_hangup(chan);
02396                   /* And take them out of the parking lot */
02397                   if (pl) 
02398                      pl->next = pu->next;
02399                   else
02400                      parkinglot = pu->next;
02401                   pt = pu;
02402                   pu = pu->next;
02403                   con = ast_context_find(parking_con);
02404                   if (con) {
02405                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
02406                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02407                      else {
02408                         notify_metermaids(pt->parkingexten, parking_con);
02409                      }
02410                   } else
02411                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02412                   free(pt);
02413                   break;
02414                } else {
02415                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02416                   ast_frfree(f);
02417                   if (pu->moh_trys < 3 && !chan->generatordata) {
02418                      if (option_debug)
02419                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
02420                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
02421                         S_OR(parkmohclass, NULL),
02422                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
02423                      pu->moh_trys++;
02424                   }
02425                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
02426                }
02427 
02428             } /* end for */
02429             if (x >= AST_MAX_FDS) {
02430 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
02431                   if (chan->fds[x] > -1) {
02432                      FD_SET(chan->fds[x], &nrfds);
02433                      FD_SET(chan->fds[x], &nefds);
02434                      if (chan->fds[x] > max)
02435                         max = chan->fds[x];
02436                   }
02437                }
02438                /* Keep track of our shortest wait */
02439                if (tms < ms || ms < 0)
02440                   ms = tms;
02441                pl = pu;
02442                pu = pu->next;
02443             }
02444          }
02445       } /* end while */
02446       ast_mutex_unlock(&parking_lock);
02447       rfds = nrfds;
02448       efds = nefds;
02449       {
02450          struct timeval tv = ast_samp2tv(ms, 1000);
02451          /* Wait for something to happen */
02452          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02453       }
02454       pthread_testcancel();
02455    }
02456    return NULL;   /* Never reached */
02457 }

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

Todo:
XXX should probably return res

Definition at line 1179 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().

01180 {
01181    struct ast_app *app;
01182    struct ast_call_feature *feature = data;
01183    struct ast_channel *work, *idle;
01184    int res;
01185 
01186    if (!feature) { /* shouldn't ever happen! */
01187       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01188       return -1; 
01189    }
01190 
01191    if (sense == FEATURE_SENSE_CHAN) {
01192       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01193          return FEATURE_RETURN_KEEPTRYING;
01194       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01195          work = chan;
01196          idle = peer;
01197       } else {
01198          work = peer;
01199          idle = chan;
01200       }
01201    } else {
01202       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01203          return FEATURE_RETURN_KEEPTRYING;
01204       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01205          work = peer;
01206          idle = chan;
01207       } else {
01208          work = chan;
01209          idle = peer;
01210       }
01211    }
01212 
01213    if (!(app = pbx_findapp(feature->app))) {
01214       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01215       return -2;
01216    }
01217 
01218    ast_autoservice_start(idle);
01219    
01220    if (!ast_strlen_zero(feature->moh_class))
01221       ast_moh_start(idle, feature->moh_class, NULL);
01222 
01223    res = pbx_exec(work, app, feature->app_args);
01224 
01225    if (!ast_strlen_zero(feature->moh_class))
01226       ast_moh_stop(idle);
01227 
01228    ast_autoservice_stop(idle);
01229 
01230    if (res)
01231       return FEATURE_RETURN_SUCCESSBREAK;
01232    
01233    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01234 }

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.

Parameters:
chan,peer,config,code,sense 
Return values:
res on success.
-1 on failure.

Definition at line 1355 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().

01355                                                                                                                                           {
01356 
01357    char dynamic_features_buf[128];
01358    const char *peer_dynamic_features, *chan_dynamic_features;
01359    struct ast_flags features;
01360    struct ast_call_feature feature;
01361    if (sense == FEATURE_SENSE_CHAN) {
01362       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01363    }
01364    else {
01365       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01366    }
01367 
01368    ast_channel_lock(peer);
01369    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
01370    ast_channel_unlock(peer);
01371 
01372    ast_channel_lock(chan);
01373    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
01374    ast_channel_unlock(chan);
01375 
01376    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,""));
01377 
01378    if (option_debug > 2) {
01379       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);
01380    }
01381 
01382    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
01383 }

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.

Parameters:
chan,peer,config,code,sense,dynamic_features char buf,feature flags,operation,feature
Lock features list, browse for code, unlock list If a feature is found and the operation variable is set, that feature's operation is executed. The first feature found is copied to the feature parameter.
Return values:
res on success.
-1 on failure.

Definition at line 1274 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().

01277 {
01278    int x;
01279    struct ast_call_feature *tmpfeature;
01280    char *tmp, *tok;
01281    int res = FEATURE_RETURN_PASSDIGITS;
01282    int feature_detected = 0;
01283 
01284    if (!(peer && chan && config) && operation) {
01285       return -1; /* can not run feature operation */
01286    }
01287 
01288    ast_rwlock_rdlock(&features_lock);
01289    for (x = 0; x < FEATURES_COUNT; x++) {
01290       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
01291           !ast_strlen_zero(builtin_features[x].exten)) {
01292          /* Feature is up for consideration */
01293          if (!strcmp(builtin_features[x].exten, code)) {
01294             if (option_debug > 2) {
01295                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);
01296             }
01297             if (operation) {
01298                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01299             }
01300             memcpy(feature, &builtin_features[x], sizeof(feature));
01301             feature_detected = 1;
01302             break;
01303          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01304             if (res == FEATURE_RETURN_PASSDIGITS)
01305                res = FEATURE_RETURN_STOREDIGITS;
01306          }
01307       }
01308    }
01309    ast_rwlock_unlock(&features_lock);
01310 
01311    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
01312       return res;
01313    }
01314 
01315    tmp = dynamic_features_buf;
01316 
01317    while ((tok = strsep(&tmp, "#"))) {
01318       AST_RWLIST_RDLOCK(&feature_list);
01319       if (!(tmpfeature = find_dynamic_feature(tok))) {
01320          AST_RWLIST_UNLOCK(&feature_list);
01321          continue;
01322       }
01323 
01324       /* Feature is up for consideration */
01325       if (!strcmp(tmpfeature->exten, code)) {
01326          if (option_debug > 2) {
01327             ast_log(LOG_NOTICE, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
01328          }
01329          if (operation) {
01330             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
01331          }
01332          memcpy(feature, tmpfeature, sizeof(feature));
01333          if (res != FEATURE_RETURN_KEEPTRYING) {
01334             AST_RWLIST_UNLOCK(&feature_list);
01335             break;
01336          }
01337          res = FEATURE_RETURN_PASSDIGITS;
01338       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
01339          res = FEATURE_RETURN_STOREDIGITS;
01340 
01341       AST_RWLIST_UNLOCK(&feature_list);
01342    }
01343 
01344    return res;
01345 }

static struct ast_call_feature* find_dynamic_feature ( const char *  name  )  [static]

find a feature by name

Definition at line 1165 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().

01166 {
01167    struct ast_call_feature *tmp;
01168 
01169    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01170       if (!strcasecmp(tmp->sname, name)) {
01171          break;
01172       }
01173    }
01174 
01175    return tmp;
01176 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 759 of file res_features.c.

References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().

Referenced by builtin_blindtransfer(), and do_atxfer().

00760 {
00761         ast_indicate(chan, AST_CONTROL_UNHOLD);
00762   
00763         return ast_autoservice_stop(chan);
00764 }

static int handle_parkedcalls ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2722 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.

02723 {
02724    struct parkeduser *cur;
02725    int numparked = 0;
02726 
02727    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02728       , "Context", "Extension", "Pri", "Timeout");
02729 
02730    ast_mutex_lock(&parking_lock);
02731 
02732    for (cur = parkinglot; cur; cur = cur->next) {
02733       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02734          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02735          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02736 
02737       numparked++;
02738    }
02739    ast_mutex_unlock(&parking_lock);
02740    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02741 
02742 
02743    return RESULT_SUCCESS;
02744 }

static int handle_showfeatures ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2680 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.

02681 {
02682    int i;
02683    struct ast_call_feature *feature;
02684    char format[] = "%-25s %-7s %-7s\n";
02685 
02686    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02687    ast_cli(fd, format, "---------------", "-------", "-------");
02688 
02689    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02690 
02691    ast_rwlock_rdlock(&features_lock);
02692    for (i = 0; i < FEATURES_COUNT; i++)
02693       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02694    ast_rwlock_unlock(&features_lock);
02695 
02696    ast_cli(fd, "\n");
02697    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02698    ast_cli(fd, format, "---------------", "-------", "-------");
02699    if (AST_RWLIST_EMPTY(&feature_list)) {
02700       ast_cli(fd, "(none)\n");
02701    } else {
02702       AST_RWLIST_RDLOCK(&feature_list);
02703       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
02704          ast_cli(fd, format, feature->sname, "no def", feature->exten);
02705       }
02706       AST_RWLIST_UNLOCK(&feature_list);
02707    }
02708    ast_cli(fd, "\nCall parking\n");
02709    ast_cli(fd, "------------\n");
02710    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02711    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02712    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02713    ast_cli(fd,"\n");
02714    
02715    return RESULT_SUCCESS;
02716 }

static int load_config ( void   )  [static]

Definition at line 2918 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.

02919 {
02920    int start = 0, end = 0;
02921    int res;
02922    struct ast_context *con = NULL;
02923    struct ast_config *cfg = NULL;
02924    struct ast_variable *var = NULL;
02925    char old_parking_ext[AST_MAX_EXTENSION];
02926    char old_parking_con[AST_MAX_EXTENSION] = "";
02927 
02928    if (!ast_strlen_zero(parking_con)) {
02929       strcpy(old_parking_ext, parking_ext);
02930       strcpy(old_parking_con, parking_con);
02931    } 
02932 
02933    /* Reset to defaults */
02934    strcpy(parking_con, "parkedcalls");
02935    strcpy(parking_con_dial, "park-dial");
02936    strcpy(parking_ext, "700");
02937    strcpy(pickup_ext, "*8");
02938    strcpy(parkmohclass, "default");
02939    courtesytone[0] = '\0';
02940    strcpy(xfersound, "beep");
02941    strcpy(xferfailsound, "pbx-invalid");
02942    parking_start = 701;
02943    parking_stop = 750;
02944    parkfindnext = 0;
02945    adsipark = 0;
02946    parkaddhints = 0;
02947    parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
02948    parkedcallreparking = 0;
02949    parkedcallhangup = 0;
02950    parkedcallrecording = 0;
02951 
02952    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02953    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02954    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02955 
02956    cfg = ast_config_load("features.conf");
02957    if (!cfg) {
02958       ast_log(LOG_WARNING,"Could not load features.conf\n");
02959       return AST_MODULE_LOAD_DECLINE;
02960    }
02961    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02962       if (!strcasecmp(var->name, "parkext")) {
02963          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02964       } else if (!strcasecmp(var->name, "context")) {
02965          ast_copy_string(parking_con, var->value, sizeof(parking_con));
02966       } else if (!strcasecmp(var->name, "parkingtime")) {
02967          if ((sscanf(var->value, "%30d", &parkingtime) != 1) || (parkingtime < 1)) {
02968             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02969             parkingtime = DEFAULT_PARK_TIME;
02970          } else
02971             parkingtime = parkingtime * 1000;
02972       } else if (!strcasecmp(var->name, "parkpos")) {
02973          if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
02974             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);
02975          } else {
02976             parking_start = start;
02977             parking_stop = end;
02978          }
02979       } else if (!strcasecmp(var->name, "findslot")) {
02980          parkfindnext = (!strcasecmp(var->value, "next"));
02981       } else if (!strcasecmp(var->name, "parkinghints")) {
02982          parkaddhints = ast_true(var->value);
02983       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
02984          if (!strcasecmp(var->value, "no"))
02985             parkedcalltransfers = 0;
02986          else if (!strcasecmp(var->value, "caller"))
02987             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
02988          else if (!strcasecmp(var->value, "callee"))
02989             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
02990          else if (!strcasecmp(var->value, "both"))
02991             parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
02992       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
02993          if (!strcasecmp(var->value, "no"))
02994             parkedcallreparking = 0;
02995          else if (!strcasecmp(var->value, "caller"))
02996             parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
02997          else if (!strcasecmp(var->value, "callee"))
02998             parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
02999          else if (!strcasecmp(var->value, "both"))
03000             parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
03001       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
03002          if (!strcasecmp(var->value, "no"))
03003             parkedcallhangup = 0;
03004          else if (!strcasecmp(var->value, "caller"))
03005             parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
03006          else if (!strcasecmp(var->value, "callee"))
03007             parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
03008          else if (!strcasecmp(var->value, "both"))
03009             parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
03010       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
03011          if (!strcasecmp(var->value, "no"))
03012             parkedcallrecording = 0;
03013          else if (!strcasecmp(var->value, "caller"))
03014             parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
03015          else if (!strcasecmp(var->value, "callee"))
03016             parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
03017          else if (!strcasecmp(var->value, "both"))
03018             parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
03019       } else if (!strcasecmp(var->name, "adsipark")) {
03020          adsipark = ast_true(var->value);
03021       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03022          if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03023             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03024             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03025          } else
03026             transferdigittimeout = transferdigittimeout * 1000;
03027       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03028          if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03029             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03030             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03031          }
03032       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03033          if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03034             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03035             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03036          } else
03037             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03038       } else if (!strcasecmp(var->name, "courtesytone")) {
03039          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03040       }  else if (!strcasecmp(var->name, "parkedplay")) {
03041          if (!strcasecmp(var->value, "both"))
03042             parkedplay = 2;
03043          else if (!strcasecmp(var->value, "parked"))
03044             parkedplay = 1;
03045          else
03046             parkedplay = 0;
03047       } else if (!strcasecmp(var->name, "xfersound")) {
03048          ast_copy_string(xfersound, var->value, sizeof(xfersound));
03049       } else if (!strcasecmp(var->name, "xferfailsound")) {
03050          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03051       } else if (!strcasecmp(var->name, "pickupexten")) {
03052          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03053       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03054          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
03055       }
03056    }
03057 
03058    unmap_features();
03059    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03060       if (remap_feature(var->name, var->value))
03061          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03062    }
03063 
03064    /* Map a key combination to an application*/
03065    ast_unregister_features();
03066    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03067       char *tmp_val = ast_strdupa(var->value);
03068       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
03069       struct ast_call_feature *feature;
03070 
03071       /* strsep() sets the argument to NULL if match not found, and it
03072        * is safe to use it with a NULL argument, so we don't check
03073        * between calls.
03074        */
03075       exten = strsep(&tmp_val,",");
03076       activatedby = strsep(&tmp_val,",");
03077       app = strsep(&tmp_val,",");
03078       app_args = strsep(&tmp_val,",");
03079       moh_class = strsep(&tmp_val,",");
03080 
03081       activateon = strsep(&activatedby, "/");   
03082 
03083       /*! \todo XXX var_name or app_args ? */
03084       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03085          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03086             app, exten, activateon, var->name);
03087          continue;
03088       }
03089 
03090       AST_RWLIST_RDLOCK(&feature_list);
03091       if ((feature = find_dynamic_feature(var->name))) {
03092          AST_RWLIST_UNLOCK(&feature_list);
03093          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03094          continue;
03095       }
03096       AST_RWLIST_UNLOCK(&feature_list);
03097             
03098       if (!(feature = ast_calloc(1, sizeof(*feature))))
03099          continue;               
03100 
03101       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03102       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03103       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03104       
03105       if (app_args) 
03106          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03107 
03108       if (moh_class)
03109          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03110          
03111       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03112       feature->operation = feature_exec_app;
03113       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03114 
03115       /* Allow caller and calle to be specified for backwards compatability */
03116       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03117          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03118       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03119          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03120       else {
03121          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03122             " must be 'self', or 'peer'\n", var->name);
03123          continue;
03124       }
03125 
03126       if (ast_strlen_zero(activatedby))
03127          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03128       else if (!strcasecmp(activatedby, "caller"))
03129          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03130       else if (!strcasecmp(activatedby, "callee"))
03131          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03132       else if (!strcasecmp(activatedby, "both"))
03133          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03134       else {
03135          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03136             " must be 'caller', or 'callee', or 'both'\n", var->name);
03137          continue;
03138       }
03139 
03140       ast_register_feature(feature);
03141          
03142       if (option_verbose >= 1)
03143          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
03144    }   
03145    ast_config_destroy(cfg);
03146 
03147    /* Remove the old parking extension */
03148    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03149       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
03150             notify_metermaids(old_parking_ext, old_parking_con);
03151       if (option_debug)
03152          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03153    }
03154    
03155    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
03156       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
03157       return -1;
03158    }
03159    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03160    if (parkaddhints)
03161       park_add_hints(parking_con, parking_start, parking_stop);
03162    if (!res)
03163       notify_metermaids(ast_parking_ext(), parking_con);
03164    return res;
03165 
03166 }

static int load_module ( void   )  [static]

Definition at line 3173 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.

03174 {
03175    int res;
03176    
03177    memset(parking_ext, 0, sizeof(parking_ext));
03178    memset(parking_con, 0, sizeof(parking_con));
03179 
03180    if ((res = load_config()))
03181       return res;
03182    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03183    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03184    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03185    if (!res)
03186       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03187    if (!res) {
03188       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03189       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03190          "Park a channel", mandescr_park); 
03191    }
03192 
03193    res |= ast_devstate_prov_add("Park", metermaidstate);
03194 
03195    return res;
03196 }

static int manager_park ( struct mansession s,
const struct message m 
) [static]

Definition at line 2813 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().

02814 {
02815    const char *channel = astman_get_header(m, "Channel");
02816    const char *channel2 = astman_get_header(m, "Channel2");
02817    const char *timeout = astman_get_header(m, "Timeout");
02818    char buf[BUFSIZ];
02819    int to = 0;
02820    int res = 0;
02821    int parkExt = 0;
02822    struct ast_channel *ch1, *ch2;
02823 
02824    if (ast_strlen_zero(channel)) {
02825       astman_send_error(s, m, "Channel not specified");
02826       return 0;
02827    }
02828 
02829    if (ast_strlen_zero(channel2)) {
02830       astman_send_error(s, m, "Channel2 not specified");
02831       return 0;
02832    }
02833 
02834    ch1 = ast_get_channel_by_name_locked(channel);
02835    if (!ch1) {
02836       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02837       astman_send_error(s, m, buf);
02838       return 0;
02839    }
02840 
02841    ch2 = ast_get_channel_by_name_locked(channel2);
02842    if (!ch2) {
02843       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02844       astman_send_error(s, m, buf);
02845       ast_channel_unlock(ch1);
02846       return 0;
02847    }
02848 
02849    if (!ast_strlen_zero(timeout)) {
02850       sscanf(timeout, "%30d", &to);
02851    }
02852 
02853    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02854    if (!res) {
02855       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02856       astman_send_ack(s, m, "Park successful");
02857    } else {
02858       astman_send_error(s, m, "Park failure");
02859    }
02860 
02861    ast_channel_unlock(ch1);
02862    ast_channel_unlock(ch2);
02863 
02864    return 0;
02865 }

static int manager_parking_status ( struct mansession s,
const struct message m 
) [static]

Dump lot status.

Definition at line 2766 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().

02767 {
02768    struct parkeduser *cur;
02769    const char *id = astman_get_header(m, "ActionID");
02770    char idText[256] = "";
02771 
02772    if (!ast_strlen_zero(id))
02773       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02774 
02775    astman_send_ack(s, m, "Parked calls will follow");
02776 
02777    ast_mutex_lock(&parking_lock);
02778 
02779    for (cur = parkinglot; cur; cur = cur->next) {
02780       astman_append(s, "Event: ParkedCall\r\n"
02781          "Exten: %d\r\n"
02782          "Channel: %s\r\n"
02783          "From: %s\r\n"
02784          "Timeout: %ld\r\n"
02785          "CallerID: %s\r\n"
02786          "CallerIDName: %s\r\n"
02787          "%s"
02788          "\r\n",
02789          cur->parkingnum, cur->chan->name, cur->peername,
02790          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02791          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02792          S_OR(cur->chan->cid.cid_name, ""),
02793          idText);
02794    }
02795 
02796    astman_append(s,
02797       "Event: ParkedCallsComplete\r\n"
02798       "%s"
02799       "\r\n",idText);
02800 
02801    ast_mutex_unlock(&parking_lock);
02802 
02803    return RESULT_SUCCESS;
02804 }

static int masq_park_call ( struct ast_channel rchan,
struct ast_channel peer,
int  timeout,
int *  extout,
int  play_announcement,
const char *  orig_chan_name 
) [static]

Definition at line 557 of file res_features.c.

References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), parkeduser::chan, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_PARKFAILED, LOG_WARNING, ast_channel::name, park_call_full(), park_space_reserve(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

Referenced by ast_masq_park_call(), and masq_park_call_announce().

00558 {
00559    struct ast_channel *chan;
00560    struct ast_frame *f;
00561    struct parkeduser *pu;
00562    int park_status;
00563 
00564    if ((pu = park_space_reserve(rchan)) == NULL) {
00565       if (peer)
00566          ast_stream_and_wait(peer, "beeperr", peer->language, "");
00567       return FEATURE_RETURN_PARKFAILED;
00568    }
00569 
00570    /* Make a new, fake channel that we'll use to masquerade in the real one */
00571    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00572       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00573       return -1;
00574    }
00575 
00576    /* Make formats okay */
00577    chan->readformat = rchan->readformat;
00578    chan->writeformat = rchan->writeformat;
00579    ast_channel_masquerade(chan, rchan);
00580 
00581    /* Setup the extensions and such */
00582    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00583 
00584    /* Make the masq execute */
00585    if ((f = ast_read(chan))) {
00586       ast_frfree(f);
00587    }
00588 
00589    if (peer == rchan) {
00590       peer = chan;
00591    }
00592 
00593    if (!play_announcement || !orig_chan_name) {
00594       /* chan is the channel being parked, peer is the effective park-er */
00595       orig_chan_name = ast_strdupa(peer->name);
00596    }
00597 
00598    park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu);
00599    if (park_status == 1) {
00600       /* would be nice to play: "invalid parking extension" */
00601       ast_hangup(chan);
00602       return -1;
00603    }
00604 
00605    return 0;
00606 }

static int masq_park_call_announce ( struct ast_channel rchan,
struct ast_channel peer,
int  timeout,
int *  extout,
const char *  orig_chan_name 
) [static]

Definition at line 613 of file res_features.c.

References masq_park_call().

Referenced by builtin_blindtransfer(), builtin_parkcall(), and park_call_exec().

00614 {
00615    return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
00616 }

static int metermaidstate ( const char *  data  )  [static]

metermaids callback from devicestate.c

Definition at line 328 of file res_features.c.

References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_log(), ast_strdupa, context, exten, LOG_DEBUG, and option_debug.

Referenced by load_module().

00329 {
00330    int res = AST_DEVICE_INVALID;
00331    char *context = ast_strdupa(data);
00332    char *exten;
00333 
00334    exten = strsep(&context, "@");
00335    if (!context)
00336       return res;
00337    
00338    if (option_debug > 3)
00339       ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00340 
00341    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00342 
00343    if (!res)
00344       return AST_DEVICE_NOT_INUSE;
00345    else
00346       return AST_DEVICE_INUSE;
00347 }

static void notify_metermaids ( char *  exten,
char *  context 
) [static]

Notify metermaids that we've changed an extension.

Definition at line 317 of file res_features.c.

References ast_device_state_changed(), ast_log(), LOG_DEBUG, and option_debug.

Referenced by do_parking_thread(), park_call_full(), and park_exec().

00318 {
00319    if (option_debug > 3)
00320       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00321 
00322    /* Send notification to devicestate subsystem */
00323    ast_device_state_changed("park:%s@%s", exten, context);
00324    return;
00325 }

static void park_add_hints ( char *  context,
int  start,
int  stop 
) [static]

Add parking hints for all defined parking lots.

Definition at line 2904 of file res_features.c.

References ast_add_extension(), AST_MAX_EXTENSION, exten, PRIORITY_HINT, and registrar.

02905 {
02906    int numext;
02907    char device[AST_MAX_EXTENSION];
02908    char exten[10];
02909 
02910    for (numext = start; numext <= stop; numext++) {
02911       snprintf(exten, sizeof(exten), "%d", numext);
02912       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02913       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02914    }
02915 }

static int park_call_exec ( struct ast_channel chan,
void *  data 
) [static]

Park a call.

Definition at line 2460 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().

02461 {
02462    /* Cache the original channel name in case we get masqueraded in the middle
02463     * of a park--it is still theoretically possible for a transfer to happen before
02464     * we get here, but it is _really_ unlikely */
02465    char *orig_chan_name = ast_strdupa(chan->name);
02466    char orig_exten[AST_MAX_EXTENSION];
02467    int orig_priority = chan->priority;
02468 
02469    /* Data is unused at the moment but could contain a parking
02470       lot context eventually */
02471    int res = 0;
02472    struct ast_module_user *u;
02473 
02474    u = ast_module_user_add(chan);
02475 
02476    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
02477 
02478    /* Setup the exten/priority to be s/1 since we don't know
02479       where this call should return */
02480    strcpy(chan->exten, "s");
02481    chan->priority = 1;
02482    /* Answer if call is not up */
02483    if (chan->_state != AST_STATE_UP)
02484       res = ast_answer(chan);
02485    /* Sleep to allow VoIP streams to settle down */
02486    if (!res)
02487       res = ast_safe_sleep(chan, 1000);
02488    /* Park the call */
02489    if (!res) {
02490       res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name);
02491       /* Continue on in the dialplan */
02492       if (res == 1) {
02493          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
02494          chan->priority = orig_priority;
02495          res = 0;
02496       } else if (!res) {
02497          res = 1;
02498       }
02499    }
02500 
02501    ast_module_user_remove(u);
02502 
02503    return res;
02504 }

static int park_call_full ( struct ast_channel chan,
struct ast_channel peer,
int  timeout,
int *  extout,
const char *  orig_chan_name,
struct parkeduser pu 
) [static]

Definition at line 420 of file res_features.c.

References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_bridged_channel(), AST_CHANNEL_NAME, ast_channel_unlock, ast_clear_flag, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_copy_string(), AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_get_channel_by_name_locked(), ast_indicate_data(), ast_log(), ast_say_digits(), ast_set_flag, ast_strlen_zero(), ast_tvnow(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, option_verbose, park_space_reserve(), parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, S_OR, parkeduser::start, strdup, ast_channel::tech, ast_channel_tech::type, and VERBOSE_PREFIX_2.

Referenced by ast_park_call(), and masq_park_call().

00421 {
00422    struct ast_context *con;
00423    int parkingnum_copy;
00424    const char *event_from;
00425 
00426    /* Get a valid space if not already done */
00427    if (pu == NULL)
00428       pu = park_space_reserve(chan);
00429    if (pu == NULL)
00430       return 1; /* Continue execution if possible */
00431 
00432    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
00433    
00434    chan->appl = "Parked Call";
00435    chan->data = NULL; 
00436 
00437    pu->chan = chan;
00438    
00439    /* Put the parked channel on hold if we have two different channels */
00440    if (chan != peer) {
00441       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00442          S_OR(parkmohclass, NULL),
00443          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00444    }
00445    
00446    pu->start = ast_tvnow();
00447    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00448    if (extout)
00449       *extout = pu->parkingnum;
00450 
00451    if (peer) { 
00452       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
00453          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
00454          and we need the callback name to be that of transferer.  Since local,1/2 have the same
00455          name we can be tricky and just grab the bridged channel from the other side of the local
00456       */
00457       if (!strcasecmp(peer->tech->type, "Local")) {
00458          struct ast_channel *tmpchan, *base_peer;
00459          char other_side[AST_CHANNEL_NAME];
00460          char *c;
00461          ast_copy_string(other_side, S_OR(orig_chan_name, peer->name), sizeof(other_side));
00462          if ((c = strrchr(other_side, ','))) {
00463             *++c = '1';
00464          }
00465          if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00466             if ((base_peer = ast_bridged_channel(tmpchan))) {
00467                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00468             }
00469             ast_channel_unlock(tmpchan);
00470          }
00471       } else {
00472          ast_copy_string(pu->peername, S_OR(orig_chan_name, peer->name), sizeof(pu->peername));
00473       }
00474    }
00475 
00476    /* Remember what had been dialed, so that if the parking
00477       expires, we try to come back to the same place */
00478    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00479    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00480    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00481    parkingnum_copy = pu->parkingnum;
00482 
00483    /* If parking a channel directly (peer == chan), don't quite yet get parking running on it.
00484      * All parking lot entires are put into the parking lot with notquiteyet on. */
00485    if (peer != chan) 
00486       pu->notquiteyet = 0;
00487 
00488    if (option_verbose > 1) 
00489       ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00490 
00491    if (peer) {
00492       event_from = peer->name;
00493    } else {
00494       event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
00495    }
00496 
00497    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00498       "Exten: %s\r\n"
00499       "Channel: %s\r\n"
00500       "From: %s\r\n"
00501       "Timeout: %ld\r\n"
00502       "CallerID: %s\r\n"
00503       "CallerIDName: %s\r\n",
00504       pu->parkingexten, pu->chan->name, event_from ? event_from : "",
00505       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00506       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00507       S_OR(pu->chan->cid.cid_name, "<unknown>")
00508       );
00509 
00510    if (peer && adsipark && ast_adsi_available(peer)) {
00511       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00512       ast_adsi_unload_session(peer);
00513    }
00514 
00515    con = ast_context_find(parking_con);
00516    if (!con) 
00517       con = ast_context_create(NULL, parking_con, registrar);
00518    if (!con)   /* Still no context? Bad */
00519       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00520    if (con) {
00521       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free_ptr, registrar)) {
00522          notify_metermaids(pu->parkingexten, parking_con);
00523       }
00524    }
00525 
00526    /* Wake up the (presumably select()ing) thread */
00527    pthread_kill(parking_thread, SIGURG);
00528 
00529    /* Only say number if it's a number and the channel hasn't been masqueraded away */
00530    if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) {
00531       /* Make sure we don't start saying digits to the channel being parked */
00532       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00533       /* Tell the peer channel the number of the parking space */
00534       ast_say_digits(peer, parkingnum_copy, "", peer->language);
00535       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00536    }
00537 
00538    if (peer == chan) { /* pu->notquiteyet = 1 */
00539       /* Wake up parking thread if we're really done */
00540       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00541          S_OR(parkmohclass, NULL),
00542          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00543       pu->notquiteyet = 0;
00544       pthread_kill(parking_thread, SIGURG);
00545    }
00546    return 0;
00547 }

static int park_exec ( struct ast_channel chan,
void *  data 
) [static]

Pickup parked call.

Todo:
XXX we would like to wait on both!

Todo:
XXX Play a message XXX

Definition at line 2507 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().

02508 {
02509    int res = 0;
02510    struct ast_module_user *u;
02511    struct ast_channel *peer=NULL;
02512    struct parkeduser *pu, *pl=NULL;
02513    struct ast_context *con;
02514 
02515    int park;
02516    struct ast_bridge_config config;
02517 
02518    if (!data) {
02519       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
02520       return -1;
02521    }
02522 
02523    u = ast_module_user_add(chan);
02524 
02525    park = atoi((char *)data);
02526    ast_mutex_lock(&parking_lock);
02527    pu = parkinglot;
02528    while(pu) {
02529       if (pu->parkingnum == park) {
02530          if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
02531             ast_mutex_unlock(&parking_lock);
02532             ast_module_user_remove(u);
02533             return -1;
02534          }
02535          if (pl)
02536             pl->next = pu->next;
02537          else
02538             parkinglot = pu->next;
02539          break;
02540       }
02541       pl = pu;
02542       pu = pu->next;
02543    }
02544    ast_mutex_unlock(&parking_lock);
02545    if (pu) {
02546       peer = pu->chan;
02547       con = ast_context_find(parking_con);
02548       if (con) {
02549          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
02550             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02551          else
02552             notify_metermaids(pu->parkingexten, parking_con);
02553       } else
02554          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02555 
02556       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
02557          "Exten: %s\r\n"
02558          "Channel: %s\r\n"
02559          "From: %s\r\n"
02560          "CallerID: %s\r\n"
02561          "CallerIDName: %s\r\n",
02562          pu->parkingexten, pu->chan->name, chan->name,
02563          S_OR(pu->chan->cid.cid_num, "<unknown>"),
02564          S_OR(pu->chan->cid.cid_name, "<unknown>")
02565          );
02566 
02567       free(pu);
02568    }
02569    /* JK02: it helps to answer the channel if not already up */
02570    if (chan->_state != AST_STATE_UP)
02571       ast_answer(chan);
02572 
02573    if (peer) {
02574       struct ast_datastore *features_datastore;
02575       struct ast_dial_features *dialfeatures = NULL;
02576 
02577       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
02578 
02579       if (!ast_strlen_zero(courtesytone)) {
02580          int error = 0;
02581          ast_indicate(peer, AST_CONTROL_UNHOLD);
02582          if (parkedplay == 0) {
02583             error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
02584          } else if (parkedplay == 1) {
02585             error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
02586          } else if (parkedplay == 2) {
02587             if (!ast_streamfile(chan, courtesytone, chan->language) &&
02588                   !ast_streamfile(peer, courtesytone, chan->language)) {
02589                /*! \todo XXX we would like to wait on both! */
02590                res = ast_waitstream(chan, "");
02591                if (res >= 0)
02592                   res = ast_waitstream(peer, "");
02593                if (res < 0)
02594                   error = 1;
02595             }
02596                         }
02597          if (error) {
02598             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02599             ast_hangup(peer);
02600             ast_module_user_remove(u);
02601             return -1;
02602          }
02603       } else
02604          ast_indicate(peer, AST_CONTROL_UNHOLD);
02605 
02606       res = ast_channel_make_compatible(chan, peer);
02607       if (res < 0) {
02608          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02609          ast_hangup(peer);
02610          ast_module_user_remove(u);
02611          return -1;
02612       }
02613       /* This runs sorta backwards, since we give the incoming channel control, as if it
02614          were the person called. */
02615       if (option_verbose > 2)
02616          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
02617 
02618       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02619       ast_cdr_setdestchan(chan->cdr, peer->name);
02620       memset(&config, 0, sizeof(struct ast_bridge_config));
02621 
02622       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
02623       ast_channel_lock(peer);
02624       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
02625          dialfeatures = features_datastore->data;
02626       }
02627       ast_channel_unlock(peer);
02628 
02629       if (dialfeatures) {
02630          ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL);
02631       }
02632 
02633       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
02634          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02635       }
02636       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
02637          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02638       }
02639       if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
02640          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
02641       }
02642       if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
02643          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
02644       }
02645       if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
02646          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
02647       }
02648       if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
02649          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
02650       }
02651       if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
02652          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
02653       }
02654       if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
02655          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
02656       }
02657       res = ast_bridge_call(chan, peer, &config);
02658 
02659       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02660       ast_cdr_setdestchan(chan->cdr, peer->name);
02661 
02662       /* Simulate the PBX hanging up */
02663       ast_hangup(peer);
02664       ast_module_user_remove(u);
02665       return -1;
02666    } else {
02667       /*! \todo XXX Play a message XXX */
02668       if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02669          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02670       if (option_verbose > 2) 
02671          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02672       res = -1;
02673    }
02674 
02675    ast_module_user_remove(u);
02676 
02677    return -1;
02678 }

static struct parkeduser* park_space_reserve ( struct ast_channel chan  )  [static]

Definition at line 349 of file res_features.c.

References ast_calloc, ast_exists_extension(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), parkeduser::chan, free, LOG_WARNING, parkeduser::next, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, and pbx_builtin_getvar_helper().

Referenced by masq_park_call(), and park_call_full().

00350 {
00351    struct parkeduser *pu, *cur;
00352    int i, parking_space = -1, parking_range;
00353    const char *parkingexten;
00354 
00355    /* Allocate memory for parking data */
00356    if (!(pu = ast_calloc(1, sizeof(*pu)))) 
00357       return NULL;
00358 
00359    /* Lock parking lot */
00360    ast_mutex_lock(&parking_lock);
00361    /* Check for channel variable PARKINGEXTEN */
00362    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00363    if (!ast_strlen_zero(parkingexten)) {
00364       /*!\note The API forces us to specify a numeric parking slot, even
00365        * though the architecture would tend to support non-numeric extensions
00366        * (as are possible with SIP, for example).  Hence, we enforce that
00367        * limitation here.  If extout was not numeric, we could permit
00368        * arbitrary non-numeric extensions.
00369        */
00370       if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) {
00371          ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00372          ast_mutex_unlock(&parking_lock);
00373          free(pu);
00374          return NULL;
00375       }
00376       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00377 
00378       if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
00379          ast_mutex_unlock(&parking_lock);
00380          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00381          free(pu);
00382          return NULL;
00383       }
00384    } else {
00385       /* Select parking space within range */
00386       parking_range = parking_stop - parking_start+1;
00387       for (i = 0; i < parking_range; i++) {
00388          parking_space = (i + parking_offset) % parking_range + parking_start;
00389          cur = parkinglot;
00390          while(cur) {
00391             if (cur->parkingnum == parking_space) 
00392                break;
00393             cur = cur->next;
00394          }
00395          if (!cur)
00396             break;
00397       }
00398 
00399       if (!(i < parking_range)) {
00400          ast_log(LOG_WARNING, "No more parking spaces\n");
00401          ast_mutex_unlock(&parking_lock);
00402          free(pu);
00403          return NULL;
00404       }
00405       /* Set pointer for next parking */
00406       if (parkfindnext) 
00407          parking_offset = parking_space - parking_start + 1;
00408       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00409    }
00410    
00411    pu->notquiteyet = 1;
00412    pu->parkingnum = parking_space;
00413    pu->next = parkinglot;
00414    parkinglot = pu;
00415    ast_mutex_unlock(&parking_lock);
00416 
00417    return pu;
00418 }

static struct ast_cdr* pick_unlocked_cdr ( struct ast_cdr cdr  )  [static]

Definition at line 1601 of file res_features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

01602 {
01603    struct ast_cdr *cdr_orig = cdr;
01604    while (cdr) {
01605       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
01606          return cdr;
01607       cdr = cdr->next;
01608    }
01609    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
01610 }

static void post_manager_event ( const char *  s,
char *  parkingexten,
struct ast_channel chan 
) [static]

Definition at line 2211 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().

02212 {
02213    manager_event(EVENT_FLAG_CALL, s,
02214       "Exten: %s\r\n"
02215       "Channel: %s\r\n"
02216       "CallerID: %s\r\n"
02217       "CallerIDName: %s\r\n\r\n",
02218       parkingexten, 
02219       chan->name,
02220       S_OR(chan->cid.cid_num, "<unknown>"),
02221       S_OR(chan->cid.cid_name, "<unknown>")
02222       );
02223 }

static const char* real_ctx ( struct ast_channel transferer,
struct ast_channel transferee 
) [static]

Find the context for the transfer.

Definition at line 767 of file res_features.c.

References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, pbx_builtin_getvar_helper(), and s.

Referenced by builtin_blindtransfer(), and do_atxfer().

00768 {
00769         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00770         if (ast_strlen_zero(s))
00771                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00772         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00773                 s = transferer->macrocontext;
00774         if (ast_strlen_zero(s))
00775                 s = transferer->context;
00776         return s;  
00777 }

static int reload ( void   )  [static]

Definition at line 3168 of file res_features.c.

References load_config().

03169 {
03170    return load_config();
03171 }

static int remap_feature ( const char *  name,
const char *  value 
) [static]

Definition at line 1246 of file res_features.c.

References ast_copy_string(), ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, exten, FEATURES_COUNT, and features_lock.

01247 {
01248    int x, res = -1;
01249 
01250    ast_rwlock_wrlock(&features_lock);
01251    for (x = 0; x < FEATURES_COUNT; x++) {
01252       if (strcasecmp(builtin_features[x].sname, name))
01253          continue;
01254 
01255       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01256       res = 0;
01257       break;
01258    }
01259    ast_rwlock_unlock(&features_lock);
01260 
01261    return res;
01262 }

static void set_bridge_features_on_config ( struct ast_bridge_config config,
const char *  features 
) [static]

Definition at line 1612 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().

01613 {
01614    const char *feature;
01615 
01616    if (ast_strlen_zero(features)) {
01617       return;
01618    }
01619 
01620    for (feature = features; *feature; feature++) {
01621       switch (*feature) {
01622       case 'T' :
01623       case 't' :
01624          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
01625          break;
01626       case 'K' :
01627       case 'k' :
01628          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
01629          break;
01630       case 'H' :
01631       case 'h' :
01632          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
01633          break;
01634       case 'W' :
01635       case 'w' :
01636          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
01637          break;
01638       default :
01639          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
01640       }
01641    }
01642 }

static void set_c_e_p ( struct ast_channel chan,
const char *  context,
const char *  ext,
int  pri 
) [static]

store context, priority and extension

Definition at line 225 of file res_features.c.

References ast_copy_string(), ast_channel::context, ast_channel::exten, and ast_channel::priority.

Referenced by builtin_blindtransfer(), do_parking_thread(), and masq_park_call().

00226 {
00227    ast_copy_string(chan->context, context, sizeof(chan->context));
00228    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00229    chan->priority = pri;
00230 }

static void set_config_flags ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config 
) [static]

Definition at line 1391 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().

01392 {
01393    int x;
01394 
01395    ast_clear_flag(config, AST_FLAGS_ALL);
01396 
01397    ast_rwlock_rdlock(&features_lock);
01398    for (x = 0; x < FEATURES_COUNT; x++) {
01399       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01400          continue;
01401 
01402       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01403          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01404 
01405       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01406          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01407    }
01408    ast_rwlock_unlock(&features_lock);
01409 
01410    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01411       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01412 
01413       if (dynamic_features) {
01414          char *tmp = ast_strdupa(dynamic_features);
01415          char *tok;
01416          struct ast_call_feature *feature;
01417 
01418          /* while we have a feature */
01419          while ((tok = strsep(&tmp, "#"))) {
01420             AST_RWLIST_RDLOCK(&feature_list);
01421             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01422                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01423                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01424                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01425                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01426             }
01427             AST_RWLIST_UNLOCK(&feature_list);
01428          }
01429       }
01430    }
01431 }

static void set_peers ( struct ast_channel **  caller,
struct ast_channel **  callee,
struct ast_channel peer,
struct ast_channel chan,
int  sense 
) [static]

set caller and callee according to the direction

Definition at line 621 of file res_features.c.

References parkeduser::chan, and FEATURE_SENSE_PEER.

Referenced by builtin_automonitor(), builtin_blindtransfer(), builtin_parkcall(), and do_atxfer().

00623 {
00624    if (sense == FEATURE_SENSE_PEER) {
00625       *caller = peer;
00626       *callee = chan;
00627    } else {
00628       *callee = peer;
00629       *caller = chan;
00630    }
00631 }

static int unload_module ( void   )  [static]

Definition at line 3199 of file res_features.c.

References ast_cli_unregister_multiple(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), cli_features, parkcall, and parkedcall.

03200 {
03201    ast_module_user_hangup_all();
03202 
03203    ast_manager_unregister("ParkedCalls");
03204    ast_manager_unregister("Park");
03205    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03206    ast_unregister_application(parkcall);
03207    ast_devstate_prov_del("Park");
03208    return ast_unregister_application(parkedcall);
03209 }

static void unmap_features ( void   )  [static]

Definition at line 1236 of file res_features.c.

References ast_rwlock_unlock, ast_rwlock_wrlock, builtin_features, exten, FEATURES_COUNT, and features_lock.

01237 {
01238    int x;
01239 
01240    ast_rwlock_wrlock(&features_lock);
01241    for (x = 0; x < FEATURES_COUNT; x++)
01242       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01243    ast_rwlock_unlock(&features_lock);
01244 }


Variable Documentation

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 = "6989f2ec67f8497e38c12890500c525b" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 3215 of file res_features.c.

int adsipark [static]

Definition at line 117 of file res_features.c.

Referenced by load_config().

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 3215 of file res_features.c.

int atxfernoanswertimeout [static]

Definition at line 122 of file res_features.c.

Referenced by load_config().

struct ast_call_feature builtin_features[] [static]

Definition at line 1110 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 2755 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 2750 of file res_features.c.

char courtesytone[256] [static]

Courtesy tone

Definition at line 109 of file res_features.c.

Referenced by load_config(), and park_exec().

char* descrip [static]

Initial value:

 "ParkedCall(exten):"
"Used to connect to a parked call.  This application is always\n"
"registered internally and does not need to be explicitly added\n"
"into the dialplan, although you should include the 'parkedcalls'\n"
"context.\n"

Definition at line 129 of file res_features.c.

char* descrip2 [static]

Definition at line 139 of file res_features.c.

struct ast_datastore_info dial_features_info

Initial value:

 {
   .type = "dial-features",
   .destroy = dial_features_destroy,
   .duplicate = dial_features_duplicate,
}

Definition at line 201 of file res_features.c.

Referenced by add_features_datastores(), do_atxfer(), do_parking_thread(), and park_exec().

int featuredigittimeout [static]

Definition at line 120 of file res_features.c.

ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static]

Definition at line 1108 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]

Definition at line 2806 of file res_features.c.

Referenced by load_module().

struct ast_app* monitor_app = NULL [static]

Definition at line 150 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 151 of file res_features.c.

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 94 of file res_features.c.

Referenced by load_config().

char* parkcall = PARK_APP_NAME [static]

Definition at line 135 of file res_features.c.

Referenced by load_module(), and unload_module().

char* parkedcall = "ParkedCall" [static]

Definition at line 92 of file res_features.c.

Referenced by load_module(), and unload_module().

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]

Definition at line 115 of file res_features.c.

Referenced by load_config().

char parking_con[AST_MAX_EXTENSION] [static]

Context for which parking is made accessible

Definition at line 96 of file res_features.c.

Referenced by handle_showfeatures(), load_config(), load_module(), and park_exec().

char parking_con_dial[AST_MAX_EXTENSION] [static]

Context for dialback for parking (KLUDGE)

Definition at line 97 of file res_features.c.

Referenced by load_config().

char parking_ext[AST_MAX_EXTENSION] [static]

Extension you type to park the call

Definition at line 98 of file res_features.c.

Referenced by handle_showfeatures(), load_config(), and load_module().

ast_mutex_t parking_lock = { PTHREAD_MUTEX_INITIALIZER , 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INITIALIZER } [static]

protects all static variables above

Definition at line 170 of file res_features.c.

Referenced by do_parking_thread(), handle_parkedcalls(), manager_parking_status(), park_exec(), and park_space_reserve().

int parking_offset [static]

Definition at line 114 of file res_features.c.

int parking_start [static]

First available extension for parking

Definition at line 101 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

int parking_stop [static]

Last available extension for parking

Definition at line 102 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

pthread_t parking_thread [static]

Definition at line 172 of file res_features.c.

Referenced by load_module().

struct parkeduser* parkinglot [static]

Definition at line 168 of file res_features.c.

Referenced by do_parking_thread(), handle_parkedcalls(), manager_parking_status(), park_exec(), and park_space_reserve().

int parkingtime = DEFAULT_PARK_TIME [static]

No more than 45 seconds parked before you do something with them

Definition at line 95 of file res_features.c.

char parkmohclass[MAX_MUSICCLASS] [static]

Music class used for parking

Definition at line 100 of file res_features.c.

Referenced by load_config().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 99 of file res_features.c.

Referenced by load_config().

char* registrar = "res_features" [static]

Registrar for operations

Definition at line 124 of file res_features.c.

char showfeatures_help[] [static]

Initial value:

"Usage: feature list\n"
"       Lists currently configured features.\n"

Definition at line 2718 of file res_features.c.

char showparked_help[] [static]

Initial value:

"Usage: show parkedcalls\n"
"       Lists currently parked calls.\n"

Definition at line 2746 of file res_features.c.

char* synopsis = "Answer a parked call" [static]

Definition at line 127 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 137 of file res_features.c.

int transferdigittimeout [static]

Definition at line 119 of file res_features.c.

Referenced by load_config().

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]

Call transfer sound

Definition at line 111 of file res_features.c.

Referenced by load_config().


Generated on Thu Jan 28 17:36:11 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7