Tue Apr 28 22:50:45 2009

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 FEATURE_SENSE_CHAN   (1 << 0)
#define FEATURE_SENSE_PEER   (1 << 1)
#define FEATURES_COUNT   (sizeof(builtin_features) / sizeof(builtin_features[0]))
#define MAX_DIAL_FEATURE_OPTIONS   30

Enumerations

enum  {
  AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
  AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3)
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
static void * ast_bridge_call_thread (void *data)
static void ast_bridge_call_thread_launch (void *data)
static int ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static struct ast_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 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 = "f450f61f60e761b3aa089ebed76ca8a5" , .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 = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static int parking_offset
static int parking_start
static int parking_stop
static pthread_t parking_thread
static struct 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.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 80 of file res_features.c.

Referenced by ast_feature_interpret(), and feature_exec_app().

#define FEATURE_RETURN_PARKFAILED   25

Definition at line 81 of file res_features.c.

Referenced by builtin_blindtransfer(), and masq_park_call().

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 77 of file res_features.c.

Referenced by ast_bridge_call(), and ast_feature_interpret().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 78 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_SUCCESS   23

Definition at line 79 of file res_features.c.

Referenced by ast_bridge_call(), builtin_automonitor(), builtin_blindtransfer(), do_atxfer(), and feature_exec_app().

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 76 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 617 of file res_features.c.

Referenced by ast_bridge_call(), ast_feature_interpret(), cmd_atxfer(), and feature_exec_app().

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 618 of file res_features.c.

Referenced by ast_bridge_call(), cmd_atxfer(), and set_peers().

#define FEATURES_COUNT   (sizeof(builtin_features) / sizeof(builtin_features[0]))

Definition at line 1108 of file res_features.c.

Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().

#define MAX_DIAL_FEATURE_OPTIONS   30

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 3127 of file res_features.c.

static void __unreg_module ( void   )  [static]

Definition at line 3127 of file res_features.c.

static void add_features_datastores ( struct ast_channel caller,
struct ast_channel callee,
struct ast_bridge_config config 
) [static]

Definition at line 1580 of file res_features.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, AST_FLAGS_ALL, ast_log(), config, ast_datastore::data, DATASTORE_INHERIT_FOREVER, dial_features_info, ast_datastore::inheritance, and LOG_WARNING.

Referenced by ast_bridge_call().

01581 {
01582    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
01583    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
01584 
01585    ast_channel_lock(caller);
01586    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
01587    ast_channel_unlock(caller);
01588    if (!ds_caller_features) {
01589       if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
01590          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
01591          return;
01592       }
01593       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
01594          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
01595          ast_channel_datastore_free(ds_caller_features);
01596          return;
01597       }
01598       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
01599       caller_features->is_caller = 1;
01600       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
01601       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
01602       ds_caller_features->data = caller_features;
01603       ast_channel_lock(caller);
01604       ast_channel_datastore_add(caller, ds_caller_features);
01605       ast_channel_unlock(caller);
01606    } else {
01607       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
01608        * flags over from the atxfer to the caller */
01609       return;
01610    }
01611 
01612    ast_channel_lock(callee);
01613    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
01614    ast_channel_unlock(callee);
01615    if (!ds_callee_features) {
01616       if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
01617          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
01618          return;
01619       }
01620       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
01621          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
01622          ast_channel_datastore_free(ds_callee_features);
01623          return;
01624       }
01625       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
01626       callee_features->is_caller = 0;
01627       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
01628       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
01629       ds_callee_features->data = callee_features;
01630       ast_channel_lock(callee);
01631       ast_channel_datastore_add(callee, ds_callee_features);
01632       ast_channel_unlock(callee);
01633    }
01634 
01635    return;
01636 }

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

Definition at line 301 of file res_features.c.

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

Referenced by park_call_full().

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

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

Bridge a call, optionally allowing redirection.

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

Todo:
XXX how do we guarantee the latter ?

Definition at line 1647 of file res_features.c.

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, ast_answer(), AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_ATXFERCMD, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verbose(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, cmd_atxfer(), config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, ast_option_header::option, option_debug, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, VERBOSE_PREFIX_2, and ast_channel::visible_indication.

Referenced by app_exec(), ast_bridge_call_thread(), do_atxfer(), park_exec(), and try_calling().

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

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

Definition at line 270 of file res_features.c.

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

Referenced by ast_bridge_call_thread_launch().

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

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 287 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by do_atxfer().

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

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

Definition at line 1266 of file res_features.c.

References ast_copy_flags, AST_FLAGS_ALL, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), builtin_features, config, ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, FEATURES_COUNT, features_lock, find_dynamic_feature(), ast_flags::flags, ast_call_feature::fname, LOG_DEBUG, ast_channel::name, ast_call_feature::operation, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, and VERBOSE_PREFIX_3.

Referenced by ast_bridge_call().

01267 {
01268    int x;
01269    struct ast_flags features;
01270    struct ast_call_feature *feature;
01271    const char *dynamic_features;
01272    char *tmp, *tok;
01273    int res = FEATURE_RETURN_PASSDIGITS;
01274    int feature_detected = 0;
01275 
01276    if (sense == FEATURE_SENSE_CHAN) {
01277       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
01278       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01279    } else {
01280       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01281       dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01282    }
01283    if (option_debug > 2)
01284       ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features);
01285 
01286    ast_rwlock_rdlock(&features_lock);
01287    for (x = 0; x < FEATURES_COUNT; x++) {
01288       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01289           !ast_strlen_zero(builtin_features[x].exten)) {
01290          /* Feature is up for consideration */
01291          if (!strcmp(builtin_features[x].exten, code)) {
01292             if (option_debug > 2) {
01293                ast_log(LOG_DEBUG, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
01294             }
01295             res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01296             feature_detected = 1;
01297             break;
01298          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01299             if (res == FEATURE_RETURN_PASSDIGITS)
01300                res = FEATURE_RETURN_STOREDIGITS;
01301          }
01302       }
01303    }
01304    ast_rwlock_unlock(&features_lock);
01305 
01306    if (ast_strlen_zero(dynamic_features) || feature_detected)
01307       return res;
01308 
01309    tmp = ast_strdupa(dynamic_features);
01310 
01311    while ((tok = strsep(&tmp, "#"))) {
01312       AST_RWLIST_RDLOCK(&feature_list);   
01313       if (!(feature = find_dynamic_feature(tok))) {
01314          AST_RWLIST_UNLOCK(&feature_list);
01315          continue;
01316       }
01317          
01318       /* Feature is up for consideration */
01319       if (!strcmp(feature->exten, code)) {
01320          if (option_verbose > 2)
01321             ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01322          res = feature->operation(chan, peer, config, code, sense, feature);
01323          if (res != FEATURE_RETURN_KEEPTRYING) {
01324             AST_RWLIST_UNLOCK(&feature_list);
01325             break;
01326          }
01327          res = FEATURE_RETURN_PASSDIGITS;
01328       } else if (!strncmp(feature->exten, code, strlen(code)))
01329          res = FEATURE_RETURN_STOREDIGITS;
01330 
01331       AST_RWLIST_UNLOCK(&feature_list);
01332    }
01333    
01334    return res;
01335 }

