Thu Oct 11 06:44:12 2012

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 <signal.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"

Include dependency graph for res_features.c:

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)
}
enum  feature_interpret_op { FEATURE_INTERPRET_DETECT, FEATURE_INTERPRET_DO, FEATURE_INTERPRET_CHECK }

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
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.
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_list
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_list
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 clear_dialed_interfaces (struct ast_channel *chan)
static void dial_features_destroy (void *data)
static void * dial_features_duplicate (void *data)
static void * do_parking_thread (void *ignore)
 Take care of parked calls and unpark them if needed.
static int feature_check (struct ast_channel *chan, struct ast_flags *features, char *code)
 Check if a feature exists.
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, feature_interpret_op operation, struct ast_call_feature *feature)
 Helper function for feature_interpret and ast_feature_detect.
static struct ast_channelfeature_request_and_dial (struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language)
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 int pickup_do (struct ast_channel *chan, struct ast_channel *target)
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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static int adsipark
static const struct
ast_module_info
ast_module_info = &__mod_info
static int atxfernoanswertimeout
static struct ast_call_feature builtin_features []
static struct ast_cli_entry cli_features []
static struct ast_cli_entry cli_show_features_deprecated
static char courtesytone [256]
static char * descrip
static char * descrip2
struct 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 122 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

Definition at line 119 of file res_features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 120 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 117 of file res_features.c.

Referenced by load_config().

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 118 of file res_features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 125 of file res_features.c.

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 130 of file res_features.c.

#define FEATURE_RETURN_PARKFAILED   25

Definition at line 131 of file res_features.c.

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 127 of file res_features.c.

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 128 of file res_features.c.

#define FEATURE_RETURN_SUCCESS   23

Definition at line 129 of file res_features.c.

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 126 of file res_features.c.

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

#define MAX_DIAL_FEATURE_OPTIONS   30

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

00133      {
00134    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00135    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00136    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00137    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00138    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00139    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00140 };

Enumerator:
FEATURE_INTERPRET_DETECT 
FEATURE_INTERPRET_DO 
FEATURE_INTERPRET_CHECK 

Definition at line 142 of file res_features.c.

00142              {
00143    FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */
00144    FEATURE_INTERPRET_DO,     /* Used by feature_interpret */
00145    FEATURE_INTERPRET_CHECK,  /* Used by feature_check */
00146 } feature_interpret_op;


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 3760 of file res_features.c.

static void __unreg_module ( void   )  [static]

Definition at line 3760 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 2041 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(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, ast_dial_features::features_callee, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, ast_datastore::inheritance, ast_dial_features::is_caller, and LOG_WARNING.

Referenced by ast_bridge_call().

02042 {
02043    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
02044    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
02045 
02046    ast_channel_lock(caller);
02047    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
02048    ast_channel_unlock(caller);
02049    if (!ds_caller_features) {
02050       if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
02051          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
02052          return;
02053       }
02054       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
02055          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02056          ast_channel_datastore_free(ds_caller_features);
02057          return;
02058       }
02059       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
02060       caller_features->is_caller = 1;
02061       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
02062       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
02063       ds_caller_features->data = caller_features;
02064       ast_channel_lock(caller);
02065       ast_channel_datastore_add(caller, ds_caller_features);
02066       ast_channel_unlock(caller);
02067    } else {
02068       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
02069        * flags over from the atxfer to the caller */
02070       return;
02071    }
02072 
02073    ast_channel_lock(callee);
02074    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
02075    ast_channel_unlock(callee);
02076    if (!ds_callee_features) {
02077       if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
02078          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
02079          return;
02080       }
02081       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
02082          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02083          ast_channel_datastore_free(ds_callee_features);
02084          return;
02085       }
02086       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
02087       callee_features->is_caller = 0;
02088       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
02089       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
02090       ds_callee_features->data = callee_features;
02091       ast_channel_lock(callee);
02092       ast_channel_datastore_add(callee, ds_callee_features);
02093       ast_channel_unlock(callee);
02094    }
02095 
02096    return;
02097 }

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

Definition at line 473 of file res_features.c.

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

Referenced by park_call_full().

00474 {
00475    int res;
00476    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00477    char tmp[256];
00478    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00479 
00480    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00481    message[0] = tmp;
00482    res = ast_adsi_load_session(chan, NULL, 0, 1);
00483    if (res == -1)
00484       return res;
00485    return ast_adsi_print(chan, message, justify, 1);
00486 }

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

