Thu Mar 25 10:39:29 2010

Asterisk developer's documentation


res_features.c File Reference

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

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

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  ast_dial_features
struct  feature_list
struct  parkeduser

Defines

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

Enumerations

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

Functions

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

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Call Features Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static int adsipark
static const struct ast_module_infoast_module_info = &__mod_info
static int atxfernoanswertimeout
static struct ast_call_feature builtin_features []
static struct ast_cli_entry cli_features []
static struct ast_cli_entry cli_show_features_deprecated
static char courtesytone [256]
static char * descrip
static char * descrip2
ast_datastore_info dial_features_info
static int featuredigittimeout
static ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER
static char mandescr_park []
static struct ast_appmonitor_app = NULL
static int monitor_ok = 1
static int parkaddhints = 0
static char * parkcall = PARK_APP_NAME
static char * parkedcall = "ParkedCall"
static int parkedcallhangup
static int parkedcallrecording
static int parkedcallreparking
static int parkedcalltransfers
static int parkedplay = 0
static int parkfindnext
static char parking_con [AST_MAX_EXTENSION]
static char parking_con_dial [AST_MAX_EXTENSION]
static char parking_ext [AST_MAX_EXTENSION]
static ast_mutex_t parking_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static int parking_offset
static int parking_start
static int parking_stop
static pthread_t parking_thread
static struct parkeduserparkinglot
static 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 72 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   1000

Definition at line 69 of file res_features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 70 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 67 of file res_features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 68 of file res_features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 75 of file res_features.c.

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 80 of file res_features.c.

#define FEATURE_RETURN_PARKFAILED   25

Definition at line 81 of file res_features.c.

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 77 of file res_features.c.

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 78 of file res_features.c.

#define FEATURE_RETURN_SUCCESS   23

Definition at line 79 of file res_features.c.

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 76 of file res_features.c.

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

Definition at line 1146 of file res_features.c.

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

#define MAX_DIAL_FEATURE_OPTIONS   30

Definition at line 73 of file res_features.c.

Referenced by do_parking_thread().


Enumeration Type Documentation

anonymous enum

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 83 of file res_features.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 3281 of file res_features.c.

static void __unreg_module ( void   )  [static]

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

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

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

Definition at line 305 of file res_features.c.

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

Referenced by park_call_full().

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

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

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

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

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

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

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

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

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 291 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by do_atxfer().

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

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

References feature_interpret_helper().

Referenced by detect_disconnect().

01426                                                                                                                            {
01427 
01428    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
01429 }

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

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

Definition at line 1474 of file res_features.c.

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

Referenced by do_atxfer().

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

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

References masq_park_call().

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

00616 {
00617    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00618 }

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

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00560 {
00561    return park_call_full(chan, peer, timeout, extout, NULL, NULL);
00562 }

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

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