static struct ast_channel * ast_feature_request_and_dial ( struct ast_channel caller,
const char *  type,
int  format,
void *  data,
int  timeout,
int *  outstate,
const char *  cid_num,
const char *  cid_name,
const char *  language 
) [static]

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

Definition at line 1380 of file res_features.c.

References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), ast_waitfor_n(), builtin_features, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, len(), LOG_NOTICE, ast_channel::name, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.

Referenced by do_atxfer().

01381 {
01382    int state = 0;
01383    int cause = 0;
01384    int to;
01385    struct ast_channel *chan;
01386    struct ast_channel *monitor_chans[2];
01387    struct ast_channel *active_channel;
01388    int res = 0, ready = 0;
01389    
01390    if ((chan = ast_request(type, format, data, &cause))) {
01391       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01392       ast_string_field_set(chan, language, language);
01393       ast_channel_inherit_variables(caller, chan); 
01394       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01395          
01396       if (!ast_call(chan, data, timeout)) {
01397          struct timeval started;
01398          int x, len = 0;
01399          char *disconnect_code = NULL, *dialed_code = NULL;
01400 
01401          ast_indicate(caller, AST_CONTROL_RINGING);
01402          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01403          ast_rwlock_rdlock(&features_lock);
01404          for (x = 0; x < FEATURES_COUNT; x++) {
01405             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01406                continue;
01407 
01408             disconnect_code = builtin_features[x].exten;
01409             len = strlen(disconnect_code) + 1;
01410             dialed_code = alloca(len);
01411             memset(dialed_code, 0, len);
01412             break;
01413          }
01414          ast_rwlock_unlock(&features_lock);
01415          x = 0;
01416          started = ast_tvnow();
01417          to = timeout;
01418          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01419             struct ast_frame *f = NULL;
01420 
01421             monitor_chans[0] = caller;
01422             monitor_chans[1] = chan;
01423             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01424 
01425             /* see if the timeout has been violated */
01426             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01427                state = AST_CONTROL_UNHOLD;
01428                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01429                break; /*doh! timeout*/
01430             }
01431 
01432             if (!active_channel)
01433                continue;
01434 
01435             if (chan && (chan == active_channel)){
01436                f = ast_read(chan);
01437                if (f == NULL) { /*doh! where'd he go?*/
01438                   state = AST_CONTROL_HANGUP;
01439                   res = 0;
01440                   break;
01441                }
01442                
01443                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01444                   if (f->subclass == AST_CONTROL_RINGING) {
01445                      state = f->subclass;
01446                      if (option_verbose > 2)
01447                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01448                      ast_indicate(caller, AST_CONTROL_RINGING);
01449                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01450                      state = f->subclass;
01451                      if (option_verbose > 2)
01452                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01453                      ast_indicate(caller, AST_CONTROL_BUSY);
01454                      ast_frfree(f);
01455                      f = NULL;
01456                      break;
01457                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01458                      /* This is what we are hoping for */
01459                      state = f->subclass;
01460                      ast_frfree(f);
01461                      f = NULL;
01462                      ready=1;
01463                      break;
01464                   } else if (f->subclass != -1) {
01465                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01466                   }
01467                   /* else who cares */
01468                }
01469 
01470             } else if (caller && (active_channel == caller)) {
01471                f = ast_read(caller);
01472                if (f == NULL) { /*doh! where'd he go?*/
01473                   if (caller->_softhangup && !chan->_softhangup) {
01474                      /* make this a blind transfer */
01475                      ready = 1;
01476                      break;
01477                   }
01478                   state = AST_CONTROL_HANGUP;
01479                   res = 0;
01480                   break;
01481                }
01482                
01483                if (f->frametype == AST_FRAME_DTMF) {
01484                   dialed_code[x++] = f->subclass;
01485                   dialed_code[x] = '\0';
01486                   if (strlen(dialed_code) == len) {
01487                      x = 0;
01488                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01489                      x = 0;
01490                      dialed_code[x] = '\0';
01491                   }
01492                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01493                      /* Caller Canceled the call */
01494                      state = AST_CONTROL_UNHOLD;
01495                      ast_frfree(f);
01496                      f = NULL;
01497                      break;
01498                   }
01499                }
01500             }
01501             if (f)
01502                ast_frfree(f);
01503          } /* end while */
01504       } else
01505          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01506    } else {
01507       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01508       switch(cause) {
01509       case AST_CAUSE_BUSY:
01510          state = AST_CONTROL_BUSY;
01511          break;
01512       case AST_CAUSE_CONGESTION:
01513          state = AST_CONTROL_CONGESTION;
01514          break;
01515       }
01516    }
01517    
01518    ast_indicate(caller, -1);
01519    if (chan && ready) {
01520       if (chan->_state == AST_STATE_UP) 
01521          state = AST_CONTROL_ANSWER;
01522       res = 0;
01523    } else if(chan) {
01524       res = -1;
01525       ast_hangup(chan);
01526       chan = NULL;
01527    } else {
01528       res = -1;
01529    }
01530    
01531    if (outstate)
01532       *outstate = state;
01533 
01534    return chan;
01535 }

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

Park a call via a masqueraded channel.

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 607 of file res_features.c.

References masq_park_call().

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

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

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

Park a call and read back parked location.

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 2780 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.

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

