Mon Mar 31 07:42:22 2008

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 dependency graph for res_features.c:

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
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_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
#define FEATURE_RETURN_PASSDIGITS   21
#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
#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)
}
enum  { BRIDGE_OPT_PLAYTONE = (1 << 0) }

Functions

static int action_bridge (struct mansession *s, const struct message *m)
static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
 AST_APP_OPTIONS (bridge_exec_options, BEGIN_OPTIONS END_OPTIONS)
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)
static AST_LIST_HEAD_STATIC (feature_list, ast_call_feature)
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Call Features Resource",.load=load_module,.unload=unload_module,.reload=reload,)
 AST_MUTEX_DEFINE_STATIC (parking_lock)
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
 AST_RWLOCK_DEFINE_STATIC (features_lock)
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 bridge_exec (struct ast_channel *chan, void *data)
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
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 do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan)
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 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, char *orig_chan_name)
static int park_exec (struct ast_channel *chan, void *data)
 Pickup parked call.
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 int adsipark
static char * app_bridge = "Bridge"
static int atxfernoanswertimeout
static char * bridge_descrip
static char * bridge_synopsis = "Bridge two channels"
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 char mandescr_bridge []
static char mandescr_park []
static struct ast_appmonitor_app = NULL
static int monitor_ok = 1
static int parkaddhints = 0
static char * parkcall = "Park"
static char * parkedcall = "ParkedCall"
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 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 71 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500

Definition at line 68 of file res_features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 69 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 66 of file res_features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 67 of file res_features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 510 of file res_features.c.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 517 of file res_features.c.

Referenced by ast_feature_interpret(), and feature_exec_app().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 513 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 514 of file res_features.c.

Referenced by ast_bridge_call(), and ast_feature_interpret().

#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 512 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 515 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_SUCCESS   23

Definition at line 516 of file res_features.c.

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

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 511 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 519 of file res_features.c.

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

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 520 of file res_features.c.

Referenced by ast_bridge_call(), and set_peers().

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

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

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

anonymous enum

Enumerator:
BRIDGE_OPT_PLAYTONE 

Definition at line 2594 of file res_features.c.

02594      {
02595    BRIDGE_OPT_PLAYTONE = (1 << 0),
02596 };


Function Documentation

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

Definition at line 2079 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_free(), ast_channel_make_compatible(), ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), ast_mutex_unlock(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), do_bridge_masquerade(), errno, ast_channel::lock, LOG_WARNING, playtone(), s, and xfersound.

Referenced by load_module().

02080 {
02081    const char *channela = astman_get_header(m, "Channel1");
02082    const char *channelb = astman_get_header(m, "Channel2");
02083    const char *playtone = astman_get_header(m, "Tone");
02084    struct ast_channel *chana = NULL, *chanb = NULL;
02085    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
02086    struct ast_bridge_thread_obj *tobj = NULL;
02087 
02088    /* make sure valid channels were specified */
02089    if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) {
02090       chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
02091       chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
02092       if (chana)
02093          ast_mutex_unlock(&chana->lock);
02094       if (chanb)
02095          ast_mutex_unlock(&chanb->lock);
02096 
02097       /* send errors if any of the channels could not be found/locked */
02098       if (!chana) {
02099          char buf[256];
02100          snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
02101          astman_send_error(s, m, buf);
02102          return 0;
02103       }
02104       if (!chanb) {
02105          char buf[256];
02106          snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
02107          astman_send_error(s, m, buf);
02108          return 0;
02109       }
02110    } else {
02111       astman_send_error(s, m, "Missing channel parameter in request");
02112       return 0;
02113    }
02114 
02115    /* Answer the channels if needed */
02116    if (chana->_state != AST_STATE_UP)
02117       ast_answer(chana);
02118    if (chanb->_state != AST_STATE_UP)
02119       ast_answer(chanb);
02120 
02121    /* create the placeholder channels and grab the other channels */
02122    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
02123       NULL, NULL, 0, "Bridge/%s", chana->name))) {
02124       astman_send_error(s, m, "Unable to create temporary channel!");
02125       return 1;
02126    }
02127 
02128    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
02129       NULL, NULL, 0, "Bridge/%s", chanb->name))) {
02130       astman_send_error(s, m, "Unable to create temporary channels!");
02131       ast_channel_free(tmpchana);
02132       return 1;
02133    }
02134 
02135    do_bridge_masquerade(chana, tmpchana);
02136    do_bridge_masquerade(chanb, tmpchanb);
02137    
02138    /* make the channels compatible, send error if we fail doing so */
02139    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
02140       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
02141       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
02142       ast_hangup(tmpchana);
02143       ast_hangup(tmpchanb);
02144       return 1;
02145    }
02146 
02147    /* setup the bridge thread object and start the bridge */
02148    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
02149       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
02150       astman_send_error(s, m, "Unable to spawn a new bridge thread");
02151       ast_hangup(tmpchana);
02152       ast_hangup(tmpchanb);
02153       return 1;
02154    }
02155 
02156    tobj->chan = tmpchana;
02157    tobj->peer = tmpchanb;
02158    tobj->return_to_pbx = 1;
02159    
02160    if (ast_true(playtone)) {
02161       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
02162          if (ast_waitstream(tmpchanb, "") < 0)
02163             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
02164       }
02165    }
02166 
02167    ast_bridge_call_thread_launch(tobj);
02168 
02169    astman_send_ack(s, m, "Launched bridge thread with success");
02170 
02171    return 0;
02172 }

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

Definition at line 286 of file res_features.c.

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

Referenced by park_call_full().

00287 {
00288    int res;
00289    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00290    char tmp[256];
00291    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00292 
00293    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00294    message[0] = tmp;
00295    res = ast_adsi_load_session(chan, NULL, 0, 1);
00296    if (res == -1)
00297       return res;
00298    return ast_adsi_print(chan, message, justify, 1);
00299 }

AST_APP_OPTIONS ( bridge_exec_options  ,
BEGIN_OPTIONS  END_OPTIONS 
)

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