References ast_channel::_state, ast_cdr::accountcode, ast_channel::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_DIALED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NOANSWER, ast_cdr_setaccount(), 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_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, 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_opt_transmit_silence, AST_OPTION_AUDIO_MODE, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, 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_write(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, clear_dialed_interfaces(), ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_bridge_config::end_sound, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, 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_bridge_config::play_warning, ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, VERBOSE_PREFIX_2, ast_channel::visible_indication, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

02116 {
02117    /* Copy voice back and forth between the two channels.  Give the peer
02118       the ability to transfer calls with '#<extension' syntax. */
02119    struct ast_frame *f;
02120    struct ast_channel *who;
02121    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
02122    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
02123    char orig_channame[AST_MAX_EXTENSION];
02124    char orig_peername[AST_MAX_EXTENSION];
02125 
02126    int res;
02127    int diff;
02128    int hasfeatures=0;
02129    int hadfeatures=0;
02130    int autoloopflag;
02131    int sendingdtmfdigit = 0;
02132    struct ast_option_header *aoh;
02133    struct ast_bridge_config backup_config;
02134    struct ast_cdr *bridge_cdr = NULL;
02135    struct ast_cdr *orig_peer_cdr = NULL;
02136    struct ast_cdr *chan_cdr = chan->cdr; /* the proper chan cdr, if there are forked cdrs */
02137    struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */
02138    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02139    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02140    struct ast_silence_generator *silgen = NULL;
02141 
02142    memset(&backup_config, 0, sizeof(backup_config));
02143 
02144    config->start_time = ast_tvnow();
02145 
02146    if (chan && peer) {
02147       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
02148       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
02149    } else if (chan) {
02150       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
02151    }
02152 
02153    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
02154    add_features_datastores(chan, peer, config);
02155 
02156    /* This is an interesting case.  One example is if a ringing channel gets redirected to
02157     * an extension that picks up a parked call.  This will make sure that the call taken
02158     * out of parking gets told that the channel it just got bridged to is still ringing. */
02159    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
02160       ast_indicate(peer, AST_CONTROL_RINGING);
02161    }
02162 
02163    if (monitor_ok) {
02164       const char *monitor_exec;
02165       struct ast_channel *src = NULL;
02166       if (!monitor_app) { 
02167          if (!(monitor_app = pbx_findapp("Monitor")))
02168             monitor_ok=0;
02169       }
02170       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
02171          src = chan;
02172       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
02173          src = peer;
02174       if (monitor_app && src) {
02175          char *tmp = ast_strdupa(monitor_exec);
02176          pbx_exec(src, monitor_app, tmp);
02177       }
02178    }
02179 
02180    set_config_flags(chan, peer, config);
02181    config->firstpass = 1;
02182 
02183    /* Answer if need be */
02184    if (ast_answer(chan))
02185       return -1;
02186 
02187    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
02188    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
02189    orig_peer_cdr = peer_cdr;
02190    
02191    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
02192          
02193       if (chan_cdr) {
02194          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
02195          ast_cdr_update(chan);
02196          bridge_cdr = ast_cdr_dup(chan_cdr);
02197          /* rip any forked CDR's off of the chan_cdr and attach
02198           * them to the bridge_cdr instead */
02199          bridge_cdr->next = chan_cdr->next;
02200          chan_cdr->next = NULL;
02201          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02202          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02203          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
02204             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02205          }
02206          ast_cdr_setaccount(peer, chan->accountcode);
02207       } else {
02208          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
02209          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
02210          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
02211          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
02212          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
02213          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02214          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02215          ast_cdr_setcid(bridge_cdr, chan);
02216          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
02217          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
02218          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
02219          /* Destination information */
02220          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
02221          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
02222          if (peer_cdr) {
02223             bridge_cdr->start = peer_cdr->start;
02224             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02225          } else {
02226             ast_cdr_start(bridge_cdr);
02227          }
02228       }
02229       /* peer_cdr->answer will be set when a macro runs on the peer;
02230          in that case, the bridge answer will be delayed while the
02231          macro plays on the peer channel. The peer answered the call
02232          before the macro started playing. To the phone system,
02233          this is billable time for the call, even tho the caller
02234          hears nothing but ringing while the macro does its thing. */
02235 
02236       /* Another case where the peer cdr's time will be set, is when
02237          A self-parks by pickup up phone and dialing 700, then B
02238          picks up A by dialing its parking slot; there may be more 
02239          practical paths that get the same result, tho... in which
02240          case you get the previous answer time from the Park... which
02241          is before the bridge's start time, so I added in the 
02242          tvcmp check to the if below */
02243 
02244       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
02245          ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
02246          ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
02247          if (chan_cdr) {
02248             ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
02249             ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
02250          }
02251       } else {
02252          ast_cdr_answer(bridge_cdr);
02253          if (chan_cdr) {
02254             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
02255          }
02256       }
02257       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
02258          if (chan_cdr) {
02259             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
02260          }
02261          if (peer_cdr) {
02262             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
02263          }
02264       }
02265       /* the DIALED flag may be set if a dialed channel is transfered
02266        * and then bridged to another channel.  In order for the
02267        * bridge CDR to be written, the DIALED flag must not be
02268        * present. */
02269       ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
02270    }
02271 
02272    /* If we are bridging a call, stop worrying about forwarding loops. We presume that if
02273     * a call is being bridged, that the humans in charge know what they're doing. If they
02274     * don't, well, what can we do about that? */
02275    clear_dialed_interfaces(chan);
02276    clear_dialed_interfaces(peer);
02277 
02278    for (;;) {
02279       struct ast_channel *other; /* used later */
02280 
02281       res = ast_channel_bridge(chan, peer, config, &f, &who);
02282       
02283       /* When frame is not set, we are probably involved in a situation
02284          where we've timed out.
02285          When frame is set, we'll come thru this code twice; once for DTMF_BEGIN
02286          and also for DTMF_END. If we flow into the following 'if' for both, then 
02287          our wait times are cut in half, as both will subtract from the
02288          feature_timer. Not good!
02289       */
02290       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
02291          /* Update time limit for next pass */
02292          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
02293          if (res == AST_BRIDGE_RETRY) {
02294             /* The feature fully timed out but has not been updated. Skip
02295              * the potential round error from the diff calculation and
02296              * explicitly set to expired. */
02297             config->feature_timer = -1;
02298          } else {
02299             config->feature_timer -= diff;
02300          }
02301 
02302          if (hasfeatures) {
02303             /* Running on backup config, meaning a feature might be being
02304                activated, but that's no excuse to keep things going 
02305                indefinitely! */
02306             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
02307                if (option_debug)
02308                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
02309                config->feature_timer = 0;
02310                who = chan;
02311                if (f)
02312                   ast_frfree(f);
02313                f = NULL;
02314                res = 0;
02315             } else if (config->feature_timer <= 0) {
02316                /* Not *really* out of time, just out of time for
02317                   digits to come in for features. */
02318                if (option_debug)
02319                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
02320                if (!ast_strlen_zero(peer_featurecode)) {
02321                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
02322                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
02323                }
02324                if (!ast_strlen_zero(chan_featurecode)) {
02325                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
02326                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
02327                }
02328                if (f)
02329                   ast_frfree(f);
02330                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02331                if (!hasfeatures) {
02332                   /* Restore original (possibly time modified) bridge config */
02333                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02334                   memset(&backup_config, 0, sizeof(backup_config));
02335                }
02336                hadfeatures = hasfeatures;
02337                /* Continue as we were */
02338                continue;
02339             } else if (!f) {
02340                /* The bridge returned without a frame and there is a feature in progress.
02341                 * However, we don't think the feature has quite yet timed out, so just
02342                 * go back into the bridge. */
02343                continue;
02344             }
02345          } else {
02346             if (config->feature_timer <=0) {
02347                /* We ran out of time */
02348                config->feature_timer = 0;
02349                who = chan;
02350                if (f)
02351                   ast_frfree(f);
02352                f = NULL;
02353                res = 0;
02354             }
02355          }
02356       }
02357       if (res < 0) {
02358          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
02359             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
02360          goto before_you_go;
02361       }
02362       
02363       if (!f || (f->frametype == AST_FRAME_CONTROL &&
02364             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
02365                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
02366          res = -1;
02367          break;
02368       }
02369       /* many things should be sent to the 'other' channel */
02370       other = (who == chan) ? peer : chan;
02371       if (f->frametype == AST_FRAME_CONTROL) {
02372          switch (f->subclass) {
02373          case AST_CONTROL_RINGING:
02374          case AST_CONTROL_FLASH:
02375          case -1:
02376             ast_indicate(other, f->subclass);
02377             break;
02378          case AST_CONTROL_HOLD:
02379          case AST_CONTROL_UNHOLD:
02380             ast_indicate_data(other, f->subclass, f->data, f->datalen);
02381             break;
02382          case AST_CONTROL_OPTION:
02383             aoh = f->data;
02384             /* Forward option Requests, but only ones we know are safe
02385              * These are ONLY sent by chan_iax2 and I'm not convinced that
02386              * they are useful. I haven't deleted them entirely because I
02387              * just am not sure of the ramifications of removing them. */
02388             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02389                   switch (ntohs(aoh->option)) {
02390                case AST_OPTION_TONE_VERIFY:
02391                case AST_OPTION_TDD:
02392                case AST_OPTION_RELAXDTMF:
02393                case AST_OPTION_AUDIO_MODE:
02394                   ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
02395                      f->datalen - sizeof(struct ast_option_header), 0);
02396                }
02397             }
02398             break;
02399          }
02400       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02401          struct ast_flags *cfg;
02402          char dtmfcode[2] = { f->subclass, };
02403          size_t featurelen;
02404 
02405          if (who == chan) {
02406             featurelen = strlen(chan_featurecode);
02407             cfg = &(config->features_caller);
02408          } else {
02409             featurelen = strlen(peer_featurecode);
02410             cfg = &(config->features_callee);
02411          }
02412          /* Take a peek if this (possibly) matches a feature. If not, just pass this
02413           * DTMF along untouched. If this is not the first digit of a multi-digit code
02414           * then we need to fall through and stream the characters if it matches */
02415          if (featurelen == 0
02416             && feature_check(chan, cfg, &dtmfcode[0]) == FEATURE_RETURN_PASSDIGITS) {
02417             if (option_debug > 3) {
02418                ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n");
02419             }
02420             ast_write(other, f);
02421             sendingdtmfdigit = 1;
02422          } else {
02423             /* If ast_opt_transmit_silence is set, then we need to make sure we are
02424              * transmitting something while we hold on to the DTMF waiting for a
02425              * feature. */
02426             if (!silgen && ast_opt_transmit_silence) {
02427                silgen = ast_channel_start_silence_generator(other);
02428             }
02429             if (option_debug > 3) {
02430                ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n");
02431             }
02432          }
02433       } else if (f->frametype == AST_FRAME_DTMF) {
02434          char *featurecode;
02435          int sense;
02436 
02437          hadfeatures = hasfeatures;
02438          /* This cannot overrun because the longest feature is one shorter than our buffer */
02439          if (who == chan) {
02440             sense = FEATURE_SENSE_CHAN;
02441             featurecode = chan_featurecode;
02442          } else  {
02443             sense = FEATURE_SENSE_PEER;
02444             featurecode = peer_featurecode;
02445          }
02446 
02447          if (sendingdtmfdigit == 1) {
02448             /* We let the BEGIN go through happily, so let's not bother with the END,
02449              * since we already know it's not something we bother with */
02450             ast_write(other, f);
02451             sendingdtmfdigit = 0;
02452          } else {
02453             /*! append the event to featurecode. we rely on the string being zero-filled, and
02454             * not overflowing it. 
02455             * \todo XXX how do we guarantee the latter ?
02456             */
02457             featurecode[strlen(featurecode)] = f->subclass;
02458             /* Get rid of the frame before we start doing "stuff" with the channels */
02459             ast_frfree(f);
02460             f = NULL;
02461             if (silgen) {
02462                ast_channel_stop_silence_generator(other, silgen);
02463                silgen = NULL;
02464             }
02465             config->feature_timer = backup_config.feature_timer;
02466             res = feature_interpret(chan, peer, config, featurecode, sense);
02467             switch(res) {
02468             case FEATURE_RETURN_PASSDIGITS:
02469                ast_dtmf_stream(other, who, featurecode, 0);
02470                /* Fall through */
02471             case FEATURE_RETURN_SUCCESS:
02472                memset(featurecode, 0, sizeof(chan_featurecode));
02473                break;
02474             }
02475             if (res >= FEATURE_RETURN_PASSDIGITS) {
02476                res = 0;
02477             } else {
02478                break;
02479             }
02480             hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02481             if (hadfeatures && !hasfeatures) {
02482                /* Restore backup */
02483                memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02484                memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02485             } else if (hasfeatures) {
02486                if (!hadfeatures) {
02487                   /* Backup configuration */
02488                   memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02489                   /* Setup temporary config options */
02490                   config->play_warning = 0;
02491                   ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02492                   ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02493                   config->warning_freq = 0;
02494                   config->warning_sound = NULL;
02495                   config->end_sound = NULL;
02496                   config->start_sound = NULL;
02497                   config->firstpass = 0;
02498                }
02499                config->start_time = ast_tvnow();
02500                config->feature_timer = featuredigittimeout;
02501                if (option_debug) {
02502                   ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
02503                }
02504             }
02505          }
02506       }
02507       if (f)
02508          ast_frfree(f);
02509 
02510    }
02511 
02512 before_you_go:
02513    /* Just in case something weird happened and we didn't clean up the silence generator... */
02514    if (silgen) {
02515       ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen);
02516       silgen = NULL;
02517    }
02518    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02519       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
02520       if (bridge_cdr) {
02521          ast_cdr_discard(bridge_cdr);
02522          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
02523       }
02524       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
02525    }
02526 
02527    if (config->end_bridge_callback) {
02528       config->end_bridge_callback(config->end_bridge_callback_data);
02529    }
02530 
02531    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 
02532        ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02533       struct ast_cdr *swapper = NULL;
02534       char savelastapp[AST_MAX_EXTENSION];
02535       char savelastdata[AST_MAX_EXTENSION];
02536       char save_exten[AST_MAX_EXTENSION];
02537       int  save_prio, spawn_error = 0;
02538       
02539       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02540       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02541       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02542          ast_cdr_end(bridge_cdr);
02543       }
02544       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
02545          dialplan code operate on it */
02546       ast_channel_lock(chan);
02547       if (bridge_cdr) {
02548          swapper = chan->cdr;
02549          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02550          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02551          chan->cdr = bridge_cdr;
02552       }
02553       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02554       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02555       save_prio = chan->priority;
02556       chan->priority = 1;
02557       ast_channel_unlock(chan);
02558       while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
02559          if ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) {
02560             /* Something bad happened, or a hangup has been requested. */
02561             if (option_debug)
02562                ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02563             if (option_verbose > 1)
02564                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);
02565             break;
02566          }
02567          chan->priority++;
02568       }
02569       /* swap it back */
02570       ast_channel_lock(chan);
02571       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02572       chan->priority = save_prio;
02573       if (bridge_cdr) {
02574          if (chan->cdr == bridge_cdr) {
02575             chan->cdr = swapper;
02576          } else {
02577             bridge_cdr = NULL;
02578          }
02579       }
02580       if (chan->priority != 1 || !spawn_error) {
02581          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02582       }
02583       ast_channel_unlock(chan);
02584       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
02585       if (bridge_cdr) {
02586          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02587          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02588       }
02589       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02590    }
02591    
02592    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
02593    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02594    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
02595       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02596    }
02597 
02598    /* we can post the bridge CDR at this point */
02599    if (bridge_cdr) {
02600       ast_cdr_end(bridge_cdr);
02601       ast_cdr_detach(bridge_cdr);
02602    }
02603    
02604    /* do a specialized reset on the beginning channel
02605       CDR's, if they still exist, so as not to mess up
02606       issues in future bridges;
02607       
02608       Here are the rules of the game:
02609       1. The chan and peer channel pointers will not change
02610          during the life of the bridge.
02611       2. But, in transfers, the channel names will change.
02612          between the time the bridge is started, and the
02613          time the channel ends. 
02614          Usually, when a channel changes names, it will
02615          also change CDR pointers.
02616       3. Usually, only one of the two channels (chan or peer)
02617          will change names.
02618       4. Usually, if a channel changes names during a bridge,
02619          it is because of a transfer. Usually, in these situations,
02620          it is normal to see 2 bridges running simultaneously, and
02621          it is not unusual to see the two channels that change
02622          swapped between bridges.
02623       5. After a bridge occurs, we have 2 or 3 channels' CDRs
02624          to attend to; if the chan or peer changed names,
02625          we have the before and after attached CDR's.
02626    */
02627    
02628    if (new_chan_cdr) {
02629       struct ast_channel *chan_ptr = NULL;
02630       
02631       if (strcasecmp(orig_channame, chan->name) != 0) { 
02632          /* old channel */
02633          chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02634          if (chan_ptr) {
02635             if (!ast_bridged_channel(chan_ptr)) {
02636                struct ast_cdr *cur;
02637                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02638                   if (cur == chan_cdr) {
02639                      break;
02640                   }
02641                }
02642                if (cur)
02643                   ast_cdr_specialized_reset(chan_cdr,0);
02644             }
02645             ast_channel_unlock(chan_ptr);
02646          }
02647          /* new channel */
02648          ast_cdr_specialized_reset(new_chan_cdr,0);
02649       } else {
02650          ast_cdr_specialized_reset(chan->cdr, 0); /* nothing changed, reset the chan cdr  */
02651       }
02652    }
02653 
02654    {
02655       struct ast_channel *chan_ptr = NULL;
02656       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02657       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))
02658          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
02659       if (strcasecmp(orig_peername, peer->name) != 0) { 
02660          /* old channel */
02661          chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02662          if (chan_ptr) {
02663             if (!ast_bridged_channel(chan_ptr)) {
02664                struct ast_cdr *cur;
02665                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02666                   if (cur == peer_cdr) {
02667                      break;
02668                   }
02669                }
02670                if (cur)
02671                   ast_cdr_specialized_reset(peer_cdr,0);
02672             }
02673             ast_channel_unlock(chan_ptr);
02674          }
02675          /* new channel */
02676          if (new_peer_cdr) {
02677             ast_cdr_specialized_reset(new_peer_cdr, 0);
02678          }
02679       } else {
02680          ast_cdr_specialized_reset(peer->cdr, 0); /* nothing changed, reset the peer cdr  */
02681       }
02682    }
02683    
02684    return res;
02685 }

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

Todo:
XXX for safety

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

00443 {
00444    struct ast_bridge_thread_obj *tobj = data;
00445 
00446    tobj->chan->appl = "Transferred Call";
00447    tobj->chan->data = tobj->peer->name;
00448    tobj->peer->appl = "Transferred Call";
00449    tobj->peer->data = tobj->chan->name;
00450 
00451    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00452    ast_hangup(tobj->chan);
00453    ast_hangup(tobj->peer);
00454    bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
00455    free(tobj);
00456    return NULL;
00457 }

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 459 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by builtin_atxfer().

00460 {
00461    pthread_t thread;
00462    pthread_attr_t attr;
00463    struct sched_param sched;
00464 
00465    pthread_attr_init(&attr);
00466    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00467    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00468    pthread_attr_destroy(&attr);
00469    memset(&sched, 0, sizeof(sched));
00470    pthread_setschedparam(thread, SCHED_RR, &sched);
00471 }

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

References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

01649                                                                                                                            {
01650 
01651    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
01652 }

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

References masq_park_call().

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

00786 {
00787    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00788 }

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

Park a call.

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

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00725 {
00726    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00727 }

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

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