02781 {
02782    struct ast_channel *cur = NULL;
02783    int res = -1;
02784 
02785    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02786       if (!cur->pbx && 
02787          (cur != chan) &&
02788          (chan->pickupgroup & cur->callgroup) &&
02789          ((cur->_state == AST_STATE_RINGING) ||
02790           (cur->_state == AST_STATE_RING))) {
02791             break;
02792       }
02793       ast_channel_unlock(cur);
02794    }
02795    if (cur) {
02796       if (option_debug)
02797          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02798       res = ast_answer(chan);
02799       if (res)
02800          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02801       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02802       if (res)
02803          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02804       res = ast_channel_masquerade(cur, chan);
02805       if (res)
02806          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02807       ast_channel_unlock(cur);
02808    } else   {
02809       if (option_debug)
02810          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02811    }
02812    return res;
02813 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 212 of file res_features.c.

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

00213 {
00214    return pickup_ext;
00215 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_set

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 1125 of file res_features.c.

References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verbose(), ast_call_feature::feature_entry, LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.

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

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 1142 of file res_features.c.

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

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

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1155 of file res_features.c.

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

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

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

Attended transfer ().

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 1102 of file res_features.c.

References config, and do_atxfer().

01103 {
01104    return do_atxfer(chan, peer, config, sense, NULL, NULL);
01105 }

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

Definition at line 670 of file res_features.c.

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

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

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

Definition at line 781 of file res_features.c.

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

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

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

Definition at line 754 of file res_features.c.

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

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

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

support routing for one touch call parking

Definition at line 636 of file res_features.c.

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

Referenced by do_atxfer().

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

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

Definition at line 2137 of file res_features.c.

References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, and ast_test_flag.

Referenced by do_parking_thread().

02138 {
02139    int i = 0;
02140    enum {
02141       OPT_CALLEE_REDIRECT   = 't',
02142       OPT_CALLER_REDIRECT   = 'T',
02143       OPT_CALLEE_AUTOMON    = 'w',
02144       OPT_CALLER_AUTOMON    = 'W',
02145       OPT_CALLEE_DISCONNECT = 'h',
02146       OPT_CALLER_DISCONNECT = 'H',
02147       OPT_CALLEE_PARKCALL   = 'k',
02148       OPT_CALLER_PARKCALL   = 'K',
02149    };
02150 
02151    memset(options, 0, len);
02152    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02153       options[i++] = OPT_CALLER_REDIRECT;
02154    }
02155    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02156       options[i++] = OPT_CALLER_AUTOMON;
02157    }
02158    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02159       options[i++] = OPT_CALLER_DISCONNECT;
02160    }
02161    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02162       options[i++] = OPT_CALLER_PARKCALL;
02163    }
02164 
02165    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02166       options[i++] = OPT_CALLEE_REDIRECT;
02167    }
02168    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02169       options[i++] = OPT_CALLEE_AUTOMON;
02170    }
02171    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02172       options[i++] = OPT_CALLEE_DISCONNECT;
02173    }
02174    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02175       options[i++] = OPT_CALLEE_PARKCALL;
02176    }
02177 
02178    return options;
02179 }

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

Definition at line 878 of file res_features.c.

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

Referenced by do_atxfer().

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

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Definition at line 232 of file res_features.c.

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

Referenced by builtin_blindtransfer().

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

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

Definition at line 1638 of file res_features.c.

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

Referenced by ast_bridge_call().

