Wed Feb 11 12:00:30 2009

Asterisk developer's documentation


res_features.c File Reference

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

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

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  feature_list
struct  parkeduser

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500
#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_PASSDIGITS   21
#define FEATURE_RETURN_STOREDIGITS   22
#define FEATURE_RETURN_SUCCESS   23
#define FEATURE_RETURN_SUCCESSBREAK   0
#define FEATURE_SENSE_CHAN   (1 << 0)
#define FEATURE_SENSE_PEER   (1 << 1)
#define FEATURES_COUNT   (sizeof(builtin_features) / sizeof(builtin_features[0]))

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 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)
static int ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
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 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 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 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)
static int park_exec (struct ast_channel *chan, void *data)
 Pickup parked call.
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_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 = "f450f61f60e761b3aa089ebed76ca8a5" , .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
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 parkedcalltransfers
static int parkedplay = 0
static int parkfindnext
static char parking_con [AST_MAX_EXTENSION]
static char parking_con_dial [AST_MAX_EXTENSION]
static char parking_ext [AST_MAX_EXTENSION]
static ast_mutex_t parking_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static int parking_offset
static int parking_start
static int parking_stop
static pthread_t parking_thread
static struct parkeduserparkinglot
static int parkingtime = DEFAULT_PARK_TIME
static char parkmohclass [MAX_MUSICCLASS]
static char pickup_ext [AST_MAX_EXTENSION]
static char * registrar = "res_features"
static char showfeatures_help []
static char showparked_help []
static char * synopsis = "Answer a parked call"
static char * synopsis2 = "Park yourself"
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file res_features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 72 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500

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

Referenced by builtin_disconnect().

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 544 of file res_features.c.

Referenced by ast_feature_interpret(), and feature_exec_app().

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 541 of file res_features.c.

Referenced by ast_bridge_call(), and ast_feature_interpret().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 542 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_SUCCESS   23

Definition at line 543 of file res_features.c.

Referenced by ast_bridge_call(), builtin_automonitor(), builtin_blindtransfer(), do_atxfer(), and feature_exec_app().

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 540 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 546 of file res_features.c.

Referenced by ast_bridge_call(), ast_feature_interpret(), cmd_atxfer(), and feature_exec_app().

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 547 of file res_features.c.

Referenced by ast_bridge_call(), cmd_atxfer(), and set_peers().

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

Definition at line 1030 of file res_features.c.

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


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

00074      {
00075    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00076    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00077    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00078    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00079    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00080    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00081 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2811 of file res_features.c.

static void __unreg_module ( void   )  [static]

Definition at line 2811 of file res_features.c.

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

Definition at line 257 of file res_features.c.

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

Referenced by park_call_full().

00258 {
00259    int res;
00260    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00261    char tmp[256];
00262    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00263 
00264    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00265    message[0] = tmp;
00266    res = ast_adsi_load_session(chan, NULL, 0, 1);
00267    if (res == -1)
00268       return res;
00269    return ast_adsi_print(chan, message, justify, 1);
00270 }

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

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, ast_answer(), ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), 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_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, 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_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_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, 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(), park_exec(), and try_calling().

01478 {
01479    /* Copy voice back and forth between the two channels.  Give the peer
01480       the ability to transfer calls with '#<extension' syntax. */
01481    struct ast_frame *f;
01482    struct ast_channel *who;
01483    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01484    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01485    char orig_channame[AST_MAX_EXTENSION];
01486    char orig_peername[AST_MAX_EXTENSION];
01487 
01488    int res;
01489    int diff;
01490    int hasfeatures=0;
01491    int hadfeatures=0;
01492    int autoloopflag;
01493    struct ast_option_header *aoh;
01494    struct ast_bridge_config backup_config;
01495    struct ast_cdr *bridge_cdr = NULL;
01496    struct ast_cdr *orig_peer_cdr = NULL;
01497    struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
01498    struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
01499    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
01500    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
01501 
01502    memset(&backup_config, 0, sizeof(backup_config));
01503 
01504    config->start_time = ast_tvnow();
01505 
01506    if (chan && peer) {
01507       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01508       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01509    } else if (chan) {
01510       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01511    }
01512 
01513    /* This is an interesting case.  One example is if a ringing channel gets redirected to
01514     * an extension that picks up a parked call.  This will make sure that the call taken
01515     * out of parking gets told that the channel it just got bridged to is still ringing. */
01516    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
01517       ast_indicate(peer, AST_CONTROL_RINGING);
01518    }
01519 
01520    if (monitor_ok) {
01521       const char *monitor_exec;
01522       struct ast_channel *src = NULL;
01523       if (!monitor_app) { 
01524          if (!(monitor_app = pbx_findapp("Monitor")))
01525             monitor_ok=0;
01526       }
01527       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01528          src = chan;
01529       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01530          src = peer;
01531       if (monitor_app && src) {
01532          char *tmp = ast_strdupa(monitor_exec);
01533          pbx_exec(src, monitor_app, tmp);
01534       }
01535    }
01536    
01537    set_config_flags(chan, peer, config);
01538    config->firstpass = 1;
01539 
01540    /* Answer if need be */
01541    if (ast_answer(chan))
01542       return -1;
01543 
01544    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
01545    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
01546    orig_peer_cdr = peer_cdr;
01547    
01548    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
01549          
01550       if (chan_cdr) {
01551          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
01552          ast_cdr_update(chan);
01553          bridge_cdr = ast_cdr_dup(chan_cdr);
01554          ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
01555          ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
01556       } else {
01557          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
01558          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
01559          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
01560          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
01561          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
01562          ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp));
01563          ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
01564          ast_cdr_setcid(bridge_cdr, chan);
01565          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
01566          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
01567          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
01568          /* Destination information */
01569          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
01570          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
01571          if (peer_cdr) {
01572             bridge_cdr->start = peer_cdr->start;
01573             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
01574          } else {
01575             ast_cdr_start(bridge_cdr);
01576          }
01577       }
01578       /* peer_cdr->answer will be set when a macro runs on the peer;
01579          in that case, the bridge answer will be delayed while the
01580          macro plays on the peer channel. The peer answered the call
01581          before the macro started playing. To the phone system,
01582          this is billable time for the call, even tho the caller
01583          hears nothing but ringing while the macro does its thing. */
01584       if (peer_cdr && !ast_tvzero(peer_cdr->answer)) {
01585          bridge_cdr->answer = peer_cdr->answer;
01586          chan_cdr->answer = peer_cdr->answer;
01587          bridge_cdr->disposition = peer_cdr->disposition;
01588          chan_cdr->disposition = peer_cdr->disposition;
01589       } else {
01590          ast_cdr_answer(bridge_cdr);
01591          ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
01592       }
01593       ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
01594       if (peer_cdr) {
01595          ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
01596       }
01597    }
01598    
01599    for (;;) {
01600       struct ast_channel *other; /* used later */
01601       
01602       res = ast_channel_bridge(chan, peer, config, &f, &who);
01603       
01604       if (config->feature_timer) {
01605          /* Update time limit for next pass */
01606          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01607          config->feature_timer -= diff;
01608          if (hasfeatures) {
01609             /* Running on backup config, meaning a feature might be being
01610                activated, but that's no excuse to keep things going 
01611                indefinitely! */
01612             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01613                if (option_debug)
01614                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01615                config->feature_timer = 0;
01616                who = chan;
01617                if (f)
01618                   ast_frfree(f);
01619                f = NULL;
01620                res = 0;
01621             } else if (config->feature_timer <= 0) {
01622                /* Not *really* out of time, just out of time for
01623                   digits to come in for features. */
01624                if (option_debug)
01625                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01626                if (!ast_strlen_zero(peer_featurecode)) {
01627                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01628                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01629                }
01630                if (!ast_strlen_zero(chan_featurecode)) {
01631                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01632                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01633                }
01634                if (f)
01635                   ast_frfree(f);
01636                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01637                if (!hasfeatures) {
01638                   /* Restore original (possibly time modified) bridge config */
01639                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01640                   memset(&backup_config, 0, sizeof(backup_config));
01641                }
01642                hadfeatures = hasfeatures;
01643                /* Continue as we were */
01644                continue;
01645             } else if (!f) {
01646                /* The bridge returned without a frame and there is a feature in progress.
01647                 * However, we don't think the feature has quite yet timed out, so just
01648                 * go back into the bridge. */
01649                continue;
01650             }
01651          } else {
01652             if (config->feature_timer <=0) {
01653                /* We ran out of time */
01654                config->feature_timer = 0;
01655                who = chan;
01656                if (f)
01657                   ast_frfree(f);
01658                f = NULL;
01659                res = 0;
01660             }
01661          }
01662       }
01663       if (res < 0) {
01664          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01665             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01666          goto before_you_go;
01667       }
01668       
01669       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01670             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01671                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01672          res = -1;
01673          break;
01674       }
01675       /* many things should be sent to the 'other' channel */
01676       other = (who == chan) ? peer : chan;
01677       if (f->frametype == AST_FRAME_CONTROL) {
01678          switch (f->subclass) {
01679          case AST_CONTROL_RINGING:
01680          case AST_CONTROL_FLASH:
01681          case -1:
01682             ast_indicate(other, f->subclass);
01683             break;
01684          case AST_CONTROL_HOLD:
01685          case AST_CONTROL_UNHOLD:
01686             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01687             break;
01688          case AST_CONTROL_OPTION:
01689             aoh = f->data;
01690             /* Forward option Requests */
01691             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01692                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01693                   f->datalen - sizeof(struct ast_option_header), 0);
01694             }
01695             break;
01696          case AST_CONTROL_ATXFERCMD:
01697             cmd_atxfer(chan, peer, config, who, f->data);
01698             break;
01699          }
01700       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01701          /* eat it */
01702       } else if (f->frametype == AST_FRAME_DTMF) {
01703          char *featurecode;
01704          int sense;
01705 
01706          hadfeatures = hasfeatures;
01707          /* This cannot overrun because the longest feature is one shorter than our buffer */
01708          if (who == chan) {
01709             sense = FEATURE_SENSE_CHAN;
01710             featurecode = chan_featurecode;
01711          } else  {
01712             sense = FEATURE_SENSE_PEER;
01713             featurecode = peer_featurecode;
01714          }
01715          /*! append the event to featurecode. we rely on the string being zero-filled, and
01716           * not overflowing it. 
01717           * \todo XXX how do we guarantee the latter ?
01718           */
01719          featurecode[strlen(featurecode)] = f->subclass;
01720          /* Get rid of the frame before we start doing "stuff" with the channels */
01721          ast_frfree(f);
01722          f = NULL;
01723          config->feature_timer = backup_config.feature_timer;
01724          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01725          switch(res) {
01726          case FEATURE_RETURN_PASSDIGITS:
01727             ast_dtmf_stream(other, who, featurecode, 0);
01728             /* Fall through */
01729          case FEATURE_RETURN_SUCCESS:
01730             memset(featurecode, 0, sizeof(chan_featurecode));
01731             break;
01732          }
01733          if (res >= FEATURE_RETURN_PASSDIGITS) {
01734             res = 0;
01735          } else 
01736             break;
01737          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01738          if (hadfeatures && !hasfeatures) {
01739             /* Restore backup */
01740             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01741             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01742          } else if (hasfeatures) {
01743             if (!hadfeatures) {
01744                /* Backup configuration */
01745                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01746                /* Setup temporary config options */
01747                config->play_warning = 0;
01748                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01749                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01750                config->warning_freq = 0;
01751                config->warning_sound = NULL;
01752                config->end_sound = NULL;
01753                config->start_sound = NULL;
01754                config->firstpass = 0;
01755             }
01756             config->start_time = ast_tvnow();
01757             config->feature_timer = featuredigittimeout;
01758             if (option_debug)
01759                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01760          }
01761       }
01762       if (f)
01763          ast_frfree(f);
01764 
01765    }
01766   before_you_go:
01767    if (config->end_bridge_callback) {
01768       config->end_bridge_callback(config->end_bridge_callback_data);
01769    }
01770 
01771    autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
01772    ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
01773    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
01774       struct ast_cdr *swapper = NULL;
01775       char savelastapp[AST_MAX_EXTENSION];
01776       char savelastdata[AST_MAX_EXTENSION];
01777       char save_exten[AST_MAX_EXTENSION];
01778       int  save_prio;
01779       
01780       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
01781          ast_cdr_end(bridge_cdr);
01782       }
01783       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
01784          dialplan code operate on it */
01785       ast_channel_lock(chan);
01786       if (bridge_cdr) {
01787          swapper = chan->cdr;
01788          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
01789          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
01790          chan->cdr = bridge_cdr;
01791       }
01792       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
01793       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
01794       save_prio = chan->priority;
01795       chan->priority = 1;
01796       ast_channel_unlock(chan);
01797       while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
01798          if (ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
01799             /* Something bad happened, or a hangup has been requested. */
01800             if (option_debug)
01801                ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
01802             if (option_verbose > 1)
01803                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);
01804             break;
01805          }
01806          chan->priority++;
01807       }
01808       /* swap it back */
01809       ast_channel_lock(chan);
01810       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
01811       chan->priority = save_prio;
01812       if (bridge_cdr)
01813          chan->cdr = swapper;
01814       ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
01815       ast_channel_unlock(chan);
01816       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
01817       if (bridge_cdr) {
01818          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
01819          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
01820       }
01821    }
01822    ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
01823 
01824    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
01825    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
01826    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
01827       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
01828    }
01829 
01830    /* we can post the bridge CDR at this point */
01831    if (bridge_cdr) {
01832       ast_cdr_end(bridge_cdr);
01833       ast_cdr_detach(bridge_cdr);
01834    }
01835    
01836    /* do a specialized reset on the beginning channel
01837       CDR's, if they still exist, so as not to mess up
01838       issues in future bridges;
01839       
01840       Here are the rules of the game:
01841       1. The chan and peer channel pointers will not change
01842          during the life of the bridge.
01843       2. But, in transfers, the channel names will change.
01844          between the time the bridge is started, and the
01845          time the channel ends. 
01846          Usually, when a channel changes names, it will
01847          also change CDR pointers.
01848       3. Usually, only one of the two channels (chan or peer)
01849          will change names.
01850       4. Usually, if a channel changes names during a bridge,
01851          it is because of a transfer. Usually, in these situations,
01852          it is normal to see 2 bridges running simultaneously, and
01853          it is not unusual to see the two channels that change
01854          swapped between bridges.
01855       5. After a bridge occurs, we have 2 or 3 channels' CDRs
01856          to attend to; if the chan or peer changed names,
01857          we have the before and after attached CDR's.
01858    */
01859    
01860    if (new_chan_cdr) {
01861       struct ast_channel *chan_ptr = NULL;
01862       
01863       if (strcasecmp(orig_channame, chan->name) != 0) { 
01864          /* old channel */
01865          chan_ptr = ast_get_channel_by_name_locked(orig_channame);
01866          if (chan_ptr) {
01867             if (!ast_bridged_channel(chan_ptr)) {
01868                struct ast_cdr *cur;
01869                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
01870                   if (cur == chan_cdr) {
01871                      break;
01872                   }
01873                }
01874                if (cur)
01875                   ast_cdr_specialized_reset(chan_cdr,0);
01876             }
01877             ast_channel_unlock(chan_ptr);
01878          }
01879          /* new channel */
01880          ast_cdr_specialized_reset(new_chan_cdr,0);
01881       } else {
01882          ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr  */
01883       }
01884    }
01885 
01886    {
01887       struct ast_channel *chan_ptr = NULL;
01888       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
01889       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))
01890          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
01891       if (strcasecmp(orig_peername, peer->name) != 0) { 
01892          /* old channel */
01893          chan_ptr = ast_get_channel_by_name_locked(orig_peername);
01894          if (chan_ptr) {
01895             if (!ast_bridged_channel(chan_ptr)) {
01896                struct ast_cdr *cur;
01897                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
01898                   if (cur == peer_cdr) {
01899                      break;
01900                   }
01901                }
01902                if (cur)
01903                   ast_cdr_specialized_reset(peer_cdr,0);
01904             }
01905             ast_channel_unlock(chan_ptr);
01906          }
01907          /* new channel */
01908          ast_cdr_specialized_reset(new_peer_cdr,0);
01909       } else {
01910          ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr  */
01911       }
01912    }
01913    return res;
01914 }

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

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

