Sat Aug 6 00:40:03 2011

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"

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 and read back parked location.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
 Remove all features in the list.
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 Attended transfer.
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 support routing for one touch call parking
static char * callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
static int check_compat (struct ast_channel *c, struct ast_channel *newchan)
static void check_goto_on_transfer (struct ast_channel *chan)
static void 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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static int adsipark
static const struct ast_module_infoast_module_info = &__mod_info
static int atxfernoanswertimeout
static struct ast_call_feature builtin_features []
static struct ast_cli_entry cli_features []
static struct ast_cli_entry cli_show_features_deprecated
static char courtesytone [256]
static char * descrip
static char * descrip2
ast_datastore_info dial_features_info
static int featuredigittimeout
static ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER
static char mandescr_park []
static struct ast_appmonitor_app = NULL
static int monitor_ok = 1
static int parkaddhints = 0
static char * parkcall = PARK_APP_NAME
static char * parkedcall = "ParkedCall"
static int parkedcallhangup
static int parkedcallrecording
static int parkedcallreparking
static int parkedcalltransfers
static int parkedplay = 0
static int parkfindnext
static char parking_con [AST_MAX_EXTENSION]
static char parking_con_dial [AST_MAX_EXTENSION]
static char parking_ext [AST_MAX_EXTENSION]
static ast_mutex_t parking_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static int parking_offset
static int parking_start
static int parking_stop
static pthread_t parking_thread
static struct parkeduserparkinglot
static char parkingretalertinfo [256]
static char parkingretcidname [256]
static char parkingretdahdiring [3]
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.

#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]))

Definition at line 1374 of file res_features.c.

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

#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 };

enum feature_interpret_op

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

static void __unreg_module ( void   )  [static]

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

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

Referenced by ast_bridge_call().

02058 {
02059    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
02060    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
02061 
02062    ast_channel_lock(caller);
02063    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
02064    ast_channel_unlock(caller);
02065    if (!ds_caller_features) {
02066       if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
02067          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
02068          return;
02069       }
02070       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
02071          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02072          ast_channel_datastore_free(ds_caller_features);
02073          return;
02074       }
02075       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
02076       caller_features->is_caller = 1;
02077       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
02078       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
02079       ds_caller_features->data = caller_features;
02080       ast_channel_lock(caller);
02081       ast_channel_datastore_add(caller, ds_caller_features);
02082       ast_channel_unlock(caller);
02083    } else {
02084       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
02085        * flags over from the atxfer to the caller */
02086       return;
02087    }
02088 
02089    ast_channel_lock(callee);
02090    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
02091    ast_channel_unlock(callee);
02092    if (!ds_callee_features) {
02093       if (!(ds_callee_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) {
02094          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
02095          return;
02096       }
02097       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
02098          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02099          ast_channel_datastore_free(ds_callee_features);
02100          return;
02101       }
02102       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
02103       callee_features->is_caller = 0;
02104       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
02105       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
02106       ds_callee_features->data = callee_features;
02107       ast_channel_lock(callee);
02108       ast_channel_datastore_add(callee, ds_callee_features);
02109       ast_channel_unlock(callee);
02110    }
02111 
02112    return;
02113 }

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

Definition at line 477 of file res_features.c.

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

Referenced by park_call_full().

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

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 2131 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(), config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, feature_check(), feature_interpret(), FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, ast_option_header::option, option_debug, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, VERBOSE_PREFIX_2, and ast_channel::visible_indication.

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

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

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

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

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

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 463 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by builtin_atxfer().

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

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

References FEATURE_INTERPRET_DETECT, and feature_interpret_helper().

Referenced by detect_disconnect().

01665                                                                                                                            {
01666 
01667    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
01668 }

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

References masq_park_call().

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

00793 {
00794    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00795 }

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

Park a call and read back parked location.

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

Definition at line 731 of file res_features.c.

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00732 {
00733    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00734 }

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

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