01639 {
01640    int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER;
01641    char *context = strchr(xferto, '@');;
01642    if (context)
01643       *context++ = '\0';
01644    do_atxfer(a, b, conf, sense, xferto, context);
01645 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 193 of file res_features.c.

References ast_free.

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

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

Definition at line 180 of file res_features.c.

References ast_calloc.

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

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

Attended transfer implementation.

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 904 of file res_features.c.

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

Referenced by builtin_atxfer(), and cmd_atxfer().

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

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

Take care of parked calls and unpark them if needed.

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 2182 of file res_features.c.

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

Referenced by load_module().

02183 {
02184    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
02185    FD_ZERO(&rfds);
02186    FD_ZERO(&efds);
02187 
02188    for (;;) {
02189       struct parkeduser *pu, *pl, *pt = NULL;
02190       int ms = -1;   /* select timeout, uninitialized */
02191       int max = -1;  /* max fd, none there yet */
02192       fd_set nrfds, nefds; /* args for the next select */
02193       FD_ZERO(&nrfds);
02194       FD_ZERO(&nefds);
02195 
02196       ast_mutex_lock(&parking_lock);
02197       pl = NULL;
02198       pu = parkinglot;
02199       /* navigate the list with prev-cur pointers to support removals */
02200       while (pu) {
02201          struct ast_channel *chan = pu->chan;   /* shorthand */
02202          int tms;        /* timeout for this item */
02203          int x;          /* fd index in channel */
02204          struct ast_context *con;
02205 
02206          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
02207             pl = pu;
02208             pu = pu->next;
02209             continue;
02210          }
02211          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
02212          if (tms > pu->parkingtime) {
02213             ast_indicate(chan, AST_CONTROL_UNHOLD);
02214             /* Get chan, exten from derived kludge */
02215             if (pu->peername[0]) {
02216                char *peername = ast_strdupa(pu->peername);
02217                char *cp = strrchr(peername, '-');
02218                if (cp) 
02219                   *cp = 0;
02220                con = ast_context_find(parking_con_dial);
02221                if (!con) {
02222                   con = ast_context_create(NULL, parking_con_dial, registrar);
02223                   if (!con)
02224                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
02225                }
02226                if (con) {
02227                   char returnexten[AST_MAX_EXTENSION];
02228                   struct ast_datastore *features_datastore;
02229                   struct ast_dial_features *dialfeatures = NULL;
02230 
02231                   ast_channel_lock(chan);
02232 
02233                   if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
02234                      dialfeatures = features_datastore->data;
02235 
02236                   ast_channel_unlock(chan);
02237 
02238                   if (!strncmp(peername, "Parked/", 7)) {
02239                      peername += 7;
02240                   }
02241 
02242                   if (dialfeatures) {
02243                      char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
02244                      snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
02245                   } else { /* Existing default */
02246                      ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name);
02247                      snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
02248                   }
02249 
02250                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
02251                }
02252                set_c_e_p(chan, parking_con_dial, peername, 1);
02253             } else {
02254                /* They've been waiting too long, send them back to where they came.  Theoretically they
02255                   should have their original extensions and such, but we copy to be on the safe side */
02256                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
02257             }
02258 
02259             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
02260 
02261             if (option_verbose > 1) 
02262                ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority);
02263             /* Start up the PBX, or hang them up */
02264             if (ast_pbx_start(chan))  {
02265                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
02266                ast_hangup(chan);
02267             }
02268             /* And take them out of the parking lot */
02269             if (pl) 
02270                pl->next = pu->next;
02271             else
02272                parkinglot = pu->next;
02273             pt = pu;
02274             pu = pu->next;
02275             con = ast_context_find(parking_con);
02276             if (con) {
02277                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
02278                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02279                else
02280                   notify_metermaids(pt->parkingexten, parking_con);
02281             } else
02282                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02283             free(pt);
02284          } else { /* still within parking time, process descriptors */
02285             for (x = 0; x < AST_MAX_FDS; x++) {
02286                struct ast_frame *f;
02287 
02288                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
02289                   continue;   /* nothing on this descriptor */
02290 
02291                if (FD_ISSET(chan->fds[x], &efds))
02292                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
02293                else
02294                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
02295                chan->fdno = x;
02296 
02297                /* See if they need servicing */
02298                f = ast_read(chan);
02299                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
02300                   if (f)
02301                      ast_frfree(f);
02302                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
02303 
02304                   /* There's a problem, hang them up*/
02305                   if (option_verbose > 1) 
02306                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
02307                   ast_hangup(chan);
02308                   /* And take them out of the parking lot */
02309                   if (pl) 
02310                      pl->next = pu->next;
02311                   else
02312                      parkinglot = pu->next;
02313                   pt = pu;
02314                   pu = pu->next;
02315                   con = ast_context_find(parking_con);
02316                   if (con) {
02317                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
02318                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02319                      else {
02320                         notify_metermaids(pt->parkingexten, parking_con);
02321                      }
02322                   } else
02323                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02324                   free(pt);
02325                   break;
02326                } else {
02327                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02328                   ast_frfree(f);
02329                   if (pu->moh_trys < 3 && !chan->generatordata) {
02330                      if (option_debug)
02331                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
02332                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
02333                         S_OR(parkmohclass, NULL),
02334                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
02335                      pu->moh_trys++;
02336                   }
02337                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
02338                }
02339 
02340             } /* end for */
02341             if (x >= AST_MAX_FDS) {
02342 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
02343                   if (chan->fds[x] > -1) {
02344                      FD_SET(chan->fds[x], &nrfds);
02345                      FD_SET(chan->fds[x], &nefds);
02346                      if (chan->fds[x] > max)
02347                         max = chan->fds[x];
02348                   }
02349                }
02350                /* Keep track of our shortest wait */
02351                if (tms < ms || ms < 0)
02352                   ms = tms;
02353                pl = pu;
02354                pu = pu->next;
02355             }
02356          }
02357       } /* end while */
02358       ast_mutex_unlock(&parking_lock);
02359       rfds = nrfds;
02360       efds = nefds;
02361       {
02362          struct timeval tv = ast_samp2tv(ms, 1000);
02363          /* Wait for something to happen */
02364          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02365       }
02366       pthread_testcancel();
02367    }
02368    return NULL;   /* Never reached */
02369 }

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

exec an app by feature

Todo:
XXX should probably return res

Definition at line 1181 of file res_features.c.

References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().

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

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

find a feature by name

Definition at line 1167 of file res_features.c.

References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.

Referenced by ast_feature_interpret(), and set_config_flags().

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

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 761 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

00762 {
00763         ast_indicate(chan, AST_CONTROL_UNHOLD);
00764   
00765         return ast_autoservice_stop(chan);
00766 }

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

Definition at line 2634 of file res_features.c.

References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, ast_channel::name, parkeduser::next, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.

02635 {
02636    struct parkeduser *cur;
02637    int numparked = 0;
02638 
02639    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02640       , "Context", "Extension", "Pri", "Timeout");
02641 
02642    ast_mutex_lock(&parking_lock);
02643 
02644    for (cur = parkinglot; cur; cur = cur->next) {
02645       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02646          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02647          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02648 
02649       numparked++;
02650    }
02651    ast_mutex_unlock(&parking_lock);
02652    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02653 
02654 
02655    return RESULT_SUCCESS;
02656 }

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

Definition at line 2592 of file res_features.c.

References ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), builtin_features, ast_call_feature::default_exten, ast_call_feature::exten, exten, ast_call_feature::feature_entry, FEATURES_COUNT, features_lock, ast_call_feature::fname, format, parking_con, parking_ext, parking_start, parking_stop, RESULT_SUCCESS, and ast_call_feature::sname.

02593 {
02594    int i;
02595    struct ast_call_feature *feature;
02596    char format[] = "%-25s %-7s %-7s\n";
02597 
02598    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02599    ast_cli(fd, format, "---------------", "-------", "-------");
02600 
02601    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02602 
02603    ast_rwlock_rdlock(&features_lock);
02604    for (i = 0; i < FEATURES_COUNT; i++)
02605       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02606    ast_rwlock_unlock(&features_lock);
02607 
02608    ast_cli(fd, "\n");
02609    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02610    ast_cli(fd, format, "---------------", "-------", "-------");
02611    if (AST_RWLIST_EMPTY(&feature_list)) {
02612       ast_cli(fd, "(none)\n");
02613    } else {
02614       AST_RWLIST_RDLOCK(&feature_list);
02615       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
02616          ast_cli(fd, format, feature->sname, "no def", feature->exten);
02617       }
02618       AST_RWLIST_UNLOCK(&feature_list);
02619    }
02620    ast_cli(fd, "\nCall parking\n");
02621    ast_cli(fd, "------------\n");
02622    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02623    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02624    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02625    ast_cli(fd,"\n");
02626    
02627    return RESULT_SUCCESS;
02628 }

static int load_config ( void   )  [static]

Definition at line 2830 of file res_features.c.

