Fri Feb 19 17:13:14 2010

Asterisk developer's documentation


res_features.c File Reference

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

#include "asterisk.h"
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/global_datastores.h"

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  ast_dial_features
struct  feature_list
struct  parkeduser

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000
#define DEFAULT_PARK_TIME   45000
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
#define FEATURE_RETURN_HANGUP   -1
#define FEATURE_RETURN_KEEPTRYING   24
#define FEATURE_RETURN_PARKFAILED   25
#define FEATURE_RETURN_PASSDIGITS   21
#define FEATURE_RETURN_STOREDIGITS   22
#define FEATURE_RETURN_SUCCESS   23
#define FEATURE_RETURN_SUCCESSBREAK   0
#define FEATURES_COUNT   (sizeof(builtin_features) / sizeof(builtin_features[0]))
#define MAX_DIAL_FEATURE_OPTIONS   30

Enumerations

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

Functions

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

Variables

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

static void __unreg_module ( void   )  [static]

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

01678 {
01679    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
01680    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
01681 
01682    ast_channel_lock(caller);
01683    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
01684    ast_channel_unlock(caller);
01685    if (!ds_caller_features) {
01686       if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
01687          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
01688          return;
01689       }
01690       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
01691          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
01692          ast_channel_datastore_free(ds_caller_features);
01693          return;
01694       }
01695       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
01696       caller_features->is_caller = 1;
01697       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
01698       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
01699       ds_caller_features->data = caller_features;
01700       ast_channel_lock(caller);
01701       ast_channel_datastore_add(caller, ds_caller_features);
01702       ast_channel_unlock(caller);
01703    } else {
01704       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
01705        * flags over from the atxfer to the caller */
01706       return;
01707    }
01708 
01709    ast_channel_lock(callee);
01710    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
01711    ast_channel_unlock(callee);
01712    if (!ds_callee_features) {
01713       if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
01714          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
01715          return;
01716       }
01717       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
01718          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
01719          ast_channel_datastore_free(ds_callee_features);
01720          return;
01721       }
01722       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
01723       callee_features->is_caller = 0;
01724       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
01725       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
01726       ds_callee_features->data = callee_features;
01727       ast_channel_lock(callee);
01728       ast_channel_datastore_add(callee, ds_callee_features);
01729       ast_channel_unlock(callee);
01730    }
01731 
01732    return;
01733 }

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

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

01419                                                                                                                            {
01420 
01421    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01422 }

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

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

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

Park a call via a masqueraded channel.

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

Definition at line 608 of file res_features.c.

References masq_park_call().

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

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

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

Park a call and read back parked location.

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

Definition at line 552 of file res_features.c.

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

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

char* ast_parking_ext ( void   ) 

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

Definition at line 207 of file res_features.c.

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

00208 {
00209    return parking_ext;
00210 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

02902 {
02903    struct ast_channel *cur = NULL;
02904    int res = -1;
02905 
02906    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02907       if (!cur->pbx && 
02908          (cur != chan) &&
02909          (chan->pickupgroup & cur->callgroup) &&
02910          ((cur->_state == AST_STATE_RINGING) ||
02911           (cur->_state == AST_STATE_RING))) {
02912             break;
02913       }
02914       ast_channel_unlock(cur);
02915    }
02916    if (cur) {
02917       if (option_debug)
02918          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02919       res = ast_answer(chan);
02920       if (res)
02921          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02922       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02923       if (res)
02924          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02925       res = ast_channel_masquerade(cur, chan);
02926       if (res)
02927          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02928       ast_channel_unlock(cur);
02929    } else   {
02930       if (option_debug)
02931          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02932    }
02933    return res;
02934 }

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

01157 {
01158    if (!feature) {
01159       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01160          return;
01161    }
01162   
01163    AST_RWLIST_WRLOCK(&feature_list);
01164    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01165    AST_RWLIST_UNLOCK(&feature_list);
01166 
01167    if (option_verbose >= 2) {
01168       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01169    }
01170 }

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

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