00377 {
00378    return parking_ext;
00379 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 3418 of file res_features.c.

References ast_channel::_state, ast_channel_unlock, ast_channel_walk_locked(), AST_FLAG_ZOMBIE, ast_log(), AST_STATE_RING, AST_STATE_RINGING, ast_test_flag, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, ast_channel::masq, ast_channel::name, option_debug, ast_channel::pbx, pickup_do(), and ast_channel::pickupgroup.

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

03419 {
03420    struct ast_channel *cur = NULL;
03421    int res = -1;
03422 
03423    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
03424       if (!cur->pbx && 
03425          (cur != chan) &&
03426          (chan->pickupgroup & cur->callgroup) &&
03427          ((cur->_state == AST_STATE_RINGING) ||
03428           (cur->_state == AST_STATE_RING)) &&
03429          !cur->masq &&
03430          !ast_test_flag(cur, AST_FLAG_ZOMBIE)) {
03431             break;
03432       }
03433       ast_channel_unlock(cur);
03434    }
03435    if (cur) {
03436       res = pickup_do(chan, cur);
03437       if (res) {
03438          ast_log(LOG_WARNING, "pickup %s failed by %s\n", cur->name, chan->name);
03439       }
03440       ast_channel_unlock(cur);
03441    } else   {
03442       if (option_debug)
03443          ast_log(LOG_DEBUG, "No call pickup possible... for %s\n", chan->name);
03444    }
03445    return res;
03446 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 381 of file res_features.c.

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

00382 {
00383    return pickup_ext;
00384 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_list

register new feature into feature_set

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

Referenced by load_config().

01376 {
01377    if (!feature) {
01378       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01379          return;
01380    }
01381   
01382    AST_RWLIST_WRLOCK(&feature_list);
01383    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01384    AST_RWLIST_UNLOCK(&feature_list);
01385 
01386    if (option_verbose >= 2) {
01387       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01388    }
01389 }

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_list

unregister feature from feature_set

Definition at line 1392 of file res_features.c.

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

01393 {
01394    if (!feature)
01395       return;
01396 
01397    AST_RWLIST_WRLOCK(&feature_list);
01398    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01399    AST_RWLIST_UNLOCK(&feature_list);
01400    
01401    free(feature);
01402 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1405 of file res_features.c.

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

Referenced by load_config().

01406 {
01407    struct ast_call_feature *feature;
01408 
01409    AST_RWLIST_WRLOCK(&feature_list);
01410    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01411       free(feature);
01412    }
01413    AST_RWLIST_UNLOCK(&feature_list);
01414 }

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 transfered user
peer person transfering call
config 
code 
sense feature options
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 on failure

Definition at line 1091 of file res_features.c.

References ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_flags, AST_DIGIT_ANY, ast_do_masquerade(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAGS_ALL, ast_hangup(), ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_test_flag, 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, ast_channel::context, ast_datastore::data, ast_bridge_config::end_bridge_callback_data_fixup, ast_channel::exten, feature_request_and_dial(), 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::masq, ast_channel::name, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_channel::visible_indication, and ast_channel::writeformat.

01092 {
01093    struct ast_channel *transferer;/* Party B */
01094    struct ast_channel *transferee;/* Party A */
01095    const char *transferer_real_context;
01096    char xferto[256] = "";
01097    int res;
01098    int outstate=0;
01099    struct ast_channel *newchan;
01100    struct ast_channel *xferchan;
01101    struct ast_bridge_thread_obj *tobj;
01102    struct ast_bridge_config bconfig;
01103    int l;
01104    struct ast_datastore *features_datastore;
01105    struct ast_dial_features *dialfeatures = NULL;
01106 
01107    if (option_debug)
01108       ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
01109    set_peers(&transferer, &transferee, peer, chan, sense);
01110    transferer_real_context = real_ctx(transferer, transferee);
01111 
01112    /* Start autoservice on transferee while we talk to the transferer */
01113    ast_autoservice_start(transferee);
01114    ast_indicate(transferee, AST_CONTROL_HOLD);
01115 
01116    /* Transfer */
01117    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
01118    if (res < 0) {
01119       finishup(transferee);
01120       return -1;
01121    }
01122    if (res > 0) /* If they've typed a digit already, handle it */
01123       xferto[0] = (char) res;
01124 
01125    /* this is specific of atxfer */
01126    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01127    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
01128       finishup(transferee);
01129       return -1;
01130    }
01131    l = strlen(xferto);
01132    if (res == 0) {
01133       if (l) {
01134          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
01135             xferto, transferer_real_context);
01136       } else {
01137          /* Does anyone care about this case? */
01138          ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
01139       }
01140       ast_stream_and_wait(transferer, "pbx-invalid", transferer->language, "");
01141       finishup(transferee);
01142       return FEATURE_RETURN_SUCCESS;
01143    }
01144 
01145    /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of
01146     * the different variables for handling this properly with a builtin_atxfer */
01147    if (!strcmp(xferto, ast_parking_ext())) {
01148       finishup(transferee);
01149       return builtin_parkcall(chan, peer, config, code, sense, data);
01150    }
01151 
01152    /* Append context to dialed transfer number. */
01153    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
01154 
01155    /* Stop autoservice so we can monitor all parties involved in the transfer. */
01156    if (ast_autoservice_stop(transferee) < 0) {
01157       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01158       return -1;
01159    }
01160 
01161    /* Dial party C */
01162    newchan = feature_request_and_dial(transferer, transferee, "Local",
01163       ast_best_codec(transferer->nativeformats), xferto, atxfernoanswertimeout,
01164       &outstate, transferer->cid.cid_num, transferer->cid.cid_name,
01165       transferer->language);
01166    if (option_debug) {
01167       ast_log(LOG_DEBUG, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
01168    }
01169 
01170    if (!ast_check_hangup(transferer)) {
01171       int hangup_dont = 0;
01172 
01173       /* Transferer (party B) is up */
01174       if (option_debug) {
01175          ast_log(LOG_DEBUG, "Actually doing an attended transfer.\n");
01176       }
01177 
01178       /* Start autoservice on transferee while the transferer deals with party C. */
01179       ast_autoservice_start(transferee);
01180 
01181       ast_indicate(transferer, -1);
01182       if (!newchan) {
01183          /* any reason besides user requested cancel and busy triggers the failed sound */
01184          switch (outstate) {
01185          case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */
01186          case AST_CONTROL_BUSY:
01187          case AST_CONTROL_CONGESTION:
01188             if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) {
01189                ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01190             }
01191             break;
01192          default:
01193             if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) {
01194                ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
01195             }
01196             break;
01197          }
01198          finishup(transferee);
01199          return FEATURE_RETURN_SUCCESS;
01200       }
01201 
01202       if (check_compat(transferer, newchan)) {
01203          if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) {
01204             ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
01205          }
01206          /* we do mean transferee here, NOT transferer */
01207          finishup(transferee);
01208          return FEATURE_RETURN_SUCCESS;
01209       }
01210       memset(&bconfig,0,sizeof(struct ast_bridge_config));
01211       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
01212       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
01213 
01214       /* ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we don't
01215          want that to happen here because we're also in another bridge already
01216        */
01217       if (ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)) {
01218          hangup_dont = 1;
01219       }
01220       /* Let party B and party C talk as long as they want. */
01221       ast_bridge_call(transferer, newchan, &bconfig);
01222       if (hangup_dont) {
01223          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
01224       }
01225 
01226       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
01227          ast_hangup(newchan);
01228          if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) {
01229             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01230          }
01231          finishup(transferee);
01232          return FEATURE_RETURN_SUCCESS;
01233       }
01234 
01235       /* Transferer (party B) is confirmed hung up at this point. */
01236       if (check_compat(transferee, newchan)) {
01237          finishup(transferee);
01238          return -1;
01239       }
01240 
01241       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01242       if ((ast_autoservice_stop(transferee) < 0)
01243          || (ast_waitfordigit(transferee, 100) < 0)
01244          || (ast_waitfordigit(newchan, 100) < 0)
01245          || ast_check_hangup(transferee)
01246          || ast_check_hangup(newchan)) {
01247          ast_hangup(newchan);
01248          return -1;
01249       }
01250    } else if (!ast_check_hangup(transferee)) {
01251       /* Transferer (party B) has hung up at this point.  Doing blonde transfer. */
01252       if (option_debug) {
01253          ast_log(LOG_DEBUG, "Actually doing a blonde transfer.\n");
01254       }
01255 
01256       if (!newchan) {
01257          /* No party C. */
01258          return -1;
01259       }
01260 
01261       /* newchan is up, we should prepare transferee and bridge them */
01262       if (ast_check_hangup(newchan)) {
01263          ast_hangup(newchan);
01264          return -1;
01265       }
01266       if (check_compat(transferee, newchan)) {
01267          return -1;
01268       }
01269    } else {
01270       /*
01271        * Both the transferer and transferee have hungup.  If newchan
01272        * is up, hang it up as it has no one to talk to.
01273        */
01274       if (option_debug) {
01275          ast_log(LOG_DEBUG, "Everyone is hungup.\n");
01276       }
01277       if (newchan) {
01278          ast_hangup(newchan);
01279       }
01280       return -1;
01281    }
01282 
01283    /* Initiate the channel transfer of party A to party C. */
01284 
01285    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01286    if (!xferchan) {
01287       ast_hangup(newchan);
01288       return -1;
01289    }
01290 
01291    /* Give party A a momentary ringback tone during transfer. */
01292    xferchan->visible_indication = AST_CONTROL_RINGING;
01293 
01294    /* Make formats okay */
01295    xferchan->readformat = transferee->readformat;
01296    xferchan->writeformat = transferee->writeformat;
01297 
01298    ast_channel_masquerade(xferchan, transferee);
01299    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01300    xferchan->_state = AST_STATE_UP;
01301    ast_clear_flag(xferchan, AST_FLAGS_ALL);
01302 
01303    /* Do the masquerade manually to make sure that is is completed. */
01304    ast_channel_lock(xferchan);
01305    if (xferchan->masq) {
01306       ast_do_masquerade(xferchan);
01307    }
01308    ast_channel_unlock(xferchan);
01309 
01310    newchan->_state = AST_STATE_UP;
01311    ast_clear_flag(newchan, AST_FLAGS_ALL);
01312    tobj = ast_calloc(1, sizeof(*tobj));
01313    if (!tobj) {
01314       ast_hangup(xferchan);
01315       ast_hangup(newchan);
01316       return -1;
01317    }
01318 
01319    ast_channel_lock(newchan);
01320    if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
01321       dialfeatures = features_datastore->data;
01322    }
01323    ast_channel_unlock(newchan);
01324 
01325    if (dialfeatures) {
01326       /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
01327          I don't currently understand, the abilities of newchan seem to be stored on the caller side */
01328       ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01329       dialfeatures = NULL;
01330    }
01331 
01332    ast_channel_lock(xferchan);
01333    if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
01334       dialfeatures = features_datastore->data;
01335    }
01336    ast_channel_unlock(xferchan);
01337 
01338    if (dialfeatures) {
01339       ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01340    }
01341 
01342    tobj->chan = newchan;
01343    tobj->peer = xferchan;
01344    tobj->bconfig = *config;
01345 
01346    if (tobj->bconfig.end_bridge_callback_data_fixup) {
01347       tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01348    }
01349 
01350    if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
01351       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01352    ast_bridge_call_thread_launch(tobj);
01353    return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */
01354 }

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

References ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FRAME_DTMF_END, 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, 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.

00846 {
00847    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00848    int x = 0;
00849    size_t len;
00850    struct ast_channel *caller_chan, *callee_chan;
00851 
00852    if (!monitor_ok) {
00853       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00854       return -1;
00855    }
00856 
00857    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00858       monitor_ok = 0;
00859       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00860       return -1;
00861    }
00862 
00863    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00864 
00865    if (!ast_strlen_zero(courtesytone)) {
00866       if (ast_autoservice_start(callee_chan))
00867          return -1;
00868       ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
00869       if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00870          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00871          ast_autoservice_stop(callee_chan);
00872          return -1;
00873       }
00874       if (ast_autoservice_stop(callee_chan))
00875          return -1;
00876    }
00877    
00878    if (callee_chan->monitor) {
00879       if (option_verbose > 3)
00880          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00881       ast_monitor_stop(callee_chan, 1);
00882       return FEATURE_RETURN_SUCCESS;
00883    }
00884 
00885    if (caller_chan && callee_chan) {
00886       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00887       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00888 
00889       if (!touch_format)
00890          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00891 
00892       if (!touch_monitor)
00893          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00894    
00895       if (touch_monitor) {
00896          len = strlen(touch_monitor) + 50;
00897          args = alloca(len);
00898          touch_filename = alloca(len);
00899          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00900          snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00901       } else {
00902          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00903          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00904          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00905          args = alloca(len);
00906          touch_filename = alloca(len);
00907          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00908          snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00909       }
00910 
00911       for( x = 0; x < strlen(args); x++) {
00912          if (args[x] == '/')
00913             args[x] = '-';
00914       }
00915       
00916       if (option_verbose > 3)
00917          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00918 
00919       pbx_exec(callee_chan, monitor_app, args);
00920       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00921       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00922    
00923       return FEATURE_RETURN_SUCCESS;
00924    }
00925    
00926    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00927    return -1;
00928 }

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

References ast_app_dtget(), ast_async_goto(), ast_autoservice_ignore(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FRAME_DTMF_END, 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(), 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.

00958 {
00959    struct ast_channel *transferer;
00960    struct ast_channel *transferee;
00961    const char *transferer_real_context;
00962    char xferto[256];
00963    int res;
00964    const char *orig_chan_name;
00965    int parkstatus = 0;
00966 
00967    set_peers(&transferer, &transferee, peer, chan, sense);
00968    orig_chan_name = ast_strdupa(transferer->name);
00969    transferer_real_context = real_ctx(transferer, transferee);
00970    /* Start autoservice on chan while we talk to the originator */
00971    ast_autoservice_start(transferee);
00972    ast_autoservice_ignore(transferee, AST_FRAME_DTMF_END);
00973    ast_indicate(transferee, AST_CONTROL_HOLD);
00974 
00975    memset(xferto, 0, sizeof(xferto));
00976 
00977    /* Transfer */
00978    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00979    if (res < 0) {
00980       finishup(transferee);
00981       return -1; /* error ? */
00982    }
00983    if (res > 0)   /* If they've typed a digit already, handle it */
00984       xferto[0] = (char) res;
00985 
00986    ast_stopstream(transferer);
00987    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00988    if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
00989       finishup(transferee);
00990       return -1;
00991    }
00992    if (res == 0) {
00993       if (xferto[0]) {
00994          ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
00995             xferto, transferer_real_context);
00996       } else {
00997          /* Does anyone care about this case? */
00998          ast_log(LOG_WARNING, "No digits dialed.\n");
00999       }
01000       ast_stream_and_wait(transferer, "pbx-invalid", transferer->language, "");
01001       finishup(transferee);
01002       return FEATURE_RETURN_SUCCESS;
01003    }
01004 
01005    if (!strcmp(xferto, ast_parking_ext())) {
01006       res = finishup(transferee);
01007       if (res) {
01008       } else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name))) {   /* success */
01009          /* We return non-zero, but tell the PBX not to hang the channel when
01010             the thread dies -- We have to be careful now though.  We are responsible for 
01011             hanging up the channel, else it will never be hung up! */
01012          return 0;
01013       } else {
01014          ast_log(LOG_WARNING, "Unable to park call %s, parkstatus=%d\n", transferee->name, parkstatus);
01015       }
01016       ast_autoservice_start(transferee);
01017    } else {
01018       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01019       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01020       res=finishup(transferee);
01021       if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
01022          transferer->cdr=ast_cdr_alloc();
01023          if (transferer->cdr) {
01024             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
01025             ast_cdr_start(transferer->cdr);
01026          }
01027       }
01028       if (transferer->cdr) {
01029          struct ast_cdr *swap = transferer->cdr;
01030          /* swap cdrs-- it will save us some time & work */
01031          transferer->cdr = transferee->cdr;
01032          transferee->cdr = swap;
01033       }
01034       if (!transferee->pbx) {
01035          /* Doh!  Use our handy async_goto functions */
01036          if (option_verbose > 2) 
01037             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
01038                         ,transferee->name, xferto, transferer_real_context);
01039          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01040             ast_log(LOG_WARNING, "Async goto failed :-(\n");
01041          res = -1;
01042       } else {
01043          /* Set the channel's new extension, since it exists, using transferer context */
01044          ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
01045          set_c_e_p(transferee, transferer_real_context, xferto, 0);
01046       }
01047       check_goto_on_transfer(transferer);
01048       return res;
01049    }
01050    if (parkstatus != FEATURE_RETURN_PARKFAILED
01051       && ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) {
01052       finishup(transferee);
01053       return -1;
01054    }
01055    ast_stopstream(transferer);
01056    res = finishup(transferee);
01057    if (res) {
01058       if (option_verbose > 1)
01059          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
01060       return res;
01061    }
01062    return FEATURE_RETURN_SUCCESS;
01063 }

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

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