00227 {
00228    struct ast_bridge_thread_obj *tobj = data;
00229 
00230    tobj->chan->appl = "Transferred Call";
00231    tobj->chan->data = tobj->peer->name;
00232    tobj->peer->appl = "Transferred Call";
00233    tobj->peer->data = tobj->chan->name;
00234 
00235    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00236    ast_hangup(tobj->chan);
00237    ast_hangup(tobj->peer);
00238    bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
00239    free(tobj);
00240    return NULL;
00241 }

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 243 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by do_atxfer().

00244 {
00245    pthread_t thread;
00246    pthread_attr_t attr;
00247    struct sched_param sched;
00248 
00249    pthread_attr_init(&attr);
00250    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00251    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00252    pthread_attr_destroy(&attr);
00253    memset(&sched, 0, sizeof(sched));
00254    pthread_setschedparam(thread, SCHED_RR, &sched);
00255 }

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

Definition at line 1188 of file res_features.c.

References ast_copy_flags, AST_FLAGS_ALL, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), builtin_features, config, ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, FEATURES_COUNT, features_lock, find_dynamic_feature(), ast_flags::flags, LOG_DEBUG, ast_channel::name, ast_call_feature::operation, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, and VERBOSE_PREFIX_3.

Referenced by ast_bridge_call().

01189 {
01190    int x;
01191    struct ast_flags features;
01192    struct ast_call_feature *feature;
01193    const char *dynamic_features;
01194    char *tmp, *tok;
01195    int res = FEATURE_RETURN_PASSDIGITS;
01196    int feature_detected = 0;
01197 
01198    if (sense == FEATURE_SENSE_CHAN) {
01199       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
01200       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01201    } else {
01202       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01203       dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01204    }
01205    if (option_debug > 2)
01206       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);
01207 
01208    ast_rwlock_rdlock(&features_lock);
01209    for (x = 0; x < FEATURES_COUNT; x++) {
01210       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01211           !ast_strlen_zero(builtin_features[x].exten)) {
01212          /* Feature is up for consideration */
01213          if (!strcmp(builtin_features[x].exten, code)) {
01214             res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01215             feature_detected = 1;
01216             break;
01217          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01218             if (res == FEATURE_RETURN_PASSDIGITS)
01219                res = FEATURE_RETURN_STOREDIGITS;
01220          }
01221       }
01222    }
01223    ast_rwlock_unlock(&features_lock);
01224 
01225    if (ast_strlen_zero(dynamic_features) || feature_detected)
01226       return res;
01227 
01228    tmp = ast_strdupa(dynamic_features);
01229 
01230    while ((tok = strsep(&tmp, "#"))) {
01231       AST_RWLIST_RDLOCK(&feature_list);   
01232       if (!(feature = find_dynamic_feature(tok))) {
01233          AST_RWLIST_UNLOCK(&feature_list);
01234          continue;
01235       }
01236          
01237       /* Feature is up for consideration */
01238       if (!strcmp(feature->exten, code)) {
01239          if (option_verbose > 2)
01240             ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01241          res = feature->operation(chan, peer, config, code, sense, feature);
01242          if (res != FEATURE_RETURN_KEEPTRYING) {
01243             AST_RWLIST_UNLOCK(&feature_list);
01244             break;
01245          }
01246          res = FEATURE_RETURN_PASSDIGITS;
01247       } else if (!strncmp(feature->exten, code, strlen(code)))
01248          res = FEATURE_RETURN_STOREDIGITS;
01249 
01250       AST_RWLIST_UNLOCK(&feature_list);
01251    }
01252    
01253    return res;
01254 }

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

References ast_channel::_softhangup, ast_channel::_state, ast_call(), 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_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, 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_tvdiff_ms(), ast_tvnow(), ast_verbose(), ast_waitfor_n(), 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().