References adsipark, ast_config_load(), ast_copy_string(), AST_FEATURE_FLAG_BYBOTH, ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_strlen_zero(), ast_variable_browse(), atxfernoanswertimeout, courtesytone, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_WARNING, parkaddhints, parkedcallhangup, parkedcallrecording, parkedcallreparking, parkedcalltransfers, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkmohclass, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.

02831 {
02832    int start = 0, end = 0;
02833    int res;
02834    struct ast_context *con = NULL;
02835    struct ast_config *cfg = NULL;
02836    struct ast_variable *var = NULL;
02837    char old_parking_ext[AST_MAX_EXTENSION];
02838    char old_parking_con[AST_MAX_EXTENSION] = "";
02839 
02840    if (!ast_strlen_zero(parking_con)) {
02841       strcpy(old_parking_ext, parking_ext);
02842       strcpy(old_parking_con, parking_con);
02843    } 
02844 
02845    /* Reset to defaults */
02846    strcpy(parking_con, "parkedcalls");
02847    strcpy(parking_con_dial, "park-dial");
02848    strcpy(parking_ext, "700");
02849    strcpy(pickup_ext, "*8");
02850    strcpy(parkmohclass, "default");
02851    courtesytone[0] = '\0';
02852    strcpy(xfersound, "beep");
02853    strcpy(xferfailsound, "pbx-invalid");
02854    parking_start = 701;
02855    parking_stop = 750;
02856    parkfindnext = 0;
02857    adsipark = 0;
02858    parkaddhints = 0;
02859    parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
02860    parkedcallreparking = 0;
02861    parkedcallhangup = 0;
02862    parkedcallrecording = 0;
02863 
02864    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02865    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02866    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02867 
02868    cfg = ast_config_load("features.conf");
02869    if (!cfg) {
02870       ast_log(LOG_WARNING,"Could not load features.conf\n");
02871       return AST_MODULE_LOAD_DECLINE;
02872    }
02873    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02874       if (!strcasecmp(var->name, "parkext")) {
02875          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02876       } else if (!strcasecmp(var->name, "context")) {
02877          ast_copy_string(parking_con, var->value, sizeof(parking_con));
02878       } else if (!strcasecmp(var->name, "parkingtime")) {
02879          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02880             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02881             parkingtime = DEFAULT_PARK_TIME;
02882          } else
02883             parkingtime = parkingtime * 1000;
02884       } else if (!strcasecmp(var->name, "parkpos")) {
02885          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02886             ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno);
02887          } else {
02888             parking_start = start;
02889             parking_stop = end;
02890          }
02891       } else if (!strcasecmp(var->name, "findslot")) {
02892          parkfindnext = (!strcasecmp(var->value, "next"));
02893       } else if (!strcasecmp(var->name, "parkinghints")) {
02894          parkaddhints = ast_true(var->value);
02895       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
02896          if (!strcasecmp(var->value, "no"))
02897             parkedcalltransfers = 0;
02898          else if (!strcasecmp(var->value, "caller"))
02899             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
02900          else if (!strcasecmp(var->value, "callee"))
02901             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
02902          else if (!strcasecmp(var->value, "both"))
02903             parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
02904       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
02905          if (!strcasecmp(var->value, "no"))
02906             parkedcallreparking = 0;
02907          else if (!strcasecmp(var->value, "caller"))
02908             parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
02909          else if (!strcasecmp(var->value, "callee"))
02910             parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
02911          else if (!strcasecmp(var->value, "both"))
02912             parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
02913       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
02914          if (!strcasecmp(var->value, "no"))
02915             parkedcallhangup = 0;
02916          else if (!strcasecmp(var->value, "caller"))
02917             parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
02918          else if (!strcasecmp(var->value, "callee"))
02919             parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
02920          else if (!strcasecmp(var->value, "both"))
02921             parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
02922       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
02923          if (!strcasecmp(var->value, "no"))
02924             parkedcallrecording = 0;
02925          else if (!strcasecmp(var->value, "caller"))
02926             parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
02927          else if (!strcasecmp(var->value, "callee"))
02928             parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
02929          else if (!strcasecmp(var->value, "both"))
02930             parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
02931       } else if (!strcasecmp(var->name, "adsipark")) {
02932          adsipark = ast_true(var->value);
02933       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02934          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02935             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02936             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02937          } else
02938             transferdigittimeout = transferdigittimeout * 1000;
02939       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02940          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02941             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02942             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02943          }
02944       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
02945          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
02946             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
02947             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02948          } else
02949             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
02950       } else if (!strcasecmp(var->name, "courtesytone")) {
02951          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02952       }  else if (!strcasecmp(var->name, "parkedplay")) {
02953          if (!strcasecmp(var->value, "both"))
02954             parkedplay = 2;
02955          else if (!strcasecmp(var->value, "parked"))
02956             parkedplay = 1;
02957          else
02958             parkedplay = 0;
02959       } else if (!strcasecmp(var->name, "xfersound")) {
02960          ast_copy_string(xfersound, var->value, sizeof(xfersound));
02961       } else if (!strcasecmp(var->name, "xferfailsound")) {
02962          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02963       } else if (!strcasecmp(var->name, "pickupexten")) {
02964          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02965       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
02966          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
02967       }
02968    }
02969 
02970    unmap_features();
02971    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
02972       if (remap_feature(var->name, var->value))
02973          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02974    }
02975 
02976    /* Map a key combination to an application*/
02977    ast_unregister_features();
02978    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
02979       char *tmp_val = ast_strdupa(var->value);
02980       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
02981       struct ast_call_feature *feature;
02982 
02983       /* strsep() sets the argument to NULL if match not found, and it
02984        * is safe to use it with a NULL argument, so we don't check
02985        * between calls.
02986        */
02987       exten = strsep(&tmp_val,",");
02988       activatedby = strsep(&tmp_val,",");
02989       app = strsep(&tmp_val,",");
02990       app_args = strsep(&tmp_val,",");
02991       moh_class = strsep(&tmp_val,",");
02992 
02993       activateon = strsep(&activatedby, "/");   
02994 
02995       /*! \todo XXX var_name or app_args ? */
02996       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
02997          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
02998             app, exten, activateon, var->name);
02999          continue;
03000       }
03001 
03002       AST_RWLIST_RDLOCK(&feature_list);
03003       if ((feature = find_dynamic_feature(var->name))) {
03004          AST_RWLIST_UNLOCK(&feature_list);
03005          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03006          continue;
03007       }
03008       AST_RWLIST_UNLOCK(&feature_list);
03009             
03010       if (!(feature = ast_calloc(1, sizeof(*feature))))
03011          continue;               
03012 
03013       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03014       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03015       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03016       
03017       if (app_args) 
03018          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03019 
03020       if (moh_class)
03021          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03022          
03023       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03024       feature->operation = feature_exec_app;
03025       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03026 
03027       /* Allow caller and calle to be specified for backwards compatability */
03028       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03029          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03030       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03031          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03032       else {
03033          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03034             " must be 'self', or 'peer'\n", var->name);
03035          continue;
03036       }
03037 
03038       if (ast_strlen_zero(activatedby))
03039          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03040       else if (!strcasecmp(activatedby, "caller"))
03041          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03042       else if (!strcasecmp(activatedby, "callee"))
03043          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03044       else if (!strcasecmp(activatedby, "both"))
03045          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03046       else {
03047          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03048             " must be 'caller', or 'callee', or 'both'\n", var->name);
03049          continue;
03050       }
03051 
03052       ast_register_feature(feature);
03053          
03054       if (option_verbose >= 1)
03055          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
03056    }   
03057    ast_config_destroy(cfg);
03058 
03059    /* Remove the old parking extension */
03060    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03061       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
03062             notify_metermaids(old_parking_ext, old_parking_con);
03063       if (option_debug)
03064          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03065    }
03066    
03067    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
03068       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
03069       return -1;
03070    }
03071    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03072    if (parkaddhints)
03073       park_add_hints(parking_con, parking_start, parking_stop);
03074    if (!res)
03075       notify_metermaids(ast_parking_ext(), parking_con);
03076    return res;
03077 
03078 }