01174 {
01175    if (!feature)
01176       return;
01177 
01178    AST_RWLIST_WRLOCK(&feature_list);
01179    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01180    AST_RWLIST_UNLOCK(&feature_list);
01181    
01182    free(feature);
01183 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1186 of file res_features.c.

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

01187 {
01188    struct ast_call_feature *feature;
01189 
01190    AST_RWLIST_WRLOCK(&feature_list);
01191    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01192       free(feature);
01193    }
01194    AST_RWLIST_UNLOCK(&feature_list);
01195 }

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

References config, and do_atxfer().

01134 {
01135    return do_atxfer(chan, peer, config, sense, NULL, NULL);
01136 }

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

Definition at line 668 of file res_features.c.

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

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

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

Definition at line 779 of file res_features.c.

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

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

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

Definition at line 752 of file res_features.c.

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

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

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

support routing for one touch call parking

Definition at line 634 of file res_features.c.

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

Referenced by do_atxfer().

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

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

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

02259 {
02260    int i = 0;
02261    enum {
02262       OPT_CALLEE_REDIRECT   = 't',
02263       OPT_CALLER_REDIRECT   = 'T',
02264       OPT_CALLEE_AUTOMON    = 'w',
02265       OPT_CALLER_AUTOMON    = 'W',
02266       OPT_CALLEE_DISCONNECT = 'h',
02267       OPT_CALLER_DISCONNECT = 'H',
02268       OPT_CALLEE_PARKCALL   = 'k',
02269       OPT_CALLER_PARKCALL   = 'K',
02270    };
02271 
02272    memset(options, 0, len);
02273    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02274       options[i++] = OPT_CALLER_REDIRECT;
02275    }
02276    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02277       options[i++] = OPT_CALLER_AUTOMON;
02278    }
02279    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02280       options[i++] = OPT_CALLER_DISCONNECT;
02281    }
02282    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02283       options[i++] = OPT_CALLER_PARKCALL;
02284    }
02285 
02286    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02287       options[i++] = OPT_CALLEE_REDIRECT;
02288    }
02289    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02290       options[i++] = OPT_CALLEE_AUTOMON;
02291    }
02292    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02293       options[i++] = OPT_CALLEE_DISCONNECT;
02294    }
02295    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02296       options[i++] = OPT_CALLEE_PARKCALL;
02297    }
02298 
02299    return options;
02300 }

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

Definition at line 876 of file res_features.c.

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

Referenced by do_atxfer().

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

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Definition at line 232 of file res_features.c.

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

Referenced by builtin_blindtransfer().

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

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

Definition at line 1735 of file res_features.c.

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

Referenced by ast_bridge_call().

01736 {
01737    int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER;
01738    char *context = strchr(xferto, '@');;
01739    if (context)
01740       *context++ = '\0';
01741    do_atxfer(a, b, conf, sense, xferto, context);
01742 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 193 of file res_features.c.

References ast_free.

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

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

Definition at line 180 of file res_features.c.

References ast_calloc.

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

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

Attended transfer implementation.

Parameters:
chan transfered user
peer person transfering call
config 
sense feature options
toExt 
toCont This is the actual implementation of attended transfer, it can be activated as a regular feature or through the AMI. "toExt" is the extension to transfer to (default: ask for it on the transferer channel) "toCont" is the context to transfer to (default: the one in which the transferer is)
Returns:
-1 on failure

Definition at line 902 of file res_features.c.

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

Referenced by builtin_atxfer(), and cmd_atxfer().

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

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

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

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

01213 {
01214    struct ast_app *app;
01215    struct ast_call_feature *feature = data;
01216    struct ast_channel *work, *idle;
01217    int res;
01218 
01219    if (!feature) { /* shouldn't ever happen! */
01220       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01221       return -1; 
01222    }
01223 
01224    if (sense == FEATURE_SENSE_CHAN) {
01225       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01226          return FEATURE_RETURN_KEEPTRYING;
01227       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01228          work = chan;
01229          idle = peer;
01230       } else {
01231          work = peer;
01232          idle = chan;
01233       }
01234    } else {
01235       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01236          return FEATURE_RETURN_KEEPTRYING;
01237       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01238          work = peer;
01239          idle = chan;
01240       } else {
01241          work = chan;
01242          idle = peer;
01243       }
01244    }
01245 
01246    if (!(app = pbx_findapp(feature->app))) {
01247       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01248       return -2;
01249    }
01250 
01251    ast_autoservice_start(idle);
01252    
01253    if (!ast_strlen_zero(feature->moh_class))
01254       ast_moh_start(idle, feature->moh_class, NULL);
01255 
01256    res = pbx_exec(work, app, feature->app_args);
01257 
01258    if (!ast_strlen_zero(feature->moh_class))
01259       ast_moh_stop(idle);
01260 
01261    ast_autoservice_stop(idle);
01262 
01263    if (res)
01264       return FEATURE_RETURN_SUCCESSBREAK;
01265    
01266    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01267 }

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