00931 {
00932    if (option_verbose > 3)
00933       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00934    return FEATURE_RETURN_HANGUP;
00935 }

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 811 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, masq_park_call_announce(), ast_channel::name, and set_peers().

Referenced by builtin_atxfer().

00812 {
00813    struct ast_channel *parker;
00814    struct ast_channel *parkee;
00815    int res = 0;
00816    struct ast_module_user *u;
00817    const char *orig_chan_name;
00818 
00819    u = ast_module_user_add(chan);
00820 
00821    set_peers(&parker, &parkee, peer, chan, sense);
00822    orig_chan_name = ast_strdupa(parker->name);
00823    /* we used to set chan's exten and priority to "s" and 1
00824       here, but this generates (in some cases) an invalid
00825       extension, and if "s" exists, could errantly
00826       cause execution of extensions you don't expect It
00827       makes more sense to let nature take its course
00828       when chan finishes, and let the pbx do its thing
00829       and hang up when the park is over.
00830    */
00831    if (chan->_state != AST_STATE_UP)
00832       res = ast_answer(chan);
00833    if (!res)
00834       res = ast_safe_sleep(chan, 1000);
00835 
00836    if (!res) { /* one direction used to call park_call.... */
00837       res = masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name);
00838       /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
00839    }
00840 
00841    ast_module_user_remove(u);
00842    return res;
00843 }

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

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

02702 {
02703    int i = 0;
02704    enum {
02705       OPT_CALLEE_REDIRECT   = 't',
02706       OPT_CALLER_REDIRECT   = 'T',
02707       OPT_CALLEE_AUTOMON    = 'w',
02708       OPT_CALLER_AUTOMON    = 'W',
02709       OPT_CALLEE_DISCONNECT = 'h',
02710       OPT_CALLER_DISCONNECT = 'H',
02711       OPT_CALLEE_PARKCALL   = 'k',
02712       OPT_CALLER_PARKCALL   = 'K',
02713    };
02714 
02715    memset(options, 0, len);
02716    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02717       options[i++] = OPT_CALLER_REDIRECT;
02718    }
02719    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02720       options[i++] = OPT_CALLER_AUTOMON;
02721    }
02722    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02723       options[i++] = OPT_CALLER_DISCONNECT;
02724    }
02725    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02726       options[i++] = OPT_CALLER_PARKCALL;
02727    }
02728 
02729    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02730       options[i++] = OPT_CALLEE_REDIRECT;
02731    }
02732    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02733       options[i++] = OPT_CALLEE_AUTOMON;
02734    }
02735    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02736       options[i++] = OPT_CALLEE_DISCONNECT;
02737    }
02738    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02739       options[i++] = OPT_CALLEE_PARKCALL;
02740    }
02741 
02742    return options;
02743 }

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

Definition at line 1065 of file res_features.c.

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

Referenced by builtin_atxfer().

01066 {
01067    if (ast_channel_make_compatible(c, newchan) < 0) {
01068       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01069          c->name, newchan->name);
01070       ast_hangup(newchan);
01071       return -1;
01072    }
01073    return 0;
01074 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Definition at line 401 of file res_features.c.

References ast_channel::_state, ast_channel_alloc(), ast_channel_clear_softhangup(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_SOFTHANGUP_ALL, 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().

00402 {
00403    struct ast_channel *xferchan;
00404    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00405    char *x, *goto_on_transfer;
00406    struct ast_frame *f;
00407 
00408    if (ast_strlen_zero(val))
00409       return;
00410 
00411    goto_on_transfer = ast_strdupa(val);
00412 
00413    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name)))
00414       return;
00415 
00416    for (x = goto_on_transfer; x && *x; x++) {
00417       if (*x == '^')
00418          *x = '|';
00419    }
00420    /* Make formats okay */
00421    xferchan->readformat = chan->readformat;
00422    xferchan->writeformat = chan->writeformat;
00423    ast_channel_masquerade(xferchan, chan);
00424    ast_parseable_goto(xferchan, goto_on_transfer);
00425    xferchan->_state = AST_STATE_UP;
00426    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00427    ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
00428    if ((f = ast_read(xferchan))) {
00429       ast_frfree(f);
00430       f = NULL;
00431       ast_pbx_start(xferchan);
00432    } else {
00433       ast_hangup(xferchan);
00434    }
00435 }

static void clear_dialed_interfaces ( struct ast_channel chan  )  [static]

Definition at line 2099 of file res_features.c.

References ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_log(), dialed_interface_info, LOG_DEBUG, ast_channel::name, and option_debug.

Referenced by ast_bridge_call().

02100 {
02101    struct ast_datastore *di_datastore;
02102 
02103    ast_channel_lock(chan);
02104    if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
02105       if (option_debug) {
02106          ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name);
02107       }
02108       if (!ast_channel_datastore_remove(chan, di_datastore)) {
02109          ast_channel_datastore_free(di_datastore);
02110       }
02111    }
02112    ast_channel_unlock(chan);
02113 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 362 of file res_features.c.

References ast_free.

00363 {
00364    struct ast_dial_features *df = data;
00365    if (df) {
00366       ast_free(df);
00367    }
00368 }

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

Definition at line 349 of file res_features.c.

References ast_calloc.

00350 {
00351    struct ast_dial_features *df = data, *df_copy;
00352 
00353    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00354       return NULL;
00355    }
00356 
00357    memcpy(df_copy, df, sizeof(*df));
00358 
00359    return df_copy;
00360 }

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

References ast_add_extension2(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_poll2(), ast_read(), ast_realloc, ast_samp2tv(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), callback_dialoptions(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_datastore::data, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, ast_frame::frametype, free, ast_channel::generatordata, 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, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, ast_frame::subclass, and VERBOSE_PREFIX_2.

Referenced by load_module().

02747 {
02748    /* results from previous poll, to be preserved across loops. */
02749    struct pollfd *fds = NULL;
02750    int nfds = 0;
02751    struct timeval tv;
02752 
02753    for (;;) {
02754       struct parkeduser *pu, *pl, *pt = NULL;
02755       int ms = -1;   /* poll2 timeout, uninitialized */
02756       struct pollfd *new_fds = NULL;
02757       int new_nfds = 0;
02758 
02759       ast_mutex_lock(&parking_lock);
02760       pl = NULL;
02761       pu = parkinglot;
02762       /* navigate the list with prev-cur pointers to support removals */
02763       while (pu) {
02764          struct ast_channel *chan = pu->chan;   /* shorthand */
02765          int tms;        /* timeout for this item */
02766          int x;          /* fd index in channel */
02767          struct ast_context *con;
02768 
02769          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
02770             pl = pu;
02771             pu = pu->next;
02772             continue;
02773          }
02774          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
02775          if (tms > pu->parkingtime) {
02776             ast_indicate(chan, AST_CONTROL_UNHOLD);
02777             /* Get chan, exten from derived kludge */
02778             if (pu->peername[0]) {
02779                /* Don't use ast_strdupa() inside an infinite loop */
02780                char *dash, *peername = ast_strdup(pu->peername);
02781                if (!peername) {
02782                   /* Skip for the time being. */
02783                   pl = pu;
02784                   pu = pu->next;
02785                   continue;
02786                }
02787                if ((dash = strrchr(peername, '-'))) {
02788                   *dash = '\0';
02789                }
02790                if (!(con = ast_context_find_or_create(NULL, parking_con_dial, registrar))) {
02791                   ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
02792                } else {
02793                   char returnexten[AST_MAX_EXTENSION];
02794                   struct ast_datastore *features_datastore;
02795                   struct ast_dial_features *dialfeatures = NULL;
02796 
02797                   ast_channel_lock(chan);
02798 
02799                   if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) {
02800                      dialfeatures = features_datastore->data;
02801                   }
02802 
02803                   ast_channel_unlock(chan);
02804 
02805                   if (!strncmp(peername, "Parked/", 7)) {
02806                      peername += 7;
02807                   }
02808 
02809                   if (dialfeatures) {
02810                      char buf[MAX_DIAL_FEATURE_OPTIONS] = "";
02811                      snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
02812                   } else { /* Existing default */
02813                      ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name);
02814                      snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
02815                   }
02816 
02817                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free_ptr, registrar);
02818                }
02819                set_c_e_p(chan, parking_con_dial, peername, 1);
02820                ast_free(peername);
02821             } else {
02822                /* They've been waiting too long, send them back to where they came.  Theoretically they
02823                   should have their original extensions and such, but we copy to be on the safe side */
02824                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
02825             }
02826 
02827             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
02828 
02829             if (option_verbose > 1) {
02830                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);
02831             }
02832             /* Start up the PBX, or hang them up */
02833             if (ast_pbx_start(chan))  {
02834                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
02835                ast_hangup(chan);
02836             }
02837             /* And take them out of the parking lot */
02838             if (pl) {
02839                pl->next = pu->next;
02840             } else {
02841                parkinglot = pu->next;
02842             }
02843             pt = pu;
02844             pu = pu->next;
02845             con = ast_context_find(parking_con);
02846             if (con) {
02847                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) {
02848                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02849                } else {
02850                   notify_metermaids(pt->parkingexten, parking_con);
02851                }
02852             } else {
02853                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02854             }
02855             free(pt);
02856          } else { /* still within parking time, process descriptors */
02857             for (x = 0; x < AST_MAX_FDS; x++) {
02858                struct ast_frame *f;
02859                int y;
02860 
02861                if (chan->fds[x] == -1) {
02862                   continue;   /* nothing on this descriptor */
02863                }
02864 
02865                for (y = 0; y < nfds; y++) {
02866                   if (fds[y].fd == chan->fds[x]) {
02867                      /* Found poll record! */
02868                      break;
02869                   }
02870                }
02871                if (y == nfds) {
02872                   /* Not found */
02873                   continue;
02874                }
02875 
02876                if (!(fds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
02877                   /* Next x */
02878                   continue;
02879                }
02880 
02881                if (fds[y].revents & POLLPRI) {
02882                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
02883                } else {
02884                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
02885                }
02886                chan->fdno = x;
02887 
02888                /* See if they need servicing */
02889                f = ast_read(chan);
02890                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
02891                   if (f) {
02892                      ast_frfree(f);
02893                   }
02894                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
02895 
02896                   /* There's a problem, hang them up*/
02897                   if (option_verbose > 1) {
02898                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
02899                   }
02900                   /* And take them out of the parking lot */
02901                   if (pl) {
02902                      pl->next = pu->next;
02903                   } else {
02904                      parkinglot = pu->next;
02905                   }
02906                   pt = pu;
02907                   pu = pu->next;
02908 
02909                   ast_hangup(chan);
02910                   con = ast_context_find(parking_con);
02911                   if (con) {
02912                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) {
02913                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02914                      } else {
02915                         notify_metermaids(pt->parkingexten, parking_con);
02916                      }
02917                   } else {
02918                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02919                   }
02920                   free(pt);
02921                   break;
02922                } else {
02923                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02924                   ast_frfree(f);
02925                   if (pu->moh_trys < 3 && !chan->generatordata) {
02926                      if (option_debug) {
02927                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
02928                      }
02929                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
02930                         S_OR(parkmohclass, NULL),
02931                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
02932                      pu->moh_trys++;
02933                   }
02934                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
02935                }
02936 
02937             } /* end for */
02938             if (x >= AST_MAX_FDS) {
02939 std:           for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */
02940                   if (chan->fds[x] > -1) {
02941                      void *tmp = ast_realloc(new_fds, (new_nfds + 1) * sizeof(*new_fds));
02942                      if (!tmp) {
02943                         continue;
02944                      }
02945                      new_fds = tmp;
02946                      new_fds[new_nfds].fd = chan->fds[x];
02947                      new_fds[new_nfds].events = POLLIN | POLLERR | POLLPRI;
02948                      new_fds[new_nfds].revents = 0;
02949                      new_nfds++;
02950                   }
02951                }
02952                /* Keep track of our shortest wait */
02953                if (tms < ms || ms < 0) {
02954                   ms = tms;
02955                }
02956                pl = pu;
02957                pu = pu->next;
02958             }
02959          }
02960       } /* end while */
02961       ast_mutex_unlock(&parking_lock);
02962       ast_free(fds);
02963       fds = new_fds;
02964       nfds = new_nfds;
02965       new_fds = NULL;
02966       new_nfds = 0;
02967 
02968       tv = ast_samp2tv(ms, 1000);
02969       /* Wait for something to happen */
02970       ast_poll2(fds, nfds, (ms > -1) ? &tv : NULL);
02971 
02972       pthread_testcancel();
02973    }
02974    return NULL;   /* Never reached */
02975 }

static int feature_check ( struct ast_channel chan,
struct ast_flags features,
char *  code 
) [static]

Check if a feature exists.