References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), AST_CDR_FLAG_LOCKED, ast_cdr_init(), ast_cdr_merge(), ast_cdr_setdestchan(), ast_cdr_setuserfield(), ast_cdr_start(), ast_channel_bridge(), ast_channel_setoption(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, ast_cdr::channel, config, ast_option_header::data, ast_channel::data, ast_cdr::dstchannel, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.

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

01377 {
01378    /* Copy voice back and forth between the two channels.  Give the peer
01379       the ability to transfer calls with '#<extension' syntax. */
01380    struct ast_frame *f;
01381    struct ast_channel *who;
01382    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01383    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01384    int res;
01385    int diff;
01386    int hasfeatures=0;
01387    int hadfeatures=0;
01388    struct ast_option_header *aoh;
01389    struct ast_bridge_config backup_config;
01390    struct ast_cdr *bridge_cdr;
01391 
01392    memset(&backup_config, 0, sizeof(backup_config));
01393 
01394    config->start_time = ast_tvnow();
01395 
01396    if (chan && peer) {
01397       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01398       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01399    } else if (chan)
01400       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01401 
01402    if (monitor_ok) {
01403       const char *monitor_exec;
01404       struct ast_channel *src = NULL;
01405       if (!monitor_app) { 
01406          if (!(monitor_app = pbx_findapp("Monitor")))
01407             monitor_ok=0;
01408       }
01409       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01410          src = chan;
01411       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01412          src = peer;
01413       if (monitor_app && src) {
01414          char *tmp = ast_strdupa(monitor_exec);
01415          pbx_exec(src, monitor_app, tmp);
01416       }
01417    }
01418    
01419    set_config_flags(chan, peer, config);
01420    config->firstpass = 1;
01421 
01422    /* Answer if need be */
01423    if (ast_answer(chan))
01424       return -1;
01425    peer->appl = "Bridged Call";
01426    peer->data = chan->name;
01427 
01428    /* copy the userfield from the B-leg to A-leg if applicable */
01429    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01430       char tmp[256];
01431       if (!ast_strlen_zero(chan->cdr->userfield)) {
01432          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01433          ast_cdr_appenduserfield(chan, tmp);
01434       } else
01435          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01436       /* free the peer's cdr without ast_cdr_free complaining */
01437       free(peer->cdr);
01438       peer->cdr = NULL;
01439    }
01440 
01441    for (;;) {
01442       struct ast_channel *other; /* used later */
01443 
01444       res = ast_channel_bridge(chan, peer, config, &f, &who);
01445 
01446       if (config->feature_timer) {
01447          /* Update time limit for next pass */
01448          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01449          config->feature_timer -= diff;
01450          if (hasfeatures) {
01451             /* Running on backup config, meaning a feature might be being
01452                activated, but that's no excuse to keep things going 
01453                indefinitely! */
01454             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01455                if (option_debug)
01456                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01457                config->feature_timer = 0;
01458                who = chan;
01459                if (f)
01460                   ast_frfree(f);
01461                f = NULL;
01462                res = 0;
01463             } else if (config->feature_timer <= 0) {
01464                /* Not *really* out of time, just out of time for
01465                   digits to come in for features. */
01466                if (option_debug)
01467                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01468                if (!ast_strlen_zero(peer_featurecode)) {
01469                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01470                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01471                }
01472                if (!ast_strlen_zero(chan_featurecode)) {
01473                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01474                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01475                }
01476                if (f)
01477                   ast_frfree(f);
01478                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01479                if (!hasfeatures) {
01480                   /* Restore original (possibly time modified) bridge config */
01481                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01482                   memset(&backup_config, 0, sizeof(backup_config));
01483                }
01484                hadfeatures = hasfeatures;
01485                /* Continue as we were */
01486                continue;
01487             } else if (!f) {
01488                /* The bridge returned without a frame and there is a feature in progress.
01489                 * However, we don't think the feature has quite yet timed out, so just
01490                 * go back into the bridge. */
01491                continue;
01492             }
01493          } else {
01494             if (config->feature_timer <=0) {
01495                /* We ran out of time */
01496                config->feature_timer = 0;
01497                who = chan;
01498                if (f)
01499                   ast_frfree(f);
01500                f = NULL;
01501                res = 0;
01502             }
01503          }
01504       }
01505       if (res < 0) {
01506          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01507             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01508          return -1;
01509       }
01510       
01511       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01512             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01513                f->subclass == AST_CONTROL_CONGESTION))) {
01514          res = -1;
01515          break;
01516       }
01517       /* many things should be sent to the 'other' channel */
01518       other = (who == chan) ? peer : chan;
01519       if (f->frametype == AST_FRAME_CONTROL) {
01520          switch (f->subclass) {
01521          case AST_CONTROL_RINGING:
01522          case AST_CONTROL_FLASH:
01523          case -1:
01524             ast_indicate(other, f->subclass);
01525             break;
01526          case AST_CONTROL_HOLD:
01527          case AST_CONTROL_UNHOLD:
01528             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01529             break;
01530          case AST_CONTROL_OPTION:
01531             aoh = f->data;
01532             /* Forward option Requests */
01533             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01534                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01535                   f->datalen - sizeof(struct ast_option_header), 0);
01536             }
01537             break;
01538          }
01539       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01540          /* eat it */
01541       } else if (f->frametype == AST_FRAME_DTMF) {
01542          char *featurecode;
01543          int sense;
01544 
01545          hadfeatures = hasfeatures;
01546          /* This cannot overrun because the longest feature is one shorter than our buffer */
01547          if (who == chan) {
01548             sense = FEATURE_SENSE_CHAN;
01549             featurecode = chan_featurecode;
01550          } else  {
01551             sense = FEATURE_SENSE_PEER;
01552             featurecode = peer_featurecode;
01553          }
01554          /*! append the event to featurecode. we rely on the string being zero-filled, and
01555           * not overflowing it. 
01556           * \todo XXX how do we guarantee the latter ?
01557           */
01558          featurecode[strlen(featurecode)] = f->subclass;
01559          /* Get rid of the frame before we start doing "stuff" with the channels */
01560          ast_frfree(f);
01561          f = NULL;
01562          config->feature_timer = backup_config.feature_timer;
01563          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01564          switch(res) {
01565          case FEATURE_RETURN_PASSDIGITS:
01566             ast_dtmf_stream(other, who, featurecode, 0);
01567             /* Fall through */
01568          case FEATURE_RETURN_SUCCESS:
01569             memset(featurecode, 0, sizeof(chan_featurecode));
01570             break;
01571          }
01572          if (res >= FEATURE_RETURN_PASSDIGITS) {
01573             res = 0;
01574          } else 
01575             break;
01576          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01577          if (hadfeatures && !hasfeatures) {
01578             /* Restore backup */
01579             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01580             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01581          } else if (hasfeatures) {
01582             if (!hadfeatures) {
01583                /* Backup configuration */
01584                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01585                /* Setup temporary config options */
01586                config->play_warning = 0;
01587                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01588                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01589                config->warning_freq = 0;
01590                config->warning_sound = NULL;
01591                config->end_sound = NULL;
01592                config->start_sound = NULL;
01593                config->firstpass = 0;
01594             }
01595             config->start_time = ast_tvnow();
01596             config->feature_timer = featuredigittimeout;
01597             if (option_debug)
01598                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01599          }
01600       }
01601       if (f)
01602          ast_frfree(f);
01603 
01604    }
01605 
01606    /* arrange the cdrs */
01607    bridge_cdr = ast_cdr_alloc();
01608    if (bridge_cdr) {
01609       if (chan->cdr && peer->cdr) { /* both of them? merge */
01610          ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the  destination as a base, but, really, it's random */
01611          ast_cdr_start(bridge_cdr); /* now is the time to start */
01612 
01613          /* absorb the channel cdr */
01614          ast_cdr_merge(bridge_cdr, chan->cdr);
01615          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01616             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01617          
01618          /* absorb the peer cdr */
01619          ast_cdr_merge(bridge_cdr, peer->cdr);
01620          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01621             ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
01622          
01623          peer->cdr = NULL;
01624          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01625       } else if (chan->cdr) {
01626          /* take the cdr from the channel - literally */
01627          ast_cdr_init(bridge_cdr,chan);
01628          /* absorb this data */
01629          ast_cdr_merge(bridge_cdr, chan->cdr);
01630          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01631             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01632          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01633       } else if (peer->cdr) {
01634          /* take the cdr from the peer - literally */
01635          ast_cdr_init(bridge_cdr,peer);
01636          /* absorb this data */
01637          ast_cdr_merge(bridge_cdr, peer->cdr);
01638          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01639             ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01640          peer->cdr = NULL;
01641          peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01642       } else {
01643          /* make up a new cdr */
01644          ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
01645          chan->cdr = bridge_cdr; /*  */
01646       }
01647       if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01648          if (strcmp(bridge_cdr->channel, peer->name) != 0)
01649             ast_cdr_setdestchan(bridge_cdr, peer->name);
01650          else
01651             ast_cdr_setdestchan(bridge_cdr, chan->name);
01652       }
01653    }
01654    return res;
01655 }

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_cdr_reset(), ast_cdr_setdestchan(), ast_check_hangup(), ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_channel::cdr, ast_bridge_thread_obj::chan, ast_channel::data, free, LOG_VERBOSE, LOG_WARNING, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.

Referenced by ast_bridge_call_thread_launch().

00227 {
00228    struct ast_bridge_thread_obj *tobj = data;
00229    int res;
00230 
00231    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00232    tobj->chan->data = tobj->peer->name;
00233    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00234    tobj->peer->data = tobj->chan->name;
00235 
00236    if (tobj->chan->cdr) {
00237       ast_cdr_reset(tobj->chan->cdr, NULL);
00238       ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00239    }
00240    if (tobj->peer->cdr) {
00241       ast_cdr_reset(tobj->peer->cdr, NULL);
00242       ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00243    }
00244 
00245    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00246 
00247    if (tobj->return_to_pbx) {
00248       if (!ast_check_hangup(tobj->peer)) {
00249          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00250          res = ast_pbx_start(tobj->peer);
00251          if (res != AST_PBX_SUCCESS)
00252             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00253       } else
00254          ast_hangup(tobj->peer);
00255       if (!ast_check_hangup(tobj->chan)) {
00256          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00257          res = ast_pbx_start(tobj->chan);
00258          if (res != AST_PBX_SUCCESS)
00259             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00260       } else
00261          ast_hangup(tobj->chan);
00262    } else {
00263       ast_hangup(tobj->chan);
00264       ast_hangup(tobj->peer);
00265    }
00266 
00267    free(tobj);
00268 
00269    return NULL;
00270 }

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 272 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by action_bridge(), and builtin_atxfer().

00273 {
00274    pthread_t thread;
00275    pthread_attr_t attr;
00276    struct sched_param sched;
00277 
00278    pthread_attr_init(&attr);
00279    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00280    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00281    pthread_attr_destroy(&attr);
00282    memset(&sched, 0, sizeof(sched));
00283    pthread_setschedparam(thread, SCHED_RR, &sched);
00284 }

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

References ast_copy_flags, AST_FLAGS_ALL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), 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, find_dynamic_feature(), ast_flags::flags, LOG_DEBUG, ast_call_feature::operation, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, strsep(), and VERBOSE_PREFIX_3.

Referenced by ast_bridge_call().

01087 {
01088    int x;
01089    struct ast_flags features;
01090    int res = FEATURE_RETURN_PASSDIGITS;
01091    struct ast_call_feature *feature;
01092    const char *dynamic_features;
01093    char *tmp, *tok;
01094 
01095    if (sense == FEATURE_SENSE_CHAN) {
01096       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
01097       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01098    } else {
01099       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01100       dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01101    }
01102    if (option_debug > 2)
01103       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);
01104 
01105    ast_rwlock_rdlock(&features_lock);
01106    for (x = 0; x < FEATURES_COUNT; x++) {
01107       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01108           !ast_strlen_zero(builtin_features[x].exten)) {
01109          /* Feature is up for consideration */
01110          if (!strcmp(builtin_features[x].exten, code)) {
01111             res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01112             break;
01113          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01114             if (res == FEATURE_RETURN_PASSDIGITS)
01115                res = FEATURE_RETURN_STOREDIGITS;
01116          }
01117       }
01118    }
01119    ast_rwlock_unlock(&features_lock);
01120 
01121    if (ast_strlen_zero(dynamic_features))
01122       return res;
01123 
01124    tmp = ast_strdupa(dynamic_features);
01125 
01126    while ((tok = strsep(&tmp, "#"))) {
01127       AST_LIST_LOCK(&feature_list); 
01128       if (!(feature = find_dynamic_feature(tok))) {
01129          AST_LIST_UNLOCK(&feature_list);
01130          continue;
01131       }
01132          
01133       /* Feature is up for consideration */
01134       if (!strcmp(feature->exten, code)) {
01135          if (option_verbose > 2)
01136             ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01137          res = feature->operation(chan, peer, config, code, sense, feature);
01138          if (res != FEATURE_RETURN_KEEPTRYING) {
01139             AST_LIST_UNLOCK(&feature_list);
01140             break;
01141          }
01142          res = FEATURE_RETURN_PASSDIGITS;
01143       } else if (!strncmp(feature->exten, code, strlen(code)))
01144          res = FEATURE_RETURN_STOREDIGITS;
01145 
01146       AST_LIST_UNLOCK(&feature_list);
01147    }
01148    
01149    return res;
01150 }

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

References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), 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_verbose(), ast_waitfor_n(), builtin_features, ast_channel::cdr, ast_call_feature::exten, f, FEATURES_COUNT, ast_channel::hangupcause, len, LOG_NOTICE, LOG_WARNING, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.

Referenced by builtin_atxfer().