01388                                                                                                                                           {
01389 
01390    char dynamic_features_buf[128];
01391    const char *peer_dynamic_features, *chan_dynamic_features;
01392    struct ast_flags features;
01393    struct ast_call_feature feature;
01394    if (sense == FEATURE_SENSE_CHAN) {
01395       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01396    }
01397    else {
01398       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01399    }
01400 
01401    ast_channel_lock(peer);
01402    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
01403    ast_channel_unlock(peer);
01404 
01405    ast_channel_lock(chan);
01406    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
01407    ast_channel_unlock(chan);
01408 
01409    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,""));
01410 
01411    if (option_debug > 2) {
01412       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);
01413    }
01414 
01415    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
01416 }

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

01310 {
01311    int x;
01312    struct ast_call_feature *tmpfeature;
01313    char *tmp, *tok;
01314    int res = FEATURE_RETURN_PASSDIGITS;
01315    int feature_detected = 0;
01316 
01317    if (!(peer && chan && config) && operation) {
01318       return -1; /* can not run feature operation */
01319    }
01320 
01321    ast_rwlock_rdlock(&features_lock);
01322    for (x = 0; x < FEATURES_COUNT; x++) {
01323       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
01324           !ast_strlen_zero(builtin_features[x].exten)) {
01325          /* Feature is up for consideration */
01326          if (!strcmp(builtin_features[x].exten, code)) {
01327             if (option_debug > 2) {
01328                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);
01329             }
01330             if (operation) {
01331                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01332             }
01333             memcpy(feature, &builtin_features[x], sizeof(feature));
01334             feature_detected = 1;
01335             break;
01336          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01337             if (res == FEATURE_RETURN_PASSDIGITS)
01338                res = FEATURE_RETURN_STOREDIGITS;
01339          }
01340       }
01341    }
01342    ast_rwlock_unlock(&features_lock);
01343 
01344    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
01345       return res;
01346    }
01347 
01348    tmp = dynamic_features_buf;
01349 
01350    while ((tok = strsep(&tmp, "#"))) {
01351       AST_RWLIST_RDLOCK(&feature_list);
01352       if (!(tmpfeature = find_dynamic_feature(tok))) {
01353          AST_RWLIST_UNLOCK(&feature_list);
01354          continue;
01355       }
01356 
01357       /* Feature is up for consideration */
01358       if (!strcmp(tmpfeature->exten, code)) {
01359          if (option_debug > 2) {
01360             ast_log(LOG_NOTICE, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
01361          }
01362          if (operation) {
01363             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
01364          }
01365          memcpy(feature, tmpfeature, sizeof(feature));
01366          if (res != FEATURE_RETURN_KEEPTRYING) {
01367             AST_RWLIST_UNLOCK(&feature_list);
01368             break;
01369          }
01370          res = FEATURE_RETURN_PASSDIGITS;
01371       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
01372          res = FEATURE_RETURN_STOREDIGITS;
01373 
01374       AST_RWLIST_UNLOCK(&feature_list);
01375    }
01376 
01377    return res;
01378 }

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

find a feature by name

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

01199 {
01200    struct ast_call_feature *tmp;
01201 
01202    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01203       if (!strcasecmp(tmp->sname, name)) {
01204          break;
01205       }
01206    }
01207 
01208    return tmp;
01209 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 759 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

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

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

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

02756 {
02757    struct parkeduser *cur;
02758    int numparked = 0;
02759 
02760    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02761       , "Context", "Extension", "Pri", "Timeout");
02762 
02763    ast_mutex_lock(&parking_lock);
02764 
02765    for (cur = parkinglot; cur; cur = cur->next) {
02766       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02767          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02768          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02769 
02770       numparked++;
02771    }
02772    ast_mutex_unlock(&parking_lock);
02773    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02774 
02775 
02776    return RESULT_SUCCESS;
02777 }

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

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