Definition at line 1655 of file res_features.c.

References ast_channel_lock, ast_channel_unlock, ast_strdupa, FEATURE_INTERPRET_CHECK, feature_interpret_helper(), pbx_builtin_getvar_helper(), and S_OR.

Referenced by ast_bridge_call().

01655                                                                                            {
01656    char *chan_dynamic_features;
01657    ast_channel_lock(chan);
01658    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
01659    ast_channel_unlock(chan);
01660 
01661    return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL);
01662 }

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

References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_ignore(), ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, AST_FRAME_DTMF_END, 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().

Referenced by load_config().

01432 {
01433    struct ast_app *app;
01434    struct ast_call_feature *feature = data;
01435    struct ast_channel *work, *idle;
01436    int res;
01437 
01438    if (!feature) { /* shouldn't ever happen! */
01439       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01440       return -1; 
01441    }
01442 
01443    if (sense == FEATURE_SENSE_CHAN) {
01444       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01445          return FEATURE_RETURN_KEEPTRYING;
01446       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01447          work = chan;
01448          idle = peer;
01449       } else {
01450          work = peer;
01451          idle = chan;
01452       }
01453    } else {
01454       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01455          return FEATURE_RETURN_KEEPTRYING;
01456       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01457          work = peer;
01458          idle = chan;
01459       } else {
01460          work = chan;
01461          idle = peer;
01462       }
01463    }
01464 
01465    if (!(app = pbx_findapp(feature->app))) {
01466       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01467       return -2;
01468    }
01469 
01470    ast_autoservice_start(idle);
01471    ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
01472    
01473    if (!ast_strlen_zero(feature->moh_class))
01474       ast_moh_start(idle, feature->moh_class, NULL);
01475 
01476    res = pbx_exec(work, app, feature->app_args);
01477 
01478    if (!ast_strlen_zero(feature->moh_class))
01479       ast_moh_stop(idle);
01480 
01481    ast_autoservice_stop(idle);
01482 
01483    if (res)
01484       return FEATURE_RETURN_SUCCESSBREAK;
01485    
01486    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01487 }

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

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

Referenced by ast_bridge_call().

01618                                                                                                                                           {
01619 
01620    char dynamic_features_buf[128];
01621    const char *peer_dynamic_features, *chan_dynamic_features;
01622    struct ast_flags features;
01623    struct ast_call_feature feature;
01624    if (sense == FEATURE_SENSE_CHAN) {
01625       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01626    }
01627    else {
01628       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01629    }
01630 
01631    ast_channel_lock(peer);
01632    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
01633    ast_channel_unlock(peer);
01634 
01635    ast_channel_lock(chan);
01636    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
01637    ast_channel_unlock(chan);
01638 
01639    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,""));
01640 
01641    if (option_debug > 2) {
01642       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);
01643    }
01644 
01645    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
01646 }

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,
feature_interpret_op  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 1527 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, ast_call_feature::exten, exten, FEATURE_INTERPRET_CHECK, FEATURE_INTERPRET_DO, ast_call_feature::feature_mask, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_RETURN_SUCCESS, 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(), feature_check(), and feature_interpret().

01530 {
01531    int x;
01532    struct ast_call_feature *tmpfeature;
01533    char *tmp, *tok;
01534    int res = FEATURE_RETURN_PASSDIGITS;
01535    int feature_detected = 0;
01536 
01537    if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) {
01538       return -1; /* can not run feature operation */
01539    }
01540 
01541    ast_rwlock_rdlock(&features_lock);
01542    for (x = 0; x < FEATURES_COUNT; x++) {
01543       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
01544           !ast_strlen_zero(builtin_features[x].exten)) {
01545          /* Feature is up for consideration */
01546          if (!strcmp(builtin_features[x].exten, code)) {
01547             if (option_debug > 2) {
01548                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);
01549             }
01550             if (operation == FEATURE_INTERPRET_CHECK) {
01551                res = FEATURE_RETURN_SUCCESS; /* We found something */
01552             } else if (operation == FEATURE_INTERPRET_DO) {
01553                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01554             }
01555             if (feature) {
01556                memcpy(feature, &builtin_features[x], sizeof(feature));
01557             }
01558 
01559             feature_detected = 1;
01560             break;
01561          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01562             if (res == FEATURE_RETURN_PASSDIGITS) {
01563                res = FEATURE_RETURN_STOREDIGITS;
01564             }
01565          }
01566       }
01567    }
01568    ast_rwlock_unlock(&features_lock);
01569 
01570    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
01571       return res;
01572    }
01573 
01574    tmp = dynamic_features_buf;
01575 
01576    while ((tok = strsep(&tmp, "#"))) {
01577       AST_RWLIST_RDLOCK(&feature_list);
01578       if (!(tmpfeature = find_dynamic_feature(tok))) {
01579          AST_RWLIST_UNLOCK(&feature_list);
01580          continue;
01581       }
01582 
01583       /* Feature is up for consideration */
01584       if (!strcmp(tmpfeature->exten, code)) {
01585          if (option_debug > 2) {
01586             ast_log(LOG_NOTICE, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
01587          }
01588          if (operation == FEATURE_INTERPRET_CHECK) {
01589             res = FEATURE_RETURN_SUCCESS; /* We found something */
01590          } else if (operation == FEATURE_INTERPRET_DO) {
01591             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
01592          }
01593          if (feature) {
01594             memcpy(feature, tmpfeature, sizeof(feature));
01595          }
01596          if (res != FEATURE_RETURN_KEEPTRYING) {
01597             AST_RWLIST_UNLOCK(&feature_list);
01598             break;
01599          }
01600          res = FEATURE_RETURN_PASSDIGITS;
01601       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
01602          res = FEATURE_RETURN_STOREDIGITS;
01603 
01604       AST_RWLIST_UNLOCK(&feature_list);
01605    }
01606 
01607    return res;
01608 }

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

Definition at line 1740 of file res_features.c.

References ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_inherit_variables(), ast_channel_lock, ast_channel_unlock, ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_frisolate(), ast_hangup(), ast_indicate(), ast_is_deferrable_frame(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_log(), ast_queue_frame_head(), 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(), ast_channel::call_forward, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_frame::frametype, ast_channel::hangupcause, len(), LOG_NOTICE, ast_channel::name, option_verbose, pbx_builtin_setvar_helper(), ast_frame::subclass, and VERBOSE_PREFIX_3.

Referenced by builtin_atxfer().

01744 {
01745    int state = 0;
01746    int cause = 0;
01747    int to;
01748    int caller_hungup;
01749    int transferee_hungup;
01750    struct ast_channel *chan;
01751    struct ast_channel *monitor_chans[3];
01752    struct ast_channel *active_channel;
01753    int ready = 0;
01754    struct timeval started;
01755    int x, len = 0;
01756    char *disconnect_code = NULL, *dialed_code = NULL;
01757    struct ast_frame *f;
01758    AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
01759 
01760    caller_hungup = ast_check_hangup(caller);
01761 
01762    if (!(chan = ast_request(type, format, data, &cause))) {
01763       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01764       switch (cause) {
01765       case AST_CAUSE_BUSY:
01766          state = AST_CONTROL_BUSY;
01767          break;
01768       case AST_CAUSE_CONGESTION:
01769          state = AST_CONTROL_CONGESTION;
01770          break;
01771       default:
01772          state = 0;
01773          break;
01774       }
01775       goto done;
01776    }
01777 
01778    ast_set_callerid(chan, cid_num, cid_name, cid_num);
01779    ast_string_field_set(chan, language, language);
01780    ast_channel_inherit_variables(caller, chan);
01781    pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01782 
01783    if (ast_call(chan, data, timeout)) {
01784       ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01785       switch (chan->hangupcause) {
01786       case AST_CAUSE_BUSY:
01787          state = AST_CONTROL_BUSY;
01788          break;
01789       case AST_CAUSE_CONGESTION:
01790          state = AST_CONTROL_CONGESTION;
01791          break;
01792       default:
01793          state = 0;
01794          break;
01795       }
01796       goto done;
01797    }
01798 
01799    /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01800    ast_rwlock_rdlock(&features_lock);
01801    for (x = 0; x < FEATURES_COUNT; x++) {
01802       if (strcasecmp(builtin_features[x].sname, "disconnect"))
01803          continue;
01804 
01805       disconnect_code = builtin_features[x].exten;
01806       len = strlen(disconnect_code) + 1;
01807       dialed_code = alloca(len);
01808       memset(dialed_code, 0, len);
01809       break;
01810    }
01811    ast_rwlock_unlock(&features_lock);
01812    x = 0;
01813    started = ast_tvnow();
01814    to = timeout;
01815    AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
01816 
01817    if (caller_hungup) {
01818       /* Convert to a blonde transfer */
01819       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01820       ast_indicate(transferee, AST_CONTROL_RINGING);
01821    }
01822 
01823    transferee_hungup = 0;
01824    while (!ast_check_hangup(transferee) && (chan->_state != AST_STATE_UP)) {
01825       int num_chans = 0;
01826 
01827       monitor_chans[num_chans++] = transferee;
01828       monitor_chans[num_chans++] = chan;
01829       if (!caller_hungup) {
01830          if (ast_check_hangup(caller)) {
01831             caller_hungup = 1;
01832 
01833 #if defined(ATXFER_NULL_TECH)
01834             /* Change caller's name to ensure that it will remain unique. */
01835             set_new_chan_name(caller);
01836 
01837             /*
01838              * Get rid of caller's physical technology so it is free for
01839              * other calls.
01840              */
01841             set_null_chan_tech(caller);
01842 #endif   /* defined(ATXFER_NULL_TECH) */
01843 
01844             /* Convert to a blonde transfer */
01845             ast_indicate(transferee, AST_CONTROL_UNHOLD);
01846             ast_indicate(transferee, AST_CONTROL_RINGING);
01847             started = ast_tvnow();
01848             to = timeout;
01849          } else {
01850             /* caller is not hungup so monitor it. */
01851             monitor_chans[num_chans++] = caller;
01852          }
01853       }
01854 
01855       /* see if the timeout has been violated */
01856       if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01857          state = AST_CONTROL_UNHOLD;
01858          ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", chan->name);
01859          break; /*doh! timeout*/
01860       }
01861 
01862       active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
01863       if (!active_channel)
01864          continue;
01865 
01866       f = NULL;
01867       if (transferee == active_channel) {
01868          struct ast_frame *dup_f;
01869 
01870          f = ast_read(transferee);
01871          if (f == NULL) { /*doh! where'd he go?*/
01872             transferee_hungup = 1;
01873             state = 0;
01874             break;
01875          }
01876          if (ast_is_deferrable_frame(f)) {
01877             dup_f = ast_frisolate(f);
01878             if (dup_f) {
01879                if (dup_f == f) {
01880                   f = NULL;
01881                }
01882                AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
01883             }
01884          }
01885       } else if (chan == active_channel) {
01886          if (!ast_strlen_zero(chan->call_forward)) {
01887             state = 0;
01888             chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
01889             if (!chan) {
01890                break;
01891             }
01892             continue;
01893          }
01894          f = ast_read(chan);
01895          if (f == NULL) { /*doh! where'd he go?*/
01896             switch (chan->hangupcause) {
01897             case AST_CAUSE_BUSY:
01898                state = AST_CONTROL_BUSY;
01899                break;
01900             case AST_CAUSE_CONGESTION:
01901                state = AST_CONTROL_CONGESTION;
01902                break;
01903             default:
01904                state = 0;
01905                break;
01906             }
01907             break;
01908          }
01909 
01910          if (f->frametype == AST_FRAME_CONTROL) {
01911             if (f->subclass == AST_CONTROL_RINGING) {
01912                if (option_verbose > 2)
01913                   ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01914                ast_indicate(caller, AST_CONTROL_RINGING);
01915             } else if (f->subclass == AST_CONTROL_BUSY) {
01916                state = f->subclass;
01917                if (option_verbose > 2)
01918                   ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01919                ast_indicate(caller, AST_CONTROL_BUSY);
01920                ast_frfree(f);
01921                break;
01922             } else if (f->subclass == AST_CONTROL_CONGESTION) {
01923                state = f->subclass;
01924                if (option_verbose > 2)
01925                   ast_verbose(VERBOSE_PREFIX_3 "%s is congested\n", chan->name);
01926                ast_indicate(caller, AST_CONTROL_CONGESTION);
01927                ast_frfree(f);
01928                break;
01929             } else if (f->subclass == AST_CONTROL_ANSWER) {
01930                /* This is what we are hoping for */
01931                state = f->subclass;
01932                ast_frfree(f);
01933                ready=1;
01934                break;
01935             } else if (f->subclass != -1 && f->subclass != AST_CONTROL_PROGRESS) {
01936                ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01937             }
01938             /* else who cares */
01939          } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
01940             ast_write(caller, f);
01941          }
01942       } else if (caller == active_channel) {
01943          f = ast_read(caller);
01944          if (f) {
01945             if (f->frametype == AST_FRAME_DTMF) {
01946                dialed_code[x++] = f->subclass;
01947                dialed_code[x] = '\0';
01948                if (strlen(dialed_code) == len) {
01949                   x = 0;
01950                } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01951                   x = 0;
01952                   dialed_code[x] = '\0';
01953                }
01954                if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01955                   /* Caller Canceled the call */
01956                   state = AST_CONTROL_UNHOLD;
01957                   ast_frfree(f);
01958                   break;
01959                }
01960             } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
01961                ast_write(chan, f);
01962             }
01963          }
01964       }
01965       if (f)
01966          ast_frfree(f);
01967    } /* end while */
01968 
01969    /*
01970     * We need to free all the deferred frames, but we only need to
01971     * queue the deferred frames if no hangup was received.
01972     */
01973    ast_channel_lock(transferee);
01974    transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
01975    while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
01976       if (!transferee_hungup) {
01977          ast_queue_frame_head(transferee, f);
01978       }
01979       ast_frfree(f);
01980    }
01981    ast_channel_unlock(transferee);
01982 
01983 done:
01984    ast_indicate(caller, -1);
01985    if (chan && (ready || chan->_state == AST_STATE_UP)) {
01986       state = AST_CONTROL_ANSWER;
01987    } else if (chan) {
01988       ast_hangup(chan);
01989       chan = NULL;
01990    }
01991 
01992    if (outstate)
01993       *outstate = state;
01994 
01995    return chan;
01996 }

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