01300 {
01301    int state = 0;
01302    int cause = 0;
01303    int to;
01304    struct ast_channel *chan;
01305    struct ast_channel *monitor_chans[2];
01306    struct ast_channel *active_channel;
01307    int res = 0, ready = 0;
01308    
01309    if ((chan = ast_request(type, format, data, &cause))) {
01310       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01311       ast_string_field_set(chan, language, language);
01312       ast_channel_inherit_variables(caller, chan); 
01313       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01314          
01315       if (!ast_call(chan, data, timeout)) {
01316          struct timeval started;
01317          int x, len = 0;
01318          char *disconnect_code = NULL, *dialed_code = NULL;
01319 
01320          ast_indicate(caller, AST_CONTROL_RINGING);
01321          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01322          ast_rwlock_rdlock(&features_lock);
01323          for (x = 0; x < FEATURES_COUNT; x++) {
01324             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01325                continue;
01326 
01327             disconnect_code = builtin_features[x].exten;
01328             len = strlen(disconnect_code) + 1;
01329             dialed_code = alloca(len);
01330             memset(dialed_code, 0, len);
01331             break;
01332          }
01333          ast_rwlock_unlock(&features_lock);
01334          x = 0;
01335          started = ast_tvnow();
01336          to = timeout;
01337          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01338             struct ast_frame *f = NULL;
01339 
01340             monitor_chans[0] = caller;
01341             monitor_chans[1] = chan;
01342             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01343 
01344             /* see if the timeout has been violated */
01345             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01346                state = AST_CONTROL_UNHOLD;
01347                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01348                break; /*doh! timeout*/
01349             }
01350 
01351             if (!active_channel)
01352                continue;
01353 
01354             if (chan && (chan == active_channel)){
01355                f = ast_read(chan);
01356                if (f == NULL) { /*doh! where'd he go?*/
01357                   state = AST_CONTROL_HANGUP;
01358                   res = 0;
01359                   break;
01360                }
01361                
01362                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01363                   if (f->subclass == AST_CONTROL_RINGING) {
01364                      state = f->subclass;
01365                      if (option_verbose > 2)
01366                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01367                      ast_indicate(caller, AST_CONTROL_RINGING);
01368                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01369                      state = f->subclass;
01370                      if (option_verbose > 2)
01371                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01372                      ast_indicate(caller, AST_CONTROL_BUSY);
01373                      ast_frfree(f);
01374                      f = NULL;
01375                      break;
01376                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01377                      /* This is what we are hoping for */
01378                      state = f->subclass;
01379                      ast_frfree(f);
01380                      f = NULL;
01381                      ready=1;
01382                      break;
01383                   } else if (f->subclass != -1) {
01384                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01385                   }
01386                   /* else who cares */
01387                }
01388 
01389             } else if (caller && (active_channel == caller)) {
01390                f = ast_read(caller);
01391                if (f == NULL) { /*doh! where'd he go?*/
01392                   if (caller->_softhangup && !chan->_softhangup) {
01393                      /* make this a blind transfer */
01394                      ready = 1;
01395                      break;
01396                   }
01397                   state = AST_CONTROL_HANGUP;
01398                   res = 0;
01399                   break;
01400                }
01401                
01402                if (f->frametype == AST_FRAME_DTMF) {
01403                   dialed_code[x++] = f->subclass;
01404                   dialed_code[x] = '\0';
01405                   if (strlen(dialed_code) == len) {
01406                      x = 0;
01407                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01408                      x = 0;
01409                      dialed_code[x] = '\0';
01410                   }
01411                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01412                      /* Caller Canceled the call */
01413                      state = AST_CONTROL_UNHOLD;
01414                      ast_frfree(f);
01415                      f = NULL;
01416                      break;
01417                   }
01418                }
01419             }
01420             if (f)
01421                ast_frfree(f);
01422          } /* end while */
01423       } else
01424          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01425    } else {
01426       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01427       switch(cause) {
01428       case AST_CAUSE_BUSY:
01429          state = AST_CONTROL_BUSY;
01430          break;
01431       case AST_CAUSE_CONGESTION:
01432          state = AST_CONTROL_CONGESTION;
01433          break;
01434       }
01435    }
01436    
01437    ast_indicate(caller, -1);
01438    if (chan && ready) {
01439       if (chan->_state == AST_STATE_UP) 
01440          state = AST_CONTROL_ANSWER;
01441       res = 0;
01442    } else if(chan) {
01443       res = -1;
01444       ast_hangup(chan);
01445       chan = NULL;
01446    } else {
01447       res = -1;
01448    }
01449    
01450    if (outstate)
01451       *outstate = state;
01452 
01453    return chan;
01454 }

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

References masq_park_call().

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

00531 {
00532    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00533 }

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

References park_call_full().

Referenced by iax_park_thread(), and sip_park_thread().

00483 {
00484    return park_call_full(chan, peer, timeout, extout, NULL);
00485 }

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

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

00163 {
00164    return parking_ext;
00165 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

02495 {
02496    struct ast_channel *cur = NULL;
02497    int res = -1;
02498 
02499    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02500       if (!cur->pbx && 
02501          (cur != chan) &&
02502          (chan->pickupgroup & cur->callgroup) &&
02503          ((cur->_state == AST_STATE_RINGING) ||
02504           (cur->_state == AST_STATE_RING))) {
02505             break;
02506       }
02507       ast_channel_unlock(cur);
02508    }
02509    if (cur) {
02510       if (option_debug)
02511          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02512       res = ast_answer(chan);
02513       if (res)
02514          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02515       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02516       if (res)
02517          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02518       res = ast_channel_masquerade(cur, chan);
02519       if (res)
02520          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02521       ast_channel_unlock(cur);
02522    } else   {
02523       if (option_debug)
02524          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02525    }
02526    return res;
02527 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 167 of file res_features.c.

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

00168 {
00169    return pickup_ext;
00170 }

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

01048 {
01049    if (!feature) {
01050       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01051          return;
01052    }
01053   
01054    AST_RWLIST_WRLOCK(&feature_list);
01055    AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry);
01056    AST_RWLIST_UNLOCK(&feature_list);
01057 
01058    if (option_verbose >= 2) {
01059       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01060    }
01061 }

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

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

01065 {
01066    if (!feature)
01067       return;
01068 
01069    AST_RWLIST_WRLOCK(&feature_list);
01070    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01071    AST_RWLIST_UNLOCK(&feature_list);
01072    
01073    free(feature);
01074 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1077 of file res_features.c.

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

01078 {
01079    struct ast_call_feature *feature;
01080 
01081    AST_RWLIST_WRLOCK(&feature_list);
01082    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01083       free(feature);
01084    }
01085    AST_RWLIST_UNLOCK(&feature_list);
01086 }

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

References config, and do_atxfer().

01025 {
01026    return do_atxfer(chan, peer, config, sense, NULL, NULL);
01027 }

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

00601 {
00602    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00603    int x = 0;
00604    size_t len;
00605    struct ast_channel *caller_chan, *callee_chan;
00606 
00607    if (!monitor_ok) {
00608       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00609       return -1;
00610    }
00611 
00612    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00613       monitor_ok = 0;
00614       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00615       return -1;
00616    }
00617 
00618    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00619 
00620    if (!ast_strlen_zero(courtesytone)) {
00621       if (ast_autoservice_start(callee_chan))
00622          return -1;
00623       if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00624          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00625          ast_autoservice_stop(callee_chan);
00626          return -1;
00627       }
00628       if (ast_autoservice_stop(callee_chan))
00629          return -1;
00630    }
00631    
00632    if (callee_chan->monitor) {
00633       if (option_verbose > 3)
00634          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00635       ast_monitor_stop(callee_chan, 1);
00636       return FEATURE_RETURN_SUCCESS;
00637    }
00638 
00639    if (caller_chan && callee_chan) {
00640       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00641       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00642 
00643       if (!touch_format)
00644          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00645 
00646       if (!touch_monitor)
00647          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00648    
00649       if (touch_monitor) {
00650          len = strlen(touch_monitor) + 50;
00651          args = alloca(len);
00652          touch_filename = alloca(len);
00653          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00654          snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00655       } else {
00656          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00657          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00658          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00659          args = alloca(len);
00660          touch_filename = alloca(len);
00661          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00662          snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00663       }
00664 
00665       for( x = 0; x < strlen(args); x++) {
00666          if (args[x] == '/')
00667             args[x] = '-';
00668       }
00669       
00670       if (option_verbose > 3)
00671          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00672 
00673       pbx_exec(callee_chan, monitor_app, args);
00674       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00675       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00676    
00677       return FEATURE_RETURN_SUCCESS;
00678    }
00679    
00680    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00681    return -1;
00682 }

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

References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_setdestchan(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_indicate(), ast_log(), ast_parking_ext(), ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_verbose(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, 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.

00712 {
00713    struct ast_channel *transferer;
00714    struct ast_channel *transferee;
00715    const char *transferer_real_context;
00716    char xferto[256];
00717    int res;
00718    const char *orig_chan_name;
00719 
00720    set_peers(&transferer, &transferee, peer, chan, sense);
00721    orig_chan_name = ast_strdupa(transferer->name);
00722    transferer_real_context = real_ctx(transferer, transferee);
00723    /* Start autoservice on chan while we talk to the originator */
00724    ast_autoservice_start(transferee);
00725    ast_indicate(transferee, AST_CONTROL_HOLD);
00726 
00727    memset(xferto, 0, sizeof(xferto));
00728    
00729    /* Transfer */
00730    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00731    if (res < 0) {
00732       finishup(transferee);
00733       return -1; /* error ? */
00734    }
00735    if (res > 0)   /* If they've typed a digit already, handle it */
00736       xferto[0] = (char) res;
00737 
00738    ast_stopstream(transferer);
00739    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00740    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00741       finishup(transferee);
00742       return res;
00743    }
00744    if (!strcmp(xferto, ast_parking_ext())) {
00745       res = finishup(transferee);
00746       if (res)
00747          res = -1;
00748       else if (!masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name)) {   /* success */
00749          /* We return non-zero, but tell the PBX not to hang the channel when
00750             the thread dies -- We have to be careful now though.  We are responsible for 
00751             hanging up the channel, else it will never be hung up! */
00752          return 0;
00753       } else {
00754          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00755       }
00756       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
00757    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00758       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
00759       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
00760       res=finishup(transferee);
00761       if (!transferer->cdr) {
00762          transferer->cdr=ast_cdr_alloc();
00763          if (transferer) {
00764             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
00765             ast_cdr_start(transferer->cdr);
00766          }
00767       }
00768       if (transferer->cdr) {
00769          ast_cdr_setdestchan(transferer->cdr, transferee->name);
00770          ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00771       }
00772       if (!transferee->pbx) {
00773          /* Doh!  Use our handy async_goto functions */
00774          if (option_verbose > 2) 
00775             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00776                         ,transferee->name, xferto, transferer_real_context);
00777          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00778             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00779          res = -1;
00780       } else {
00781          /* Set the channel's new extension, since it exists, using transferer context */
00782          set_c_e_p(transferee, transferer_real_context, xferto, 0);
00783       }
00784       check_goto_on_transfer(transferer);
00785       return res;
00786    } else {
00787       if (option_verbose > 2) 
00788          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00789    }
00790    if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00791       finishup(transferee);
00792       return -1;
00793    }
00794    ast_stopstream(transferer);
00795    res = finishup(transferee);
00796    if (res) {
00797       if (option_verbose > 1)
00798          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00799       return res;
00800    }
00801    return FEATURE_RETURN_SUCCESS;
00802 }

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

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