00381 {
00382    return parking_ext;
00383 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

03450 {
03451    struct ast_channel *cur = NULL;
03452    int res = -1;
03453 
03454    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
03455       if (!cur->pbx && 
03456          (cur != chan) &&
03457          (chan->pickupgroup & cur->callgroup) &&
03458          ((cur->_state == AST_STATE_RINGING) ||
03459           (cur->_state == AST_STATE_RING)) &&
03460          !cur->masq &&
03461          !ast_test_flag(cur, AST_FLAG_ZOMBIE)) {
03462             break;
03463       }
03464       ast_channel_unlock(cur);
03465    }
03466    if (cur) {
03467       res = pickup_do(chan, cur);
03468       if (res) {
03469          ast_log(LOG_WARNING, "pickup %s failed by %s\n", cur->name, chan->name);
03470       }
03471       ast_channel_unlock(cur);
03472    } else   {
03473       if (option_debug)
03474          ast_log(LOG_DEBUG, "No call pickup possible... for %s\n", chan->name);
03475    }
03476    return res;
03477 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 385 of file res_features.c.

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

00386 {
00387    return pickup_ext;
00388 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_set

Parameters:
feature an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call.

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

01392 {
01393    if (!feature) {
01394       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01395          return;
01396    }
01397   
01398    AST_RWLIST_WRLOCK(&feature_list);
01399    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01400    AST_RWLIST_UNLOCK(&feature_list);
01401 
01402    if (option_verbose >= 2) {
01403       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01404    }
01405 }

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 1408 of file res_features.c.

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

01409 {
01410    if (!feature)
01411       return;
01412 
01413    AST_RWLIST_WRLOCK(&feature_list);
01414    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01415    AST_RWLIST_UNLOCK(&feature_list);
01416    
01417    free(feature);
01418 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1421 of file res_features.c.

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

01422 {
01423    struct ast_call_feature *feature;
01424 
01425    AST_RWLIST_WRLOCK(&feature_list);
01426    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01427       free(feature);
01428    }
01429    AST_RWLIST_UNLOCK(&feature_list);
01430 }

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 1107 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(), builtin_parkcall(), check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_datastore::data, dial_features_info, 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_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_channel::visible_indication, and ast_channel::writeformat.

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

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 852 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, EVENT_FLAG_USER, FEATURE_RETURN_SUCCESS, ast_channel::language, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_event(), ast_channel::monitor, monitor_app, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), ast_channel::uniqueid, and VERBOSE_PREFIX_3.

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

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

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

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

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

00947 {
00948    if (option_verbose > 3)
00949       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00950    return FEATURE_RETURN_HANGUP;
00951 }

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

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

Referenced by builtin_atxfer().

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

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

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

02718 {
02719    int i = 0;
02720    enum {
02721       OPT_CALLEE_REDIRECT   = 't',
02722       OPT_CALLER_REDIRECT   = 'T',
02723       OPT_CALLEE_AUTOMON    = 'w',
02724       OPT_CALLER_AUTOMON    = 'W',
02725       OPT_CALLEE_DISCONNECT = 'h',
02726       OPT_CALLER_DISCONNECT = 'H',
02727       OPT_CALLEE_PARKCALL   = 'k',
02728       OPT_CALLER_PARKCALL   = 'K',
02729    };
02730 
02731    memset(options, 0, len);
02732    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02733       options[i++] = OPT_CALLER_REDIRECT;
02734    }
02735    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02736       options[i++] = OPT_CALLER_AUTOMON;
02737    }
02738    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02739       options[i++] = OPT_CALLER_DISCONNECT;
02740    }
02741    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02742       options[i++] = OPT_CALLER_PARKCALL;
02743    }
02744 
02745    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02746       options[i++] = OPT_CALLEE_REDIRECT;
02747    }
02748    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02749       options[i++] = OPT_CALLEE_AUTOMON;
02750    }
02751    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02752       options[i++] = OPT_CALLEE_DISCONNECT;
02753    }
02754    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02755       options[i++] = OPT_CALLEE_PARKCALL;
02756    }
02757 
02758    return options;
02759 }

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

Definition at line 1081 of file res_features.c.

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

Referenced by builtin_atxfer().

01082 {
01083    if (ast_channel_make_compatible(c, newchan) < 0) {
01084       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01085          c->name, newchan->name);
01086       ast_hangup(newchan);
01087       return -1;
01088    }
01089    return 0;
01090 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

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

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