find a feature by name

Definition at line 1417 of file res_features.c.

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

Referenced by feature_interpret_helper(), load_config(), and set_config_flags().

01418 {
01419    struct ast_call_feature *tmp;
01420 
01421    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01422       if (!strcasecmp(tmp->sname, name)) {
01423          break;
01424       }
01425    }
01426 
01427    return tmp;
01428 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 937 of file res_features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00938 {
00939         ast_indicate(chan, AST_CONTROL_UNHOLD);
00940   
00941         return ast_autoservice_stop(chan);
00942 }

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

Definition at line 3244 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, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.

03245 {
03246    struct parkeduser *cur;
03247    int numparked = 0;
03248 
03249    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
03250       , "Context", "Extension", "Pri", "Timeout");
03251 
03252    ast_mutex_lock(&parking_lock);
03253 
03254    for (cur = parkinglot; cur; cur = cur->next) {
03255       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
03256          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
03257          ,cur->priority, (long) cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
03258 
03259       numparked++;
03260    }
03261    ast_mutex_unlock(&parking_lock);
03262    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
03263 
03264 
03265    return RESULT_SUCCESS;
03266 }

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

Definition at line 3202 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(), ast_call_feature::default_exten, ast_call_feature::exten, exten, ast_call_feature::feature_entry, FEATURES_COUNT, features_lock, ast_call_feature::fname, format, RESULT_SUCCESS, and ast_call_feature::sname.

03203 {
03204    int i;
03205    struct ast_call_feature *feature;
03206    char format[] = "%-25s %-7s %-7s\n";
03207 
03208    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
03209    ast_cli(fd, format, "---------------", "-------", "-------");
03210 
03211    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
03212 
03213    ast_rwlock_rdlock(&features_lock);
03214    for (i = 0; i < FEATURES_COUNT; i++)
03215       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
03216    ast_rwlock_unlock(&features_lock);
03217 
03218    ast_cli(fd, "\n");
03219    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
03220    ast_cli(fd, format, "---------------", "-------", "-------");
03221    if (AST_RWLIST_EMPTY(&feature_list)) {
03222       ast_cli(fd, "(none)\n");
03223    } else {
03224       AST_RWLIST_RDLOCK(&feature_list);
03225       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
03226          ast_cli(fd, format, feature->sname, "no def", feature->exten);
03227       }
03228       AST_RWLIST_UNLOCK(&feature_list);
03229    }
03230    ast_cli(fd, "\nCall parking\n");
03231    ast_cli(fd, "------------\n");
03232    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
03233    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
03234    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
03235    ast_cli(fd,"\n");
03236    
03237    return RESULT_SUCCESS;
03238 }

static int load_config ( void   )  [static]

Todo:
XXX var_name or app_args ?

Definition at line 3463 of file res_features.c.

References ast_call_feature::app, app, ast_call_feature::app_args, ast_add_extension2(), ast_calloc, ast_config_destroy(), ast_config_load(), ast_context_create(), ast_context_find(), ast_context_remove_extension2(), ast_copy_string(), AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FEATURE_FLAG_ONPEER, AST_FEATURE_FLAG_ONSELF, ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_parking_ext(), ast_register_feature(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_variable_browse(), ast_verbose(), DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_TIME, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_MOH_LEN, FEATURE_SNAME_LEN, find_dynamic_feature(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_variable::name, ast_variable::next, notify_metermaids(), ast_call_feature::operation, option_debug, option_verbose, park_add_hints(), remap_feature(), ast_call_feature::sname, unmap_features(), ast_variable::value, var, and VERBOSE_PREFIX_2.

03464 {
03465    int start = 0, end = 0;
03466    int res;
03467    struct ast_context *con = NULL;
03468    struct ast_config *cfg = NULL;
03469    struct ast_variable *var = NULL;
03470    char old_parking_ext[AST_MAX_EXTENSION];
03471    char old_parking_con[AST_MAX_EXTENSION] = "";
03472 
03473    if (!ast_strlen_zero(parking_con)) {
03474       strcpy(old_parking_ext, parking_ext);
03475       strcpy(old_parking_con, parking_con);
03476    } 
03477 
03478    /* Reset to defaults */
03479    strcpy(parking_con, "parkedcalls");
03480    strcpy(parking_con_dial, "park-dial");
03481    strcpy(parking_ext, "700");
03482    strcpy(pickup_ext, "*8");
03483    strcpy(parkmohclass, "default");
03484    courtesytone[0] = '\0';
03485    strcpy(xfersound, "beep");
03486    strcpy(xferfailsound, "beeperr");
03487    parking_start = 701;
03488    parking_stop = 750;
03489    parkfindnext = 0;
03490    adsipark = 0;
03491    parkaddhints = 0;
03492    parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
03493    parkedcallreparking = 0;
03494    parkedcallhangup = 0;
03495    parkedcallrecording = 0;
03496 
03497    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03498    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03499    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03500 
03501    cfg = ast_config_load("features.conf");
03502    if (!cfg) {
03503       ast_log(LOG_WARNING,"Could not load features.conf\n");
03504       return AST_MODULE_LOAD_DECLINE;
03505    }
03506    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03507       if (!strcasecmp(var->name, "parkext")) {
03508          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
03509       } else if (!strcasecmp(var->name, "context")) {
03510          ast_copy_string(parking_con, var->value, sizeof(parking_con));
03511       } else if (!strcasecmp(var->name, "parkingtime")) {
03512          if ((sscanf(var->value, "%30d", &parkingtime) != 1) || (parkingtime < 1)) {
03513             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
03514             parkingtime = DEFAULT_PARK_TIME;
03515          } else
03516             parkingtime = parkingtime * 1000;
03517       } else if (!strcasecmp(var->name, "parkpos")) {
03518          if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
03519             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);
03520          } else {
03521             parking_start = start;
03522             parking_stop = end;
03523          }
03524       } else if (!strcasecmp(var->name, "findslot")) {
03525          parkfindnext = (!strcasecmp(var->value, "next"));
03526       } else if (!strcasecmp(var->name, "parkinghints")) {
03527          parkaddhints = ast_true(var->value);
03528       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
03529          if (!strcasecmp(var->value, "no"))
03530             parkedcalltransfers = 0;
03531          else if (!strcasecmp(var->value, "caller"))
03532             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
03533          else if (!strcasecmp(var->value, "callee"))
03534             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
03535          else if (!strcasecmp(var->value, "both"))
03536             parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
03537       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
03538          if (!strcasecmp(var->value, "no"))
03539             parkedcallreparking = 0;
03540          else if (!strcasecmp(var->value, "caller"))
03541             parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
03542          else if (!strcasecmp(var->value, "callee"))
03543             parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
03544          else if (!strcasecmp(var->value, "both"))
03545             parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
03546       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
03547          if (!strcasecmp(var->value, "no"))
03548             parkedcallhangup = 0;
03549          else if (!strcasecmp(var->value, "caller"))
03550             parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
03551          else if (!strcasecmp(var->value, "callee"))
03552             parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
03553          else if (!strcasecmp(var->value, "both"))
03554             parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
03555       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
03556          if (!strcasecmp(var->value, "no"))
03557             parkedcallrecording = 0;
03558          else if (!strcasecmp(var->value, "caller"))
03559             parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
03560          else if (!strcasecmp(var->value, "callee"))
03561             parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
03562          else if (!strcasecmp(var->value, "both"))
03563             parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
03564       } else if (!strcasecmp(var->name, "adsipark")) {
03565          adsipark = ast_true(var->value);
03566       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03567          if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03568             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03569             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03570          } else
03571             transferdigittimeout = transferdigittimeout * 1000;
03572       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03573          if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03574             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03575             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03576          }
03577       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03578          if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03579             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03580             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03581          } else
03582             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03583       } else if (!strcasecmp(var->name, "courtesytone")) {
03584          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03585       }  else if (!strcasecmp(var->name, "parkedplay")) {
03586          if (!strcasecmp(var->value, "both"))
03587             parkedplay = 2;
03588          else if (!strcasecmp(var->value, "parked"))
03589             parkedplay = 1;
03590          else
03591             parkedplay = 0;
03592       } else if (!strcasecmp(var->name, "xfersound")) {
03593          ast_copy_string(xfersound, var->value, sizeof(xfersound));
03594       } else if (!strcasecmp(var->name, "xferfailsound")) {
03595          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03596       } else if (!strcasecmp(var->name, "pickupexten")) {
03597          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03598       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03599          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
03600       }
03601    }
03602 
03603    unmap_features();
03604    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03605       if (remap_feature(var->name, var->value))
03606          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03607    }
03608 
03609    /* Map a key combination to an application*/
03610    ast_unregister_features();
03611    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03612       char *tmp_val = ast_strdupa(var->value);
03613       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
03614       struct ast_call_feature *feature;
03615 
03616       /* strsep() sets the argument to NULL if match not found, and it
03617        * is safe to use it with a NULL argument, so we don't check
03618        * between calls.
03619        */
03620       exten = strsep(&tmp_val,",");
03621       activatedby = strsep(&tmp_val,",");
03622       app = strsep(&tmp_val,",");
03623       app_args = strsep(&tmp_val,",");
03624       moh_class = strsep(&tmp_val,",");
03625 
03626       activateon = strsep(&activatedby, "/");   
03627 
03628       /*! \todo XXX var_name or app_args ? */
03629       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03630          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03631             app, exten, activateon, var->name);
03632          continue;
03633       }
03634 
03635       AST_RWLIST_RDLOCK(&feature_list);
03636       if ((feature = find_dynamic_feature(var->name))) {
03637          AST_RWLIST_UNLOCK(&feature_list);
03638          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03639          continue;
03640       }
03641       AST_RWLIST_UNLOCK(&feature_list);
03642             
03643       if (!(feature = ast_calloc(1, sizeof(*feature))))
03644          continue;               
03645 
03646       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03647       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03648       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03649       
03650       if (app_args) 
03651          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03652 
03653       if (moh_class)
03654          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03655          
03656       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03657       feature->operation = feature_exec_app;
03658       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03659 
03660       /* Allow caller and calle to be specified for backwards compatability */
03661       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03662          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03663       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03664          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03665       else {
03666          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03667             " must be 'self', or 'peer'\n", var->name);
03668          continue;
03669       }
03670 
03671       if (ast_strlen_zero(activatedby))
03672          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03673       else if (!strcasecmp(activatedby, "caller"))
03674          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03675       else if (!strcasecmp(activatedby, "callee"))
03676          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03677       else if (!strcasecmp(activatedby, "both"))
03678          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03679       else {
03680          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03681             " must be 'caller', or 'callee', or 'both'\n", var->name);
03682          continue;
03683       }
03684 
03685       ast_register_feature(feature);
03686          
03687       if (option_verbose >= 1)
03688          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
03689    }   
03690    ast_config_destroy(cfg);
03691 
03692    /* Remove the old parking extension */
03693    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03694       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
03695             notify_metermaids(old_parking_ext, old_parking_con);
03696       if (option_debug)
03697          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03698    }
03699    
03700    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
03701       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
03702       return -1;
03703    }
03704    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03705    if (parkaddhints)
03706       park_add_hints(parking_con, parking_start, parking_stop);
03707    if (!res)
03708       notify_metermaids(ast_parking_ext(), parking_con);
03709    return res;
03710 
03711 }

static int load_module ( void   )  [static]

Definition at line 3718 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(), do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), and park_exec().

03719 {
03720    int res;
03721    
03722    memset(parking_ext, 0, sizeof(parking_ext));
03723    memset(parking_con, 0, sizeof(parking_con));
03724 
03725    if ((res = load_config()))
03726       return res;
03727    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03728    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03729    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03730    if (!res)
03731       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03732    if (!res) {
03733       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03734       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03735          "Park a channel", mandescr_park); 
03736    }
03737 
03738    res |= ast_devstate_prov_add("Park", metermaidstate);
03739 
03740    return res;
03741 }

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

Definition at line 3335 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(), and astman_send_error().

Referenced by load_module().