01196 {
01197    int state = 0;
01198    int cause = 0;
01199    int to;
01200    struct ast_channel *chan;
01201    struct ast_channel *monitor_chans[2];
01202    struct ast_channel *active_channel;
01203    int res = 0, ready = 0;
01204    
01205    if ((chan = ast_request(type, format, data, &cause))) {
01206       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01207       ast_string_field_set(chan, language, language);
01208       ast_channel_inherit_variables(caller, chan); 
01209       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01210       if (!chan->cdr) {
01211          chan->cdr=ast_cdr_alloc();
01212          if (chan->cdr) {
01213             ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
01214             ast_cdr_start(chan->cdr);
01215          }
01216       }
01217          
01218       if (!ast_call(chan, data, timeout)) {
01219          struct timeval started;
01220          int x, len = 0;
01221          char *disconnect_code = NULL, *dialed_code = NULL;
01222 
01223          ast_indicate(caller, AST_CONTROL_RINGING);
01224          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01225          ast_rwlock_rdlock(&features_lock);
01226          for (x = 0; x < FEATURES_COUNT; x++) {
01227             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01228                continue;
01229 
01230             disconnect_code = builtin_features[x].exten;
01231             len = strlen(disconnect_code) + 1;
01232             dialed_code = alloca(len);
01233             memset(dialed_code, 0, len);
01234             break;
01235          }
01236          ast_rwlock_unlock(&features_lock);
01237          x = 0;
01238          started = ast_tvnow();
01239          to = timeout;
01240          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01241             struct ast_frame *f = NULL;
01242 
01243             monitor_chans[0] = caller;
01244             monitor_chans[1] = chan;
01245             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01246 
01247             /* see if the timeout has been violated */
01248             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01249                state = AST_CONTROL_UNHOLD;
01250                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01251                break; /*doh! timeout*/
01252             }
01253 
01254             if (!active_channel)
01255                continue;
01256 
01257             if (chan && (chan == active_channel)){
01258                f = ast_read(chan);
01259                if (f == NULL) { /*doh! where'd he go?*/
01260                   state = AST_CONTROL_HANGUP;
01261                   res = 0;
01262                   break;
01263                }
01264                
01265                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01266                   if (f->subclass == AST_CONTROL_RINGING) {
01267                      state = f->subclass;
01268                      if (option_verbose > 2)
01269                         ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01270                      ast_indicate(caller, AST_CONTROL_RINGING);
01271                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01272                      state = f->subclass;
01273                      if (option_verbose > 2)
01274                         ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01275                      ast_indicate(caller, AST_CONTROL_BUSY);
01276                      ast_frfree(f);
01277                      f = NULL;
01278                      break;
01279                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01280                      /* This is what we are hoping for */
01281                      state = f->subclass;
01282                      ast_frfree(f);
01283                      f = NULL;
01284                      ready=1;
01285                      break;
01286                   } else if (f->subclass != -1) {
01287                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01288                   }
01289                   /* else who cares */
01290                }
01291 
01292             } else if (caller && (active_channel == caller)) {
01293                f = ast_read(caller);
01294                if (f == NULL) { /*doh! where'd he go?*/
01295                   if (caller->_softhangup && !chan->_softhangup) {
01296                      /* make this a blind transfer */
01297                      ready = 1;
01298                      break;
01299                   }
01300                   state = AST_CONTROL_HANGUP;
01301                   res = 0;
01302                   break;
01303                }
01304                
01305                if (f->frametype == AST_FRAME_DTMF) {
01306                   dialed_code[x++] = f->subclass;
01307                   dialed_code[x] = '\0';
01308                   if (strlen(dialed_code) == len) {
01309                      x = 0;
01310                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01311                      x = 0;
01312                      dialed_code[x] = '\0';
01313                   }
01314                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01315                      /* Caller Canceled the call */
01316                      state = AST_CONTROL_UNHOLD;
01317                      ast_frfree(f);
01318                      f = NULL;
01319                      break;
01320                   }
01321                }
01322             }
01323             if (f)
01324                ast_frfree(f);
01325          } /* end while */
01326       } else
01327          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01328    } else {
01329       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01330       switch(cause) {
01331       case AST_CAUSE_BUSY:
01332          state = AST_CONTROL_BUSY;
01333          break;
01334       case AST_CAUSE_CONGESTION:
01335          state = AST_CONTROL_CONGESTION;
01336          break;
01337       }
01338    }
01339    
01340    ast_indicate(caller, -1);
01341    if (chan && ready) {
01342       if (chan->_state == AST_STATE_UP) 
01343          state = AST_CONTROL_ANSWER;
01344       res = 0;
01345    } else if(chan) {
01346       res = -1;
01347       ast_hangup(chan);
01348       chan = NULL;
01349    } else {
01350       res = -1;
01351    }
01352    
01353    if (outstate)
01354       *outstate = state;
01355 
01356    if (chan && res <= 0) {
01357       if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
01358          char tmp[256];
01359          ast_cdr_init(chan->cdr, chan);
01360          snprintf(tmp, 256, "%s/%s", type, (char *)data);
01361          ast_cdr_setapp(chan->cdr,"Dial",tmp);
01362          ast_cdr_update(chan);
01363          ast_cdr_start(chan->cdr);
01364          ast_cdr_end(chan->cdr);
01365          /* If the cause wasn't handled properly */
01366          if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01367             ast_cdr_failed(chan->cdr);
01368       } else {
01369          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01370       }
01371    }
01372    
01373    return chan;
01374 }

static AST_LIST_HEAD_STATIC ( feature_list  ,
ast_call_feature   
) [static]

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

References ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_channel::context, ast_channel::exten, f, LOG_WARNING, park_call_full(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

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

00478 {
00479    struct ast_channel *chan;
00480    struct ast_frame *f;
00481    char *orig_chan_name = NULL;
00482 
00483    /* Make a new, fake channel that we'll use to masquerade in the real one */
00484    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00485       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00486       return -1;
00487    }
00488 
00489    /* Make formats okay */
00490    chan->readformat = rchan->readformat;
00491    chan->writeformat = rchan->writeformat;
00492    ast_channel_masquerade(chan, rchan);
00493 
00494    /* Setup the extensions and such */
00495    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00496 
00497    /* Make the masq execute */
00498    f = ast_read(chan);
00499    if (f)
00500       ast_frfree(f);
00501 
00502    orig_chan_name = ast_strdupa(chan->name);
00503 
00504    park_call_full(chan, peer, timeout, extout, orig_chan_name);
00505 
00506    return 0;
00507 }

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_GLOBAL_SYMBOLS  ,
"Call Features Resource"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

AST_MUTEX_DEFINE_STATIC ( parking_lock   ) 

protects all static variables above

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

References park_call_full().

Referenced by builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), and sip_park_thread().

00473 {
00474    return park_call_full(chan, peer, timeout, extout, NULL);
00475 }

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

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

00160 {
00161    return parking_ext;
00162 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2324 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, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.

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

02325 {
02326    struct ast_channel *cur = NULL;
02327    int res = -1;
02328 
02329    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
02330       if (!cur->pbx && 
02331          (cur != chan) &&
02332          (chan->pickupgroup & cur->callgroup) &&
02333          ((cur->_state == AST_STATE_RINGING) ||
02334           (cur->_state == AST_STATE_RING))) {
02335             break;
02336       }
02337       ast_channel_unlock(cur);
02338    }
02339    if (cur) {
02340       if (option_debug)
02341          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02342       res = ast_answer(chan);
02343       if (res)
02344          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02345       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02346       if (res)
02347          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02348       res = ast_channel_masquerade(cur, chan);
02349       if (res)
02350          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02351       ast_channel_unlock(cur);
02352    } else   {
02353       if (option_debug)
02354          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02355    }
02356    return res;
02357 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 164 of file res_features.c.

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

00165 {
00166    return pickup_ext;
00167 }

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

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_verbose(), LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.

00946 {
00947    if (!feature) {
00948       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00949          return;
00950    }
00951   
00952    AST_LIST_LOCK(&feature_list);
00953    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00954    AST_LIST_UNLOCK(&feature_list);
00955 
00956    if (option_verbose >= 2) 
00957       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00958 }

AST_RWLOCK_DEFINE_STATIC ( features_lock   ) 

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00962 {
00963    if (!feature)
00964       return;
00965 
00966    AST_LIST_LOCK(&feature_list);
00967    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00968    AST_LIST_UNLOCK(&feature_list);
00969    free(feature);
00970 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 973 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

00974 {
00975    struct ast_call_feature *feature;
00976 
00977    AST_LIST_LOCK(&feature_list);
00978    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00979       free(feature);
00980    AST_LIST_UNLOCK(&feature_list);
00981 }

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

Definition at line 2602 of file res_features.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_channel_alloc(), ast_channel_make_compatible(), ast_check_hangup(), AST_DECLARE_APP_ARGS, ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_unlock(), ast_pbx_start(), AST_PBX_SUCCESS, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), BRIDGE_OPT_PLAYTONE, ast_channel::context, do_bridge_masquerade(), EVENT_FLAG_CALL, ast_channel::exten, ast_channel::lock, LOG_DEBUG, LOG_WARNING, manager_event(), option_debug, pbx_builtin_setvar_helper(), ast_channel::priority, and xfersound.

Referenced by load_module().

02603 {
02604    struct ast_module_user *u;
02605    struct ast_channel *current_dest_chan, *final_dest_chan;
02606    char *tmp_data  = NULL;
02607    struct ast_flags opts = { 0, };
02608    struct ast_bridge_config bconfig = { { 0, }, };
02609 
02610    AST_DECLARE_APP_ARGS(args,
02611       AST_APP_ARG(dest_chan);
02612       AST_APP_ARG(options);
02613    );
02614    
02615    if (ast_strlen_zero(data)) {
02616       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
02617       return -1;
02618    }
02619    
02620    u = ast_module_user_add(chan);
02621 
02622    tmp_data = ast_strdupa(data);
02623    AST_STANDARD_APP_ARGS(args, tmp_data);
02624    if (!ast_strlen_zero(args.options))
02625       ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options);
02626 
02627    /* avoid bridge with ourselves */
02628    if (!strncmp(chan->name, args.dest_chan, 
02629       strlen(chan->name) < strlen(args.dest_chan) ? 
02630       strlen(chan->name) : strlen(args.dest_chan))) {
02631       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
02632       manager_event(EVENT_FLAG_CALL, "BridgeExec",
02633                "Response: Failed\r\n"
02634                "Reason: Unable to bridge channel to itself\r\n"
02635                "Channel1: %s\r\n"
02636                "Channel2: %s\r\n",
02637                chan->name, args.dest_chan);
02638       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
02639       ast_module_user_remove(u);
02640       return 0;
02641    }
02642 
02643    /* make sure we have a valid end point */
02644    if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 
02645       strlen(args.dest_chan)))) {
02646       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
02647          "cannot get its lock\n", args.dest_chan);
02648       manager_event(EVENT_FLAG_CALL, "BridgeExec",
02649                "Response: Failed\r\n"
02650                "Reason: Cannot grab end point\r\n"
02651                "Channel1: %s\r\n"
02652                "Channel2: %s\r\n", chan->name, args.dest_chan);
02653       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
02654       ast_module_user_remove(u);
02655       return 0;
02656    }
02657    ast_mutex_unlock(&current_dest_chan->lock);
02658 
02659    /* answer the channel if needed */
02660    if (current_dest_chan->_state != AST_STATE_UP)
02661       ast_answer(current_dest_chan);
02662 
02663    /* try to allocate a place holder where current_dest_chan will be placed */
02664    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
02665       NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) {
02666       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
02667       manager_event(EVENT_FLAG_CALL, "BridgeExec",
02668                "Response: Failed\r\n"
02669                "Reason: cannot create placeholder\r\n"
02670                "Channel1: %s\r\n"
02671                "Channel2: %s\r\n", chan->name, args.dest_chan);
02672    }
02673    do_bridge_masquerade(current_dest_chan, final_dest_chan);
02674 
02675    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
02676    /* try to make compatible, send error if we fail */
02677    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
02678       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
02679       manager_event(EVENT_FLAG_CALL, "BridgeExec",
02680                "Response: Failed\r\n"
02681                "Reason: Could not make channels compatible for bridge\r\n"
02682                "Channel1: %s\r\n"
02683                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
02684       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
02685       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
02686       ast_module_user_remove(u);
02687       return 0;
02688    }
02689 
02690    /* Report that the bridge will be successfull */
02691    manager_event(EVENT_FLAG_CALL, "BridgeExec",
02692             "Response: Success\r\n"
02693             "Channel1: %s\r\n"
02694             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
02695 
02696    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
02697    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
02698       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
02699          if (ast_waitstream(final_dest_chan, "") < 0)
02700             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
02701       }
02702    }
02703    
02704    /* do the bridge */
02705    ast_bridge_call(chan, final_dest_chan, &bconfig);
02706 
02707    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
02708    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
02709    if (!ast_check_hangup(final_dest_chan)) {
02710       if (option_debug) {
02711          ast_log(LOG_DEBUG, "starting new PBX in %s,%s,%d for chan %s\n", 
02712          final_dest_chan->context, final_dest_chan->exten, 
02713          final_dest_chan->priority, final_dest_chan->name);
02714       }
02715 
02716       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
02717          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
02718          ast_hangup(final_dest_chan);
02719       } else if (option_debug)
02720          ast_log(LOG_DEBUG, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
02721    } else {
02722       if (option_debug)
02723          ast_log(LOG_DEBUG, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name);
02724       ast_hangup(final_dest_chan);
02725    }
02726 
02727    ast_module_user_remove(u);
02728 
02729    return 0;
02730 }

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