00212 {
00213    return parking_ext;
00214 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2923 of file res_features.c.

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

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

02924 {
02925    struct ast_channel *cur = NULL;
02926    int res = -1;
02927 
02928    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02929       if (!cur->pbx && 
02930          (cur != chan) &&
02931          (chan->pickupgroup & cur->callgroup) &&
02932          ((cur->_state == AST_STATE_RINGING) ||
02933           (cur->_state == AST_STATE_RING))) {
02934             break;
02935       }
02936       ast_channel_unlock(cur);
02937    }
02938    if (cur) {
02939       if (option_debug)
02940          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02941       res = ast_answer(chan);
02942       if (res)
02943          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02944       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02945       if (res)
02946          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02947       res = ast_channel_masquerade(cur, chan);
02948       if (res)
02949          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02950       ast_channel_unlock(cur);
02951    } else   {
02952       if (option_debug)
02953          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02954    }
02955    return res;
02956 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 216 of file res_features.c.

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

00217 {
00218    return pickup_ext;
00219 }

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

01164 {
01165    if (!feature) {
01166       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01167          return;
01168    }
01169   
01170    AST_RWLIST_WRLOCK(&feature_list);
01171    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01172    AST_RWLIST_UNLOCK(&feature_list);
01173 
01174    if (option_verbose >= 2) {
01175       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01176    }
01177 }

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

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

01181 {
01182    if (!feature)
01183       return;
01184 
01185    AST_RWLIST_WRLOCK(&feature_list);
01186    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01187    AST_RWLIST_UNLOCK(&feature_list);
01188    
01189    free(feature);
01190 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1193 of file res_features.c.

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

01194 {
01195    struct ast_call_feature *feature;
01196 
01197    AST_RWLIST_WRLOCK(&feature_list);
01198    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01199       free(feature);
01200    }
01201    AST_RWLIST_UNLOCK(&feature_list);
01202 }

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

Attended transfer ().

Parameters:
chan 
peer 
config 
code 
sense 
data Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel.
Returns:
-1 means what failure/success both?

Definition at line 1140 of file res_features.c.

References config, and do_atxfer().

01141 {
01142    return do_atxfer(chan, peer, config, sense, NULL, NULL);
01143 }

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

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

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

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

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

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

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

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

00760 {
00761    if (option_verbose > 3)
00762       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00763    return FEATURE_RETURN_HANGUP;
00764 }

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

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

Referenced by do_atxfer().

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

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

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

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

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

Definition at line 883 of file res_features.c.

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

Referenced by do_atxfer().

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

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Definition at line 236 of file res_features.c.

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

Referenced by builtin_blindtransfer().

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

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

Definition at line 1742 of file res_features.c.

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

Referenced by ast_bridge_call().

01743 {
01744    int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER;
01745    char *context = strchr(xferto, '@');;
01746    if (context)
01747       *context++ = '\0';
01748    do_atxfer(a, b, conf, sense, xferto, context);
01749 }

static void dial_features_destroy ( void *  data  )  [static]

Definition at line 197 of file res_features.c.

References ast_free.

00198 {
00199    struct ast_dial_features *df = data;
00200    if (df) {
00201       ast_free(df);
00202    }
00203 }

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

Definition at line 184 of file res_features.c.

References ast_calloc.

00185 {
00186    struct ast_dial_features *df = data, *df_copy;
00187 
00188    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00189       return NULL;
00190    }
00191 
00192    memcpy(df_copy, df, sizeof(*df));
00193 
00194    return df_copy;
00195 }

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

Attended transfer implementation.

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

Definition at line 909 of file res_features.c.

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

Referenced by builtin_atxfer(), and cmd_atxfer().

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

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

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

Referenced by load_module().

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

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

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

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

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

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

Referenced by ast_bridge_call().

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

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

Helper function for feature_interpret and ast_feature_detect.

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

Definition at line 1314 of file res_features.c.

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

Referenced by ast_feature_detect(), and feature_interpret().

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

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

find a feature by name

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

01206 {
01207    struct ast_call_feature *tmp;
01208 
01209    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01210       if (!strcasecmp(tmp->sname, name)) {
01211          break;
01212       }
01213    }
01214 
01215    return tmp;
01216 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 766 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

00767 {
00768         ast_indicate(chan, AST_CONTROL_UNHOLD);
00769   
00770         return ast_autoservice_stop(chan);
00771 }

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

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

02778 {
02779    struct parkeduser *cur;
02780    int numparked = 0;
02781 
02782    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02783       , "Context", "Extension", "Pri", "Timeout");
02784 
02785    ast_mutex_lock(&parking_lock);
02786 
02787    for (cur = parkinglot; cur; cur = cur->next) {
02788       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02789          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02790          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02791 
02792       numparked++;
02793    }
02794    ast_mutex_unlock(&parking_lock);
02795    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02796 
02797 
02798    return RESULT_SUCCESS;
02799 }

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

Definition at line 2735 of file res_features.c.

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

02736 {
02737    int i;
02738    struct ast_call_feature *feature;
02739    char format[] = "%-25s %-7s %-7s\n";
02740 
02741    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02742    ast_cli(fd, format, "---------------", "-------", "-------");
02743 
02744    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02745 
02746    ast_rwlock_rdlock(&features_lock);
02747    for (i = 0; i < FEATURES_COUNT; i++)
02748       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02749    ast_rwlock_unlock(&features_lock);
02750 
02751    ast_cli(fd, "\n");
02752    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02753    ast_cli(fd, format, "---------------", "-------", "-------");
02754    if (AST_RWLIST_EMPTY(&feature_list)) {
02755       ast_cli(fd, "(none)\n");
02756    } else {
02757       AST_RWLIST_RDLOCK(&feature_list);
02758       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
02759          ast_cli(fd, format, feature->sname, "no def", feature->exten);
02760       }
02761       AST_RWLIST_UNLOCK(&feature_list);
02762    }
02763    ast_cli(fd, "\nCall parking\n");
02764    ast_cli(fd, "------------\n");
02765    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02766    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02767    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02768    ast_cli(fd,"\n");
02769    
02770    return RESULT_SUCCESS;
02771 }