static void clear_dialed_interfaces ( struct ast_channel chan  )  [static]

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

02116 {
02117    struct ast_datastore *di_datastore;
02118 
02119    ast_channel_lock(chan);
02120    if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
02121       if (option_debug) {
02122          ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name);
02123       }
02124       if (!ast_channel_datastore_remove(chan, di_datastore)) {
02125          ast_channel_datastore_free(di_datastore);
02126       }
02127    }
02128    ast_channel_unlock(chan);
02129 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 366 of file res_features.c.

References ast_free.

00367 {
00368    struct ast_dial_features *df = data;
00369    if (df) {
00370       ast_free(df);
00371    }
00372 }

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

Definition at line 353 of file res_features.c.

References ast_calloc.

00354 {
00355    struct ast_dial_features *df = data, *df_copy;
00356 
00357    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00358       return NULL;
00359    }
00360 
00361    memcpy(df_copy, df, sizeof(*df));
00362 
00363    return df_copy;
00364 }

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 2762 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_pbx_start(), ast_read(), ast_realloc, ast_set_flag, ast_strdup, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), callback_dialoptions(), parkeduser::chan, ast_channel::context, parkeduser::context, dahdi_chan_name, dahdi_chan_name_len, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, 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, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, and VERBOSE_PREFIX_2.

Referenced by load_module().

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

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

Check if a feature exists.

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

01671                                                                                            {
01672    char *chan_dynamic_features;
01673    ast_channel_lock(chan);
01674    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
01675    ast_channel_unlock(chan);
01676 
01677    return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL);
01678 }

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

01448 {
01449    struct ast_app *app;
01450    struct ast_call_feature *feature = data;
01451    struct ast_channel *work, *idle;
01452    int res;
01453 
01454    if (!feature) { /* shouldn't ever happen! */
01455       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01456       return -1; 
01457    }
01458 
01459    if (sense == FEATURE_SENSE_CHAN) {
01460       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01461          return FEATURE_RETURN_KEEPTRYING;
01462       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01463          work = chan;
01464          idle = peer;
01465       } else {
01466          work = peer;
01467          idle = chan;
01468       }
01469    } else {
01470       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01471          return FEATURE_RETURN_KEEPTRYING;
01472       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01473          work = peer;
01474          idle = chan;
01475       } else {
01476          work = chan;
01477          idle = peer;
01478       }
01479    }
01480 
01481    if (!(app = pbx_findapp(feature->app))) {
01482       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01483       return -2;
01484    }
01485 
01486    ast_autoservice_start(idle);
01487    ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
01488    
01489    if (!ast_strlen_zero(feature->moh_class))
01490       ast_moh_start(idle, feature->moh_class, NULL);
01491 
01492    res = pbx_exec(work, app, feature->app_args);
01493 
01494    if (!ast_strlen_zero(feature->moh_class))
01495       ast_moh_stop(idle);
01496 
01497    ast_autoservice_stop(idle);
01498 
01499    if (res)
01500       return FEATURE_RETURN_SUCCESSBREAK;
01501    
01502    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01503 }

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

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

Referenced by ast_bridge_call().

01634                                                                                                                                           {
01635 
01636    char dynamic_features_buf[128];
01637    const char *peer_dynamic_features, *chan_dynamic_features;
01638    struct ast_flags features;
01639    struct ast_call_feature feature;
01640    if (sense == FEATURE_SENSE_CHAN) {
01641       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
01642    }
01643    else {
01644       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
01645    }
01646 
01647    ast_channel_lock(peer);
01648    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
01649    ast_channel_unlock(peer);
01650 
01651    ast_channel_lock(chan);
01652    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
01653    ast_channel_unlock(chan);
01654 
01655    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,""));
01656 
01657    if (option_debug > 2) {
01658       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);
01659    }
01660 
01661    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
01662 }

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

References ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strlen_zero(), ast_test_flag, builtin_features, config, ast_call_feature::exten, exten, 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().

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

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]

Definition at line 1756 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(), builtin_features, ast_channel::call_forward, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_channel::hangupcause, len(), LOG_NOTICE, ast_channel::name, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.