Definition at line 785 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_masquerade(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, 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_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_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_channel::visible_indication, and ast_channel::writeformat.

00786 {
00787    struct ast_channel *transferer;
00788    struct ast_channel *transferee;
00789    const char *transferer_real_context;
00790    char xferto[256] = "";
00791    int res;
00792    int outstate=0;
00793    struct ast_channel *newchan;
00794    struct ast_channel *xferchan;
00795    struct ast_bridge_thread_obj *tobj;
00796    struct ast_bridge_config bconfig;
00797    struct ast_frame *f;
00798    int l;
00799 
00800    if (option_debug)
00801       ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00802    set_peers(&transferer, &transferee, peer, chan, sense);
00803         transferer_real_context = real_ctx(transferer, transferee);
00804    /* Start autoservice on chan while we talk to the originator */
00805    ast_autoservice_start(transferee);
00806    ast_indicate(transferee, AST_CONTROL_HOLD);
00807    
00808    /* Transfer */
00809    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00810    if (res < 0) {
00811       finishup(transferee);
00812       return res;
00813    }
00814    if (res > 0) /* If they've typed a digit already, handle it */
00815       xferto[0] = (char) res;
00816 
00817    /* this is specific of atxfer */
00818    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00819         if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00820                 finishup(transferee);
00821                 return res;
00822         }
00823    if (res == 0) {
00824       ast_log(LOG_WARNING, "Did not read data.\n");
00825       finishup(transferee);
00826       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00827          return -1;
00828       return FEATURE_RETURN_SUCCESS;
00829    }
00830 
00831    /* valid extension, res == 1 */
00832    if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00833       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00834       finishup(transferee);
00835       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00836          return -1;
00837       return FEATURE_RETURN_SUCCESS;
00838    }
00839 
00840    l = strlen(xferto);
00841    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);   /* append context */
00842    newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00843       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
00844    ast_indicate(transferer, -1);
00845    if (!newchan) {
00846       finishup(transferee);
00847       /* any reason besides user requested cancel and busy triggers the failed sound */
00848       if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00849             ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
00850          return -1;
00851       return FEATURE_RETURN_SUCCESS;
00852    }
00853 
00854    if (check_compat(transferer, newchan)) {
00855       /* we do mean transferee here, NOT transferer */
00856       finishup(transferee);
00857       return -1;
00858    }
00859    memset(&bconfig,0,sizeof(struct ast_bridge_config));
00860    ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00861    ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00862    res = ast_bridge_call(transferer, newchan, &bconfig);
00863    if (newchan->_softhangup || !transferer->_softhangup) {
00864       ast_hangup(newchan);
00865       if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
00866          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00867       finishup(transferee);
00868       transferer->_softhangup = 0;
00869       return FEATURE_RETURN_SUCCESS;
00870    }
00871    
00872    if (check_compat(transferee, newchan)) {
00873       finishup(transferee);
00874       return -1;
00875    }
00876 
00877    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00878    
00879    if ((ast_autoservice_stop(transferee) < 0)
00880       || (ast_waitfordigit(transferee, 100) < 0)
00881       || (ast_waitfordigit(newchan, 100) < 0) 
00882       || ast_check_hangup(transferee) 
00883       || ast_check_hangup(newchan)) {
00884       ast_hangup(newchan);
00885       return -1;
00886    }
00887 
00888    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
00889    if (!xferchan) {
00890       ast_hangup(newchan);
00891       return -1;
00892    }
00893    /* Make formats okay */
00894    xferchan->visible_indication = transferer->visible_indication;
00895    xferchan->readformat = transferee->readformat;
00896    xferchan->writeformat = transferee->writeformat;
00897    ast_channel_masquerade(xferchan, transferee);
00898    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00899    xferchan->_state = AST_STATE_UP;
00900    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00901    xferchan->_softhangup = 0;
00902 
00903    if ((f = ast_read(xferchan)))
00904       ast_frfree(f);
00905 
00906    newchan->_state = AST_STATE_UP;
00907    ast_clear_flag(newchan, AST_FLAGS_ALL);   
00908    newchan->_softhangup = 0;
00909 
00910    tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
00911    if (!tobj) {
00912       ast_hangup(xferchan);
00913       ast_hangup(newchan);
00914       return -1;
00915    }
00916    tobj->chan = newchan;
00917    tobj->peer = xferchan;
00918    tobj->bconfig = *config;
00919 
00920    if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
00921       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00922    ast_bridge_call_thread_launch(tobj);
00923    return -1;  /* XXX meaning the channel is bridged ? */
00924 }

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 571 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, len, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::monitor, monitor_app, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3.

00572 {
00573    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00574    int x = 0;
00575    size_t len;
00576    struct ast_channel *caller_chan, *callee_chan;
00577 
00578    if (!monitor_ok) {
00579       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00580       return -1;
00581    }
00582 
00583    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00584       monitor_ok = 0;
00585       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00586       return -1;
00587    }
00588 
00589    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00590 
00591    if (!ast_strlen_zero(courtesytone)) {
00592       if (ast_autoservice_start(callee_chan))
00593          return -1;
00594       if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00595          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00596          ast_autoservice_stop(callee_chan);
00597          return -1;
00598       }
00599       if (ast_autoservice_stop(callee_chan))
00600          return -1;
00601    }
00602    
00603    if (callee_chan->monitor) {
00604       if (option_verbose > 3)
00605          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00606       ast_monitor_stop(callee_chan, 1);
00607       return FEATURE_RETURN_SUCCESS;
00608    }
00609 
00610    if (caller_chan && callee_chan) {
00611       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00612       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00613 
00614       if (!touch_format)
00615          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00616 
00617       if (!touch_monitor)
00618          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00619    
00620       if (touch_monitor) {
00621          len = strlen(touch_monitor) + 50;
00622          args = alloca(len);
00623          touch_filename = alloca(len);
00624          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00625          snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00626       } else {
00627          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00628          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00629          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00630          args = alloca(len);
00631          touch_filename = alloca(len);
00632          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00633          snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00634       }
00635 
00636       for(x = 0; x < strlen(args); x++) {
00637          if (args[x] == '/')
00638             args[x] = '-';
00639       }
00640       
00641       if (option_verbose > 3)
00642          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00643 
00644       pbx_exec(callee_chan, monitor_app, args);
00645       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00646       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00647    
00648       return FEATURE_RETURN_SUCCESS;
00649    }
00650    
00651    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00652    return -1;
00653 }

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 682 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_park_call(), ast_parking_ext(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_stopstream(), ast_stream_and_wait(), ast_verbose(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, finishup(), LOG_WARNING, option_verbose, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.

00683 {
00684    struct ast_channel *transferer;
00685    struct ast_channel *transferee;
00686    const char *transferer_real_context;
00687    char xferto[256];
00688    int res;
00689 
00690    set_peers(&transferer, &transferee, peer, chan, sense);
00691    transferer_real_context = real_ctx(transferer, transferee);
00692    /* Start autoservice on chan while we talk to the originator */
00693    ast_autoservice_start(transferee);
00694    ast_indicate(transferee, AST_CONTROL_HOLD);
00695 
00696    memset(xferto, 0, sizeof(xferto));
00697    
00698    /* Transfer */
00699    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00700    if (res < 0) {
00701       finishup(transferee);
00702       return -1; /* error ? */
00703    }
00704    if (res > 0)   /* If they've typed a digit already, handle it */
00705       xferto[0] = (char) res;
00706 
00707    ast_stopstream(transferer);
00708    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00709    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00710       finishup(transferee);
00711       return res;
00712    }
00713    if (!strcmp(xferto, ast_parking_ext())) {
00714       res = finishup(transferee);
00715       if (res)
00716          res = -1;
00717       else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
00718          /* We return non-zero, but tell the PBX not to hang the channel when
00719             the thread dies -- We have to be careful now though.  We are responsible for 
00720             hanging up the channel, else it will never be hung up! */
00721 
00722          return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
00723       } else {
00724          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00725       }
00726       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
00727    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00728       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
00729       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00730       res=finishup(transferee);
00731       if (!transferer->cdr) {
00732          transferer->cdr=ast_cdr_alloc();
00733          if (transferer) {
00734             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
00735             ast_cdr_start(transferer->cdr);
00736          }
00737       }
00738       if (transferer->cdr) {
00739          ast_cdr_setdestchan(transferer->cdr, transferee->name);
00740          ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00741       }
00742       if (!transferee->pbx) {
00743          /* Doh!  Use our handy async_goto functions */
00744          if (option_verbose > 2) 
00745             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00746                         ,transferee->name, xferto, transferer_real_context);
00747          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00748             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00749          res = -1;
00750       } else {
00751          /* Set the channel's new extension, since it exists, using transferer context */
00752          set_c_e_p(transferee, transferer_real_context, xferto, 0);
00753       }
00754       check_goto_on_transfer(transferer);
00755       return res;
00756    } else {
00757       if (option_verbose > 2) 
00758          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00759    }
00760    if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0) {
00761       finishup(transferee);
00762       return -1;
00763    }
00764    ast_stopstream(transferer);
00765    res = finishup(transferee);
00766    if (res) {
00767       if (option_verbose > 1)
00768          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00769       return res;
00770    }
00771    return FEATURE_RETURN_SUCCESS;
00772 }

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

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