static int load_config ( void   )  [static]

Definition at line 2973 of file res_features.c.

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

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

static int load_module ( void   )  [static]

Definition at line 3234 of file res_features.c.

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

03235 {
03236    int res;
03237    
03238    memset(parking_ext, 0, sizeof(parking_ext));
03239    memset(parking_con, 0, sizeof(parking_con));
03240 
03241    if ((res = load_config()))
03242       return res;
03243    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03244    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03245    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03246    if (!res)
03247       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03248    if (!res) {
03249       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03250       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03251          "Park a channel", mandescr_park); 
03252    }
03253 
03254    res |= ast_devstate_prov_add("Park", metermaidstate);
03255 
03256    return res;
03257 }

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

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

02869 {
02870    const char *channel = astman_get_header(m, "Channel");
02871    const char *channel2 = astman_get_header(m, "Channel2");
02872    const char *timeout = astman_get_header(m, "Timeout");
02873    char buf[BUFSIZ];
02874    int to = 0;
02875    int res = 0;
02876    int parkExt = 0;
02877    struct ast_channel *ch1, *ch2;
02878 
02879    if (ast_strlen_zero(channel)) {
02880       astman_send_error(s, m, "Channel not specified");
02881       return 0;
02882    }
02883 
02884    if (ast_strlen_zero(channel2)) {
02885       astman_send_error(s, m, "Channel2 not specified");
02886       return 0;
02887    }
02888 
02889    ch1 = ast_get_channel_by_name_locked(channel);
02890    if (!ch1) {
02891       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02892       astman_send_error(s, m, buf);
02893       return 0;
02894    }
02895 
02896    ch2 = ast_get_channel_by_name_locked(channel2);
02897    if (!ch2) {
02898       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02899       astman_send_error(s, m, buf);
02900       ast_channel_unlock(ch1);
02901       return 0;
02902    }
02903 
02904    if (!ast_strlen_zero(timeout)) {
02905       sscanf(timeout, "%30d", &to);
02906    }
02907 
02908    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02909    if (!res) {
02910       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02911       astman_send_ack(s, m, "Park successful");
02912    } else {
02913       astman_send_error(s, m, "Park failure");
02914    }
02915 
02916    ast_channel_unlock(ch1);
02917    ast_channel_unlock(ch2);
02918 
02919    return 0;
02920 }

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

Dump lot status.

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

02822 {
02823    struct parkeduser *cur;
02824    const char *id = astman_get_header(m, "ActionID");
02825    char idText[256] = "";
02826 
02827    if (!ast_strlen_zero(id))
02828       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02829 
02830    astman_send_ack(s, m, "Parked calls will follow");
02831 
02832    ast_mutex_lock(&parking_lock);
02833 
02834    for (cur = parkinglot; cur; cur = cur->next) {
02835       astman_append(s, "Event: ParkedCall\r\n"
02836          "Exten: %d\r\n"
02837          "Channel: %s\r\n"
02838          "From: %s\r\n"
02839          "Timeout: %ld\r\n"
02840          "CallerID: %s\r\n"
02841          "CallerIDName: %s\r\n"
02842          "%s"
02843          "\r\n",
02844          cur->parkingnum, cur->chan->name, cur->peername,
02845          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02846          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02847          S_OR(cur->chan->cid.cid_name, ""),
02848          idText);
02849    }
02850 
02851    astman_append(s,
02852       "Event: ParkedCallsComplete\r\n"
02853       "%s"
02854       "\r\n",idText);
02855 
02856    ast_mutex_unlock(&parking_lock);
02857 
02858    return RESULT_SUCCESS;
02859 }

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

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

Referenced by ast_masq_park_call(), and masq_park_call_announce().

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

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

References masq_park_call().

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

00621 {
00622    return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
00623 }

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

metermaids callback from devicestate.c

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

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

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

Notify metermaids that we've changed an extension.

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

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

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

Add parking hints for all defined parking lots.

Definition at line 2959 of file res_features.c.

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

02960 {
02961    int numext;
02962    char device[AST_MAX_EXTENSION];
02963    char exten[10];
02964 
02965    for (numext = start; numext <= stop; numext++) {
02966       snprintf(exten, sizeof(exten), "%d", numext);
02967       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02968       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02969    }
02970 }

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