static int load_module ( void   )  [static]

Definition at line 3085 of file res_features.c.

References ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application(), cli_features, descrip, descrip2, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), mandescr_park, metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, synopsis, and synopsis2.

03086 {
03087    int res;
03088    
03089    memset(parking_ext, 0, sizeof(parking_ext));
03090    memset(parking_con, 0, sizeof(parking_con));
03091 
03092    if ((res = load_config()))
03093       return res;
03094    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03095    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03096    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03097    if (!res)
03098       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03099    if (!res) {
03100       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03101       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03102          "Park a channel", mandescr_park); 
03103    }
03104 
03105    res |= ast_devstate_prov_add("Park", metermaidstate);
03106 
03107    return res;
03108 }

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

Definition at line 2725 of file res_features.c.

References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and s.

Referenced by load_module().

02726 {
02727    const char *channel = astman_get_header(m, "Channel");
02728    const char *channel2 = astman_get_header(m, "Channel2");
02729    const char *timeout = astman_get_header(m, "Timeout");
02730    char buf[BUFSIZ];
02731    int to = 0;
02732    int res = 0;
02733    int parkExt = 0;
02734    struct ast_channel *ch1, *ch2;
02735 
02736    if (ast_strlen_zero(channel)) {
02737       astman_send_error(s, m, "Channel not specified");
02738       return 0;
02739    }
02740 
02741    if (ast_strlen_zero(channel2)) {
02742       astman_send_error(s, m, "Channel2 not specified");
02743       return 0;
02744    }
02745 
02746    ch1 = ast_get_channel_by_name_locked(channel);
02747    if (!ch1) {
02748       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02749       astman_send_error(s, m, buf);
02750       return 0;
02751    }
02752 
02753    ch2 = ast_get_channel_by_name_locked(channel2);
02754    if (!ch2) {
02755       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02756       astman_send_error(s, m, buf);
02757       ast_channel_unlock(ch1);
02758       return 0;
02759    }
02760 
02761    if (!ast_strlen_zero(timeout)) {
02762       sscanf(timeout, "%d", &to);
02763    }
02764 
02765    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02766    if (!res) {
02767       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02768       astman_send_ack(s, m, "Park successful");
02769    } else {
02770       astman_send_error(s, m, "Park failure");
02771    }
02772 
02773    ast_channel_unlock(ch1);
02774    ast_channel_unlock(ch2);
02775 
02776    return 0;
02777 }

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

Dump lot status.

Definition at line 2678 of file res_features.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::name, parkeduser::next, parking_lock, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.

Referenced by load_module().

02679 {
02680    struct parkeduser *cur;
02681    const char *id = astman_get_header(m, "ActionID");
02682    char idText[256] = "";
02683 
02684    if (!ast_strlen_zero(id))
02685       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02686 
02687    astman_send_ack(s, m, "Parked calls will follow");
02688 
02689    ast_mutex_lock(&parking_lock);
02690 
02691    for (cur = parkinglot; cur; cur = cur->next) {
02692       astman_append(s, "Event: ParkedCall\r\n"
02693          "Exten: %d\r\n"
02694          "Channel: %s\r\n"
02695          "From: %s\r\n"
02696          "Timeout: %ld\r\n"
02697          "CallerID: %s\r\n"
02698          "CallerIDName: %s\r\n"
02699          "%s"
02700          "\r\n",
02701          cur->parkingnum, cur->chan->name, cur->peername,
02702          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02703          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02704          S_OR(cur->chan->cid.cid_name, ""),
02705          idText);
02706    }
02707 
02708    astman_append(s,
02709       "Event: ParkedCallsComplete\r\n"
02710       "%s"
02711       "\r\n",idText);
02712 
02713    ast_mutex_unlock(&parking_lock);
02714 
02715    return RESULT_SUCCESS;
02716 }

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

Definition at line 557 of file res_features.c.

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

Referenced by ast_masq_park_call(), and masq_park_call_announce().

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

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

Definition at line 612 of file res_features.c.

References masq_park_call().

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

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

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

metermaids callback from devicestate.c

Definition at line 328 of file res_features.c.

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

Referenced by load_module().

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

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

Notify metermaids that we've changed an extension.

Definition at line 317 of file res_features.c.

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

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

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

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

Add parking hints for all defined parking lots.

Definition at line 2816 of file res_features.c.

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