00656 {
00657    if (option_verbose > 3)
00658       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00659    return FEATURE_RETURN_HANGUP;
00660 }

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

References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_park_call(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_safe_sleep(), AST_STATE_UP, ast_module_user::chan, ast_channel::exten, FEATURE_SENSE_CHAN, ast_channel::priority, and set_peers().

00539 {
00540    struct ast_channel *parker;
00541         struct ast_channel *parkee;
00542    int res = 0;
00543    struct ast_module_user *u;
00544 
00545    u = ast_module_user_add(chan);
00546 
00547    set_peers(&parker, &parkee, peer, chan, sense);
00548    /* Setup the exten/priority to be s/1 since we don't know
00549       where this call should return */
00550    strcpy(chan->exten, "s");
00551    chan->priority = 1;
00552    if (chan->_state != AST_STATE_UP)
00553       res = ast_answer(chan);
00554    if (!res)
00555       res = ast_safe_sleep(chan, 1000);
00556    if (!res)
00557       res = ast_park_call(parkee, parker, 0, NULL);
00558 
00559    ast_module_user_remove(u);
00560 
00561    if (!res) {
00562       if (sense == FEATURE_SENSE_CHAN)
00563          res = AST_PBX_NO_HANGUP_PEER;
00564       else
00565          res = AST_PBX_KEEPALIVE;
00566    }
00567    return res;
00568 
00569 }

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

Definition at line 774 of file res_features.c.

References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING.

Referenced by builtin_atxfer().

00775 {
00776    if (ast_channel_make_compatible(c, newchan) < 0) {
00777       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00778          c->name, newchan->name);
00779       ast_hangup(newchan);
00780       return -1;
00781    }
00782    return 0;
00783 }

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, 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, 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 do_bridge_masquerade ( struct ast_channel chan,
struct ast_channel tmpchan 
) [static]

Definition at line 2063 of file res_features.c.

References ast_channel::_state, ast_channel_masquerade(), ast_do_masquerade(), ast_explicit_goto(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_setstate(), ast_channel::context, ast_channel::exten, ast_channel::lock, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

Referenced by action_bridge(), and bridge_exec().

02064 {
02065    ast_moh_stop(chan);
02066    ast_mutex_lock(&chan->lock);
02067    ast_setstate(tmpchan, chan->_state);
02068    tmpchan->readformat = chan->readformat;
02069    tmpchan->writeformat = chan->writeformat;
02070    ast_channel_masquerade(tmpchan, chan);
02071    ast_mutex_lock(&tmpchan->lock);
02072    ast_do_masquerade(tmpchan);
02073    /* when returning from bridge, the channel will continue at the next priority */
02074    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
02075    ast_mutex_unlock(&tmpchan->lock);
02076    ast_mutex_unlock(&chan->lock);
02077 }

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

References ast_add_extension2(), 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_select(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, 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().

01673 {
01674    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
01675    FD_ZERO(&rfds);
01676    FD_ZERO(&efds);
01677 
01678    for (;;) {
01679       struct parkeduser *pu, *pl, *pt = NULL;
01680       int ms = -1;   /* select timeout, uninitialized */
01681       int max = -1;  /* max fd, none there yet */
01682       fd_set nrfds, nefds; /* args for the next select */
01683       FD_ZERO(&nrfds);
01684       FD_ZERO(&nefds);
01685 
01686       ast_mutex_lock(&parking_lock);
01687       pl = NULL;
01688       pu = parkinglot;
01689       /* navigate the list with prev-cur pointers to support removals */
01690       while (pu) {
01691          struct ast_channel *chan = pu->chan;   /* shorthand */
01692          int tms;        /* timeout for this item */
01693          int x;          /* fd index in channel */
01694          struct ast_context *con;
01695 
01696          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
01697             pl = pu;
01698             pu = pu->next;
01699             continue;
01700          }
01701          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01702          if (tms > pu->parkingtime) {
01703             ast_indicate(chan, AST_CONTROL_UNHOLD);
01704             /* Get chan, exten from derived kludge */
01705             if (pu->peername[0]) {
01706                char *peername = ast_strdupa(pu->peername);
01707                char *cp = strrchr(peername, '-');
01708                if (cp) 
01709                   *cp = 0;
01710                con = ast_context_find(parking_con_dial);
01711                if (!con) {
01712                   con = ast_context_create(NULL, parking_con_dial, registrar);
01713                   if (!con)
01714                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01715                }
01716                if (con) {
01717                   char returnexten[AST_MAX_EXTENSION];
01718                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01719                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01720                }
01721                set_c_e_p(chan, parking_con_dial, peername, 1);
01722             } else {
01723                /* They've been waiting too long, send them back to where they came.  Theoretically they
01724                   should have their original extensions and such, but we copy to be on the safe side */
01725                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
01726             }
01727 
01728             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
01729 
01730             if (option_verbose > 1) 
01731                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);
01732             /* Start up the PBX, or hang them up */
01733             if (ast_pbx_start(chan))  {
01734                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
01735                ast_hangup(chan);
01736             }
01737             /* And take them out of the parking lot */
01738             if (pl) 
01739                pl->next = pu->next;
01740             else
01741                parkinglot = pu->next;
01742             pt = pu;
01743             pu = pu->next;
01744             con = ast_context_find(parking_con);
01745             if (con) {
01746                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01747                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01748                else
01749                   notify_metermaids(pt->parkingexten, parking_con);
01750             } else
01751                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01752             free(pt);
01753          } else { /* still within parking time, process descriptors */
01754             for (x = 0; x < AST_MAX_FDS; x++) {
01755                struct ast_frame *f;
01756 
01757                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
01758                   continue;   /* nothing on this descriptor */
01759 
01760                if (FD_ISSET(chan->fds[x], &efds))
01761                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
01762                else
01763                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
01764                chan->fdno = x;
01765 
01766                /* See if they need servicing */
01767                f = ast_read(chan);
01768                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
01769                   if (f)
01770                      ast_frfree(f);
01771                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
01772 
01773                   /* There's a problem, hang them up*/
01774                   if (option_verbose > 1) 
01775                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
01776                   ast_hangup(chan);
01777                   /* And take them out of the parking lot */
01778                   if (pl) 
01779                      pl->next = pu->next;
01780                   else
01781                      parkinglot = pu->next;
01782                   pt = pu;
01783                   pu = pu->next;
01784                   con = ast_context_find(parking_con);
01785                   if (con) {
01786                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01787                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01788                   else
01789                      notify_metermaids(pt->parkingexten, parking_con);
01790                   } else
01791                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01792                   free(pt);
01793                   break;
01794                } else {
01795                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01796                   ast_frfree(f);
01797                   if (pu->moh_trys < 3 && !chan->generatordata) {
01798                      if (option_debug)
01799                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01800                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01801                         S_OR(parkmohclass, NULL),
01802                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
01803                      pu->moh_trys++;
01804                   }
01805                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
01806                }
01807 
01808             } /* end for */
01809             if (x >= AST_MAX_FDS) {
01810 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
01811                   if (chan->fds[x] > -1) {
01812                      FD_SET(chan->fds[x], &nrfds);
01813                      FD_SET(chan->fds[x], &nefds);
01814                      if (chan->fds[x] > max)
01815                         max = chan->fds[x];
01816                   }
01817                }
01818                /* Keep track of our shortest wait */
01819                if (tms < ms || ms < 0)
01820                   ms = tms;
01821                pl = pu;
01822                pu = pu->next;
01823             }
01824          }
01825       } /* end while */
01826       ast_mutex_unlock(&parking_lock);
01827       rfds = nrfds;
01828       efds = nefds;
01829       {
01830          struct timeval tv = ast_samp2tv(ms, 1000);
01831          /* Wait for something to happen */
01832          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01833       }
01834       pthread_testcancel();
01835    }
01836    return NULL;   /* Never reached */
01837 }

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 997 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_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_strlen_zero(), ast_test_flag, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_NO_HANGUP_PEER, FEATURE_RETURN_PBX_KEEPALIVE, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().

00998 {
00999    struct ast_app *app;
01000    struct ast_call_feature *feature = data;
01001    struct ast_channel *work, *idle;
01002    int res;
01003 
01004    if (!feature) { /* shouldn't ever happen! */
01005       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01006       return -1; 
01007    }
01008 
01009    if (sense == FEATURE_SENSE_CHAN) {
01010       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01011          return FEATURE_RETURN_KEEPTRYING;
01012       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01013          work = chan;
01014          idle = peer;
01015       } else {
01016          work = peer;
01017          idle = chan;
01018       }
01019    } else {
01020       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01021          return FEATURE_RETURN_KEEPTRYING;
01022       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01023          work = peer;
01024          idle = chan;
01025       } else {
01026          work = chan;
01027          idle = peer;
01028       }
01029    }
01030 
01031    if (!(app = pbx_findapp(feature->app))) {
01032       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01033       return -2;
01034    }
01035 
01036    ast_autoservice_start(idle);
01037    
01038    if (!ast_strlen_zero(feature->moh_class))
01039       ast_moh_start(idle, feature->moh_class, NULL);
01040 
01041    res = pbx_exec(work, app, feature->app_args);
01042 
01043    if (!ast_strlen_zero(feature->moh_class))
01044       ast_moh_stop(idle);
01045 
01046    ast_autoservice_stop(idle);
01047 
01048    if (res == AST_PBX_KEEPALIVE)
01049       return FEATURE_RETURN_PBX_KEEPALIVE;
01050    else if (res == AST_PBX_NO_HANGUP_PEER)
01051       return FEATURE_RETURN_NO_HANGUP_PEER;
01052    else if (res)
01053       return FEATURE_RETURN_SUCCESSBREAK;
01054    
01055    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01056 }

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