Park a call.

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

02516 {
02517    /* Cache the original channel name in case we get masqueraded in the middle
02518     * of a park--it is still theoretically possible for a transfer to happen before
02519     * we get here, but it is _really_ unlikely */
02520    char *orig_chan_name = ast_strdupa(chan->name);
02521    char orig_exten[AST_MAX_EXTENSION];
02522    int orig_priority = chan->priority;
02523 
02524    /* Data is unused at the moment but could contain a parking
02525       lot context eventually */
02526    int res = 0;
02527    struct ast_module_user *u;
02528 
02529    u = ast_module_user_add(chan);
02530 
02531    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
02532 
02533    /* Setup the exten/priority to be s/1 since we don't know
02534       where this call should return */
02535    strcpy(chan->exten, "s");
02536    chan->priority = 1;
02537    /* Answer if call is not up */
02538    if (chan->_state != AST_STATE_UP)
02539       res = ast_answer(chan);
02540    /* Sleep to allow VoIP streams to settle down */
02541    if (!res)
02542       res = ast_safe_sleep(chan, 1000);
02543    /* Park the call */
02544    if (!res) {
02545       res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name);
02546       /* Continue on in the dialplan */
02547       if (res == 1) {
02548          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
02549          chan->priority = orig_priority;
02550          res = 0;
02551       } else if (!res) {
02552          res = 1;
02553       }
02554    }
02555 
02556    ast_module_user_remove(u);
02557 
02558    return res;
02559 }

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

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

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

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

Referenced by load_module().

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

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

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

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

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

Definition at line 1641 of file res_features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

01642 {
01643    struct ast_cdr *cdr_orig = cdr;
01644    while (cdr) {
01645       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
01646          return cdr;
01647       cdr = cdr->next;
01648    }
01649    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
01650 }

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

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

02252 {
02253    manager_event(EVENT_FLAG_CALL, s,
02254       "Exten: %s\r\n"
02255       "Channel: %s\r\n"
02256       "CallerID: %s\r\n"
02257       "CallerIDName: %s\r\n\r\n",
02258       parkingexten, 
02259       chan->name,
02260       S_OR(chan->cid.cid_num, "<unknown>"),
02261       S_OR(chan->cid.cid_name, "<unknown>")
02262       );
02263 }

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

Find the context for the transfer.

Definition at line 774 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

00775 {
00776         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00777         if (ast_strlen_zero(s))
00778                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00779         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00780                 s = transferer->macrocontext;
00781         if (ast_strlen_zero(s))
00782                 s = transferer->context;
00783         return s;  
00784 }

static int reload ( void   )  [static]

Definition at line 3229 of file res_features.c.

References load_config().

03230 {
03231    return load_config();
03232 }

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

Definition at line 1286 of file res_features.c.

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

01287 {
01288    int x, res = -1;
01289 
01290    ast_rwlock_wrlock(&features_lock);
01291    for (x = 0; x < FEATURES_COUNT; x++) {
01292       if (strcasecmp(builtin_features[x].sname, name))
01293          continue;
01294 
01295       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01296       res = 0;
01297       break;
01298    }
01299    ast_rwlock_unlock(&features_lock);
01300 
01301    return res;
01302 }

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

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

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

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

00230 {
00231    ast_copy_string(chan->context, context, sizeof(chan->context));
00232    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00233    chan->priority = pri;
00234 }

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

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

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

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

References parkeduser::chan, and FEATURE_SENSE_PEER.

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

00630 {
00631    if (sense == FEATURE_SENSE_PEER) {
00632       *caller = peer;
00633       *callee = chan;
00634    } else {
00635       *callee = peer;
00636       *caller = chan;
00637    }
00638 }

static int unload_module ( void   )  [static]

Definition at line 3260 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(), cli_features, parkcall, parkedcall, parking_con_dial, and registrar.

03261 {
03262    struct ast_context *con;
03263    ast_module_user_hangup_all();
03264 
03265    ast_manager_unregister("ParkedCalls");
03266    ast_manager_unregister("Park");
03267    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03268    ast_unregister_application(parkcall);
03269    ast_devstate_prov_del("Park");
03270    /* Delete park-dial context */
03271    con = ast_context_find(parking_con_dial);
03272    if(con)
03273          ast_context_destroy(con, registrar);
03274    return ast_unregister_application(parkedcall);
03275 }

static void unmap_features ( void   )  [static]