02714 {
02715    int i;
02716    struct ast_call_feature *feature;
02717    char format[] = "%-25s %-7s %-7s\n";
02718 
02719    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02720    ast_cli(fd, format, "---------------", "-------", "-------");
02721 
02722    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02723 
02724    ast_rwlock_rdlock(&features_lock);
02725    for (i = 0; i < FEATURES_COUNT; i++)
02726       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02727    ast_rwlock_unlock(&features_lock);
02728 
02729    ast_cli(fd, "\n");
02730    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02731    ast_cli(fd, format, "---------------", "-------", "-------");
02732    if (AST_RWLIST_EMPTY(&feature_list)) {
02733       ast_cli(fd, "(none)\n");
02734    } else {
02735       AST_RWLIST_RDLOCK(&feature_list);
02736       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
02737          ast_cli(fd, format, feature->sname, "no def", feature->exten);
02738       }
02739       AST_RWLIST_UNLOCK(&feature_list);
02740    }
02741    ast_cli(fd, "\nCall parking\n");
02742    ast_cli(fd, "------------\n");
02743    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02744    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02745    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02746    ast_cli(fd,"\n");
02747    
02748    return RESULT_SUCCESS;
02749 }

static int load_config ( void   )  [static]

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

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

static int load_module ( void   )  [static]

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

03207 {
03208    int res;
03209    
03210    memset(parking_ext, 0, sizeof(parking_ext));
03211    memset(parking_con, 0, sizeof(parking_con));
03212 
03213    if ((res = load_config()))
03214       return res;
03215    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03216    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03217    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03218    if (!res)
03219       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03220    if (!res) {
03221       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03222       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03223          "Park a channel", mandescr_park); 
03224    }
03225 
03226    res |= ast_devstate_prov_add("Park", metermaidstate);
03227 
03228    return res;
03229 }

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

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

02847 {
02848    const char *channel = astman_get_header(m, "Channel");
02849    const char *channel2 = astman_get_header(m, "Channel2");
02850    const char *timeout = astman_get_header(m, "Timeout");
02851    char buf[BUFSIZ];
02852    int to = 0;
02853    int res = 0;
02854    int parkExt = 0;
02855    struct ast_channel *ch1, *ch2;
02856 
02857    if (ast_strlen_zero(channel)) {
02858       astman_send_error(s, m, "Channel not specified");
02859       return 0;
02860    }
02861 
02862    if (ast_strlen_zero(channel2)) {
02863       astman_send_error(s, m, "Channel2 not specified");
02864       return 0;
02865    }
02866 
02867    ch1 = ast_get_channel_by_name_locked(channel);
02868    if (!ch1) {
02869       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02870       astman_send_error(s, m, buf);
02871       return 0;
02872    }
02873 
02874    ch2 = ast_get_channel_by_name_locked(channel2);
02875    if (!ch2) {
02876       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02877       astman_send_error(s, m, buf);
02878       ast_channel_unlock(ch1);
02879       return 0;
02880    }
02881 
02882    if (!ast_strlen_zero(timeout)) {
02883       sscanf(timeout, "%30d", &to);
02884    }
02885 
02886    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02887    if (!res) {
02888       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02889       astman_send_ack(s, m, "Park successful");
02890    } else {
02891       astman_send_error(s, m, "Park failure");
02892    }
02893 
02894    ast_channel_unlock(ch1);
02895    ast_channel_unlock(ch2);
02896 
02897    return 0;
02898 }

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