find a feature by name

Definition at line 984 of file res_features.c.

References AST_LIST_TRAVERSE, and ast_call_feature::sname.

Referenced by ast_feature_interpret(), and set_config_flags().

00985 {
00986    struct ast_call_feature *tmp;
00987 
00988    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00989       if (!strcasecmp(tmp->sname, name))
00990          break;
00991    }
00992 
00993    return tmp;
00994 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 662 of file res_features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00663 {
00664         ast_indicate(chan, AST_CONTROL_UNHOLD);
00665   
00666         return ast_autoservice_stop(chan);
00667 }

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

Definition at line 2178 of file res_features.c.

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

02179 {
02180    struct parkeduser *cur;
02181    int numparked = 0;
02182 
02183    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02184       , "Context", "Extension", "Pri", "Timeout");
02185 
02186    ast_mutex_lock(&parking_lock);
02187 
02188    for (cur = parkinglot; cur; cur = cur->next) {
02189       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02190          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02191          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02192 
02193       numparked++;
02194    }
02195    ast_mutex_unlock(&parking_lock);
02196    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02197 
02198 
02199    return RESULT_SUCCESS;
02200 }

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

Definition at line 2018 of file res_features.c.

References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_pickup_ext(), ast_rwlock_rdlock(), ast_rwlock_unlock(), builtin_features, ast_call_feature::default_exten, ast_call_feature::exten, exten, FEATURES_COUNT, ast_call_feature::fname, format, parking_con, parking_ext, parking_start, parking_stop, RESULT_SUCCESS, and ast_call_feature::sname.

02019 {
02020    int i;
02021    struct ast_call_feature *feature;
02022    char format[] = "%-25s %-7s %-7s\n";
02023 
02024    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02025    ast_cli(fd, format, "---------------", "-------", "-------");
02026 
02027    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02028 
02029    ast_rwlock_rdlock(&features_lock);
02030    for (i = 0; i < FEATURES_COUNT; i++)
02031       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02032    ast_rwlock_unlock(&features_lock);
02033 
02034    ast_cli(fd, "\n");
02035    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02036    ast_cli(fd, format, "---------------", "-------", "-------");
02037    if (AST_LIST_EMPTY(&feature_list))
02038       ast_cli(fd, "(none)\n");
02039    else {
02040       AST_LIST_LOCK(&feature_list);
02041       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
02042          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
02043       AST_LIST_UNLOCK(&feature_list);
02044    }
02045    ast_cli(fd, "\nCall parking\n");
02046    ast_cli(fd, "------------\n");
02047    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02048    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02049    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02050    ast_cli(fd,"\n");
02051    
02052    return RESULT_SUCCESS;
02053 }

static int load_config ( void   )  [static]

Definition at line 2374 of file res_features.c.

References adsipark, ast_config_load(), 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, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkmohclass, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.

02375 {
02376    int start = 0, end = 0;
02377    int res;
02378    struct ast_context *con = NULL;
02379    struct ast_config *cfg = NULL;
02380    struct ast_variable *var = NULL;
02381    char old_parking_ext[AST_MAX_EXTENSION];
02382    char old_parking_con[AST_MAX_EXTENSION] = "";
02383 
02384    if (!ast_strlen_zero(parking_con)) {
02385       strcpy(old_parking_ext, parking_ext);
02386       strcpy(old_parking_con, parking_con);
02387    } 
02388 
02389    /* Reset to defaults */
02390    strcpy(parking_con, "parkedcalls");
02391    strcpy(parking_con_dial, "park-dial");
02392    strcpy(parking_ext, "700");
02393    strcpy(pickup_ext, "*8");
02394    strcpy(parkmohclass, "default");
02395    courtesytone[0] = '\0';
02396    strcpy(xfersound, "beep");
02397    strcpy(xferfailsound, "pbx-invalid");
02398    parking_start = 701;
02399    parking_stop = 750;
02400    parkfindnext = 0;
02401    adsipark = 0;
02402    parkaddhints = 0;
02403 
02404    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02405    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02406    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02407 
02408    cfg = ast_config_load("features.conf");
02409    if (!cfg) {
02410       ast_log(LOG_WARNING,"Could not load features.conf\n");
02411       return AST_MODULE_LOAD_DECLINE;
02412    }
02413    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02414       if (!strcasecmp(var->name, "parkext")) {
02415          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02416       } else if (!strcasecmp(var->name, "context")) {
02417          ast_copy_string(parking_con, var->value, sizeof(parking_con));
02418       } else if (!strcasecmp(var->name, "parkingtime")) {
02419          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02420             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02421             parkingtime = DEFAULT_PARK_TIME;
02422          } else
02423             parkingtime = parkingtime * 1000;
02424       } else if (!strcasecmp(var->name, "parkpos")) {
02425          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02426             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);
02427          } else {
02428             parking_start = start;
02429             parking_stop = end;
02430          }
02431       } else if (!strcasecmp(var->name, "findslot")) {
02432          parkfindnext = (!strcasecmp(var->value, "next"));
02433       } else if (!strcasecmp(var->name, "parkinghints")) {
02434          parkaddhints = ast_true(var->value);
02435       } else if (!strcasecmp(var->name, "adsipark")) {
02436          adsipark = ast_true(var->value);
02437       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02438          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02439             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02440             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02441          } else
02442             transferdigittimeout = transferdigittimeout * 1000;
02443       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02444          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02445             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02446             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02447          }
02448       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
02449          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
02450             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
02451             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02452          } else
02453             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
02454       } else if (!strcasecmp(var->name, "courtesytone")) {
02455          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02456       }  else if (!strcasecmp(var->name, "parkedplay")) {
02457          if (!strcasecmp(var->value, "both"))
02458             parkedplay = 2;
02459          else if (!strcasecmp(var->value, "parked"))
02460             parkedplay = 1;
02461          else
02462             parkedplay = 0;
02463       } else if (!strcasecmp(var->name, "xfersound")) {
02464          ast_copy_string(xfersound, var->value, sizeof(xfersound));
02465       } else if (!strcasecmp(var->name, "xferfailsound")) {
02466          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02467       } else if (!strcasecmp(var->name, "pickupexten")) {
02468          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02469       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
02470          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
02471       }
02472    }
02473 
02474    unmap_features();
02475    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
02476       if (remap_feature(var->name, var->value))
02477          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02478    }
02479 
02480    /* Map a key combination to an application*/
02481    ast_unregister_features();
02482    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
02483       char *tmp_val = ast_strdupa(var->value);
02484       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
02485       struct ast_call_feature *feature;
02486 
02487       /* strsep() sets the argument to NULL if match not found, and it
02488        * is safe to use it with a NULL argument, so we don't check
02489        * between calls.
02490        */
02491       exten = strsep(&tmp_val,",");
02492       activatedby = strsep(&tmp_val,",");
02493       app = strsep(&tmp_val,",");
02494       app_args = strsep(&tmp_val,",");
02495       moh_class = strsep(&tmp_val,",");
02496 
02497       activateon = strsep(&activatedby, "/");   
02498 
02499       /*! \todo XXX var_name or app_args ? */
02500       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
02501          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
02502             app, exten, activateon, var->name);
02503          continue;
02504       }
02505 
02506       AST_LIST_LOCK(&feature_list);
02507       if ((feature = find_dynamic_feature(var->name))) {
02508          AST_LIST_UNLOCK(&feature_list);
02509          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
02510          continue;
02511       }
02512       AST_LIST_UNLOCK(&feature_list);
02513             
02514       if (!(feature = ast_calloc(1, sizeof(*feature))))
02515          continue;               
02516 
02517       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
02518       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
02519       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
02520       
02521       if (app_args) 
02522          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
02523 
02524       if (moh_class)
02525          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
02526          
02527       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
02528       feature->operation = feature_exec_app;
02529       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
02530 
02531       /* Allow caller and calle to be specified for backwards compatability */
02532       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
02533          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
02534       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
02535          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
02536       else {
02537          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
02538             " must be 'self', or 'peer'\n", var->name);
02539          continue;
02540       }
02541 
02542       if (ast_strlen_zero(activatedby))
02543          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02544       else if (!strcasecmp(activatedby, "caller"))
02545          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
02546       else if (!strcasecmp(activatedby, "callee"))
02547          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
02548       else if (!strcasecmp(activatedby, "both"))
02549          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02550       else {
02551          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
02552             " must be 'caller', or 'callee', or 'both'\n", var->name);
02553          continue;
02554       }
02555 
02556       ast_register_feature(feature);
02557          
02558       if (option_verbose >= 1)
02559          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
02560    }   
02561    ast_config_destroy(cfg);
02562 
02563    /* Remove the old parking extension */
02564    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02565       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
02566             notify_metermaids(old_parking_ext, old_parking_con);
02567       if (option_debug)
02568          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02569    }
02570    
02571    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
02572       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02573       return -1;
02574    }
02575    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
02576    if (parkaddhints)
02577       park_add_hints(parking_con, parking_start, parking_stop);
02578    if (!res)
02579       notify_metermaids(ast_parking_ext(), parking_con);
02580    return res;
02581 
02582 }

static int load_module ( void   )  [static]

Definition at line 2737 of file res_features.c.

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

02738 {
02739    int res;
02740 
02741    ast_register_application(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip); 
02742 
02743    memset(parking_ext, 0, sizeof(parking_ext));
02744    memset(parking_con, 0, sizeof(parking_con));
02745 
02746    if ((res = load_config()))
02747       return res;
02748    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02749    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02750    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02751    if (!res)
02752       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02753    if (!res) {
02754       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
02755       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
02756          "Park a channel", mandescr_park); 
02757       ast_manager_register2("Bridge", EVENT_FLAG_COMMAND, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
02758    }
02759 
02760    res |= ast_devstate_prov_add("Park", metermaidstate);
02761 
02762    return res;
02763 }

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