Definition at line 1276 of file res_features.c.

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

01277 {
01278    int x;
01279 
01280    ast_rwlock_wrlock(&features_lock);
01281    for (x = 0; x < FEATURES_COUNT; x++)
01282       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01283    ast_rwlock_unlock(&features_lock);
01284 }


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

int adsipark [static]

Definition at line 121 of file res_features.c.

Referenced by load_config().

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 3281 of file res_features.c.

int atxfernoanswertimeout [static]

Definition at line 126 of file res_features.c.

Referenced by load_config().

struct ast_call_feature builtin_features[] [static]

Definition at line 1150 of file res_features.c.

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

struct ast_cli_entry cli_features[] [static]

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

char courtesytone[256] [static]

Courtesy tone

Definition at line 109 of file res_features.c.

Referenced by load_config(), and park_exec().

char* descrip [static]

Initial value:

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

Definition at line 133 of file res_features.c.

char* descrip2 [static]

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

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

int featuredigittimeout [static]

Definition at line 124 of file res_features.c.

ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static]

Definition at line 1148 of file res_features.c.

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

char mandescr_park[] [static]

Definition at line 2861 of file res_features.c.

Referenced by load_module().

struct ast_app* monitor_app = NULL [static]

Definition at line 154 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 155 of file res_features.c.

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 94 of file res_features.c.

Referenced by load_config().

char* parkcall = PARK_APP_NAME [static]

Definition at line 139 of file res_features.c.

Referenced by load_module(), and unload_module().

char* parkedcall = "ParkedCall" [static]

Definition at line 92 of file res_features.c.

Referenced by load_module(), and unload_module().

int parkedcallhangup [static]

Who can DISCONNECT after picking up a parked call

Definition at line 106 of file res_features.c.

Referenced by load_config(), and park_exec().

int parkedcallrecording [static]

Who can AUTOMON after picking up a parked call

Definition at line 107 of file res_features.c.

Referenced by load_config(), and park_exec().

int parkedcallreparking [static]

Who can PARKCALL after picking up a parked call

Definition at line 105 of file res_features.c.

Referenced by load_config(), and park_exec().

int parkedcalltransfers [static]

Who can REDIRECT after picking up a parked a call

Definition at line 104 of file res_features.c.

Referenced by load_config(), and park_exec().

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 110 of file res_features.c.

Referenced by park_exec().

int parkfindnext [static]

Definition at line 119 of file res_features.c.

Referenced by load_config().

char parking_con[AST_MAX_EXTENSION] [static]

Context for which parking is made accessible

Definition at line 96 of file res_features.c.

Referenced by handle_showfeatures(), load_config(), load_module(), and park_exec().

char parking_con_dial[AST_MAX_EXTENSION] [static]

Context for dialback for parking (KLUDGE)

Definition at line 97 of file res_features.c.

Referenced by load_config(), and unload_module().

char parking_ext[AST_MAX_EXTENSION] [static]

Extension you type to park the call

Definition at line 98 of file res_features.c.

Referenced by handle_showfeatures(), load_config(), and load_module().

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

protects all static variables above

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

int parking_start [static]

First available extension for parking

Definition at line 101 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

int parking_stop [static]

Last available extension for parking

Definition at line 102 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

pthread_t parking_thread [static]

Definition at line 176 of file res_features.c.

Referenced by load_module().

struct parkeduser* parkinglot [static]

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

char parkingretcidname[256] [static]

Callerid name of returned parked call

Definition at line 114 of file res_features.c.

char parkingretdahdiring[3] [static]

Distinctive ring if chantech = DAHDI

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

char parkmohclass[MAX_MUSICCLASS] [static]

Music class used for parking

Definition at line 100 of file res_features.c.

Referenced by load_config().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 99 of file res_features.c.

Referenced by load_config().

char* registrar = "res_features" [static]

Registrar for operations

Definition at line 128 of file res_features.c.

char showfeatures_help[] [static]

Initial value:

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

Definition at line 2773 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 2801 of file res_features.c.

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

Definition at line 131 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 141 of file res_features.c.

int transferdigittimeout [static]

Definition at line 123 of file res_features.c.

Referenced by load_config().

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 112 of file res_features.c.

Referenced by load_config().

char xfersound[256] [static]

Call transfer sound

Definition at line 111 of file res_features.c.

Referenced by load_config().


Generated on Thu Mar 25 10:39:29 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7