Dump lot status.

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

02800 {
02801    struct parkeduser *cur;
02802    const char *id = astman_get_header(m, "ActionID");
02803    char idText[256] = "";
02804 
02805    if (!ast_strlen_zero(id))
02806       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02807 
02808    astman_send_ack(s, m, "Parked calls will follow");
02809 
02810    ast_mutex_lock(&parking_lock);
02811 
02812    for (cur = parkinglot; cur; cur = cur->next) {
02813       astman_append(s, "Event: ParkedCall\r\n"
02814          "Exten: %d\r\n"
02815          "Channel: %s\r\n"
02816          "From: %s\r\n"
02817          "Timeout: %ld\r\n"
02818          "CallerID: %s\r\n"
02819          "CallerIDName: %s\r\n"
02820          "%s"
02821          "\r\n",
02822          cur->parkingnum, cur->chan->name, cur->peername,
02823          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02824          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02825          S_OR(cur->chan->cid.cid_name, ""),
02826          idText);
02827    }
02828 
02829    astman_append(s,
02830       "Event: ParkedCallsComplete\r\n"
02831       "%s"
02832       "\r\n",idText);
02833 
02834    ast_mutex_unlock(&parking_lock);
02835 
02836    return RESULT_SUCCESS;
02837 }

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

Definition at line 557 of file res_features.c.

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

Referenced by ast_masq_park_call(), and masq_park_call_announce().

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

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

Definition at line 613 of file res_features.c.

References masq_park_call().

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

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

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

metermaids callback from devicestate.c

Definition at line 328 of file res_features.c.

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

Referenced by load_module().

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

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

Notify metermaids that we've changed an extension.

Definition at line 317 of file res_features.c.

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

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

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

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

Add parking hints for all defined parking lots.

Definition at line 2937 of file res_features.c.

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

02938 {
02939    int numext;
02940    char device[AST_MAX_EXTENSION];
02941    char exten[10];
02942 
02943    for (numext = start; numext <= stop; numext++) {
02944       snprintf(exten, sizeof(exten), "%d", numext);
02945       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02946       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02947    }
02948 }

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

Park a call.

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

02494 {
02495    /* Cache the original channel name in case we get masqueraded in the middle
02496     * of a park--it is still theoretically possible for a transfer to happen before
02497     * we get here, but it is _really_ unlikely */
02498    char *orig_chan_name = ast_strdupa(chan->name);
02499    char orig_exten[AST_MAX_EXTENSION];
02500    int orig_priority = chan->priority;
02501 
02502    /* Data is unused at the moment but could contain a parking
02503       lot context eventually */
02504    int res = 0;
02505    struct ast_module_user *u;
02506 
02507    u = ast_module_user_add(chan);
02508 
02509    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
02510 
02511    /* Setup the exten/priority to be s/1 since we don't know
02512       where this call should return */
02513    strcpy(chan->exten, "s");
02514    chan->priority = 1;
02515    /* Answer if call is not up */
02516    if (chan->_state != AST_STATE_UP)
02517       res = ast_answer(chan);
02518    /* Sleep to allow VoIP streams to settle down */
02519    if (!res)
02520       res = ast_safe_sleep(chan, 1000);
02521    /* Park the call */
02522    if (!res) {
02523       res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name);
02524       /* Continue on in the dialplan */
02525       if (res == 1) {
02526          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
02527          chan->priority = orig_priority;
02528          res = 0;
02529       } else if (!res) {
02530          res = 1;
02531       }
02532    }
02533 
02534    ast_module_user_remove(u);
02535 
02536    return res;
02537 }

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

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

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

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