00685 {
00686    if (option_verbose > 3)
00687       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00688    return FEATURE_RETURN_HANGUP;
00689 }

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

00566 {
00567    struct ast_channel *parker;
00568    struct ast_channel *parkee;
00569    int res = 0;
00570    struct ast_module_user *u;
00571    const char *orig_chan_name;
00572 
00573    u = ast_module_user_add(chan);
00574 
00575    set_peers(&parker, &parkee, peer, chan, sense);
00576    orig_chan_name = ast_strdupa(parker->name);
00577    /* we used to set chan's exten and priority to "s" and 1
00578       here, but this generates (in some cases) an invalid
00579       extension, and if "s" exists, could errantly
00580       cause execution of extensions you don't expect It
00581       makes more sense to let nature take its course
00582       when chan finishes, and let the pbx do its thing
00583       and hang up when the park is over.
00584    */
00585    if (chan->_state != AST_STATE_UP)
00586       res = ast_answer(chan);
00587    if (!res)
00588       res = ast_safe_sleep(chan, 1000);
00589 
00590    if (!res) { /* one direction used to call park_call.... */
00591       masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name);
00592       res = 0; /* PBX should hangup zombie channel */
00593    }
00594 
00595    ast_module_user_remove(u);
00596    return res;
00597 
00598 }

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

Definition at line 804 of file res_features.c.

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

Referenced by do_atxfer().

00805 {
00806    if (ast_channel_make_compatible(c, newchan) < 0) {
00807       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00808          c->name, newchan->name);
00809       ast_hangup(newchan);
00810       return -1;
00811    }
00812    return 0;
00813 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

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

00188 {
00189    struct ast_channel *xferchan;
00190    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00191    char *x, *goto_on_transfer;
00192    struct ast_frame *f;
00193 
00194    if (ast_strlen_zero(val))
00195       return;
00196 
00197    goto_on_transfer = ast_strdupa(val);
00198 
00199    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name)))
00200       return;
00201 
00202    for (x = goto_on_transfer; x && *x; x++) {
00203       if (*x == '^')
00204          *x = '|';
00205    }
00206    /* Make formats okay */
00207    xferchan->readformat = chan->readformat;
00208    xferchan->writeformat = chan->writeformat;
00209    ast_channel_masquerade(xferchan, chan);
00210    ast_parseable_goto(xferchan, goto_on_transfer);
00211    xferchan->_state = AST_STATE_UP;
00212    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00213    xferchan->_softhangup = 0;
00214    if ((f = ast_read(xferchan))) {
00215       ast_frfree(f);
00216       f = NULL;
00217       ast_pbx_start(xferchan);
00218    } else {
00219       ast_hangup(xferchan);
00220    }
00221 }

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

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

Referenced by ast_bridge_call().

01469 {
01470    int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER;
01471    char *context = strchr(xferto, '@');;
01472    if (context)
01473       *context++ = '\0';
01474    do_atxfer(a, b, conf, sense, xferto, context);
01475 }

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

References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_copy_string(), AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_datastore::data, dial_features_info, ast_bridge_config::end_bridge_callback_data_fixup, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_dial_features::features_callee, ast_bridge_config::features_caller, finishup(), ast_dial_features::is_caller, 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().

00831 {
00832    struct ast_channel *transferer;
00833    struct ast_channel *transferee;
00834    const char *transferer_real_context;
00835    const char *transfer_context;
00836    char xferto[256] = "";
00837    int res;
00838    int outstate=0;
00839    struct ast_channel *newchan;
00840    struct ast_channel *xferchan;
00841    struct ast_bridge_thread_obj *tobj;
00842    struct ast_bridge_config bconfig;
00843    struct ast_frame *f;
00844    int l;
00845    struct ast_datastore *features_datastore;
00846    struct ast_dial_features *dialfeatures = NULL;
00847 
00848    if (option_debug)
00849       ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00850    set_peers(&transferer, &transferee, peer, chan, sense);
00851    transferer_real_context = real_ctx(transferer, transferee);
00852    transfer_context = S_OR(toCont, transferer_real_context);
00853 
00854    /* Start autoservice on chan while we talk to the originator */
00855    ast_autoservice_start(transferee);
00856    ast_indicate(transferee, AST_CONTROL_HOLD);
00857 
00858    if (!ast_strlen_zero(toExt)) {
00859       ast_copy_string(xferto, toExt, sizeof(xferto));
00860    } else {
00861       /* Ask for extension to transfer to on the transferer channel */
00862       res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00863       if (res < 0) {
00864          finishup(transferee);
00865          return res;
00866       }
00867       if (res > 0) /* If they've typed a digit already, handle it */
00868          xferto[0] = (char) res;
00869 
00870       /* this is specific of atxfer */
00871       res = ast_app_dtget(transferer, transfer_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00872       if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00873          finishup(transferee);
00874          return res;
00875       }
00876       if (res == 0) {
00877          ast_log(LOG_WARNING, "Did not read data.\n");
00878          finishup(transferee);
00879          if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00880             return -1;
00881          return FEATURE_RETURN_SUCCESS;
00882       }
00883    }
00884 
00885    /* valid extension, res == 1 */
00886    if (!ast_exists_extension(transferer, transfer_context, xferto, 1, transferer->cid.cid_num)) {
00887       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transfer_context);
00888       finishup(transferee);
00889       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00890          return -1;
00891       return FEATURE_RETURN_SUCCESS;
00892    }
00893 
00894    l = strlen(xferto);
00895    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transfer_context); /* append context */
00896    newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00897       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
00898 
00899    /* If we are the callee and we are being transferred, after the masquerade
00900    * caller features will really be the original callee features */
00901    ast_channel_lock(transferee);
00902    if ((features_datastore = ast_channel_datastore_find(transferee, &dial_features_info, NULL))) {
00903       dialfeatures = features_datastore->data;
00904    }
00905    ast_channel_unlock(transferee);
00906 
00907    if (dialfeatures && !dialfeatures->is_caller) {
00908       ast_copy_flags(&(config->features_caller), &(dialfeatures->features_callee), AST_FLAGS_ALL);
00909    }
00910 
00911    ast_indicate(transferer, -1);
00912    if (!newchan) {
00913       finishup(transferee);
00914       /* any reason besides user requested cancel and busy triggers the failed sound */
00915       if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00916             ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
00917          return -1;
00918       return FEATURE_RETURN_SUCCESS;
00919    }
00920 
00921    if (check_compat(transferer, newchan)) {
00922       /* we do mean transferee here, NOT transferer */
00923       finishup(transferee);
00924       return -1;
00925    }
00926    memset(&bconfig,0,sizeof(struct ast_bridge_config));
00927    ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00928    ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00929    res = ast_bridge_call(transferer, newchan, &bconfig);
00930    if (newchan->_softhangup || !transferer->_softhangup) {
00931       ast_hangup(newchan);
00932       if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
00933          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00934       finishup(transferee);
00935       transferer->_softhangup = 0;
00936       return FEATURE_RETURN_SUCCESS;
00937    }
00938    
00939    if (check_compat(transferee, newchan)) {
00940       finishup(transferee);
00941       return -1;
00942    }
00943 
00944    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00945    
00946    if ((ast_autoservice_stop(transferee) < 0)
00947       || (ast_waitfordigit(transferee, 100) < 0)
00948       || (ast_waitfordigit(newchan, 100) < 0) 
00949       || ast_check_hangup(transferee) 
00950       || ast_check_hangup(newchan)) {
00951       ast_hangup(newchan);
00952       return -1;
00953    }
00954 
00955    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
00956    if (!xferchan) {
00957       ast_hangup(newchan);
00958       return -1;
00959    }
00960    /* Make formats okay */
00961    xferchan->visible_indication = transferer->visible_indication;
00962    xferchan->readformat = transferee->readformat;
00963    xferchan->writeformat = transferee->writeformat;
00964    ast_channel_masquerade(xferchan, transferee);
00965    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00966    xferchan->_state = AST_STATE_UP;
00967    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00968    xferchan->_softhangup = 0;
00969 
00970    if ((f = ast_read(xferchan)))
00971       ast_frfree(f);
00972 
00973    newchan->_state = AST_STATE_UP;
00974    ast_clear_flag(newchan, AST_FLAGS_ALL);   
00975    newchan->_softhangup = 0;
00976 
00977    tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
00978    if (!tobj) {
00979       ast_hangup(xferchan);
00980       ast_hangup(newchan);
00981       return -1;
00982    }
00983     
00984    /* For the case where the transfer target is being connected with the original
00985       caller store the target's original features, and apply to the bridge */
00986    ast_channel_lock(newchan);
00987    if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
00988       dialfeatures = features_datastore->data;
00989    }
00990    ast_channel_unlock(newchan);
00991 
00992    if (dialfeatures) {
00993       ast_copy_flags(&(config->features_callee), &(dialfeatures->features_callee), AST_FLAGS_ALL);
00994    }
00995 
00996    tobj->chan = newchan;
00997    tobj->peer = xferchan;
00998    tobj->bconfig = *config;
00999 
01000    if (tobj->bconfig.end_bridge_callback_data_fixup) {
01001       tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01002    }
01003 
01004    if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
01005       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01006    ast_bridge_call_thread_launch(tobj);
01007    return -1;  /* XXX meaning the channel is bridged ? */
01008 }

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 1931 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, 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(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, ast_channel::name, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, ast_dial_features::options, 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().

01932 {
01933    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
01934    FD_ZERO(&rfds);
01935    FD_ZERO(&efds);
01936 
01937    for (;;) {
01938       struct parkeduser *pu, *pl, *pt = NULL;
01939       int ms = -1;   /* select timeout, uninitialized */
01940       int max = -1;  /* max fd, none there yet */
01941       fd_set nrfds, nefds; /* args for the next select */
01942       FD_ZERO(&nrfds);
01943       FD_ZERO(&nefds);
01944 
01945       ast_mutex_lock(&parking_lock);
01946       pl = NULL;
01947       pu = parkinglot;
01948       /* navigate the list with prev-cur pointers to support removals */
01949       while (pu) {
01950          struct ast_channel *chan = pu->chan;   /* shorthand */
01951          int tms;        /* timeout for this item */
01952          int x;          /* fd index in channel */
01953          struct ast_context *con;
01954 
01955          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
01956             pl = pu;
01957             pu = pu->next;
01958             continue;
01959          }
01960          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01961          if (tms > pu->parkingtime) {
01962             ast_indicate(chan, AST_CONTROL_UNHOLD);
01963             /* Get chan, exten from derived kludge */
01964             if (pu->peername[0]) {
01965                char *peername = ast_strdupa(pu->peername);
01966                char *cp = strrchr(peername, '-');
01967                if (cp) 
01968                   *cp = 0;
01969                con = ast_context_find(parking_con_dial);
01970                if (!con) {
01971                   con = ast_context_create(NULL, parking_con_dial, registrar);
01972                   if (!con)
01973                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01974                }
01975                if (con) {
01976                   char returnexten[AST_MAX_EXTENSION];
01977                   struct ast_datastore *features_datastore;
01978                   struct ast_dial_features *dialfeatures = NULL;
01979 
01980                   ast_channel_lock(chan);
01981 
01982                   if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
01983                      dialfeatures = features_datastore->data;
01984 
01985                   ast_channel_unlock(chan);
01986 
01987                   if (!strncmp(peername, "Parked/", 7)) {
01988                      peername += 7;
01989                   }
01990 
01991                   if (dialfeatures)
01992                      snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, dialfeatures->options);
01993                   else /* Existing default */
01994                      snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
01995 
01996                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01997                }
01998                set_c_e_p(chan, parking_con_dial, peername, 1);
01999             } else {
02000                /* They've been waiting too long, send them back to where they came.  Theoretically they
02001                   should have their original extensions and such, but we copy to be on the safe side */
02002                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
02003             }
02004 
02005             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
02006 
02007             if (option_verbose > 1) 
02008                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);
02009             /* Start up the PBX, or hang them up */
02010             if (ast_pbx_start(chan))  {
02011                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
02012                ast_hangup(chan);
02013             }
02014             /* And take them out of the parking lot */
02015             if (pl) 
02016                pl->next = pu->next;
02017             else
02018                parkinglot = pu->next;
02019             pt = pu;
02020             pu = pu->next;
02021             con = ast_context_find(parking_con);
02022             if (con) {
02023                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
02024                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02025                else
02026                   notify_metermaids(pt->parkingexten, parking_con);
02027             } else
02028                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02029             free(pt);
02030          } else { /* still within parking time, process descriptors */
02031             for (x = 0; x < AST_MAX_FDS; x++) {
02032                struct ast_frame *f;
02033 
02034                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
02035                   continue;   /* nothing on this descriptor */
02036 
02037                if (FD_ISSET(chan->fds[x], &efds))
02038                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
02039                else
02040                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
02041                chan->fdno = x;
02042 
02043                /* See if they need servicing */
02044                f = ast_read(chan);
02045                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
02046                   if (f)
02047                      ast_frfree(f);
02048                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
02049 
02050                   /* There's a problem, hang them up*/
02051                   if (option_verbose > 1) 
02052                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
02053                   ast_hangup(chan);
02054                   /* And take them out of the parking lot */
02055                   if (pl) 
02056                      pl->next = pu->next;
02057                   else
02058                      parkinglot = pu->next;
02059                   pt = pu;
02060                   pu = pu->next;
02061                   con = ast_context_find(parking_con);
02062                   if (con) {
02063                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
02064                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02065                      else {
02066                         notify_metermaids(pt->parkingexten, parking_con);
02067                      }
02068                   } else
02069                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02070                   free(pt);
02071                   break;
02072                } else {
02073                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02074                   ast_frfree(f);
02075                   if (pu->moh_trys < 3 && !chan->generatordata) {
02076                      if (option_debug)
02077                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
02078                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
02079                         S_OR(parkmohclass, NULL),
02080                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
02081                      pu->moh_trys++;
02082                   }
02083                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
02084                }
02085 
02086             } /* end for */
02087             if (x >= AST_MAX_FDS) {
02088 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
02089                   if (chan->fds[x] > -1) {
02090                      FD_SET(chan->fds[x], &nrfds);
02091                      FD_SET(chan->fds[x], &nefds);
02092                      if (chan->fds[x] > max)
02093                         max = chan->fds[x];
02094                   }
02095                }
02096                /* Keep track of our shortest wait */
02097                if (tms < ms || ms < 0)
02098                   ms = tms;
02099                pl = pu;
02100                pu = pu->next;
02101             }
02102          }
02103       } /* end while */
02104       ast_mutex_unlock(&parking_lock);
02105       rfds = nrfds;
02106       efds = nefds;
02107       {
02108          struct timeval tv = ast_samp2tv(ms, 1000);
02109          /* Wait for something to happen */
02110          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02111       }
02112       pthread_testcancel();
02113    }
02114    return NULL;   /* Never reached */
02115 }

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