Definition at line 2269 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(), s, and timeout.

Referenced by load_module().

02270 {
02271    const char *channel = astman_get_header(m, "Channel");
02272    const char *channel2 = astman_get_header(m, "Channel2");
02273    const char *timeout = astman_get_header(m, "Timeout");
02274    char buf[BUFSIZ];
02275    int to = 0;
02276    int res = 0;
02277    int parkExt = 0;
02278    struct ast_channel *ch1, *ch2;
02279 
02280    if (ast_strlen_zero(channel)) {
02281       astman_send_error(s, m, "Channel not specified");
02282       return 0;
02283    }
02284 
02285    if (ast_strlen_zero(channel2)) {
02286       astman_send_error(s, m, "Channel2 not specified");
02287       return 0;
02288    }
02289 
02290    ch1 = ast_get_channel_by_name_locked(channel);
02291    if (!ch1) {
02292       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02293       astman_send_error(s, m, buf);
02294       return 0;
02295    }
02296 
02297    ch2 = ast_get_channel_by_name_locked(channel2);
02298    if (!ch2) {
02299       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02300       astman_send_error(s, m, buf);
02301       ast_channel_unlock(ch1);
02302       return 0;
02303    }
02304 
02305    if (!ast_strlen_zero(timeout)) {
02306       sscanf(timeout, "%d", &to);
02307    }
02308 
02309    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02310    if (!res) {
02311       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02312       astman_send_ack(s, m, "Park successful");
02313    } else {
02314       astman_send_error(s, m, "Park failure");
02315    }
02316 
02317    ast_channel_unlock(ch1);
02318    ast_channel_unlock(ch2);
02319 
02320    return 0;
02321 }

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

Dump lot status.

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

Referenced by load_module().

02223 {
02224    struct parkeduser *cur;
02225    const char *id = astman_get_header(m, "ActionID");
02226    char idText[256] = "";
02227 
02228    if (!ast_strlen_zero(id))
02229       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02230 
02231    astman_send_ack(s, m, "Parked calls will follow");
02232 
02233    ast_mutex_lock(&parking_lock);
02234 
02235    for (cur = parkinglot; cur; cur = cur->next) {
02236       astman_append(s, "Event: ParkedCall\r\n"
02237          "Exten: %d\r\n"
02238          "Channel: %s\r\n"
02239          "From: %s\r\n"
02240          "Timeout: %ld\r\n"
02241          "CallerID: %s\r\n"
02242          "CallerIDName: %s\r\n"
02243          "%s"
02244          "\r\n",
02245          cur->parkingnum, cur->chan->name, cur->peername,
02246          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02247          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02248          S_OR(cur->chan->cid.cid_name, ""),
02249          idText);
02250    }
02251 
02252    astman_append(s,
02253       "Event: ParkedCallsComplete\r\n"
02254       "%s"
02255       "\r\n",idText);
02256 
02257    ast_mutex_unlock(&parking_lock);
02258 
02259    return RESULT_SUCCESS;
02260 }

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

metermaids callback from devicestate.c

Definition at line 313 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, option_debug, and strsep().

Referenced by load_module().

00314 {
00315    int res = AST_DEVICE_INVALID;
00316    char *context = ast_strdupa(data);
00317    char *exten;
00318 
00319    exten = strsep(&context, "@");
00320    if (!context)
00321       return res;
00322    
00323    if (option_debug > 3)
00324       ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00325 
00326    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00327 
00328    if (!res)
00329       return AST_DEVICE_NOT_INUSE;
00330    else
00331       return AST_DEVICE_INUSE;
00332 }

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

Notify metermaids that we've changed an extension.

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

00303 {
00304    if (option_debug > 3)
00305       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00306 
00307    /* Send notification to devicestate subsystem */
00308    ast_device_state_changed("park:%s@%s", exten, context);
00309    return;
00310 }

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

Add parking hints for all defined parking lots.

Definition at line 2360 of file res_features.c.

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

02361 {
02362    int numext;
02363    char device[AST_MAX_EXTENSION];
02364    char exten[10];
02365 
02366    for (numext = start; numext <= stop; numext++) {
02367       snprintf(exten, sizeof(exten), "%d", numext);
02368       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02369       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02370    }
02371 }

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

Park a call.

Definition at line 1840 of file res_features.c.

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

Referenced by load_module().

01841 {
01842    /* Cache the original channel name in case we get masqueraded in the middle
01843     * of a park--it is still theoretically possible for a transfer to happen before
01844     * we get here, but it is _really_ unlikely */
01845    char *orig_chan_name = ast_strdupa(chan->name);
01846    char orig_exten[AST_MAX_EXTENSION];
01847    int orig_priority = chan->priority;
01848 
01849    /* Data is unused at the moment but could contain a parking
01850       lot context eventually */
01851    int res = 0;
01852    struct ast_module_user *u;
01853 
01854    u = ast_module_user_add(chan);
01855 
01856    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
01857 
01858    /* Setup the exten/priority to be s/1 since we don't know
01859       where this call should return */
01860    strcpy(chan->exten, "s");
01861    chan->priority = 1;
01862    /* Answer if call is not up */
01863    if (chan->_state != AST_STATE_UP)
01864       res = ast_answer(chan);
01865    /* Sleep to allow VoIP streams to settle down */
01866    if (!res)
01867       res = ast_safe_sleep(chan, 1000);
01868    /* Park the call */
01869    if (!res) {
01870       res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
01871       /* Continue on in the dialplan */
01872       if (res == 1) {
01873          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
01874          chan->priority = orig_priority;
01875          res = 0;
01876       } else if (!res)
01877          res = AST_PBX_KEEPALIVE;
01878    }
01879 
01880    ast_module_user_remove(u);
01881 
01882    return res;
01883 }

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

Definition at line 334 of file res_features.c.

References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_calloc, ast_clear_flag, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_exists_extension(), AST_FLAG_MASQ_NOSTREAM, ast_free, ast_indicate_data(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_set_flag, ast_strlen_zero(), 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(), parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, pbx_builtin_getvar_helper(), ast_channel::priority, S_OR, strdup, and VERBOSE_PREFIX_2.

Referenced by ast_masq_park_call(), ast_park_call(), and park_call_exec().

00335 {
00336    struct parkeduser *pu, *cur;
00337    int i, x = -1, parking_range;
00338    struct ast_context *con;
00339    const char *parkingexten;
00340    
00341    /* Allocate memory for parking data */
00342    if (!(pu = ast_calloc(1, sizeof(*pu)))) 
00343       return -1;
00344 
00345    /* Lock parking lot */
00346    ast_mutex_lock(&parking_lock);
00347    /* Check for channel variable PARKINGEXTEN */
00348    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00349    if (!ast_strlen_zero(parkingexten)) {
00350       if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
00351          ast_mutex_unlock(&parking_lock);
00352          free(pu);
00353          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00354          return 1;   /* Continue execution if possible */
00355       }
00356       ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
00357       x = atoi(parkingexten);
00358    } else {
00359       /* Select parking space within range */
00360       parking_range = parking_stop - parking_start+1;
00361       for (i = 0; i < parking_range; i++) {
00362          x = (i + parking_offset) % parking_range + parking_start;
00363          cur = parkinglot;
00364          while(cur) {
00365             if (cur->parkingnum == x) 
00366                break;
00367             cur = cur->next;
00368          }
00369          if (!cur)
00370             break;
00371       }
00372 
00373       if (!(i < parking_range)) {
00374          ast_log(LOG_WARNING, "No more parking spaces\n");
00375          free(pu);
00376          ast_mutex_unlock(&parking_lock);
00377          return -1;
00378       }
00379       /* Set pointer for next parking */
00380       if (parkfindnext) 
00381          parking_offset = x - parking_start + 1;
00382    }
00383    
00384    chan->appl = "Parked Call";
00385    chan->data = NULL; 
00386 
00387    pu->chan = chan;
00388    
00389    /* Put the parked channel on hold if we have two different channels */
00390    if (chan != peer) {
00391       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00392          S_OR(parkmohclass, NULL),
00393          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00394    }
00395    
00396    pu->start = ast_tvnow();
00397    pu->parkingnum = x;
00398    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00399    if (extout)
00400       *extout = x;
00401 
00402    if (peer) 
00403       ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00404 
00405    /* Remember what had been dialed, so that if the parking
00406       expires, we try to come back to the same place */
00407    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00408    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00409    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00410    pu->next = parkinglot;
00411    parkinglot = pu;
00412 
00413    /* If parking a channel directly, don't quiet yet get parking running on it */
00414    if (peer == chan) 
00415       pu->notquiteyet = 1;
00416    ast_mutex_unlock(&parking_lock);
00417    /* Wake up the (presumably select()ing) thread */
00418    pthread_kill(parking_thread, SIGURG);
00419    if (option_verbose > 1) 
00420       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));
00421 
00422    if (pu->parkingnum != -1)
00423       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00424    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00425       "Exten: %s\r\n"
00426       "Channel: %s\r\n"
00427       "From: %s\r\n"
00428       "Timeout: %ld\r\n"
00429       "CallerID: %s\r\n"
00430       "CallerIDName: %s\r\n",
00431       pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00432       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00433       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00434       S_OR(pu->chan->cid.cid_name, "<unknown>")
00435       );
00436 
00437    if (peer && adsipark && ast_adsi_available(peer)) {
00438       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00439       ast_adsi_unload_session(peer);
00440    }
00441 
00442    con = ast_context_find(parking_con);
00443    if (!con) 
00444       con = ast_context_create(NULL, parking_con, registrar);
00445    if (!con)   /* Still no context? Bad */
00446       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00447    /* Tell the peer channel the number of the parking space */
00448    if (peer && ((pu->parkingnum != -1 && ast_strlen_zero(orig_chan_name)) || !strcasecmp(peer->name, orig_chan_name))) { /* Only say number if it's a number and the channel hasn't been masqueraded away */
00449       /* Make sure we don't start saying digits to the channel being parked */
00450       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00451       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00452       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00453    }
00454    if (con) {
00455       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
00456          notify_metermaids(pu->parkingexten, parking_con);
00457    }
00458    if (pu->notquiteyet) {
00459       /* Wake up parking thread if we're really done */
00460       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00461          S_OR(parkmohclass, NULL),
00462          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00463       pu->notquiteyet = 0;
00464       pthread_kill(parking_thread, SIGURG);
00465    }
00466    return 0;
00467 }

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 1886 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_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, 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, error(), EVENT_FLAG_CALL, free, LOG_WARNING, manager_event(), parkeduser::next, notify_metermaids(), option_verbose, parkedplay, parking_con, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.