03336 {
03337    const char *channel = astman_get_header(m, "Channel");
03338    const char *channel2 = astman_get_header(m, "Channel2");
03339    const char *timeout = astman_get_header(m, "Timeout");
03340    char buf[BUFSIZ];
03341    int to = 0;
03342    int res = 0;
03343    int parkExt = 0;
03344    struct ast_channel *ch1, *ch2;
03345 
03346    if (ast_strlen_zero(channel)) {
03347       astman_send_error(s, m, "Channel not specified");
03348       return 0;
03349    }
03350 
03351    if (ast_strlen_zero(channel2)) {
03352       astman_send_error(s, m, "Channel2 not specified");
03353       return 0;
03354    }
03355 
03356    ch1 = ast_get_channel_by_name_locked(channel);
03357    if (!ch1) {
03358       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
03359       astman_send_error(s, m, buf);
03360       return 0;
03361    }
03362 
03363    ch2 = ast_get_channel_by_name_locked(channel2);
03364    if (!ch2) {
03365       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
03366       astman_send_error(s, m, buf);
03367       ast_channel_unlock(ch1);
03368       return 0;
03369    }
03370 
03371    if (!ast_strlen_zero(timeout)) {
03372       sscanf(timeout, "%30d", &to);
03373    }
03374 
03375    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
03376    if (!res) {
03377       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
03378       astman_send_ack(s, m, "Park successful");
03379    } else {
03380       astman_send_error(s, m, "Park failure");
03381    }
03382 
03383    ast_channel_unlock(ch1);
03384    ast_channel_unlock(ch2);
03385 
03386    return 0;
03387 }

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

Dump lot status.

Definition at line 3288 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, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, S_OR, and parkeduser::start.

Referenced by load_module().

03289 {
03290    struct parkeduser *cur;
03291    const char *id = astman_get_header(m, "ActionID");
03292    char idText[256] = "";
03293 
03294    if (!ast_strlen_zero(id))
03295       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
03296 
03297    astman_send_ack(s, m, "Parked calls will follow");
03298 
03299    ast_mutex_lock(&parking_lock);
03300 
03301    for (cur = parkinglot; cur; cur = cur->next) {
03302       astman_append(s, "Event: ParkedCall\r\n"
03303          "Exten: %d\r\n"
03304          "Channel: %s\r\n"
03305          "From: %s\r\n"
03306          "Timeout: %ld\r\n"
03307          "CallerID: %s\r\n"
03308          "CallerIDName: %s\r\n"
03309          "%s"
03310          "\r\n",
03311          cur->parkingnum, cur->chan->name, cur->peername,
03312          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
03313          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
03314          S_OR(cur->chan->cid.cid_name, ""),
03315          idText);
03316    }
03317 
03318    astman_append(s,
03319       "Event: ParkedCallsComplete\r\n"
03320       "%s"
03321       "\r\n",idText);
03322 
03323    ast_mutex_unlock(&parking_lock);
03324 
03325    return RESULT_SUCCESS;
03326 }

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

References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_copy_string(), ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_PARKFAILED, ast_channel::language, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, 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().

00730 {
00731    struct ast_channel *chan;
00732    struct ast_frame *f;
00733    struct parkeduser *pu;
00734    int park_status;
00735 
00736    if ((pu = park_space_reserve(rchan)) == NULL) {
00737       if (peer)
00738          ast_stream_and_wait(peer, "beeperr", peer->language, "");
00739       return FEATURE_RETURN_PARKFAILED;
00740    }
00741 
00742    /* Make a new, fake channel that we'll use to masquerade in the real one */
00743    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00744       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00745       return -1;
00746    }
00747 
00748    /* Make formats okay */
00749    chan->readformat = rchan->readformat;
00750    chan->writeformat = rchan->writeformat;
00751    ast_channel_masquerade(chan, rchan);
00752 
00753    /* Setup the extensions and such */
00754    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00755 
00756    /* Setup the macro extension and such */
00757    ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext));
00758    ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten));
00759    chan->macropriority = rchan->macropriority;
00760 
00761    /* Make the masq execute */
00762    if ((f = ast_read(chan))) {
00763       ast_frfree(f);
00764    }
00765 
00766    if (peer == rchan) {
00767       peer = chan;
00768    }
00769 
00770    if (peer && (!play_announcement || !orig_chan_name)) {
00771       /* chan is the channel being parked, peer is the effective park-er */
00772       orig_chan_name = ast_strdupa(peer->name);
00773    }
00774 
00775    park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu);
00776    if (park_status == 1) {
00777       /* would be nice to play: "invalid parking extension" */
00778       ast_hangup(chan);
00779       return -1;
00780    }
00781 
00782    return 0;
00783 }

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

References masq_park_call().

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

00791 {
00792    return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
00793 }

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

metermaids callback from devicestate.c

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

00501 {
00502    int res = AST_DEVICE_INVALID;
00503    char *context = ast_strdupa(data);
00504    char *exten;
00505 
00506    exten = strsep(&context, "@");
00507    if (!context)
00508       return res;
00509    
00510    if (option_debug > 3)
00511       ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00512 
00513    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00514 
00515    if (!res)
00516       return AST_DEVICE_NOT_INUSE;
00517    else
00518       return AST_DEVICE_INUSE;
00519 }

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

Notify metermaids that we've changed an extension.

Definition at line 489 of file res_features.c.

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

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

00490 {
00491    if (option_debug > 3)
00492       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00493 
00494    /* Send notification to devicestate subsystem */
00495    ast_device_state_changed("park:%s@%s", exten, context);
00496    return;
00497 }

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

Add parking hints for all defined parking lots.

Definition at line 3449 of file res_features.c.

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

Referenced by load_config().

03450 {
03451    int numext;
03452    char device[AST_MAX_EXTENSION];
03453    char exten[10];
03454 
03455    for (numext = start; numext <= stop; numext++) {
03456       snprintf(exten, sizeof(exten), "%d", numext);
03457       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03458       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03459    }
03460 }

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

Park a call.

Definition at line 2978 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_channel::exten, masq_park_call_announce(), ast_channel::name, orig_exten(), and ast_channel::priority.

Referenced by load_module().

02979 {
02980    /* Cache the original channel name in case we get masqueraded in the middle
02981     * of a park--it is still theoretically possible for a transfer to happen before
02982     * we get here, but it is _really_ unlikely */
02983    char *orig_chan_name = ast_strdupa(chan->name);
02984    char orig_exten[AST_MAX_EXTENSION];
02985    int orig_priority = chan->priority;
02986 
02987    /* Data is unused at the moment but could contain a parking
02988       lot context eventually */
02989    int res = 0;
02990    struct ast_module_user *u;
02991 
02992    u = ast_module_user_add(chan);
02993 
02994    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
02995 
02996    /* Setup the exten/priority to be s/1 since we don't know
02997       where this call should return */
02998    strcpy(chan->exten, "s");
02999    chan->priority = 1;
03000    /* Answer if call is not up */
03001    if (chan->_state != AST_STATE_UP)
03002       res = ast_answer(chan);
03003    /* Sleep to allow VoIP streams to settle down */
03004    if (!res)
03005       res = ast_safe_sleep(chan, 1000);
03006    /* Park the call */
03007    if (!res) {
03008       res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name);
03009       /* Continue on in the dialplan */
03010       if (res == 1) {
03011          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
03012          chan->priority = orig_priority;
03013          res = 0;
03014       } else if (!res) {
03015          res = 1;
03016       }
03017    }
03018 
03019    ast_module_user_remove(u);
03020 
03021    return res;
03022 }

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 592 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, ast_channel::language, 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().

00593 {
00594    struct ast_context *con;
00595    int parkingnum_copy;
00596    const char *event_from;
00597 
00598    /* Get a valid space if not already done */
00599    if (pu == NULL)
00600       pu = park_space_reserve(chan);
00601    if (pu == NULL)
00602       return 1; /* Continue execution if possible */
00603 
00604    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
00605    
00606    chan->appl = "Parked Call";
00607    chan->data = NULL; 
00608 
00609    pu->chan = chan;
00610    
00611    /* Put the parked channel on hold if we have two different channels */
00612    if (chan != peer) {
00613       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00614          S_OR(parkmohclass, NULL),
00615          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00616    }
00617    
00618    pu->start = ast_tvnow();
00619    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00620    if (extout)
00621       *extout = pu->parkingnum;
00622 
00623    if (peer) { 
00624       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
00625          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
00626          and we need the callback name to be that of transferer.  Since local,1/2 have the same
00627          name we can be tricky and just grab the bridged channel from the other side of the local
00628       */
00629       if (!strcasecmp(peer->tech->type, "Local")) {
00630          struct ast_channel *tmpchan, *base_peer;
00631          char other_side[AST_CHANNEL_NAME];
00632          char *c;
00633          ast_copy_string(other_side, S_OR(orig_chan_name, peer->name), sizeof(other_side));
00634          if ((c = strrchr(other_side, ','))) {
00635             *++c = '1';
00636          }
00637          if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00638             if ((base_peer = ast_bridged_channel(tmpchan))) {
00639                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00640             }
00641             ast_channel_unlock(tmpchan);
00642          }
00643       } else {
00644          ast_copy_string(pu->peername, S_OR(orig_chan_name, peer->name), sizeof(pu->peername));
00645       }
00646    }
00647 
00648    /* Remember what had been dialed, so that if the parking
00649       expires, we try to come back to the same place */
00650    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00651    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00652    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00653    parkingnum_copy = pu->parkingnum;
00654 
00655    /* If parking a channel directly (peer == chan), don't quite yet get parking running on it.
00656      * All parking lot entires are put into the parking lot with notquiteyet on. */
00657    if (peer != chan) 
00658       pu->notquiteyet = 0;
00659 
00660    if (option_verbose > 1) 
00661       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));
00662 
00663    if (peer) {
00664       event_from = peer->name;
00665    } else {
00666       event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
00667    }
00668 
00669    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00670       "Exten: %s\r\n"
00671       "Channel: %s\r\n"
00672       "From: %s\r\n"
00673       "Timeout: %ld\r\n"
00674       "CallerID: %s\r\n"
00675       "CallerIDName: %s\r\n",
00676       pu->parkingexten, pu->chan->name, event_from ? event_from : "",
00677       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00678       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00679       S_OR(pu->chan->cid.cid_name, "<unknown>")
00680       );
00681 
00682    if (peer && adsipark && ast_adsi_available(peer)) {
00683       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00684       ast_adsi_unload_session(peer);
00685    }
00686 
00687    con = ast_context_find(parking_con);
00688    if (!con) 
00689       con = ast_context_create(NULL, parking_con, registrar);
00690    if (!con)   /* Still no context? Bad */
00691       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00692    if (con) {
00693       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free_ptr, registrar)) {
00694          notify_metermaids(pu->parkingexten, parking_con);
00695       }
00696    }
00697 
00698    /* Wake up the (presumably poll()ing) thread */
00699    pthread_kill(parking_thread, SIGURG);
00700 
00701    /* Only say number if it's a number and the channel hasn't been masqueraded away */
00702    if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) {
00703       /* Make sure we don't start saying digits to the channel being parked */
00704       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00705       /* Tell the peer channel the number of the parking space */
00706       ast_say_digits(peer, parkingnum_copy, "", peer->language);
00707       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00708    }
00709 
00710    if (peer == chan) { /* pu->notquiteyet = 1 */
00711       /* Wake up parking thread if we're really done */
00712       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00713          S_OR(parkmohclass, NULL),
00714          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00715       pu->notquiteyet = 0;
00716       pthread_kill(parking_thread, SIGURG);
00717    }
00718    return 0;
00719 }

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 3025 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(), ast_channel::cdr, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_datastore::data, EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_dial_features::features_caller, free, ast_channel::language, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parking_lock, parkeduser::parkingexten, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.

Referenced by load_module().