01104 {
01105    struct ast_app *app;
01106    struct ast_call_feature *feature = data;
01107    struct ast_channel *work, *idle;
01108    int res;
01109 
01110    if (!feature) { /* shouldn't ever happen! */
01111       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01112       return -1; 
01113    }
01114 
01115    if (sense == FEATURE_SENSE_CHAN) {
01116       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01117          return FEATURE_RETURN_KEEPTRYING;
01118       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01119          work = chan;
01120          idle = peer;
01121       } else {
01122          work = peer;
01123          idle = chan;
01124       }
01125    } else {
01126       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01127          return FEATURE_RETURN_KEEPTRYING;
01128       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01129          work = peer;
01130          idle = chan;
01131       } else {
01132          work = chan;
01133          idle = peer;
01134       }
01135    }
01136 
01137    if (!(app = pbx_findapp(feature->app))) {
01138       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01139       return -2;
01140    }
01141 
01142    ast_autoservice_start(idle);
01143    
01144    if (!ast_strlen_zero(feature->moh_class))
01145       ast_moh_start(idle, feature->moh_class, NULL);
01146 
01147    res = pbx_exec(work, app, feature->app_args);
01148 
01149    if (!ast_strlen_zero(feature->moh_class))
01150       ast_moh_stop(idle);
01151 
01152    ast_autoservice_stop(idle);
01153 
01154    if (res)
01155       return FEATURE_RETURN_SUCCESSBREAK;
01156    
01157    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01158 }

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

find a feature by name

Definition at line 1089 of file res_features.c.

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

Referenced by ast_feature_interpret(), and set_config_flags().

01090 {
01091    struct ast_call_feature *tmp;
01092 
01093    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01094       if (!strcasecmp(tmp->sname, name)) {
01095          break;
01096       }
01097    }
01098 
01099    return tmp;
01100 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 691 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

00692 {
00693         ast_indicate(chan, AST_CONTROL_UNHOLD);
00694   
00695         return ast_autoservice_stop(chan);
00696 }

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

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

02349 {
02350    struct parkeduser *cur;
02351    int numparked = 0;
02352 
02353    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02354       , "Context", "Extension", "Pri", "Timeout");
02355 
02356    ast_mutex_lock(&parking_lock);
02357 
02358    for (cur = parkinglot; cur; cur = cur->next) {
02359       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02360          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02361          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02362 
02363       numparked++;
02364    }
02365    ast_mutex_unlock(&parking_lock);
02366    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02367 
02368 
02369    return RESULT_SUCCESS;
02370 }

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

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

02307 {
02308    int i;
02309    struct ast_call_feature *feature;
02310    char format[] = "%-25s %-7s %-7s\n";
02311 
02312    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02313    ast_cli(fd, format, "---------------", "-------", "-------");
02314 
02315    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02316 
02317    ast_rwlock_rdlock(&features_lock);
02318    for (i = 0; i < FEATURES_COUNT; i++)
02319       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02320    ast_rwlock_unlock(&features_lock);
02321 
02322    ast_cli(fd, "\n");
02323    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02324    ast_cli(fd, format, "---------------", "-------", "-------");
02325    if (AST_RWLIST_EMPTY(&feature_list)) {
02326       ast_cli(fd, "(none)\n");
02327    } else {
02328       AST_RWLIST_RDLOCK(&feature_list);
02329       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
02330          ast_cli(fd, format, feature->sname, "no def", feature->exten);
02331       }
02332       AST_RWLIST_UNLOCK(&feature_list);
02333    }
02334    ast_cli(fd, "\nCall parking\n");
02335    ast_cli(fd, "------------\n");
02336    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02337    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02338    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02339    ast_cli(fd,"\n");
02340    
02341    return RESULT_SUCCESS;
02342 }

static int load_config ( void   )  [static]

Definition at line 2544 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, parkedcalltransfers, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkmohclass, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.