Referenced by builtin_atxfer().

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

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

find a feature by name

Definition at line 1433 of file res_features.c.

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

Referenced by feature_interpret_helper(), and set_config_flags().

01434 {
01435    struct ast_call_feature *tmp;
01436 
01437    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01438       if (!strcasecmp(tmp->sname, name)) {
01439          break;
01440       }
01441    }
01442 
01443    return tmp;
01444 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 953 of file res_features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00954 {
00955         ast_indicate(chan, AST_CONTROL_UNHOLD);
00956   
00957         return ast_autoservice_stop(chan);
00958 }

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

Definition at line 3275 of file res_features.c.

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

03276 {
03277    struct parkeduser *cur;
03278    int numparked = 0;
03279 
03280    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
03281       , "Context", "Extension", "Pri", "Timeout");
03282 
03283    ast_mutex_lock(&parking_lock);
03284 
03285    for (cur = parkinglot; cur; cur = cur->next) {
03286       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
03287          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
03288          ,cur->priority, (long) cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
03289 
03290       numparked++;
03291    }
03292    ast_mutex_unlock(&parking_lock);
03293    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
03294 
03295 
03296    return RESULT_SUCCESS;
03297 }

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

Definition at line 3233 of file res_features.c.

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

03234 {
03235    int i;
03236    struct ast_call_feature *feature;
03237    char format[] = "%-25s %-7s %-7s\n";
03238 
03239    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
03240    ast_cli(fd, format, "---------------", "-------", "-------");
03241 
03242    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
03243 
03244    ast_rwlock_rdlock(&features_lock);
03245    for (i = 0; i < FEATURES_COUNT; i++)
03246       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
03247    ast_rwlock_unlock(&features_lock);
03248 
03249    ast_cli(fd, "\n");
03250    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
03251    ast_cli(fd, format, "---------------", "-------", "-------");
03252    if (AST_RWLIST_EMPTY(&feature_list)) {
03253       ast_cli(fd, "(none)\n");
03254    } else {
03255       AST_RWLIST_RDLOCK(&feature_list);
03256       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
03257          ast_cli(fd, format, feature->sname, "no def", feature->exten);
03258       }
03259       AST_RWLIST_UNLOCK(&feature_list);
03260    }
03261    ast_cli(fd, "\nCall parking\n");
03262    ast_cli(fd, "------------\n");
03263    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
03264    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
03265    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
03266    ast_cli(fd,"\n");
03267    
03268    return RESULT_SUCCESS;
03269 }

static int load_config ( void   )  [static]

Definition at line 3494 of file res_features.c.

References ast_config_load(), ast_copy_string(), AST_FEATURE_FLAG_BYBOTH, ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_strlen_zero(), ast_variable_browse(), DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_TRANSFER_DIGIT_TIMEOUT, LOG_WARNING, and var.

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

static int load_module ( void   )  [static]

Definition at line 3755 of file res_features.c.

References ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application(), cli_features, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), and park_exec().

03756 {
03757    int res;
03758    
03759    memset(parking_ext, 0, sizeof(parking_ext));
03760    memset(parking_con, 0, sizeof(parking_con));
03761 
03762    if ((res = load_config()))
03763       return res;
03764    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03765    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03766    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03767    if (!res)
03768       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03769    if (!res) {
03770       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03771       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03772          "Park a channel", mandescr_park); 
03773    }
03774 
03775    res |= ast_devstate_prov_add("Park", metermaidstate);
03776 
03777    return res;
03778 }

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

Definition at line 3366 of file res_features.c.

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

Referenced by load_module().

