Thu Dec 17 13:34:04 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 FEATURES_COUNT   (sizeof(builtin_features) / sizeof(builtin_features[0]))
#define MAX_DIAL_FEATURE_OPTIONS   30

Enumerations

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
static void * ast_bridge_call_thread (void *data)
static void ast_bridge_call_thread_launch (void *data)
int ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature)
 detect a feature before bridging
static struct ast_channelast_feature_request_and_dial (struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language)
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call and read back parked location.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
 Remove all features in the list.
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 Attended transfer ().
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 support routing for one touch call parking
static char * callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
static int check_compat (struct ast_channel *c, struct ast_channel *newchan)
static void check_goto_on_transfer (struct ast_channel *chan)
static void cmd_atxfer (struct ast_channel *a, struct ast_channel *b, struct ast_bridge_config *conf, struct ast_channel *who, char *xferto)
static void dial_features_destroy (void *data)
static void * dial_features_duplicate (void *data)
static int do_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, int sense, const char *toExt, const char *toCont)
 Attended transfer implementation.
static void * do_parking_thread (void *ignore)
 Take care of parked calls and unpark them if needed.
static int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 exec an app by feature
static int feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
 Check the dynamic features.
static int feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, int operation, struct ast_call_feature *feature)
 Helper function for feature_interpret and ast_feature_detect.
static struct ast_call_featurefind_dynamic_feature (const char *name)
 find a feature by name
static int finishup (struct ast_channel *chan)
static int handle_parkedcalls (int fd, int argc, char *argv[])
static int handle_showfeatures (int fd, int argc, char *argv[])
static int load_config (void)
static int load_module (void)
static int manager_park (struct mansession *s, const struct message *m)
static int manager_parking_status (struct mansession *s, const struct message *m)
 Dump lot status.
static int masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, const char *orig_chan_name)
static int masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name)
static int metermaidstate (const char *data)
 metermaids callback from devicestate.c
static void notify_metermaids (char *exten, char *context)
 Notify metermaids that we've changed an extension.
static void park_add_hints (char *context, int start, int stop)
 Add parking hints for all defined parking lots.
static int park_call_exec (struct ast_channel *chan, void *data)
 Park a call.
static int park_call_full (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name, struct parkeduser *pu)
static int park_exec (struct ast_channel *chan, void *data)
 Pickup parked call.
static struct parkeduserpark_space_reserve (struct ast_channel *chan)
static struct ast_cdrpick_unlocked_cdr (struct ast_cdr *cdr)
static void post_manager_event (const char *s, char *parkingexten, struct ast_channel *chan)
static const char * real_ctx (struct ast_channel *transferer, struct ast_channel *transferee)
 Find the context for the transfer.
static int reload (void)
static int remap_feature (const char *name, const char *value)
static void set_bridge_features_on_config (struct ast_bridge_config *config, const char *features)
static void set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri)
 store context, priority and extension
static void set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
static void set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense)
 set caller and callee according to the direction