02545 {
02546    int start = 0, end = 0;
02547    int res;
02548    struct ast_context *con = NULL;
02549    struct ast_config *cfg = NULL;
02550    struct ast_variable *var = NULL;
02551    char old_parking_ext[AST_MAX_EXTENSION];
02552    char old_parking_con[AST_MAX_EXTENSION] = "";
02553 
02554    if (!ast_strlen_zero(parking_con)) {
02555       strcpy(old_parking_ext, parking_ext);
02556       strcpy(old_parking_con, parking_con);
02557    } 
02558 
02559    /* Reset to defaults */
02560    strcpy(parking_con, "parkedcalls");
02561    strcpy(parking_con_dial, "park-dial");
02562    strcpy(parking_ext, "700");
02563    strcpy(pickup_ext, "*8");
02564    strcpy(parkmohclass, "default");
02565    courtesytone[0] = '\0';
02566    strcpy(xfersound, "beep");
02567    strcpy(xferfailsound, "pbx-invalid");
02568    parking_start = 701;
02569    parking_stop = 750;
02570    parkfindnext = 0;
02571    adsipark = 0;
02572    parkaddhints = 0;
02573    parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
02574 
02575    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02576    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02577    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02578 
02579    cfg = ast_config_load("features.conf");
02580    if (!cfg) {
02581       ast_log(LOG_WARNING,"Could not load features.conf\n");
02582       return AST_MODULE_LOAD_DECLINE;
02583    }
02584    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02585       if (!strcasecmp(var->name, "parkext")) {
02586          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02587       } else if (!strcasecmp(var->name, "context")) {
02588          ast_copy_string(parking_con, var->value, sizeof(parking_con));
02589       } else if (!strcasecmp(var->name, "parkingtime")) {
02590          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02591             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02592             parkingtime = DEFAULT_PARK_TIME;
02593          } else
02594             parkingtime = parkingtime * 1000;
02595       } else if (!strcasecmp(var->name, "parkpos")) {
02596          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02597             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);
02598          } else {
02599             parking_start = start;
02600             parking_stop = end;
02601          }
02602       } else if (!strcasecmp(var->name, "findslot")) {
02603          parkfindnext = (!strcasecmp(var->value, "next"));
02604       } else if (!strcasecmp(var->name, "parkinghints")) {
02605          parkaddhints = ast_true(var->value);
02606       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
02607          if (!strcasecmp(var->value, "no"))
02608             parkedcalltransfers = 0;
02609          else if (!strcasecmp(var->value, "caller"))
02610             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
02611          else if (!strcasecmp(var->value, "callee"))
02612             parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
02613          else if (!strcasecmp(var->value, "both"))
02614             parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
02615       } else if (!strcasecmp(var->name, "adsipark")) {
02616          adsipark = ast_true(var->value);
02617       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02618          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02619             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02620             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02621          } else
02622             transferdigittimeout = transferdigittimeout * 1000;
02623       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02624          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02625             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02626             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02627          }
02628       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
02629          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
02630             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
02631             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02632          } else
02633             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
02634       } else if (!strcasecmp(var->name, "courtesytone")) {
02635          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02636       }  else if (!strcasecmp(var->name, "parkedplay")) {
02637          if (!strcasecmp(var->value, "both"))
02638             parkedplay = 2;
02639          else if (!strcasecmp(var->value, "parked"))
02640             parkedplay = 1;
02641          else
02642             parkedplay = 0;
02643       } else if (!strcasecmp(var->name, "xfersound")) {
02644          ast_copy_string(xfersound, var->value, sizeof(xfersound));
02645       } else if (!strcasecmp(var->name, "xferfailsound")) {
02646          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02647       } else if (!strcasecmp(var->name, "pickupexten")) {
02648          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02649       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
02650          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
02651       }
02652    }
02653 
02654    unmap_features();
02655    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
02656       if (remap_feature(var->name, var->value))
02657          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02658    }
02659 
02660    /* Map a key combination to an application*/
02661    ast_unregister_features();
02662    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
02663       char *tmp_val = ast_strdupa(var->value);
02664       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
02665       struct ast_call_feature *feature;
02666 
02667       /* strsep() sets the argument to NULL if match not found, and it
02668        * is safe to use it with a NULL argument, so we don't check
02669        * between calls.
02670        */
02671       exten = strsep(&tmp_val,",");
02672       activatedby = strsep(&tmp_val,",");
02673       app = strsep(&tmp_val,",");
02674       app_args = strsep(&tmp_val,",");
02675       moh_class = strsep(&tmp_val,",");
02676 
02677       activateon = strsep(&activatedby, "/");   
02678 
02679       /*! \todo XXX var_name or app_args ? */
02680       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
02681          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
02682             app, exten, activateon, var->name);
02683          continue;
02684       }
02685 
02686       AST_RWLIST_RDLOCK(&feature_list);
02687       if ((feature = find_dynamic_feature(var->name))) {
02688          AST_RWLIST_UNLOCK(&feature_list);
02689          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
02690          continue;
02691       }
02692       AST_RWLIST_UNLOCK(&feature_list);
02693             
02694       if (!(feature = ast_calloc(1, sizeof(*feature))))
02695          continue;               
02696 
02697       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
02698       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
02699       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
02700       
02701       if (app_args) 
02702          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
02703 
02704       if (moh_class)
02705          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
02706          
02707       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
02708       feature->operation = feature_exec_app;
02709       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
02710 
02711       /* Allow caller and calle to be specified for backwards compatability */
02712       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
02713          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
02714       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
02715          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
02716       else {
02717          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
02718             " must be 'self', or 'peer'\n", var->name);
02719          continue;
02720       }
02721 
02722       if (ast_strlen_zero(activatedby))
02723          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02724       else if (!strcasecmp(activatedby, "caller"))
02725          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
02726       else if (!strcasecmp(activatedby, "callee"))
02727          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
02728       else if (!strcasecmp(activatedby, "both"))
02729          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02730       else {
02731          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
02732             " must be 'caller', or 'callee', or 'both'\n", var->name);
02733          continue;
02734       }
02735 
02736       ast_register_feature(feature);
02737          
02738       if (option_verbose >= 1)
02739          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
02740    }   
02741    ast_config_destroy(cfg);
02742 
02743    /* Remove the old parking extension */
02744    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02745       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
02746             notify_metermaids(old_parking_ext, old_parking_con);
02747       if (option_debug)
02748          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02749    }
02750    
02751    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
02752       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02753       return -1;
02754    }
02755    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
02756    if (parkaddhints)
02757       park_add_hints(parking_con, parking_start, parking_stop);
02758    if (!res)
02759       notify_metermaids(ast_parking_ext(), parking_con);
02760    return res;
02761 
02762 }

static int load_module ( void   )  [static]

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

02770 {
02771    int res;
02772    
02773    memset(parking_ext, 0, sizeof(parking_ext));
02774    memset(parking_con, 0, sizeof(parking_con));
02775 
02776    if ((res = load_config()))
02777       return res;
02778    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02779    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02780    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02781    if (!res)
02782       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02783    if (!res) {
02784       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02785       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
02786          "Park a channel", mandescr_park); 
02787    }
02788 
02789    res |= ast_devstate_prov_add("Park", metermaidstate);
02790 
02791    return res;
02792 }

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

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

02440 {
02441    const char *channel = astman_get_header(m, "Channel");
02442    const char *channel2 = astman_get_header(m, "Channel2");
02443    const char *timeout = astman_get_header(m, "Timeout");
02444    char buf[BUFSIZ];
02445    int to = 0;
02446    int res = 0;
02447    int parkExt = 0;
02448    struct ast_channel *ch1, *ch2;
02449 
02450    if (ast_strlen_zero(channel)) {
02451       astman_send_error(s, m, "Channel not specified");
02452       return 0;
02453    }
02454 
02455    if (ast_strlen_zero(channel2)) {
02456       astman_send_error(s, m, "Channel2 not specified");
02457       return 0;
02458    }
02459 
02460    ch1 = ast_get_channel_by_name_locked(channel);
02461    if (!ch1) {
02462       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02463       astman_send_error(s, m, buf);
02464       return 0;
02465    }
02466 
02467    ch2 = ast_get_channel_by_name_locked(channel2);
02468    if (!ch2) {
02469       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02470       astman_send_error(s, m, buf);
02471       ast_channel_unlock(ch1);
02472       return 0;
02473    }
02474 
02475    if (!ast_strlen_zero(timeout)) {
02476       sscanf(timeout, "%d", &to);
02477    }
02478 
02479    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02480    if (!res) {
02481       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02482       astman_send_ack(s, m, "Park successful");
02483    } else {
02484       astman_send_error(s, m, "Park failure");
02485    }
02486 
02487    ast_channel_unlock(ch1);
02488    ast_channel_unlock(ch2);
02489 
02490    return 0;
02491 }

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

Dump lot status.

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

02393 {
02394    struct parkeduser *cur;
02395    const char *id = astman_get_header(m, "ActionID");
02396    char idText[256] = "";
02397 
02398    if (!ast_strlen_zero(id))
02399       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02400 
02401    astman_send_ack(s, m, "Parked calls will follow");
02402 
02403    ast_mutex_lock(&parking_lock);
02404 
02405    for (cur = parkinglot; cur; cur = cur->next) {
02406       astman_append(s, "Event: ParkedCall\r\n"
02407          "Exten: %d\r\n"
02408          "Channel: %s\r\n"
02409          "From: %s\r\n"
02410          "Timeout: %ld\r\n"
02411          "CallerID: %s\r\n"
02412          "CallerIDName: %s\r\n"
02413          "%s"
02414          "\r\n",
02415          cur->parkingnum, cur->chan->name, cur->peername,
02416          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02417          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02418          S_OR(cur->chan->cid.cid_name, ""),
02419          idText);
02420    }
02421 
02422    astman_append(s,
02423       "Event: ParkedCallsComplete\r\n"
02424       "%s"
02425       "\r\n",idText);
02426 
02427    ast_mutex_unlock(&parking_lock);
02428 
02429    return RESULT_SUCCESS;
02430 }

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 487 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_channel::context, ast_channel::exten, f, LOG_WARNING, ast_channel::name, park_call_full(), 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().

00488 {
00489    struct ast_channel *chan;
00490    struct ast_frame *f;
00491    int park_status;
00492 
00493    /* Make a new, fake channel that we'll use to masquerade in the real one */
00494    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00495       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00496       return -1;
00497    }
00498 
00499    /* Make formats okay */
00500    chan->readformat = rchan->readformat;
00501    chan->writeformat = rchan->writeformat;
00502    ast_channel_masquerade(chan, rchan);
00503 
00504    /* Setup the extensions and such */
00505    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00506 
00507    /* Make the masq execute */
00508    if ((f = ast_read(chan))) {
00509       ast_frfree(f);
00510    }
00511 
00512    if (peer == rchan) {
00513       peer = chan;
00514    }
00515 
00516    if (!play_announcement || !orig_chan_name) {
00517       orig_chan_name = ast_strdupa(chan->name);
00518    }
00519 
00520    park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name);
00521    if (park_status == 1) {
00522       /* would be nice to play: "invalid parking extension" */
00523       ast_hangup(chan);
00524       return -1;
00525    }
00526 
00527    return 0;
00528 }

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