01635 {
01636    struct ast_cdr *cdr_orig = cdr;
01637    while (cdr) {
01638       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
01639          return cdr;
01640       cdr = cdr->next;
01641    }
01642    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
01643 }

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

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

02245 {
02246    manager_event(EVENT_FLAG_CALL, s,
02247       "Exten: %s\r\n"
02248       "Channel: %s\r\n"
02249       "CallerID: %s\r\n"
02250       "CallerIDName: %s\r\n\r\n",
02251       parkingexten, 
02252       chan->name,
02253       S_OR(chan->cid.cid_num, "<unknown>"),
02254       S_OR(chan->cid.cid_name, "<unknown>")
02255       );
02256 }

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

Find the context for the transfer.

Definition at line 767 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

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

static int reload ( void   )  [static]

Definition at line 3201 of file res_features.c.

References load_config().

03202 {
03203    return load_config();
03204 }

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

Definition at line 1279 of file res_features.c.

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

01280 {
01281    int x, res = -1;
01282 
01283    ast_rwlock_wrlock(&features_lock);
01284    for (x = 0; x < FEATURES_COUNT; x++) {
01285       if (strcasecmp(builtin_features[x].sname, name))
01286          continue;
01287 
01288       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01289       res = 0;
01290       break;
01291    }
01292    ast_rwlock_unlock(&features_lock);
01293 
01294    return res;
01295 }

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

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

01646 {
01647    const char *feature;
01648 
01649    if (ast_strlen_zero(features)) {
01650       return;
01651    }
01652 
01653    for (feature = features; *feature; feature++) {
01654       switch (*feature) {
01655       case 'T' :
01656       case 't' :
01657          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
01658          break;
01659       case 'K' :
01660       case 'k' :
01661          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
01662          break;
01663       case 'H' :
01664       case 'h' :
01665          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
01666          break;
01667       case 'W' :
01668       case 'w' :
01669          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
01670          break;
01671       default :
01672          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
01673       }
01674    }
01675 }

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

01425 {
01426    int x;
01427 
01428    ast_clear_flag(config, AST_FLAGS_ALL);
01429 
01430    ast_rwlock_rdlock(&features_lock);
01431    for (x = 0; x < FEATURES_COUNT; x++) {
01432       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01433          continue;
01434 
01435       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01436          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01437 
01438       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01439          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01440    }
01441    ast_rwlock_unlock(&features_lock);
01442 
01443    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01444       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01445 
01446       if (dynamic_features) {
01447          char *tmp = ast_strdupa(dynamic_features);
01448          char *tok;
01449          struct ast_call_feature *feature;
01450 
01451          /* while we have a feature */
01452          while ((tok = strsep(&tmp, "#"))) {
01453             AST_RWLIST_RDLOCK(&feature_list);
01454             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01455                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01456                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01457                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01458                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01459             }
01460             AST_RWLIST_UNLOCK(&feature_list);
01461          }
01462       }
01463    }
01464 }

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

set caller and callee according to the direction

Definition at line 621 of file res_features.c.

References parkeduser::chan, and FEATURE_SENSE_PEER.

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

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

static int unload_module ( void   )  [static]

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

03233 {
03234    ast_module_user_hangup_all();
03235 
03236    ast_manager_unregister("ParkedCalls");
03237    ast_manager_unregister("Park");
03238    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03239    ast_unregister_application(parkcall);
03240    ast_devstate_prov_del("Park");
03241    return ast_unregister_application(parkedcall);
03242 }

static void unmap_features ( void   )  [static]

Definition at line 1269 of file res_features.c.

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

01270 {
01271    int x;
01272 
01273    ast_rwlock_wrlock(&features_lock);
01274    for (x = 0; x < FEATURES_COUNT; x++)
01275       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01276    ast_rwlock_unlock(&features_lock);
01277 }


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 3248 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 3248 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 1143 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 2788 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 2783 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 1141 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 2839 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 2751 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 2779 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 Fri Feb 19 17:13:15 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7