03026 {
03027    int res = 0;
03028    struct ast_module_user *u;
03029    struct ast_channel *peer=NULL;
03030    struct parkeduser *pu, *pl=NULL;
03031    struct ast_context *con;
03032 
03033    int park;
03034    struct ast_bridge_config config;
03035 
03036    if (!data) {
03037       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
03038       return -1;
03039    }
03040 
03041    u = ast_module_user_add(chan);
03042 
03043    park = atoi((char *)data);
03044    ast_mutex_lock(&parking_lock);
03045    pu = parkinglot;
03046    while(pu) {
03047       if (pu->parkingnum == park && !pu->notquiteyet) {
03048          if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
03049             ast_mutex_unlock(&parking_lock);
03050             ast_module_user_remove(u);
03051             return -1;
03052          }
03053          if (pl)
03054             pl->next = pu->next;
03055          else
03056             parkinglot = pu->next;
03057          break;
03058       }
03059       pl = pu;
03060       pu = pu->next;
03061    }
03062    ast_mutex_unlock(&parking_lock);
03063    if (pu) {
03064       peer = pu->chan;
03065       con = ast_context_find(parking_con);
03066       if (con) {
03067          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
03068             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
03069          else
03070             notify_metermaids(pu->parkingexten, parking_con);
03071       } else
03072          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
03073 
03074       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
03075          "Exten: %s\r\n"
03076          "Channel: %s\r\n"
03077          "From: %s\r\n"
03078          "CallerID: %s\r\n"
03079          "CallerIDName: %s\r\n",
03080          pu->parkingexten, pu->chan->name, chan->name,
03081          S_OR(pu->chan->cid.cid_num, "<unknown>"),
03082          S_OR(pu->chan->cid.cid_name, "<unknown>")
03083          );
03084 
03085       free(pu);
03086    }
03087    /* JK02: it helps to answer the channel if not already up */
03088    if (chan->_state != AST_STATE_UP)
03089       ast_answer(chan);
03090 
03091    if (peer) {
03092       struct ast_datastore *features_datastore;
03093       struct ast_dial_features *dialfeatures = NULL;
03094 
03095       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
03096 
03097       if (!ast_strlen_zero(courtesytone)) {
03098          int error = 0;
03099          ast_indicate(peer, AST_CONTROL_UNHOLD);
03100          if (parkedplay == 0) {
03101             error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
03102          } else if (parkedplay == 1) {
03103             error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
03104          } else if (parkedplay == 2) {
03105             if (!ast_streamfile(chan, courtesytone, chan->language) &&
03106                   !ast_streamfile(peer, courtesytone, chan->language)) {
03107                /*! \todo XXX we would like to wait on both! */
03108                res = ast_waitstream(chan, "");
03109                if (res >= 0)
03110                   res = ast_waitstream(peer, "");
03111                if (res < 0)
03112                   error = 1;
03113             }
03114                         }
03115          if (error) {
03116             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
03117             ast_hangup(peer);
03118             ast_module_user_remove(u);
03119             return -1;
03120          }
03121       } else
03122          ast_indicate(peer, AST_CONTROL_UNHOLD);
03123 
03124       res = ast_channel_make_compatible(chan, peer);
03125       if (res < 0) {
03126          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
03127          ast_hangup(peer);
03128          ast_module_user_remove(u);
03129          return -1;
03130       }
03131       /* This runs sorta backwards, since we give the incoming channel control, as if it
03132          were the person called. */
03133       if (option_verbose > 2)
03134          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
03135 
03136       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03137       ast_cdr_setdestchan(chan->cdr, peer->name);
03138       memset(&config, 0, sizeof(struct ast_bridge_config));
03139 
03140       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
03141       ast_channel_lock(peer);
03142       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
03143          dialfeatures = features_datastore->data;
03144       }
03145       ast_channel_unlock(peer);
03146 
03147       /* When the datastores for both caller and callee are created, both the callee and caller channels
03148        * use the features_caller flag variable to represent themselves. With that said, the config.features_callee
03149        * flags should be copied from the datastore's caller feature flags regardless if peer was a callee
03150        * or caller. */
03151       if (dialfeatures) {
03152          ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
03153       }
03154 
03155       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03156          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
03157       }
03158       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03159          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
03160       }
03161       if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03162          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
03163       }
03164       if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03165          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
03166       }
03167       if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03168          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
03169       }
03170       if ((parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03171          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
03172       }
03173       if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03174          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
03175       }
03176       if ((parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03177          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
03178       }
03179       res = ast_bridge_call(chan, peer, &config);
03180 
03181       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03182       ast_cdr_setdestchan(chan->cdr, peer->name);
03183 
03184       /* Simulate the PBX hanging up */
03185       ast_hangup(peer);
03186       ast_module_user_remove(u);
03187       return -1;
03188    } else {
03189       /*! \todo XXX Play a message XXX */
03190       if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
03191          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
03192       if (option_verbose > 2) 
03193          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
03194       res = -1;
03195    }
03196 
03197    ast_module_user_remove(u);
03198 
03199    return -1;
03200 }

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

Note:
The API forces us to specify a numeric parking slot, even though the architecture would tend to support non-numeric extensions (as are possible with SIP, for example). Hence, we enforce that limitation here. If extout was not numeric, we could permit arbitrary non-numeric extensions.

Definition at line 521 of file res_features.c.

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

Referenced by masq_park_call(), and park_call_full().

00522 {
00523    struct parkeduser *pu, *cur;
00524    int i, parking_space = -1, parking_range;
00525    const char *parkingexten;
00526 
00527    /* Allocate memory for parking data */
00528    if (!(pu = ast_calloc(1, sizeof(*pu)))) 
00529       return NULL;
00530 
00531    /* Lock parking lot */
00532    ast_mutex_lock(&parking_lock);
00533    /* Check for channel variable PARKINGEXTEN */
00534    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00535    if (!ast_strlen_zero(parkingexten)) {
00536       /*!\note The API forces us to specify a numeric parking slot, even
00537        * though the architecture would tend to support non-numeric extensions
00538        * (as are possible with SIP, for example).  Hence, we enforce that
00539        * limitation here.  If extout was not numeric, we could permit
00540        * arbitrary non-numeric extensions.
00541        */
00542       if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) {
00543          ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00544          ast_mutex_unlock(&parking_lock);
00545          free(pu);
00546          return NULL;
00547       }
00548       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00549 
00550       if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
00551          ast_mutex_unlock(&parking_lock);
00552          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00553          free(pu);
00554          return NULL;
00555       }
00556    } else {
00557       /* Select parking space within range */
00558       parking_range = parking_stop - parking_start+1;
00559       for (i = 0; i < parking_range; i++) {
00560          parking_space = (i + parking_offset) % parking_range + parking_start;
00561          cur = parkinglot;
00562          while(cur) {
00563             if (cur->parkingnum == parking_space) 
00564                break;
00565             cur = cur->next;
00566          }
00567          if (!cur)
00568             break;
00569       }
00570 
00571       if (!(i < parking_range)) {
00572          ast_log(LOG_WARNING, "No more parking spaces\n");
00573          ast_mutex_unlock(&parking_lock);
00574          free(pu);
00575          return NULL;
00576       }
00577       /* Set pointer for next parking */
00578       if (parkfindnext) 
00579          parking_offset = parking_space - parking_start + 1;
00580       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00581    }
00582    
00583    pu->notquiteyet = 1;
00584    pu->parkingnum = parking_space;
00585    pu->next = parkinglot;
00586    parkinglot = pu;
00587    ast_mutex_unlock(&parking_lock);
00588 
00589    return pu;
00590 }

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

Definition at line 1998 of file res_features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

01999 {
02000    struct ast_cdr *cdr_orig = cdr;
02001    while (cdr) {
02002       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02003          return cdr;
02004       cdr = cdr->next;
02005    }
02006    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
02007 }

static int pickup_do ( struct ast_channel chan,
struct ast_channel target 
) [static]

Definition at line 3395 of file res_features.c.

References ast_answer(), ast_channel_masquerade(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), LOG_DEBUG, LOG_WARNING, ast_channel::name, and option_debug.

03396 {
03397    if (option_debug)
03398       ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
03399 
03400    if (ast_answer(chan)) {
03401       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
03402       return -1;
03403    }
03404 
03405    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
03406       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
03407       return -1;
03408    }
03409 
03410    if (ast_channel_masquerade(target, chan)) {
03411       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
03412       return -1;
03413    }
03414 
03415    return 0;
03416 }

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

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

02688 {
02689    manager_event(EVENT_FLAG_CALL, s,
02690       "Exten: %s\r\n"
02691       "Channel: %s\r\n"
02692       "CallerID: %s\r\n"
02693       "CallerIDName: %s\r\n\r\n",
02694       parkingexten, 
02695       chan->name,
02696       S_OR(chan->cid.cid_num, "<unknown>"),
02697       S_OR(chan->cid.cid_name, "<unknown>")
02698       );
02699 }

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

Find the context for the transfer.

Definition at line 945 of file res_features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00946 {
00947         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00948         if (ast_strlen_zero(s))
00949                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00950         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00951                 s = transferer->macrocontext;
00952         if (ast_strlen_zero(s))
00953                 s = transferer->context;
00954         return s;  
00955 }

static int reload ( void   )  [static]

Definition at line 3713 of file res_features.c.

References load_config().

03714 {
03715    return load_config();
03716 }

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

Definition at line 1499 of file res_features.c.

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

Referenced by load_config().

01500 {
01501    int x, res = -1;
01502 
01503    ast_rwlock_wrlock(&features_lock);
01504    for (x = 0; x < FEATURES_COUNT; x++) {
01505       if (strcasecmp(builtin_features[x].sname, name))
01506          continue;
01507 
01508       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01509       res = 0;
01510       break;
01511    }
01512    ast_rwlock_unlock(&features_lock);
01513 
01514    return res;
01515 }

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

Definition at line 2009 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(), ast_bridge_config::features_caller, and LOG_WARNING.

Referenced by ast_bridge_call().

02010 {
02011    const char *feature;
02012 
02013    if (ast_strlen_zero(features)) {
02014       return;
02015    }
02016 
02017    for (feature = features; *feature; feature++) {
02018       switch (*feature) {
02019       case 'T' :
02020       case 't' :
02021          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
02022          break;
02023       case 'K' :
02024       case 'k' :
02025          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
02026          break;
02027       case 'H' :
02028       case 'h' :
02029          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
02030          break;
02031       case 'W' :
02032       case 'w' :
02033          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
02034          break;
02035       default :
02036          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
02037       }
02038    }
02039 }

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

00395 {
00396    ast_copy_string(chan->context, context, sizeof(chan->context));
00397    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00398    chan->priority = pri;
00399 }

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

Definition at line 1664 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, ast_call_feature::feature_mask, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, features_lock, find_dynamic_feature(), and pbx_builtin_getvar_helper().

Referenced by ast_bridge_call().

01665 {
01666    int x;
01667 
01668    ast_clear_flag(config, AST_FLAGS_ALL);
01669 
01670    ast_rwlock_rdlock(&features_lock);
01671    for (x = 0; x < FEATURES_COUNT; x++) {
01672       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01673          continue;
01674 
01675       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01676          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01677 
01678       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01679          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01680    }
01681    ast_rwlock_unlock(&features_lock);
01682 
01683    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01684       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01685 
01686       if (dynamic_features) {
01687          char *tmp = ast_strdupa(dynamic_features);
01688          char *tok;
01689          struct ast_call_feature *feature;
01690 
01691          /* while we have a feature */
01692          while ((tok = strsep(&tmp, "#"))) {
01693             AST_RWLIST_RDLOCK(&feature_list);
01694             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01695                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01696                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01697                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01698                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01699             }
01700             AST_RWLIST_UNLOCK(&feature_list);
01701          }
01702       }
01703    }
01704 }

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

References FEATURE_SENSE_PEER.

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

00800 {
00801    if (sense == FEATURE_SENSE_PEER) {
00802       *caller = peer;
00803       *callee = chan;
00804    } else {
00805       *callee = peer;
00806       *caller = chan;
00807    }
00808 }

static int unload_module ( void   )  [static]

static void unmap_features ( void   )  [static]

Definition at line 1489 of file res_features.c.

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

Referenced by load_config().

01490 {
01491    int x;
01492 
01493    ast_rwlock_wrlock(&features_lock);
01494    for (x = 0; x < FEATURES_COUNT; x++)
01495       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01496    ast_rwlock_unlock(&features_lock);
01497 }


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

Definition at line 3760 of file res_features.c.

int adsipark [static]

Definition at line 173 of file res_features.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 3760 of file res_features.c.

int atxfernoanswertimeout [static]

Definition at line 178 of file res_features.c.

Definition at line 1362 of file res_features.c.

struct ast_cli_entry cli_features[] [static]

Definition at line 3277 of file res_features.c.

Initial value:

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

Definition at line 3272 of file res_features.c.

char courtesytone[256] [static]

Courtesy tone

Definition at line 165 of file res_features.c.

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

char* descrip2 [static]

Definition at line 195 of file res_features.c.

Initial value:

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

Definition at line 370 of file res_features.c.

int featuredigittimeout [static]

Definition at line 176 of file res_features.c.

ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static]

char mandescr_park[] [static]

Definition at line 3328 of file res_features.c.

struct ast_app* monitor_app = NULL [static]

Definition at line 206 of file res_features.c.

int monitor_ok = 1 [static]

Definition at line 207 of file res_features.c.

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 150 of file res_features.c.

char* parkcall = PARK_APP_NAME [static]

Definition at line 191 of file res_features.c.

char* parkedcall = "ParkedCall" [static]

Definition at line 148 of file res_features.c.

int parkedcallhangup [static]

Who can DISCONNECT after picking up a parked call

Definition at line 162 of file res_features.c.

int parkedcallrecording [static]

Who can AUTOMON after picking up a parked call

Definition at line 163 of file res_features.c.

int parkedcallreparking [static]

Who can PARKCALL after picking up a parked call

Definition at line 161 of file res_features.c.

int parkedcalltransfers [static]

Who can REDIRECT after picking up a parked a call

Definition at line 160 of file res_features.c.

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 166 of file res_features.c.

int parkfindnext [static]

Definition at line 171 of file res_features.c.

char parking_con[AST_MAX_EXTENSION] [static]

Context for which parking is made accessible

Definition at line 152 of file res_features.c.

char parking_con_dial[AST_MAX_EXTENSION] [static]

Context for dialback for parking (KLUDGE)

Definition at line 153 of file res_features.c.

char parking_ext[AST_MAX_EXTENSION] [static]

Extension you type to park the call

Definition at line 154 of file res_features.c.

ast_mutex_t parking_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

protects all static variables above

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

int parking_start [static]

First available extension for parking

Definition at line 157 of file res_features.c.

int parking_stop [static]

Last available extension for parking

Definition at line 158 of file res_features.c.

pthread_t parking_thread [static]

Definition at line 228 of file res_features.c.

struct parkeduser* parkinglot [static]

Definition at line 224 of file res_features.c.

int parkingtime = DEFAULT_PARK_TIME [static]

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

Definition at line 151 of file res_features.c.

char parkmohclass[MAX_MUSICCLASS] [static]

Music class used for parking

Definition at line 156 of file res_features.c.

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 155 of file res_features.c.

char* registrar = "res_features" [static]

Registrar for operations

Definition at line 180 of file res_features.c.

char showfeatures_help[] [static]

Initial value:

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

Definition at line 3240 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 3268 of file res_features.c.

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

Definition at line 183 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 193 of file res_features.c.

int transferdigittimeout [static]

Definition at line 175 of file res_features.c.

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 168 of file res_features.c.

char xfersound[256] [static]

Call transfer sound

Definition at line 167 of file res_features.c.


Generated on Thu Oct 11 06:44:13 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6