References masq_park_call().

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

00536 {
00537    return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
00538 }

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

metermaids callback from devicestate.c

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

00285 {
00286    int res = AST_DEVICE_INVALID;
00287    char *context = ast_strdupa(data);
00288    char *exten;
00289 
00290    exten = strsep(&context, "@");
00291    if (!context)
00292       return res;
00293    
00294    if (option_debug > 3)
00295       ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00296 
00297    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00298 
00299    if (!res)
00300       return AST_DEVICE_NOT_INUSE;
00301    else
00302       return AST_DEVICE_INUSE;
00303 }

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

Notify metermaids that we've changed an extension.

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

00274 {
00275    if (option_debug > 3)
00276       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00277 
00278    /* Send notification to devicestate subsystem */
00279    ast_device_state_changed("park:%s@%s", exten, context);
00280    return;
00281 }

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

Add parking hints for all defined parking lots.

Definition at line 2530 of file res_features.c.

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

02531 {
02532    int numext;
02533    char device[AST_MAX_EXTENSION];
02534    char exten[10];
02535 
02536    for (numext = start; numext <= stop; numext++) {
02537       snprintf(exten, sizeof(exten), "%d", numext);
02538       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02539       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02540    }
02541 }

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

Park a call.

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

02119 {
02120    /* Cache the original channel name in case we get masqueraded in the middle
02121     * of a park--it is still theoretically possible for a transfer to happen before
02122     * we get here, but it is _really_ unlikely */
02123    char *orig_chan_name = ast_strdupa(chan->name);
02124    char orig_exten[AST_MAX_EXTENSION];
02125    int orig_priority = chan->priority;
02126 
02127    /* Data is unused at the moment but could contain a parking
02128       lot context eventually */
02129    int res = 0;
02130    struct ast_module_user *u;
02131 
02132    u = ast_module_user_add(chan);
02133 
02134    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
02135 
02136    /* Setup the exten/priority to be s/1 since we don't know
02137       where this call should return */
02138    strcpy(chan->exten, "s");
02139    chan->priority = 1;
02140    /* Answer if call is not up */
02141    if (chan->_state != AST_STATE_UP)
02142       res = ast_answer(chan);
02143    /* Sleep to allow VoIP streams to settle down */
02144    if (!res)
02145       res = ast_safe_sleep(chan, 1000);
02146    /* Park the call */
02147    if (!res) {
02148       res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name);
02149       /* Continue on in the dialplan */
02150       if (res == 1) {
02151          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
02152          chan->priority = orig_priority;
02153          res = 0;
02154       } else if (!res) {
02155          res = 1;
02156       }
02157    }
02158 
02159    ast_module_user_remove(u);
02160 
02161    return res;
02162 }

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

Definition at line 305 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_calloc, AST_CHANNEL_NAME, ast_channel_unlock, ast_clear_flag, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_copy_string(), ast_exists_extension(), AST_FLAG_MASQ_NOSTREAM, ast_free, ast_get_channel_by_name_locked(), ast_indicate_data(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_set_flag, ast_strlen_zero(), ast_tvnow(), ast_verbose(), ast_channel::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), option_verbose, parking_lock, parkinglot, parkeduser::parkingnum, pbx_builtin_getvar_helper(), ast_channel::priority, S_OR, strdup, ast_channel::tech, ast_channel_tech::type, and VERBOSE_PREFIX_2.

Referenced by ast_park_call(), and masq_park_call().

00306 {
00307    struct parkeduser *pu, *cur;
00308    int i, x = -1, parking_range, parkingnum_copy;
00309    struct ast_context *con;
00310    const char *parkingexten;
00311    
00312    /* Allocate memory for parking data */
00313    if (!(pu = ast_calloc(1, sizeof(*pu)))) 
00314       return -1;
00315 
00316    /* Lock parking lot */
00317    ast_mutex_lock(&parking_lock);
00318    /* Check for channel variable PARKINGEXTEN */
00319    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00320    if (!ast_strlen_zero(parkingexten)) {
00321       /*!\note The API forces us to specify a numeric parking slot, even
00322        * though the architecture would tend to support non-numeric extensions
00323        * (as are possible with SIP, for example).  Hence, we enforce that
00324        * limitation here.  If extout was not numeric, we could permit
00325        * arbitrary non-numeric extensions.
00326        */
00327       if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) {
00328          ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00329          ast_mutex_unlock(&parking_lock);
00330          free(pu);
00331          return 1;   /* Continue execution if possible */
00332       }
00333       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00334 
00335       if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
00336          ast_mutex_unlock(&parking_lock);
00337          free(pu);
00338          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00339          return 1;   /* Continue execution if possible */
00340       }
00341    } else {
00342       /* Select parking space within range */
00343       parking_range = parking_stop - parking_start+1;
00344       for (i = 0; i < parking_range; i++) {
00345          x = (i + parking_offset) % parking_range + parking_start;
00346          cur = parkinglot;
00347          while(cur) {
00348             if (cur->parkingnum == x) 
00349                break;
00350             cur = cur->next;
00351          }
00352          if (!cur)
00353             break;
00354       }
00355 
00356       if (!(i < parking_range)) {
00357          ast_log(LOG_WARNING, "No more parking spaces\n");
00358          free(pu);
00359          ast_mutex_unlock(&parking_lock);
00360          return -1;
00361       }
00362       /* Set pointer for next parking */
00363       if (parkfindnext) 
00364          parking_offset = x - parking_start + 1;
00365       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00366    }
00367    
00368    chan->appl = "Parked Call";
00369    chan->data = NULL; 
00370 
00371    pu->chan = chan;
00372    
00373    /* Put the parked channel on hold if we have two different channels */
00374    if (chan != peer) {
00375       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00376          S_OR(parkmohclass, NULL),
00377          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00378    }
00379    
00380    pu->start = ast_tvnow();
00381    pu->parkingnum = x;
00382    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00383    if (extout)
00384       *extout = x;
00385 
00386    if (peer) { 
00387       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
00388          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
00389          and we need the callback name to be that of transferer.  Since local,1/2 have the same
00390          name we can be tricky and just grab the bridged channel from the other side of the local
00391       */
00392       if (!strcasecmp(peer->tech->type, "Local")) {
00393          struct ast_channel *tmpchan, *base_peer;
00394          char other_side[AST_CHANNEL_NAME];
00395          char *c;
00396          ast_copy_string(other_side, S_OR(orig_chan_name, peer->name), sizeof(other_side));
00397          if ((c = strrchr(other_side, ','))) {
00398             *++c = '1';
00399          }
00400          if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00401             if ((base_peer = ast_bridged_channel(tmpchan))) {
00402                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00403             }
00404             ast_channel_unlock(tmpchan);
00405          }
00406       } else {
00407          ast_copy_string(pu->peername, S_OR(orig_chan_name, peer->name), sizeof(pu->peername));
00408       }
00409    }
00410 
00411    /* Remember what had been dialed, so that if the parking
00412       expires, we try to come back to the same place */
00413    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00414    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00415    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00416    pu->next = parkinglot;
00417    parkinglot = pu;
00418    parkingnum_copy = pu->parkingnum;
00419    /* If parking a channel directly, don't quite yet get parking running on it */
00420    if (peer == chan) 
00421       pu->notquiteyet = 1;
00422 
00423    if (option_verbose > 1) 
00424       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));
00425 
00426    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00427       "Exten: %s\r\n"
00428       "Channel: %s\r\n"
00429       "From: %s\r\n"
00430       "Timeout: %ld\r\n"
00431       "CallerID: %s\r\n"
00432       "CallerIDName: %s\r\n",
00433       pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00434       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00435       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00436       S_OR(pu->chan->cid.cid_name, "<unknown>")
00437       );
00438 
00439    if (peer && adsipark && ast_adsi_available(peer)) {
00440       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00441       ast_adsi_unload_session(peer);
00442    }
00443 
00444    con = ast_context_find(parking_con);
00445    if (!con) 
00446       con = ast_context_create(NULL, parking_con, registrar);
00447    if (!con)   /* Still no context? Bad */
00448       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00449    if (con) {
00450       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) {
00451          notify_metermaids(pu->parkingexten, parking_con);
00452       }
00453    }
00454 
00455    ast_mutex_unlock(&parking_lock);
00456    /* Wake up the (presumably select()ing) thread */
00457    pthread_kill(parking_thread, SIGURG);
00458 
00459    /* Only say number if it's a number and the channel hasn't been masqueraded away */
00460    if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) {
00461       /* Make sure we don't start saying digits to the channel being parked */
00462       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00463       /* Tell the peer channel the number of the parking space */
00464       ast_say_digits(peer, parkingnum_copy, "", peer->language);
00465       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00466    }
00467 
00468    if (peer == chan) { /* pu->notquiteyet = 1 */
00469       /* Wake up parking thread if we're really done */
00470       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00471          S_OR(parkmohclass, NULL),
00472          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00473       pu->notquiteyet = 0;
00474       pthread_kill(parking_thread, SIGURG);
00475    }
00476    return 0;
00477 }

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

References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_REDIRECT, 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, EVENT_FLAG_CALL, free, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), option_verbose, 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().