02817 {
02818    int numext;
02819    char device[AST_MAX_EXTENSION];
02820    char exten[10];
02821 
02822    for (numext = start; numext <= stop; numext++) {
02823       snprintf(exten, sizeof(exten), "%d", numext);
02824       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02825       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02826    }
02827 }

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

Park a call.

Definition at line 2372 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_copy_string(), AST_MAX_EXTENSION, ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_module_user::chan, ast_channel::exten, masq_park_call_announce(), ast_channel::name, orig_exten(), and ast_channel::priority.

Referenced by load_module().

02373 {
02374    /* Cache the original channel name in case we get masqueraded in the middle
02375     * of a park--it is still theoretically possible for a transfer to happen before
02376     * we get here, but it is _really_ unlikely */
02377    char *orig_chan_name = ast_strdupa(chan->name);
02378    char orig_exten[AST_MAX_EXTENSION];
02379    int orig_priority = chan->priority;
02380 
02381    /* Data is unused at the moment but could contain a parking
02382       lot context eventually */
02383    int res = 0;
02384    struct ast_module_user *u;
02385 
02386    u = ast_module_user_add(chan);
02387 
02388    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
02389 
02390    /* Setup the exten/priority to be s/1 since we don't know
02391       where this call should return */
02392    strcpy(chan->exten, "s");
02393    chan->priority = 1;
02394    /* Answer if call is not up */
02395    if (chan->_state != AST_STATE_UP)
02396       res = ast_answer(chan);
02397    /* Sleep to allow VoIP streams to settle down */
02398    if (!res)
02399       res = ast_safe_sleep(chan, 1000);
02400    /* Park the call */
02401    if (!res) {
02402       res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name);
02403       /* Continue on in the dialplan */
02404       if (res == 1) {
02405          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
02406          chan->priority = orig_priority;
02407          res = 0;
02408       } else if (!res) {
02409          res = 1;
02410       }
02411    }
02412 
02413    ast_module_user_remove(u);
02414 
02415    return res;
02416 }

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

Definition at line 420 of file res_features.c.

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

Referenced by ast_park_call(), and masq_park_call().

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

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

Pickup parked call.

Todo:
XXX we would like to wait on both!

Todo:
XXX Play a message XXX

Definition at line 2419 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, ast_copy_flags, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, ast_datastore::data, dial_features_info, EVENT_FLAG_CALL, ast_dial_features::features_callee, ast_dial_features::features_caller, free, ast_dial_features::is_caller, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), option_verbose, parkedcallhangup, parkedcallrecording, parkedcallreparking, parkedcalltransfers, parkedplay, parking_con, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.

Referenced by load_module().

02420 {
02421    int res = 0;
02422    struct ast_module_user *u;
02423    struct ast_channel *peer=NULL;
02424    struct parkeduser *pu, *pl=NULL;
02425    struct ast_context *con;
02426 
02427    int park;
02428    struct ast_bridge_config config;
02429 
02430    if (!data) {
02431       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
02432       return -1;
02433    }
02434 
02435    u = ast_module_user_add(chan);
02436 
02437    park = atoi((char *)data);
02438    ast_mutex_lock(&parking_lock);
02439    pu = parkinglot;
02440    while(pu) {
02441       if (pu->parkingnum == park) {
02442          if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
02443             ast_mutex_unlock(&parking_lock);
02444             ast_module_user_remove(u);
02445             return -1;
02446          }
02447          if (pl)
02448             pl->next = pu->next;
02449          else
02450             parkinglot = pu->next;
02451          break;
02452       }
02453       pl = pu;
02454       pu = pu->next;
02455    }
02456    ast_mutex_unlock(&parking_lock);
02457    if (pu) {
02458       peer = pu->chan;
02459       con = ast_context_find(parking_con);
02460       if (con) {
02461          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
02462             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02463          else
02464             notify_metermaids(pu->parkingexten, parking_con);
02465       } else
02466          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02467 
02468       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
02469          "Exten: %s\r\n"
02470          "Channel: %s\r\n"
02471          "From: %s\r\n"
02472          "CallerID: %s\r\n"
02473          "CallerIDName: %s\r\n",
02474          pu->parkingexten, pu->chan->name, chan->name,
02475          S_OR(pu->chan->cid.cid_num, "<unknown>"),
02476          S_OR(pu->chan->cid.cid_name, "<unknown>")
02477          );
02478 
02479       free(pu);
02480    }
02481    /* JK02: it helps to answer the channel if not already up */
02482    if (chan->_state != AST_STATE_UP)
02483       ast_answer(chan);
02484 
02485    if (peer) {
02486       struct ast_datastore *features_datastore;
02487       struct ast_dial_features *dialfeatures = NULL;
02488 
02489       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
02490 
02491       if (!ast_strlen_zero(courtesytone)) {
02492          int error = 0;
02493          ast_indicate(peer, AST_CONTROL_UNHOLD);
02494          if (parkedplay == 0) {
02495             error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
02496          } else if (parkedplay == 1) {
02497             error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
02498          } else if (parkedplay == 2) {
02499             if (!ast_streamfile(chan, courtesytone, chan->language) &&
02500                   !ast_streamfile(peer, courtesytone, chan->language)) {
02501                /*! \todo XXX we would like to wait on both! */
02502                res = ast_waitstream(chan, "");
02503                if (res >= 0)
02504                   res = ast_waitstream(peer, "");
02505                if (res < 0)
02506                   error = 1;
02507             }
02508                         }
02509          if (error) {
02510             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02511             ast_hangup(peer);
02512             ast_module_user_remove(u);
02513             return -1;
02514          }
02515       } else
02516          ast_indicate(peer, AST_CONTROL_UNHOLD);
02517 
02518       res = ast_channel_make_compatible(chan, peer);
02519       if (res < 0) {
02520          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02521          ast_hangup(peer);
02522          ast_module_user_remove(u);
02523          return -1;
02524       }
02525       /* This runs sorta backwards, since we give the incoming channel control, as if it
02526          were the person called. */
02527       if (option_verbose > 2)
02528          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
02529 
02530       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02531       ast_cdr_setdestchan(chan->cdr, peer->name);
02532       memset(&config, 0, sizeof(struct ast_bridge_config));
02533 
02534       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
02535       ast_channel_lock(peer);
02536       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
02537          dialfeatures = features_datastore->data;
02538       }
02539       ast_channel_unlock(peer);
02540 
02541       if (dialfeatures) {
02542          ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL);
02543       }
02544 
02545       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
02546          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02547       }
02548       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
02549          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02550       }
02551       if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
02552          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
02553       }
02554       if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
02555          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
02556       }
02557       if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
02558          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
02559       }
02560       if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
02561          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
02562       }
02563       if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
02564          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
02565       }
02566       if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
02567          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
02568       }
02569       res = ast_bridge_call(chan, peer, &config);
02570 
02571       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02572       ast_cdr_setdestchan(chan->cdr, peer->name);
02573 
02574       /* Simulate the PBX hanging up */
02575       ast_hangup(peer);
02576       ast_module_user_remove(u);
02577       return res;
02578    } else {
02579       /*! \todo XXX Play a message XXX */
02580       if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02581          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02582       if (option_verbose > 2) 
02583          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02584       res = -1;
02585    }
02586 
02587    ast_module_user_remove(u);
02588 
02589    return res;
02590 }

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