03367 {
03368    const char *channel = astman_get_header(m, "Channel");
03369    const char *channel2 = astman_get_header(m, "Channel2");
03370    const char *timeout = astman_get_header(m, "Timeout");
03371    char buf[BUFSIZ];
03372    int to = 0;
03373    int res = 0;
03374    int parkExt = 0;
03375    struct ast_channel *ch1, *ch2;
03376 
03377    if (ast_strlen_zero(channel)) {
03378       astman_send_error(s, m, "Channel not specified");
03379       return 0;
03380    }
03381 
03382    if (ast_strlen_zero(channel2)) {
03383       astman_send_error(s, m, "Channel2 not specified");
03384       return 0;
03385    }
03386 
03387    ch1 = ast_get_channel_by_name_locked(channel);
03388    if (!ch1) {
03389       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
03390       astman_send_error(s, m, buf);
03391       return 0;
03392    }
03393 
03394    ch2 = ast_get_channel_by_name_locked(channel2);
03395    if (!ch2) {
03396       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
03397       astman_send_error(s, m, buf);
03398       ast_channel_unlock(ch1);
03399       return 0;
03400    }
03401 
03402    if (!ast_strlen_zero(timeout)) {
03403       sscanf(timeout, "%30d", &to);
03404    }
03405 
03406    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
03407    if (!res) {
03408       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
03409       astman_send_ack(s, m, "Park successful");
03410    } else {
03411       astman_send_error(s, m, "Park failure");
03412    }
03413 
03414    ast_channel_unlock(ch1);
03415    ast_channel_unlock(ch2);
03416 
03417    return 0;
03418 }

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

Dump lot status.

Definition at line 3319 of file res_features.c.

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

Referenced by load_module().

03320 {
03321    struct parkeduser *cur;
03322    const char *id = astman_get_header(m, "ActionID");
03323    char idText[256] = "";
03324 
03325    if (!ast_strlen_zero(id))
03326       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
03327 
03328    astman_send_ack(s, m, "Parked calls will follow");
03329 
03330    ast_mutex_lock(&parking_lock);
03331 
03332    for (cur = parkinglot; cur; cur = cur->next) {
03333       astman_append(s, "Event: ParkedCall\r\n"
03334          "Exten: %d\r\n"
03335          "Channel: %s\r\n"
03336          "From: %s\r\n"
03337          "Timeout: %ld\r\n"
03338          "CallerID: %s\r\n"
03339          "CallerIDName: %s\r\n"
03340          "%s"
03341          "\r\n",
03342          cur->parkingnum, cur->chan->name, cur->peername,
03343          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
03344          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
03345          S_OR(cur->chan->cid.cid_name, ""),
03346          idText);
03347    }
03348 
03349    astman_append(s,
03350       "Event: ParkedCallsComplete\r\n"
03351       "%s"
03352       "\r\n",idText);
03353 
03354    ast_mutex_unlock(&parking_lock);
03355 
03356    return RESULT_SUCCESS;
03357 }

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 736 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(), parkeduser::chan, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_PARKFAILED, 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().

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

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

References masq_park_call().

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

00798 {
00799    return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
00800 }

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

metermaids callback from devicestate.c

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

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

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

Notify metermaids that we've changed an extension.

Definition at line 493 of file res_features.c.

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

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

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

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

Add parking hints for all defined parking lots.

Definition at line 3480 of file res_features.c.

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

03481 {
03482    int numext;
03483    char device[AST_MAX_EXTENSION];
03484    char exten[10];
03485 
03486    for (numext = start; numext <= stop; numext++) {
03487       snprintf(exten, sizeof(exten), "%d", numext);
03488       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03489       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03490    }
03491 }

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

Park a call.

Definition at line 3009 of file res_features.c.

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

Referenced by load_module().

03010 {
03011    /* Cache the original channel name in case we get masqueraded in the middle
03012     * of a park--it is still theoretically possible for a transfer to happen before
03013     * we get here, but it is _really_ unlikely */
03014    char *orig_chan_name = ast_strdupa(chan->name);
03015    char orig_exten[AST_MAX_EXTENSION];
03016    int orig_priority = chan->priority;
03017 
03018    /* Data is unused at the moment but could contain a parking
03019       lot context eventually */
03020    int res = 0;
03021    struct ast_module_user *u;
03022 
03023    u = ast_module_user_add(chan);
03024 
03025    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
03026 
03027    /* Setup the exten/priority to be s/1 since we don't know
03028       where this call should return */
03029    strcpy(chan->exten, "s");
03030    chan->priority = 1;
03031    /* Answer if call is not up */
03032    if (chan->_state != AST_STATE_UP)
03033       res = ast_answer(chan);
03034    /* Sleep to allow VoIP streams to settle down */
03035    if (!res)
03036       res = ast_safe_sleep(chan, 1000);
03037    /* Park the call */
03038    if (!res) {
03039       res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name);
03040       /* Continue on in the dialplan */
03041       if (res == 1) {
03042          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
03043          chan->priority = orig_priority;
03044          res = 0;
03045       } else if (!res) {
03046          res = 1;
03047       }
03048    }
03049 
03050    ast_module_user_remove(u);
03051 
03052    return res;
03053 }

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