Referenced by load_module().

01887 {
01888    int res = 0;
01889    struct ast_module_user *u;
01890    struct ast_channel *peer=NULL;
01891    struct parkeduser *pu, *pl=NULL;
01892    struct ast_context *con;
01893 
01894    int park;
01895    struct ast_bridge_config config;
01896 
01897    if (!data) {
01898       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
01899       return -1;
01900    }
01901    
01902    u = ast_module_user_add(chan);
01903 
01904    park = atoi((char *)data);
01905    ast_mutex_lock(&parking_lock);
01906    pu = parkinglot;
01907    while(pu) {
01908       if (pu->parkingnum == park) {
01909          if (pl)
01910             pl->next = pu->next;
01911          else
01912             parkinglot = pu->next;
01913          break;
01914       }
01915       pl = pu;
01916       pu = pu->next;
01917    }
01918    ast_mutex_unlock(&parking_lock);
01919    if (pu) {
01920       peer = pu->chan;
01921       con = ast_context_find(parking_con);
01922       if (con) {
01923          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
01924             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01925          else
01926             notify_metermaids(pu->parkingexten, parking_con);
01927       } else
01928          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01929 
01930       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01931          "Exten: %s\r\n"
01932          "Channel: %s\r\n"
01933          "From: %s\r\n"
01934          "CallerID: %s\r\n"
01935          "CallerIDName: %s\r\n",
01936          pu->parkingexten, pu->chan->name, chan->name,
01937          S_OR(pu->chan->cid.cid_num, "<unknown>"),
01938          S_OR(pu->chan->cid.cid_name, "<unknown>")
01939          );
01940 
01941       free(pu);
01942    }
01943    /* JK02: it helps to answer the channel if not already up */
01944    if (chan->_state != AST_STATE_UP)
01945       ast_answer(chan);
01946 
01947    if (peer) {
01948       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
01949       
01950       if (!ast_strlen_zero(courtesytone)) {
01951          int error = 0;
01952          ast_indicate(peer, AST_CONTROL_UNHOLD);
01953          if (parkedplay == 0) {
01954             error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
01955          } else if (parkedplay == 1) {
01956             error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
01957          } else if (parkedplay == 2) {
01958             if (!ast_streamfile(chan, courtesytone, chan->language) &&
01959                   !ast_streamfile(peer, courtesytone, chan->language)) {
01960                /*! \todo XXX we would like to wait on both! */
01961                res = ast_waitstream(chan, "");
01962                if (res >= 0)
01963                   res = ast_waitstream(peer, "");
01964                if (res < 0)
01965                   error = 1;
01966             }
01967                         }
01968          if (error) {
01969             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01970             ast_hangup(peer);
01971             ast_module_user_remove(u);
01972             return -1;
01973          }
01974       } else
01975          ast_indicate(peer, AST_CONTROL_UNHOLD); 
01976 
01977       res = ast_channel_make_compatible(chan, peer);
01978       if (res < 0) {
01979          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01980          ast_hangup(peer);
01981          ast_module_user_remove(u);
01982          return -1;
01983       }
01984       /* This runs sorta backwards, since we give the incoming channel control, as if it
01985          were the person called. */
01986       if (option_verbose > 2) 
01987          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01988 
01989       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
01990       ast_cdr_setdestchan(chan->cdr, peer->name);
01991       memset(&config, 0, sizeof(struct ast_bridge_config));
01992       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01993       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01994       res = ast_bridge_call(chan, peer, &config);
01995 
01996       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
01997       ast_cdr_setdestchan(chan->cdr, peer->name);
01998 
01999       /* Simulate the PBX hanging up */
02000       if (res != AST_PBX_NO_HANGUP_PEER)
02001          ast_hangup(peer);
02002       ast_module_user_remove(u);
02003       return res;
02004    } else {
02005       /*! \todo XXX Play a message XXX */
02006       if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02007          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02008       if (option_verbose > 2) 
02009          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02010       res = -1;
02011    }
02012 
02013    ast_module_user_remove(u);
02014 
02015    return res;
02016 }

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

Definition at line 1657 of file res_features.c.

References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event(), and S_OR.

Referenced by do_parking_thread().

01658 {
01659    manager_event(EVENT_FLAG_CALL, s,
01660       "Exten: %s\r\n"
01661       "Channel: %s\r\n"
01662       "CallerID: %s\r\n"
01663       "CallerIDName: %s\r\n\r\n",
01664       parkingexten, 
01665       chan->name,
01666       S_OR(chan->cid.cid_num, "<unknown>"),
01667       S_OR(chan->cid.cid_name, "<unknown>")
01668       );
01669 }

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

Find the context for the transfer.

Definition at line 670 of file res_features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00671 {
00672         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00673         if (ast_strlen_zero(s))
00674                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00675         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00676                 s = transferer->macrocontext;
00677         if (ast_strlen_zero(s))
00678                 s = transferer->context;
00679         return s;  
00680 }

static int reload ( void   )  [static]

Definition at line 2732 of file res_features.c.

References load_config().

02733 {
02734    return load_config();
02735 }

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

Definition at line 1068 of file res_features.c.

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

01069 {
01070    int x, res = -1;
01071 
01072    ast_rwlock_wrlock(&features_lock);
01073    for (x = 0; x < FEATURES_COUNT; x++) {
01074       if (strcasecmp(builtin_features[x].sname, name))
01075          continue;
01076 
01077       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01078       res = 0;
01079       break;
01080    }
01081    ast_rwlock_unlock(&features_lock);
01082 
01083    return res;
01084 }

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_channel::context, ast_channel::exten, and ast_channel::priority.

Referenced by ast_masq_park_call(), builtin_blindtransfer(), and do_parking_thread().

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 1152 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_LIST_LOCK, AST_LIST_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, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

01153 {
01154    int x;
01155    
01156    ast_clear_flag(config, AST_FLAGS_ALL);
01157 
01158    ast_rwlock_rdlock(&features_lock);
01159    for (x = 0; x < FEATURES_COUNT; x++) {
01160       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01161          continue;
01162 
01163       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01164          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01165 
01166       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01167          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01168    }
01169    ast_rwlock_unlock(&features_lock);
01170    
01171    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01172       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01173 
01174       if (dynamic_features) {
01175          char *tmp = ast_strdupa(dynamic_features);
01176          char *tok;
01177          struct ast_call_feature *feature;
01178 
01179          /* while we have a feature */
01180          while ((tok = strsep(&tmp, "#"))) {
01181             AST_LIST_LOCK(&feature_list);
01182             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01183                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01184                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01185                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01186                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01187             }
01188             AST_LIST_UNLOCK(&feature_list);
01189          }
01190       }
01191    }
01192 }

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

References FEATURE_SENSE_PEER.

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

00527 {
00528    if (sense == FEATURE_SENSE_PEER) {
00529       *caller = peer;
00530       *callee = chan;
00531    } else {
00532       *callee = peer;
00533       *caller = chan;
00534    }
00535 }

static int unload_module ( void   )  [static]

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

static void unmap_features ( void   )  [static]

Definition at line 1058 of file res_features.c.

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

01059 {
01060    int x;
01061 
01062    ast_rwlock_wrlock(&features_lock);
01063    for (x = 0; x < FEATURES_COUNT; x++)
01064       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01065    ast_rwlock_unlock(&features_lock);
01066 }


Variable Documentation

int adsipark [static]

Definition at line 102 of file res_features.c.

Referenced by load_config().

char* app_bridge = "Bridge" [static]

Definition at line 2584 of file res_features.c.

int atxfernoanswertimeout [static]

Definition at line 107 of file res_features.c.

Referenced by load_config().

char* bridge_descrip [static]

Definition at line 2586 of file res_features.c.

char* bridge_synopsis = "Bridge two channels" [static]

Definition at line 2585 of file res_features.c.

struct ast_call_feature builtin_features[] [static]

Definition at line 932 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 2211 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 2206 of file res_features.c.

char courtesytone[256] [static]

Courtesy tone

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

char* descrip2 [static]

Definition at line 124 of file res_features.c.

int featuredigittimeout [static]

Definition at line 105 of file res_features.c.

char mandescr_bridge[] [static]

Definition at line 2055 of file res_features.c.

Referenced by load_module().

char mandescr_park[] [static]

Definition at line 2262 of file res_features.c.

Referenced by load_module().

struct ast_app* monitor_app = NULL [static]

Definition at line 135 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 136 of file res_features.c.

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 84 of file res_features.c.

Referenced by load_config().

char* parkcall = "Park" [static]

Definition at line 120 of file res_features.c.

Referenced by load_module(), and unload_module().

char* parkedcall = "ParkedCall" [static]

Definition at line 82 of file res_features.c.

Referenced by load_module(), and unload_module().

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 95 of file res_features.c.

Referenced by park_exec().

int parkfindnext [static]

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

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

int parking_offset [static]

Definition at line 99 of file res_features.c.

int parking_start [static]

First available extension for parking

Definition at line 91 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

int parking_stop [static]

Last available extension for parking

Definition at line 92 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

pthread_t parking_thread [static]

Definition at line 157 of file res_features.c.

Referenced by load_module().

struct parkeduser* parkinglot [static]

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

char parkmohclass[MAX_MUSICCLASS] [static]

Music class used for parking

Definition at line 90 of file res_features.c.

Referenced by load_config().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 89 of file res_features.c.

Referenced by load_config().

char* registrar = "res_features" [static]

Registrar for operations

Definition at line 109 of file res_features.c.

char showfeatures_help[] [static]

Initial value:

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

Definition at line 2174 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 2202 of file res_features.c.

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

Definition at line 112 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 122 of file res_features.c.

int transferdigittimeout [static]

Definition at line 104 of file res_features.c.

Referenced by load_config().

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 97 of file res_features.c.

Referenced by load_config().

char xfersound[256] [static]

Call transfer sound

Definition at line 96 of file res_features.c.

Referenced by action_bridge(), bridge_exec(), and load_config().


Generated on Mon Mar 31 07:42:23 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1