Definition at line 349 of file res_features.c.

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

Referenced by masq_park_call(), and park_call_full().

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

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

Definition at line 1537 of file res_features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

01538 {
01539    struct ast_cdr *cdr_orig = cdr;
01540    while (cdr) {
01541       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
01542          return cdr;
01543       cdr = cdr->next;
01544    }
01545    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
01546 }

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

Definition at line 2123 of file res_features.c.

References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event(), ast_channel::name, and S_OR.

Referenced by do_parking_thread().

02124 {
02125    manager_event(EVENT_FLAG_CALL, s,
02126       "Exten: %s\r\n"
02127       "Channel: %s\r\n"
02128       "CallerID: %s\r\n"
02129       "CallerIDName: %s\r\n\r\n",
02130       parkingexten, 
02131       chan->name,
02132       S_OR(chan->cid.cid_num, "<unknown>"),
02133       S_OR(chan->cid.cid_name, "<unknown>")
02134       );
02135 }

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

Find the context for the transfer.

Definition at line 769 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

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

static int reload ( void   )  [static]

Definition at line 3080 of file res_features.c.

References load_config().

03081 {
03082    return load_config();
03083 }

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

Definition at line 1248 of file res_features.c.

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

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

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

Definition at line 1548 of file res_features.c.

References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), config, and LOG_WARNING.

Referenced by ast_bridge_call().

01549 {
01550    const char *feature;
01551 
01552    if (ast_strlen_zero(features)) {
01553       return;
01554    }
01555 
01556    for (feature = features; *feature; feature++) {
01557       switch (*feature) {
01558       case 'T' :
01559       case 't' :
01560          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
01561          break;
01562       case 'K' :
01563       case 'k' :
01564          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
01565          break;
01566       case 'H' :
01567       case 'h' :
01568          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
01569          break;
01570       case 'W' :
01571       case 'w' :
01572          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
01573          break;
01574       default :
01575          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
01576       }
01577    }
01578 }

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

store context, priority and extension

Definition at line 225 of file res_features.c.

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

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

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

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

Definition at line 1337 of file res_features.c.

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, config, ast_call_feature::feature_mask, FEATURES_COUNT, features_lock, find_dynamic_feature(), and pbx_builtin_getvar_helper().

Referenced by ast_bridge_call().

01338 {
01339    int x;
01340    
01341    ast_clear_flag(config, AST_FLAGS_ALL);
01342 
01343    ast_rwlock_rdlock(&features_lock);
01344    for (x = 0; x < FEATURES_COUNT; x++) {
01345       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01346          continue;
01347 
01348       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01349          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01350 
01351       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01352          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01353    }
01354    ast_rwlock_unlock(&features_lock);
01355    
01356    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01357       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01358 
01359       if (dynamic_features) {
01360          char *tmp = ast_strdupa(dynamic_features);
01361          char *tok;
01362          struct ast_call_feature *feature;
01363 
01364          /* while we have a feature */
01365          while ((tok = strsep(&tmp, "#"))) {
01366             AST_RWLIST_RDLOCK(&feature_list);
01367             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01368                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01369                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01370                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01371                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01372             }
01373             AST_RWLIST_UNLOCK(&feature_list);
01374          }
01375       }
01376    }
01377 }

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

set caller and callee according to the direction

Definition at line 623 of file res_features.c.

References parkeduser::chan, and FEATURE_SENSE_PEER.

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

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

static int unload_module ( void   )  [static]

Definition at line 3111 of file res_features.c.

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

03112 {
03113    ast_module_user_hangup_all();
03114 
03115    ast_manager_unregister("ParkedCalls");
03116    ast_manager_unregister("Park");
03117    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03118    ast_unregister_application(parkcall);
03119    ast_devstate_prov_del("Park");
03120    return ast_unregister_application(parkedcall);
03121 }

static void unmap_features ( void   )  [static]

Definition at line 1238 of file res_features.c.

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

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


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

Definition at line 3127 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 3127 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 1112 of file res_features.c.

Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().

struct ast_cli_entry cli_features[] [static]

Definition at line 2667 of file res_features.c.

struct ast_cli_entry cli_show_features_deprecated [static]

Initial value:

 {
   { "show", "features", NULL },
   handle_showfeatures, NULL,
   NULL }

Definition at line 2662 of file res_features.c.

char courtesytone[256] [static]

Courtesy tone

Definition at line 109 of file res_features.c.

Referenced by load_config(), and park_exec().

char* descrip [static]

Initial value:

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

Definition at line 129 of file res_features.c.

char* descrip2 [static]

Definition at line 139 of file res_features.c.

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 1110 of file res_features.c.

Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().

char mandescr_park[] [static]

Definition at line 2718 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 = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

protects all static variables above

Definition at line 170 of file res_features.c.

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

int parking_offset [static]

Definition at line 114 of file res_features.c.

int parking_start [static]

First available extension for parking

Definition at line 101 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

int parking_stop [static]

Last available extension for parking

Definition at line 102 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

pthread_t parking_thread [static]

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 2630 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 2658 of file res_features.c.

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

Definition at line 127 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 137 of file res_features.c.

int transferdigittimeout [static]

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 Tue Apr 28 22:50:45 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7