References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_bridged_channel(), AST_CHANNEL_NAME, ast_channel_unlock, ast_clear_flag, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_copy_string(), AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_get_channel_by_name_locked(), ast_indicate_data(), ast_log(), ast_say_digits(), ast_set_flag, ast_strlen_zero(), ast_tvnow(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, option_verbose, park_space_reserve(), parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_getvar_helper(), pbx_builtin_setvar_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().

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

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

References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, ast_copy_flags, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_datastore::data, dial_features_info, EVENT_FLAG_CALL, 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, parkinglot, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.

Referenced by load_module().

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

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

Definition at line 525 of file res_features.c.

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

Referenced by masq_park_call(), and park_call_full().

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

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

Definition at line 2014 of file res_features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

02015 {
02016    struct ast_cdr *cdr_orig = cdr;
02017    while (cdr) {
02018       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02019          return cdr;
02020       cdr = cdr->next;
02021    }
02022    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
02023 }

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

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

03427 {
03428    if (option_debug)
03429       ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
03430 
03431    if (ast_answer(chan)) {
03432       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
03433       return -1;
03434    }
03435 
03436    if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
03437       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
03438       return -1;
03439    }
03440 
03441    if (ast_channel_masquerade(target, chan)) {
03442       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
03443       return -1;
03444    }
03445 
03446    return 0;
03447 }

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

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

02704 {
02705    manager_event(EVENT_FLAG_CALL, s,
02706       "Exten: %s\r\n"
02707       "Channel: %s\r\n"
02708       "CallerID: %s\r\n"
02709       "CallerIDName: %s\r\n\r\n",
02710       parkingexten, 
02711       chan->name,
02712       S_OR(chan->cid.cid_num, "<unknown>"),
02713       S_OR(chan->cid.cid_name, "<unknown>")
02714       );
02715 }

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

Find the context for the transfer.

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

00962 {
00963         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00964         if (ast_strlen_zero(s))
00965                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00966         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00967                 s = transferer->macrocontext;
00968         if (ast_strlen_zero(s))
00969                 s = transferer->context;
00970         return s;  
00971 }

static int reload ( void   )  [static]

Definition at line 3750 of file res_features.c.

References load_config().

03751 {
03752    return load_config();
03753 }

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

Definition at line 1515 of file res_features.c.

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

01516 {
01517    int x, res = -1;
01518 
01519    ast_rwlock_wrlock(&features_lock);
01520    for (x = 0; x < FEATURES_COUNT; x++) {
01521       if (strcasecmp(builtin_features[x].sname, name))
01522          continue;
01523 
01524       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01525       res = 0;
01526       break;
01527    }
01528    ast_rwlock_unlock(&features_lock);
01529 
01530    return res;
01531 }

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

Definition at line 2025 of file res_features.c.

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

Referenced by ast_bridge_call().

02026 {
02027    const char *feature;
02028 
02029    if (ast_strlen_zero(features)) {
02030       return;
02031    }
02032 
02033    for (feature = features; *feature; feature++) {
02034       switch (*feature) {
02035       case 'T' :
02036       case 't' :
02037          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
02038          break;
02039       case 'K' :
02040       case 'k' :
02041          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
02042          break;
02043       case 'H' :
02044       case 'h' :
02045          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
02046          break;
02047       case 'W' :
02048       case 'w' :
02049          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
02050          break;
02051       default :
02052          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
02053       }
02054    }
02055 }

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

00399 {
00400    ast_copy_string(chan->context, context, sizeof(chan->context));
00401    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00402    chan->priority = pri;
00403 }

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

Definition at line 1680 of file res_features.c.

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