02166 {
02167    int res = 0;
02168    struct ast_module_user *u;
02169    struct ast_channel *peer=NULL;
02170    struct parkeduser *pu, *pl=NULL;
02171    struct ast_context *con;
02172 
02173    int park;
02174    struct ast_bridge_config config;
02175 
02176    if (!data) {
02177       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
02178       return -1;
02179    }
02180    
02181    u = ast_module_user_add(chan);
02182 
02183    park = atoi((char *)data);
02184    ast_mutex_lock(&parking_lock);
02185    pu = parkinglot;
02186    while(pu) {
02187       if (pu->parkingnum == park) {
02188          if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
02189             ast_mutex_unlock(&parking_lock);
02190             ast_module_user_remove(u);
02191             return -1;
02192          }
02193          if (pl)
02194             pl->next = pu->next;
02195          else
02196             parkinglot = pu->next;
02197          break;
02198       }
02199       pl = pu;
02200       pu = pu->next;
02201    }
02202    ast_mutex_unlock(&parking_lock);
02203    if (pu) {
02204       peer = pu->chan;
02205       con = ast_context_find(parking_con);
02206       if (con) {
02207          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
02208             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02209          else
02210             notify_metermaids(pu->parkingexten, parking_con);
02211       } else
02212          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02213 
02214       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
02215          "Exten: %s\r\n"
02216          "Channel: %s\r\n"
02217          "From: %s\r\n"
02218          "CallerID: %s\r\n"
02219          "CallerIDName: %s\r\n",
02220          pu->parkingexten, pu->chan->name, chan->name,
02221          S_OR(pu->chan->cid.cid_num, "<unknown>"),
02222          S_OR(pu->chan->cid.cid_name, "<unknown>")
02223          );
02224 
02225       free(pu);
02226    }
02227    /* JK02: it helps to answer the channel if not already up */
02228    if (chan->_state != AST_STATE_UP)
02229       ast_answer(chan);
02230 
02231    if (peer) {
02232       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
02233       
02234       if (!ast_strlen_zero(courtesytone)) {
02235          int error = 0;
02236          ast_indicate(peer, AST_CONTROL_UNHOLD);
02237          if (parkedplay == 0) {
02238             error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
02239          } else if (parkedplay == 1) {
02240             error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
02241          } else if (parkedplay == 2) {
02242             if (!ast_streamfile(chan, courtesytone, chan->language) &&
02243                   !ast_streamfile(peer, courtesytone, chan->language)) {
02244                /*! \todo XXX we would like to wait on both! */
02245                res = ast_waitstream(chan, "");
02246                if (res >= 0)
02247                   res = ast_waitstream(peer, "");
02248                if (res < 0)
02249                   error = 1;
02250             }
02251                         }
02252          if (error) {
02253             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02254             ast_hangup(peer);
02255             ast_module_user_remove(u);
02256             return -1;
02257          }
02258       } else
02259          ast_indicate(peer, AST_CONTROL_UNHOLD); 
02260 
02261       res = ast_channel_make_compatible(chan, peer);
02262       if (res < 0) {
02263          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02264          ast_hangup(peer);
02265          ast_module_user_remove(u);
02266          return -1;
02267       }
02268       /* This runs sorta backwards, since we give the incoming channel control, as if it
02269          were the person called. */
02270       if (option_verbose > 2) 
02271          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
02272 
02273       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02274       ast_cdr_setdestchan(chan->cdr, peer->name);
02275       memset(&config, 0, sizeof(struct ast_bridge_config));
02276 
02277       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
02278          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02279       }
02280       if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
02281          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02282       }
02283       res = ast_bridge_call(chan, peer, &config);
02284 
02285       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02286       ast_cdr_setdestchan(chan->cdr, peer->name);
02287 
02288       /* Simulate the PBX hanging up */
02289       ast_hangup(peer);
02290       ast_module_user_remove(u);
02291       return res;
02292    } else {
02293       /*! \todo XXX Play a message XXX */
02294       if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02295          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02296       if (option_verbose > 2) 
02297          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02298       res = -1;
02299    }
02300 
02301    ast_module_user_remove(u);
02302 
02303    return res;
02304 }

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

Definition at line 1456 of file res_features.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.

Referenced by ast_bridge_call().

01457 {
01458    struct ast_cdr *cdr_orig = cdr;
01459    while (cdr) {
01460       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
01461          return cdr;
01462       cdr = cdr->next;
01463    }
01464    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
01465 }

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

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

01917 {
01918    manager_event(EVENT_FLAG_CALL, s,
01919       "Exten: %s\r\n"
01920       "Channel: %s\r\n"
01921       "CallerID: %s\r\n"
01922       "CallerIDName: %s\r\n\r\n",
01923       parkingexten, 
01924       chan->name,
01925       S_OR(chan->cid.cid_num, "<unknown>"),
01926       S_OR(chan->cid.cid_name, "<unknown>")
01927       );
01928 }

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

Find the context for the transfer.

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

00700 {
00701         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00702         if (ast_strlen_zero(s))
00703                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00704         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00705                 s = transferer->macrocontext;
00706         if (ast_strlen_zero(s))
00707                 s = transferer->context;
00708         return s;  
00709 }

static int reload ( void   )  [static]

Definition at line 2764 of file res_features.c.

References load_config().

02765 {
02766    return load_config();
02767 }

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

Definition at line 1170 of file res_features.c.

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

01171 {
01172    int x, res = -1;
01173 
01174    ast_rwlock_wrlock(&features_lock);
01175    for (x = 0; x < FEATURES_COUNT; x++) {
01176       if (strcasecmp(builtin_features[x].sname, name))
01177          continue;
01178 
01179       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01180       res = 0;
01181       break;
01182    }
01183    ast_rwlock_unlock(&features_lock);
01184 
01185    return res;
01186 }

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

00181 {
00182    ast_copy_string(chan->context, context, sizeof(chan->context));
00183    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00184    chan->priority = pri;
00185 }

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

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

01257 {
01258    int x;
01259    
01260    ast_clear_flag(config, AST_FLAGS_ALL);
01261 
01262    ast_rwlock_rdlock(&features_lock);
01263    for (x = 0; x < FEATURES_COUNT; x++) {
01264       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01265          continue;
01266 
01267       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01268          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01269 
01270       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01271          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01272    }
01273    ast_rwlock_unlock(&features_lock);
01274    
01275    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01276       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01277 
01278       if (dynamic_features) {
01279          char *tmp = ast_strdupa(dynamic_features);
01280          char *tok;
01281          struct ast_call_feature *feature;
01282 
01283          /* while we have a feature */
01284          while ((tok = strsep(&tmp, "#"))) {
01285             AST_RWLIST_RDLOCK(&feature_list);
01286             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01287                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01288                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01289                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01290                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01291             }
01292             AST_RWLIST_UNLOCK(&feature_list);
01293          }
01294       }
01295    }
01296 }

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

References FEATURE_SENSE_PEER.

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

00554 {
00555    if (sense == FEATURE_SENSE_PEER) {
00556       *caller = peer;
00557       *callee = chan;
00558    } else {
00559       *callee = peer;
00560       *caller = chan;
00561    }
00562 }

static int unload_module ( void   )  [static]

Definition at line 2795 of file res_features.c.

References ast_cli_unregister_multiple(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), cli_features, parkcall, and parkedcall.

02796 {
02797    ast_module_user_hangup_all();
02798 
02799    ast_manager_unregister("ParkedCalls");
02800    ast_manager_unregister("Park");
02801    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02802    ast_unregister_application(parkcall);
02803    ast_devstate_prov_del("Park");
02804    return ast_unregister_application(parkedcall);
02805 }

static void unmap_features ( void   )  [static]

Definition at line 1160 of file res_features.c.

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

01161 {
01162    int x;
01163 
01164    ast_rwlock_wrlock(&features_lock);
01165    for (x = 0; x < FEATURES_COUNT; x++)
01166       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01167    ast_rwlock_unlock(&features_lock);
01168 }


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

Definition at line 2811 of file res_features.c.

int adsipark [static]

Definition at line 105 of file res_features.c.

Referenced by load_config().

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2811 of file res_features.c.

int atxfernoanswertimeout [static]

Definition at line 110 of file res_features.c.

Referenced by load_config().

struct ast_call_feature builtin_features[] [static]

Definition at line 1034 of file res_features.c.

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

struct ast_cli_entry cli_features[] [static]

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

char courtesytone[256] [static]

Courtesy tone

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

char* descrip2 [static]

Definition at line 127 of file res_features.c.

int featuredigittimeout [static]

Definition at line 108 of file res_features.c.

ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static]

Definition at line 1032 of file res_features.c.

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

char mandescr_park[] [static]

Definition at line 2432 of file res_features.c.

Referenced by load_module().

struct ast_app* monitor_app = NULL [static]

Definition at line 138 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 139 of file res_features.c.

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 85 of file res_features.c.

Referenced by load_config().

char* parkcall = PARK_APP_NAME [static]

Definition at line 123 of file res_features.c.

Referenced by load_module(), and unload_module().

char* parkedcall = "ParkedCall" [static]

Definition at line 83 of file res_features.c.

Referenced by load_module(), and unload_module().

int parkedcalltransfers [static]

Who can REDIRECT after picking up a parked a call

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

Referenced by park_exec().

int parkfindnext [static]

Definition at line 103 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 87 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 88 of file res_features.c.

Referenced by load_config().

char parking_ext[AST_MAX_EXTENSION] [static]

Extension you type to park the call

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

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

int parking_offset [static]

Definition at line 102 of file res_features.c.

int parking_start [static]

First available extension for parking

Definition at line 92 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

int parking_stop [static]

Last available extension for parking

Definition at line 93 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

pthread_t parking_thread [static]

Definition at line 160 of file res_features.c.

Referenced by load_module().

struct parkeduser* parkinglot [static]

Definition at line 156 of file res_features.c.

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

int parkingtime = DEFAULT_PARK_TIME [static]

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

Definition at line 86 of file res_features.c.

char parkmohclass[MAX_MUSICCLASS] [static]

Music class used for parking

Definition at line 91 of file res_features.c.

Referenced by load_config().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 90 of file res_features.c.

Referenced by load_config().

char* registrar = "res_features" [static]

Registrar for operations

Definition at line 112 of file res_features.c.

char showfeatures_help[] [static]

Initial value:

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

Definition at line 2344 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 2372 of file res_features.c.

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

Definition at line 115 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 125 of file res_features.c.

int transferdigittimeout [static]

Definition at line 107 of file res_features.c.

Referenced by load_config().

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 100 of file res_features.c.

Referenced by load_config().

char xfersound[256] [static]

Call transfer sound

Definition at line 99 of file res_features.c.

Referenced by load_config().


Generated on Wed Feb 11 12:00:30 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7