static int unload_module (void)
static void unmap_features (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Call Features Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .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.

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 80 of file res_features.c.

#define FEATURE_RETURN_PARKFAILED   25

Definition at line 81 of file res_features.c.

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 77 of file res_features.c.

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 78 of file res_features.c.

#define FEATURE_RETURN_SUCCESS   23

Definition at line 79 of file res_features.c.

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 76 of file res_features.c.

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

Definition at line 1105 of file res_features.c.

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

#define MAX_DIAL_FEATURE_OPTIONS   30

Definition at line 73 of file res_features.c.

Referenced by do_parking_thread().


Enumeration Type Documentation

anonymous enum

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 83 of file res_features.c.

00083      {
00084    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00085    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00086    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00087    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00088    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00089    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00090 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 3211 of file res_features.c.

static void __unreg_module ( void   )  [static]

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

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

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

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

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

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

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

Definition at line 270 of file res_features.c.

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

Referenced by ast_bridge_call_thread_launch().

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

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 287 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by do_atxfer().

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

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

detect a feature before bridging

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

Definition at line 1385 of file res_features.c.

References feature_interpret_helper().

Referenced by detect_disconnect().

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

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

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

Referenced by do_atxfer().

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

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

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

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 1122 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.

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

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

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

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

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1152 of file res_features.c.

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

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

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

References config, and do_atxfer().

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

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 667 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.

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

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 778 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.

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

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

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

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

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

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

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

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

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

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

Definition at line 875 of file res_features.c.

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

Referenced by do_atxfer().

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

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

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

Referenced by ast_bridge_call().

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

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

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

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

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

Referenced by load_module().

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

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

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

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

Check the dynamic features.

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

Definition at line 1354 of file res_features.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strdupa, config, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_flags::flags, LOG_DEBUG, ast_channel::name, option_debug, pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

01354                                                                                                                                           {
01355 
01356    char dynamic_features_buf[128];
01357    const char *peer_dynamic_features, *chan_dynamic_features;
01358    struct ast_flags features;
01359    struct ast_call_feature feature;
01360    if (sense == FEATURE_SENSE_CHAN) {
01361       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01362    }
01363    else {
01364       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01365    }
01366 
01367    ast_channel_lock(peer);
01368    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
01369    ast_channel_unlock(peer);
01370 
01371    ast_channel_lock(chan);
01372    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
01373    ast_channel_unlock(chan);
01374 
01375    snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,""));
01376 
01377    if (option_debug > 2) {
01378       ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf);
01379    }
01380 
01381    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
01382 }

static int feature_interpret_helper ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense,
char *  dynamic_features_buf,
struct ast_flags features,
int  operation,
struct ast_call_feature feature 
) [static]

Helper function for feature_interpret and ast_feature_detect.

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

Definition at line 1273 of file res_features.c.

References ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strlen_zero(), ast_test_flag, builtin_features, config, ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURES_COUNT, features_lock, find_dynamic_feature(), ast_call_feature::fname, LOG_DEBUG, LOG_NOTICE, ast_call_feature::operation, option_debug, and ast_call_feature::sname.

Referenced by ast_feature_detect(), and feature_interpret().

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

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

find a feature by name

Definition at line 1164 of file res_features.c.

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

Referenced by feature_interpret_helper(), and set_config_flags().

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

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 758 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

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

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

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

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

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

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

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

static int load_config ( void   )  [static]

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

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

static int load_module ( void   )  [static]

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

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

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

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

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

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

Dump lot status.

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

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

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

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

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

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

Park a call.

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

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

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

Definition at line 420 of file res_features.c.

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

Referenced by ast_park_call(), and masq_park_call().

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

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

Pickup parked call.

Todo:
XXX we would like to wait on both!

Todo:
XXX Play a message XXX

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

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

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

Definition at line 349 of file res_features.c.

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

Referenced by masq_park_call(), and park_call_full().

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

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

Definition at line 1600 of file res_features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

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

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

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

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

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

Find the context for the transfer.

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

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

static int reload ( void   )  [static]

Definition at line 3164 of file res_features.c.

References load_config().

03165 {
03166    return load_config();
03167 }

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

Definition at line 1245 of file res_features.c.

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

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

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

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

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

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

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

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

References parkeduser::chan, and FEATURE_SENSE_PEER.

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

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

static int unload_module ( void   )  [static]

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

03196 {
03197    ast_module_user_hangup_all();
03198 
03199    ast_manager_unregister("ParkedCalls");
03200    ast_manager_unregister("Park");
03201    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03202    ast_unregister_application(parkcall);
03203    ast_devstate_prov_del("Park");
03204    return ast_unregister_application(parkedcall);
03205 }

static void unmap_features ( void   )  [static]

Definition at line 1235 of file res_features.c.

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

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


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

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

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

struct ast_cli_entry cli_features[] [static]

Definition at line 2751 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 2746 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 1107 of file res_features.c.

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

char mandescr_park[] [static]

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

char showparked_help[] [static]

Initial value:

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

Definition at line 2742 of file res_features.c.

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

Definition at line 127 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 137 of file res_features.c.

int transferdigittimeout [static]

Definition at line 119 of file res_features.c.

Referenced by load_config().

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 112 of file res_features.c.

Referenced by load_config().

char xfersound[256] [static]

Call transfer sound

Definition at line 111 of file res_features.c.

Referenced by load_config().


Generated on Thu Dec 17 13:34:05 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7