Referenced by ast_bridge_call().

01681 {
01682    int x;
01683 
01684    ast_clear_flag(config, AST_FLAGS_ALL);
01685 
01686    ast_rwlock_rdlock(&features_lock);
01687    for (x = 0; x < FEATURES_COUNT; x++) {
01688       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01689          continue;
01690 
01691       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01692          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01693 
01694       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01695          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01696    }
01697    ast_rwlock_unlock(&features_lock);
01698 
01699    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01700       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01701 
01702       if (dynamic_features) {
01703          char *tmp = ast_strdupa(dynamic_features);
01704          char *tok;
01705          struct ast_call_feature *feature;
01706 
01707          /* while we have a feature */
01708          while ((tok = strsep(&tmp, "#"))) {
01709             AST_RWLIST_RDLOCK(&feature_list);
01710             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01711                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01712                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01713                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01714                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01715             }
01716             AST_RWLIST_UNLOCK(&feature_list);
01717          }
01718       }
01719    }
01720 }

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

References parkeduser::chan, and FEATURE_SENSE_PEER.

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

00807 {
00808    if (sense == FEATURE_SENSE_PEER) {
00809       *caller = peer;
00810       *callee = chan;
00811    } else {
00812       *callee = peer;
00813       *caller = chan;
00814    }
00815 }

static int unload_module ( void   )  [static]

Definition at line 3781 of file res_features.c.

References ast_cli_unregister_multiple(), ast_context_destroy(), ast_context_find(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), and cli_features.

03782 {
03783    struct ast_context *con;
03784    ast_module_user_hangup_all();
03785 
03786    ast_manager_unregister("ParkedCalls");
03787    ast_manager_unregister("Park");
03788    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03789    ast_unregister_application(parkcall);
03790    ast_devstate_prov_del("Park");
03791    /* Delete park-dial context */
03792    con = ast_context_find(parking_con_dial);
03793    if(con)
03794          ast_context_destroy(con, registrar);
03795    return ast_unregister_application(parkedcall);
03796 }

static void unmap_features ( void   )  [static]

Definition at line 1505 of file res_features.c.

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

01506 {
01507    int x;
01508 
01509    ast_rwlock_wrlock(&features_lock);
01510    for (x = 0; x < FEATURES_COUNT; x++)
01511       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01512    ast_rwlock_unlock(&features_lock);
01513 }


Variable Documentation

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

Definition at line 3802 of file res_features.c.

int adsipark [static]

Definition at line 177 of file res_features.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 3802 of file res_features.c.

int atxfernoanswertimeout [static]

Definition at line 182 of file res_features.c.

struct ast_call_feature builtin_features[] [static]

Definition at line 1378 of file res_features.c.

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

struct ast_cli_entry cli_features[] [static]

Definition at line 3308 of file res_features.c.

struct ast_cli_entry cli_show_features_deprecated [static]

Initial value:

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

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

char* descrip2 [static]

Definition at line 199 of file res_features.c.

struct ast_datastore_info dial_features_info

Initial value:

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

Definition at line 374 of file res_features.c.

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

int featuredigittimeout [static]

Definition at line 180 of file res_features.c.

ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static]

Definition at line 1376 of file res_features.c.

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

char mandescr_park[] [static]

Definition at line 3359 of file res_features.c.

struct ast_app* monitor_app = NULL [static]

Definition at line 210 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 211 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 195 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 175 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 230 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 174 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 232 of file res_features.c.

struct parkeduser* parkinglot [static]

Definition at line 228 of file res_features.c.

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

char parkingretalertinfo[256] [static]

Distinctive ring if chantech = SIP (adds a SIP AlertInfo header)

Definition at line 172 of file res_features.c.

char parkingretcidname[256] [static]

Callerid name of returned parked call

Definition at line 170 of file res_features.c.

char parkingretdahdiring[3] [static]

Distinctive ring if chantech = DAHDI

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

char showfeatures_help[] [static]

Initial value:

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

Definition at line 3271 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 3299 of file res_features.c.

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

Definition at line 187 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 197 of file res_features.c.

int transferdigittimeout [static]

Definition at line 179 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 Sat Aug 6 00:40:03 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7