Sat Apr 12 07:12:53 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 "asterisk/indications.h"

Include dependency graph for res_features.c:

Go to the source code of this file.

Data Structures

struct  aauser
struct  ast_bridge_thread_obj
struct  holdeduser
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)
}

Functions

static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
int ast_autoanswer_login (struct ast_channel *chan, void *data)
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)
struct ast_channelast_get_holded_call (char *uniqueid)
int ast_hold_call (struct ast_channel *chan, struct ast_channel *peer)
static AST_LIST_HEAD_STATIC (feature_list, ast_call_feature)
int ast_masq_autoanswer_login (struct ast_channel *rchan, void *data)
int ast_masq_hold_call (struct ast_channel *rchan, struct ast_channel *peer)
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 (holding_lock)
 AST_MUTEX_DEFINE_STATIC (parking_lock)
 AST_MUTEX_DEFINE_STATIC (autoanswer_lock)
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_list
int ast_retrieve_call (struct ast_channel *chan, char *uniqueid)
int ast_retrieve_call_to_death (char *uniqueid)
 AST_RWLOCK_DEFINE_STATIC (features_lock)
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_list
static void ast_unregister_features (void)
 Remove all features in the list.
static int autoanswer_exec (struct ast_channel *chan, void *data)
static int autoanswer_login_exec (struct ast_channel *chan, void *data)
static void autoanswer_reregister_extensions (void)
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_autoanswer_thread (void *ignore)
static void * do_holding_thread (void *ignore)
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_autoanswer (int fd, int argc, char *argv[])
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 int retrieve_call_exec (struct ast_channel *chan, void *data)
static void set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri)
 store context, priority and extension
static void set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
static void set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense)
 set caller and callee according to the direction
static int unload_module (void)
static void unmap_features (void)

Variables

static struct aauseraalot
static int adsipark
static int atxfernoanswertimeout
static char * autoanswer = "Autoanswer"
static pthread_t autoanswer_thread
static char * autoanswerlogin = "AutoanswerLogin"
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 char * descrip3
static char * descrip4
static int featuredigittimeout
static char * holdedcall = "HoldedCall"
static pthread_t holding_thread
static struct holdeduserholdlist
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 showautoanswer_help []
static char showfeatures_help []
static char showparked_help []
static char * synopsis = "Answer a parked call"
static char * synopsis2 = "Park yourself"
static char * synopsis3 = "Log in for autoanswer"
static char * synopsis4 = "Autoanswer a call"
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file res_features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 72 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500

Definition at line 69 of file res_features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 70 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 67 of file res_features.c.

Referenced by load_config().

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 68 of file res_features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 541 of file res_features.c.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_KEEPTRYING   24

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

Referenced by feature_exec_app().

#define FEATURE_RETURN_PASSDIGITS   21

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

Referenced by feature_exec_app().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 546 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_SUCCESS   23

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 542 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 551 of file res_features.c.

Referenced by ast_bridge_call(), and set_peers().

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


Enumeration Type Documentation

anonymous enum

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 74 of file res_features.c.

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


Function Documentation

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

Definition at line 319 of file res_features.c.

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

Referenced by park_call_full().

00320 {
00321    int res;
00322    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00323    char tmp[256];
00324    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00325 
00326    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00327    message[0] = tmp;
00328    res = ast_adsi_load_session(chan, NULL, 0, 1);
00329    if (res == -1)
00330       return res;
00331    return ast_adsi_print(chan, message, justify, 1);
00332 }

int ast_autoanswer_login ( struct ast_channel chan,
void *  data 
)

Definition at line 2576 of file res_features.c.

References ast_channel::_state, ast_channel::appl, ast_add_extension2(), ast_answer(), ast_context_create(), ast_context_find(), ast_hangup(), ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_UP, ast_strdupa, ast_verbose(), aauser::chan, aauser::context, ast_channel::data, EVENT_FLAG_CALL, aauser::exten, exten, free, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, manager_event(), aauser::next, option_verbose, s, aauser::start, strdup, strsep(), and VERBOSE_PREFIX_2.

Referenced by ast_masq_autoanswer_login(), and autoanswer_exec().

02577 {
02578    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02579       after these channels too */
02580    struct ast_context *con;
02581    char exten[AST_MAX_EXTENSION];
02582    struct aauser *pu,*pl = NULL;
02583    char *s, *stringp, *aacontext, *aaexten = NULL;
02584 
02585    s = ast_strdupa((void *) data);
02586    stringp=s;
02587    aacontext = strsep(&stringp, "|");
02588    aaexten = strsep(&stringp, "|");
02589    if (!aaexten) {
02590        aaexten = aacontext;
02591        aacontext = NULL;
02592    }
02593    if (!aaexten) {
02594       ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
02595       return -1;
02596    } else {
02597       if (!aacontext) {
02598          aacontext = "default";
02599       }
02600    }
02601 
02602    ast_mutex_lock(&autoanswer_lock);
02603    pu = aalot;
02604    while(pu) {
02605       if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
02606          if (pl)
02607             pl->next = pu->next;
02608          else
02609             aalot = pu->next;
02610          break;
02611       }
02612       pl = pu;
02613       pu = pu->next;
02614    }
02615    ast_mutex_unlock(&autoanswer_lock);
02616    if (pu) {
02617        ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context);
02618        manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02619                                "Channel: %s\r\n"
02620                                "Uniqueid: %s\r\n"
02621                                "Context: %s\r\n"
02622                                "Exten: %s\r\n"
02623                            ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02624        ast_hangup(pu->chan);
02625        free(pu);
02626    }
02627    pu = malloc(sizeof(struct aauser));
02628    if (pu) {
02629       memset(pu, 0, sizeof(pu));
02630       ast_mutex_lock(&autoanswer_lock);
02631       chan->appl = "Autoanswer";
02632       chan->data = NULL; 
02633 
02634       pu->chan = chan;
02635       if (chan->_state != AST_STATE_UP) {
02636           ast_answer(chan);
02637       }
02638 
02639       /* Start music on hold */
02640       ast_moh_start(pu->chan, NULL, NULL);
02641       gettimeofday(&pu->start, NULL);
02642       strncpy(pu->exten, aaexten, sizeof(pu->exten)-1);
02643       strncpy(pu->context, aacontext, sizeof(pu->exten)-1);
02644       pu->next = aalot;
02645       aalot = pu;
02646       con = ast_context_find(aacontext);
02647       if (!con) {
02648          con = ast_context_create(NULL,aacontext, registrar);
02649          if (!con) {
02650             ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext);
02651          }
02652       }
02653       if (con) {
02654          snprintf(exten, sizeof(exten), "%s", aaexten);
02655          ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar);
02656       }
02657 
02658       ast_mutex_unlock(&autoanswer_lock);
02659       /* Wake up the (presumably select()ing) thread */
02660       pthread_kill(autoanswer_thread, SIGURG);
02661       if (option_verbose > 1) 
02662          ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context);
02663          manager_event(EVENT_FLAG_CALL, "AutoanswerLogin",
02664                                 "Channel: %s\r\n"
02665                                 "Uniqueid: %s\r\n"
02666                "Context: %s\r\n"
02667                         "Exten: %s\r\n"
02668                         ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02669 
02670          return 0;
02671    } else {
02672       ast_log(LOG_WARNING, "Out of memory\n");
02673       return -1;
02674    }
02675    return 0;
02676 }

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 1405 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, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dstchannel, ast_bridge_config::end_sound, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, set_config_flags(), ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::userfield, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

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

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

Todo:
XXX for safety

Definition at line 280 of file res_features.c.

References ast_channel::appl, ast_bridge_call(), ast_cdr_reset(), ast_cdr_setdestchan(), ast_hangup(), ast_bridge_thread_obj::bconfig, ast_channel::cdr, ast_bridge_thread_obj::chan, ast_channel::data, free, and ast_bridge_thread_obj::peer.

Referenced by ast_bridge_call_thread_launch().

00281 {
00282    struct ast_bridge_thread_obj *tobj = data;
00283 
00284    tobj->chan->appl = "Transferred Call";
00285    tobj->chan->data = tobj->peer->name;
00286    tobj->peer->appl = "Transferred Call";
00287    tobj->peer->data = tobj->chan->name;
00288    if (tobj->chan->cdr) {
00289       ast_cdr_reset(tobj->chan->cdr, NULL);
00290       ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00291    }
00292    if (tobj->peer->cdr) {
00293       ast_cdr_reset(tobj->peer->cdr, NULL);
00294       ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00295    }
00296 
00297    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00298    ast_hangup(tobj->chan);
00299    ast_hangup(tobj->peer);
00300    bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
00301    free(tobj);
00302    return NULL;
00303 }

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 305 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by builtin_atxfer().

00306 {
00307    pthread_t thread;
00308    pthread_attr_t attr;
00309    struct sched_param sched;
00310 
00311    pthread_attr_init(&attr);
00312    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00313    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00314    pthread_attr_destroy(&attr);
00315    memset(&sched, 0, sizeof(sched));
00316    pthread_setschedparam(thread, SCHED_RR, &sched);
00317 }

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 1116 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(), ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, 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().

01117 {
01118    int x;
01119    struct ast_flags features;
01120    int res = FEATURE_RETURN_PASSDIGITS;
01121    struct ast_call_feature *feature;
01122    const char *dynamic_features;
01123    char *tmp, *tok;
01124 
01125    if (sense == FEATURE_SENSE_CHAN) {
01126       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
01127       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01128    } else {
01129       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01130       dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01131    }
01132    if (option_debug > 2)
01133       ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d dynamic=%s\n", chan->name, peer->name, sense, features.flags, dynamic_features);
01134 
01135    ast_rwlock_rdlock(&features_lock);
01136    for (x = 0; x < FEATURES_COUNT; x++) {
01137       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01138           !ast_strlen_zero(builtin_features[x].exten)) {
01139          /* Feature is up for consideration */
01140          if (!strcmp(builtin_features[x].exten, code)) {
01141             res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01142             break;
01143          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01144             if (res == FEATURE_RETURN_PASSDIGITS)
01145                res = FEATURE_RETURN_STOREDIGITS;
01146          }
01147       }
01148    }
01149    ast_rwlock_unlock(&features_lock);
01150 
01151    if (ast_strlen_zero(dynamic_features))
01152       return res;
01153 
01154    tmp = ast_strdupa(dynamic_features);
01155 
01156    while ((tok = strsep(&tmp, "#"))) {
01157       AST_LIST_LOCK(&feature_list); 
01158       if (!(feature = find_dynamic_feature(tok))) {
01159          AST_LIST_UNLOCK(&feature_list);
01160          continue;
01161       }
01162          
01163       /* Feature is up for consideration */
01164       if (!strcmp(feature->exten, code)) {
01165          if (option_verbose > 2)
01166             ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01167          res = feature->operation(chan, peer, config, code, sense, feature);
01168          if (res != FEATURE_RETURN_KEEPTRYING) {
01169             AST_LIST_UNLOCK(&feature_list);
01170             break;
01171          }
01172          res = FEATURE_RETURN_PASSDIGITS;
01173       } else if (!strncmp(feature->exten, code, strlen(code)))
01174          res = FEATURE_RETURN_STOREDIGITS;
01175 
01176       AST_LIST_UNLOCK(&feature_list);
01177    }
01178    
01179    return res;
01180 }

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 
) [static, read]

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

Definition at line 1225 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_verbose(), ast_waitfor_n(), ast_channel::cdr, ast_call_feature::exten, f, FEATURES_COUNT, ast_frame::frametype, ast_channel::hangupcause, len, LOG_NOTICE, LOG_WARNING, option_verbose, pbx_builtin_setvar_helper(), ast_frame::subclass, and VERBOSE_PREFIX_3.

Referenced by builtin_atxfer().

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

struct ast_channel* ast_get_holded_call ( char *  uniqueid  )  [read]

Definition at line 2180 of file res_features.c.

References ast_get_channel_by_uniqueid_locked(), ast_log(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), free, LOG_WARNING, holdeduser::next, option_verbose, holdeduser::uniqueid, and VERBOSE_PREFIX_3.

Referenced by ast_retrieve_call(), and ast_retrieve_call_to_death().

02181 {
02182    int res=-1;
02183    struct ast_channel *peer=NULL;
02184    struct holdeduser *pu, *pl=NULL;
02185 
02186    ast_mutex_lock(&holding_lock);
02187    pu = holdlist;
02188    while(pu) {
02189       if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) {
02190          if (pl)
02191             pl->next = pu->next;
02192          else
02193             holdlist = pu->next; 
02194          break;
02195       }
02196       pl = pu;
02197       pu = pu->next;
02198    }
02199    ast_mutex_unlock(&holding_lock);
02200    if (pu) {
02201       peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid);
02202       free(pu);
02203       if (peer) {
02204           res=0;
02205           if (option_verbose > 2) 
02206          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02207           ast_moh_stop(peer);
02208           return peer;
02209       } else {
02210           if (option_verbose > 2) 
02211          ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid);
02212           return NULL;
02213       }
02214    } else {
02215       ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid);
02216    }
02217    return NULL;
02218 }

int ast_hold_call ( struct ast_channel chan,
struct ast_channel peer 
)

Definition at line 2038 of file res_features.c.

References ast_channel::appl, ast_log(), ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), holdeduser::chan, ast_channel::data, EVENT_FLAG_CALL, LOG_WARNING, malloc, manager_event(), holdeduser::next, holdeduser::start, holdeduser::uniqueid, and holdeduser::uniqueidpeer.

Referenced by ast_masq_hold_call().

02039 {
02040    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02041       after these channels too */
02042    struct holdeduser *pu;
02043    pu = malloc(sizeof(struct holdeduser));
02044    if (pu) {
02045       memset(pu, 0, sizeof(pu));
02046       ast_mutex_lock(&holding_lock);
02047       chan->appl = "Holded Call";
02048       chan->data = NULL; 
02049 
02050       pu->chan = chan;
02051       strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid));
02052       strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer));
02053       /* Start music on hold */
02054       ast_moh_start(pu->chan, NULL, NULL);
02055       gettimeofday(&pu->start, NULL);
02056       pu->next = holdlist;
02057       holdlist = pu;
02058       ast_mutex_unlock(&holding_lock);
02059       /* Wake up the (presumably select()ing) thread */
02060       pthread_kill(holding_thread, SIGURG);
02061 
02062       manager_event(EVENT_FLAG_CALL, "HoldedCall",
02063                          "Channel1: %s\r\n"
02064                          "Channel2: %s\r\n"
02065                       "Uniqueid1: %s\r\n"
02066                       "Uniqueid2: %s\r\n"
02067                              ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid);
02068 
02069    } else {
02070       ast_log(LOG_WARNING, "Out of memory\n");
02071       return -1;
02072    }
02073    return 0;
02074 }

static AST_LIST_HEAD_STATIC ( feature_list  ,
ast_call_feature   
) [static]

int ast_masq_autoanswer_login ( struct ast_channel rchan,
void *  data 
)

Definition at line 2530 of file res_features.c.

References ast_autoanswer_login(), ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_string_field_build, ast_channel::context, ast_channel::exten, f, LOG_WARNING, name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

Referenced by autoanswer_login_exec().

02531 {
02532    struct ast_channel *chan;
02533    struct ast_frame *f;
02534    /* Make a new, fake channel that we'll use to masquerade in the real one */
02535    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name);
02536    if (chan) {
02537       /* Let us keep track of the channel name */
02538       ast_string_field_build(chan, name, "Autoanswer/%s",rchan->name);
02539       /* Make formats okay */
02540       chan->readformat = rchan->readformat;
02541       chan->writeformat = rchan->writeformat;
02542       ast_channel_masquerade(chan, rchan);
02543       /* Setup the extensions and such */
02544       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02545       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02546       chan->priority = rchan->priority;
02547       /* might be dirty but we want trackable channels */
02548       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02549       /* Make the masq execute */
02550       f = ast_read(chan);
02551       if (f)
02552          ast_frfree(f);
02553       ast_autoanswer_login(chan, data);
02554    } else {
02555       ast_log(LOG_WARNING, "Unable to create aa channel\n");
02556       return -1;
02557    }
02558    return 0;
02559 }

int ast_masq_hold_call ( struct ast_channel rchan,
struct ast_channel peer 
)

Definition at line 2076 of file res_features.c.

References ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_hold_call(), ast_log(), ast_read(), AST_STATE_DOWN, ast_string_field_build, ast_channel::context, ast_channel::exten, f, LOG_WARNING, name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

02077 {
02078    struct ast_channel *chan;
02079    struct ast_frame *f;
02080    /* Make a new, fake channel that we'll use to masquerade in the real one */
02081    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name);
02082    if (chan) {
02083       /* Let us keep track of the channel name */
02084       ast_string_field_build(chan, name, "Onhold/%s",rchan->name);
02085       /* Make formats okay */
02086       chan->readformat = rchan->readformat;
02087       chan->writeformat = rchan->writeformat;
02088       ast_channel_masquerade(chan, rchan);
02089       /* Setup the extensions and such */
02090       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02091       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02092       chan->priority = rchan->priority;
02093       /* this might be dirty, but we need to preserve the uniqueid */
02094       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02095       /* Make the masq execute */
02096       f = ast_read(chan);
02097       if (f)
02098          ast_frfree(f);
02099       ast_hold_call(chan, peer);
02100       return -1;
02101    } else {
02102       ast_log(LOG_WARNING, "Unable to create holded channel\n");
02103       return -1;
02104    }
02105    return 0;
02106 }

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

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

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

00513 {
00514    struct ast_channel *chan;
00515    struct ast_frame *f;
00516 
00517    /* Make a new, fake channel that we'll use to masquerade in the real one */
00518    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00519       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00520       return -1;
00521    }
00522 
00523    /* Make formats okay */
00524    chan->readformat = rchan->readformat;
00525    chan->writeformat = rchan->writeformat;
00526    ast_channel_masquerade(chan, rchan);
00527 
00528    /* Setup the extensions and such */
00529    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00530 
00531    /* Make the masq execute */
00532    f = ast_read(chan);
00533    if (f)
00534       ast_frfree(f);
00535 
00536    ast_park_call(chan, peer, timeout, extout);
00537    return 0;
00538 }

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 ( holding_lock   ) 

AST_MUTEX_DEFINE_STATIC ( parking_lock   ) 

protects all static variables above

AST_MUTEX_DEFINE_STATIC ( autoanswer_lock   ) 

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

Park a call.

Park a call and read back parked location.

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

Definition at line 507 of file res_features.c.

References park_call_full().

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

00508 {
00509    return park_call_full(chan, peer, timeout, extout, NULL);
00510 }

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

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

00215 {
00216    return parking_ext;
00217 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

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

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 219 of file res_features.c.

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

00220 {
00221    return pickup_ext;
00222 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_list

register new feature into feature_set

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

Referenced by load_config().

00976 {
00977    if (!feature) {
00978       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00979          return;
00980    }
00981   
00982    AST_LIST_LOCK(&feature_list);
00983    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00984    AST_LIST_UNLOCK(&feature_list);
00985 
00986    if (option_verbose >= 2) 
00987       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00988 }

int ast_retrieve_call ( struct ast_channel chan,
char *  uniqueid 
)

Definition at line 2108 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_channel_make_compatible(), AST_FEATURE_REDIRECT, ast_get_holded_call(), ast_hangup(), ast_log(), ast_moh_stop(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_verbose(), ast_waitstream(), ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, option_verbose, ast_bridge_config::play_warning, ast_bridge_config::timelimit, VERBOSE_PREFIX_3, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by retrieve_call_exec().

02109 {
02110    int res=-1, dres=-1;
02111    struct ast_channel *peer=NULL;
02112    struct ast_bridge_config config;
02113 
02114    peer = ast_get_holded_call(uniqueid);
02115 
02116    /* JK02: it helps to answer the channel if not already up */
02117    if (chan->_state != AST_STATE_UP) {
02118       ast_answer(chan);
02119    }
02120 
02121    if (peer) {
02122       ast_mutex_unlock(&peer->lock);
02123       ast_moh_stop(peer);
02124       res = ast_channel_make_compatible(chan, peer);
02125       if (res < 0) {
02126          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02127          ast_hangup(peer);
02128          return -1;
02129       }
02130       /* This runs sorta backwards, since we give the incoming channel control, as if it
02131          were the person called. */
02132       if (option_verbose > 2) 
02133          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name);
02134 
02135       memset(&config,0,sizeof(struct ast_bridge_config));
02136       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02137       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02138       config.timelimit = 0;
02139       config.play_warning = 0;
02140       config.warning_freq = 0;
02141       config.warning_sound=NULL;
02142       res = ast_bridge_call(chan,peer,&config);
02143 
02144       /* Simulate the PBX hanging up */
02145       if (res != AST_PBX_NO_HANGUP_PEER)
02146          ast_hangup(peer);
02147       return res;
02148    } else {
02149       /* XXX Play a message XXX */
02150      dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
02151      if (!dres)
02152        dres = ast_waitstream(chan, "");
02153      else {
02154        ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02155        dres = 0;
02156      }
02157    }
02158    return res;
02159 }

int ast_retrieve_call_to_death ( char *  uniqueid  ) 

Definition at line 2161 of file res_features.c.

References ast_get_holded_call(), ast_hangup(), ast_log(), ast_mutex_unlock(), ast_verbose(), ast_channel::lock, LOG_WARNING, option_verbose, and VERBOSE_PREFIX_3.

02162 {
02163    int res=-1;
02164    struct ast_channel *peer=NULL;
02165 
02166    peer = ast_get_holded_call(uniqueid);
02167 
02168    if (peer) {
02169       res=0;
02170       if (option_verbose > 2) 
02171          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02172       ast_mutex_unlock(&peer->lock);
02173       ast_hangup(peer);
02174    } else {
02175       ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
02176    }
02177    return res;
02178 }

AST_RWLOCK_DEFINE_STATIC ( features_lock   ) 

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_list

unregister feature from feature_set

Definition at line 991 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00992 {
00993    if (!feature)
00994       return;
00995 
00996    AST_LIST_LOCK(&feature_list);
00997    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00998    AST_LIST_UNLOCK(&feature_list);
00999    free(feature);
01000 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 1003 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

Referenced by load_config().

01004 {
01005    struct ast_call_feature *feature;
01006 
01007    AST_LIST_LOCK(&feature_list);
01008    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
01009       free(feature);
01010    AST_LIST_UNLOCK(&feature_list);
01011 }

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

Definition at line 2803 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_autoanswer_login(), ast_bridge_call(), ast_channel_make_compatible(), AST_FEATURE_REDIRECT, ast_hangup(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), aauser::chan, aauser::context, EVENT_FLAG_CALL, aauser::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, LOG_WARNING, manager_event(), aauser::next, option_verbose, ast_bridge_config::play_warning, s, strsep(), ast_bridge_config::timelimit, VERBOSE_PREFIX_3, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by load_module().

02804 {
02805    int res=0;
02806    struct ast_channel *peer=NULL;
02807    struct aauser *pu, *pl=NULL;
02808    struct ast_bridge_config config;
02809    char *s, *stringp, *aacontext, *aaexten = NULL;
02810    char datastring[80];
02811    struct ast_module_user *u;
02812 
02813 
02814    if (!data) {
02815       ast_log(LOG_WARNING, "Autoanswer requires an argument (extension number)\n");
02816       return -1;
02817    }
02818    s = ast_strdupa((void *) data);
02819    stringp=s;
02820    aacontext = strsep(&stringp, "|");
02821    aaexten = strsep(&stringp, "|");
02822    if (!aaexten) {
02823        aaexten = aacontext;
02824        aacontext = NULL;
02825    }
02826    if (!aaexten) {
02827       ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
02828       return -1;
02829    } else {
02830       if (!aacontext) {
02831          aacontext = "default";
02832       }
02833    }
02834 
02835    u = ast_module_user_add(chan);
02836    ast_mutex_lock(&autoanswer_lock);
02837    pu = aalot;
02838    while(pu) {
02839       if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
02840          if (pl)
02841             pl->next = pu->next;
02842          else
02843             aalot = pu->next;
02844          break;
02845       }
02846       pl = pu;
02847       pu = pu->next;
02848    }
02849    ast_mutex_unlock(&autoanswer_lock);
02850    if (pu) {
02851       peer = pu->chan;
02852       free(pu);
02853       pu = NULL;
02854    }
02855    /* JK02: it helps to answer the channel if not already up */
02856    if (chan->_state != AST_STATE_UP) {
02857       ast_answer(chan);
02858    }
02859 
02860    if (peer) {
02861       ast_moh_stop(peer);
02862       /* Play a courtesy beep in the callED channel to prefix the bridge connecting */ 
02863       if (!ast_strlen_zero(courtesytone)) {
02864          if (!ast_streamfile(peer, courtesytone, peer->language)) {
02865             if (ast_waitstream(peer, "") < 0) {
02866                ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02867                ast_hangup(peer);
02868                return -1;
02869             }
02870          }
02871       }
02872  
02873       res = ast_channel_make_compatible(chan, peer);
02874       if (res < 0) {
02875          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02876          ast_hangup(peer);
02877          return -1;
02878       }
02879       /* This runs sorta backwards, since we give the incoming channel control, as if it
02880          were the person called. */
02881       if (option_verbose > 2) 
02882          ast_verbose(VERBOSE_PREFIX_3 "Channel %s autoanswered  %s\n", peer->name, chan->name);
02883       manager_event(EVENT_FLAG_CALL, "Autoanswer",
02884                     "Channel: %s\r\n"
02885                     "Uniqueid: %s\r\n"
02886                     "Channel2: %s\r\n"
02887                     "Uniqueid2: %s\r\n"
02888                     "Context: %s\r\n"
02889                     "Exten: %s\r\n"
02890                 ,chan->name, chan->uniqueid, peer->name, peer->uniqueid, aacontext, aaexten);
02891 
02892 
02893       memset(&config,0,sizeof(struct ast_bridge_config));
02894       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02895       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02896       config.timelimit = 0;
02897       config.play_warning = 0;
02898       config.warning_freq = 0;
02899       config.warning_sound=NULL;
02900       res = ast_bridge_call(chan,peer,&config);
02901 
02902       if (option_verbose > 2) 
02903          ast_verbose(VERBOSE_PREFIX_3 "returning from bridge %s\n", peer->name);
02904          /* relogin */
02905       snprintf(datastring, sizeof(datastring) - 1, "%s|%s", aacontext, aaexten);
02906       ast_autoanswer_login(peer, datastring);
02907       return res;
02908    } else {
02909       if (option_verbose > 2) 
02910          ast_verbose(VERBOSE_PREFIX_3 "Nobody logged in for autoanswer %s@%s\n", aaexten, aacontext);
02911       res = -1;
02912    }
02913    ast_module_user_remove(u);
02914    return res;
02915 }

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

Definition at line 2561 of file res_features.c.

References ast_log(), ast_masq_autoanswer_login(), ast_module_user_add, ast_module_user_remove, and LOG_WARNING.

Referenced by load_module().

02562 {
02563    int res=0;
02564    struct ast_module_user *u;
02565 
02566    u = ast_module_user_add(chan);
02567    if (!data) {
02568       ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n");
02569       return -1;
02570    }
02571    res = ast_masq_autoanswer_login(chan, data);
02572    ast_module_user_remove(u);
02573    return res; 
02574 }

static void autoanswer_reregister_extensions ( void   )  [static]

Definition at line 2678 of file res_features.c.

References ast_add_extension2(), ast_context_create(), ast_context_find(), ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), aauser::context, aauser::exten, exten, free, LOG_ERROR, aauser::next, and strdup.

Referenced by reload().

02679 {
02680    struct aauser *cur;
02681    struct ast_context *con;
02682    char exten[AST_MAX_EXTENSION];
02683    char args[AST_MAX_EXTENSION];
02684 
02685    ast_mutex_lock(&autoanswer_lock);
02686 
02687    cur=aalot;
02688    while(cur) {
02689       con = ast_context_find(cur->context);
02690       if (!con) {
02691          con = ast_context_create(NULL,cur->context, registrar);
02692          if (!con) {
02693             ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", cur->context);
02694          }
02695       }
02696       if (con) {
02697          snprintf(exten, sizeof(exten), "%s", cur->exten);
02698          snprintf(args, sizeof(args), "%s|%s", cur->context, cur->exten);
02699          ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)args), free, registrar);
02700       }
02701       cur = cur->next;
02702    }
02703 
02704    ast_mutex_unlock(&autoanswer_lock);
02705 }

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 816 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, 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(), and ast_channel::writeformat.

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

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 602 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, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3.

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

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

Todo:
XXX Maybe we should have another message here instead of invalid extension XXX

Definition at line 713 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(), ast_channel::cdr, 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.

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

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

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

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

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 569 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_channel::exten, FEATURE_SENSE_CHAN, ast_channel::priority, and set_peers().

00570 {
00571    struct ast_channel *parker;
00572         struct ast_channel *parkee;
00573    int res = 0;
00574    struct ast_module_user *u;
00575 
00576    u = ast_module_user_add(chan);
00577 
00578    set_peers(&parker, &parkee, peer, chan, sense);
00579    /* Setup the exten/priority to be s/1 since we don't know
00580       where this call should return */
00581    strcpy(chan->exten, "s");
00582    chan->priority = 1;
00583    if (chan->_state != AST_STATE_UP)
00584       res = ast_answer(chan);
00585    if (!res)
00586       res = ast_safe_sleep(chan, 1000);
00587    if (!res)
00588       res = ast_park_call(parkee, parker, 0, NULL);
00589 
00590    ast_module_user_remove(u);
00591 
00592    if (!res) {
00593       if (sense == FEATURE_SENSE_CHAN)
00594          res = AST_PBX_NO_HANGUP_PEER;
00595       else
00596          res = AST_PBX_KEEPALIVE;
00597    }
00598    return res;
00599 
00600 }

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

Definition at line 805 of file res_features.c.

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

Referenced by builtin_atxfer().

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

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

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

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

static void* do_autoanswer_thread ( void *  ignore  )  [static]

Definition at line 2706 of file res_features.c.

References ast_clear_flag, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_frfree, ast_hangup(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_select(), ast_set_flag, ast_verbose(), aauser::chan, aauser::context, EVENT_FLAG_CALL, aauser::exten, exten, f, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, LOG_WARNING, manager_event(), aauser::next, option_verbose, aauser::start, ast_frame::subclass, and VERBOSE_PREFIX_2.

Referenced by load_module().

02707 {
02708    int ms, tms, max;
02709    struct ast_context *con;
02710    char exten[AST_MAX_EXTENSION];
02711    struct aauser *pu, *pl, *pt = NULL;
02712    struct timeval tv;
02713    struct ast_frame *f;
02714    int x;
02715    fd_set rfds, efds;
02716    fd_set nrfds, nefds;
02717    FD_ZERO(&rfds);
02718    FD_ZERO(&efds);
02719    for (;;) {
02720       ms = -1;
02721       max = -1;
02722       ast_mutex_lock(&autoanswer_lock);
02723       pl = NULL;
02724       pu = aalot;
02725       gettimeofday(&tv, NULL);
02726       FD_ZERO(&nrfds);
02727       FD_ZERO(&nefds);
02728       while(pu) {
02729          tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
02730          for (x=0;x<AST_MAX_FDS;x++) {
02731             if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
02732                if (FD_ISSET(pu->chan->fds[x], &efds))
02733                   ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
02734                else
02735                   ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
02736                pu->chan->fdno = x;
02737                /* See if they need servicing */
02738                f = ast_read(pu->chan);
02739                if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
02740                   /* There's a problem, hang them up*/
02741                   if (option_verbose > 1) 
02742                      ast_verbose(VERBOSE_PREFIX_2 "%s logged out of autoanswer app\n", pu->chan->name);
02743                   manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02744                                         "Channel: %s\r\n"
02745                                         "Uniqueid: %s\r\n"
02746                                   "Context: %s\r\n"
02747                                   "Exten: %s\r\n"
02748                               ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02749                   ast_hangup(pu->chan);
02750                   con = ast_context_find(pu->context);
02751                   if (con) {
02752                       snprintf(exten, sizeof(exten), "%s", pu->exten);
02753                       if (ast_context_remove_extension2(con, exten, 1, registrar))
02754                      ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02755                   } else {
02756                      ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten);
02757                   }
02758                   /* And take them out of the parking lot */
02759                   if (pl) 
02760                      pl->next = pu->next;
02761                   else
02762                      aalot = pu->next;
02763                   pt = pu;
02764                   pu = pu->next;
02765                   free(pt);
02766                   break;
02767                } else {
02768                   /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02769                   ast_frfree(f);
02770                   goto std;   /* XXX Ick: jumping into an else statement??? XXX */
02771                }
02772             }
02773          }
02774          if (x >= AST_MAX_FDS) {
02775 std:           for (x=0;x<AST_MAX_FDS;x++) {
02776                /* Keep this one for next one */
02777                if (pu->chan->fds[x] > -1) {
02778                   FD_SET(pu->chan->fds[x], &nrfds);
02779                   FD_SET(pu->chan->fds[x], &nefds);
02780                   if (pu->chan->fds[x] > max)
02781                      max = pu->chan->fds[x];
02782                }
02783             }
02784             /* Keep track of our longest wait */
02785             if ((tms < ms) || (ms < 0))
02786                ms = tms;
02787             pl = pu;
02788             pu = pu->next;
02789          }
02790       }
02791       ast_mutex_unlock(&autoanswer_lock);
02792       rfds = nrfds;
02793       efds = nefds;
02794       tv.tv_sec = ms / 1000;
02795       tv.tv_usec = (ms % 1000) * 1000;
02796       /* Wait for something to happen */
02797       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02798       pthread_testcancel();
02799    }
02800    return NULL;   /* Never reached */
02801 }

static void* do_holding_thread ( void *  ignore  )  [static]

Definition at line 2221 of file res_features.c.

References ast_clear_flag, AST_CONTROL_HANGUP, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_frfree, ast_hangup(), AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_select(), ast_set_flag, ast_verbose(), holdeduser::chan, f, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, holdeduser::next, option_verbose, holdeduser::start, ast_frame::subclass, and VERBOSE_PREFIX_2.

Referenced by load_module().

02222 {
02223    int ms, tms, max;
02224    struct holdeduser *pu, *pl, *pt = NULL;
02225    struct timeval tv;
02226    struct ast_frame *f;
02227    int x;
02228    fd_set rfds, efds;
02229    fd_set nrfds, nefds;
02230    FD_ZERO(&rfds);
02231    FD_ZERO(&efds);
02232    for (;;) {
02233       ms = -1;
02234       max = -1;
02235       ast_mutex_lock(&holding_lock);
02236       pl = NULL;
02237       pu = holdlist;
02238       gettimeofday(&tv, NULL);
02239       FD_ZERO(&nrfds);
02240       FD_ZERO(&nefds);
02241       while(pu) {
02242          tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
02243             for (x=0;x<AST_MAX_FDS;x++) {
02244                if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
02245                   if (FD_ISSET(pu->chan->fds[x], &efds))
02246                      ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
02247                   else
02248                      ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
02249                   pu->chan->fdno = x;
02250                   /* See if they need servicing */
02251                   f = ast_read(pu->chan);
02252                   if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
02253                      /* There's a problem, hang them up*/
02254                      if (option_verbose > 1) 
02255                         ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being onhold\n", pu->chan->name);
02256                      ast_hangup(pu->chan);
02257                      /* find the corresponding channel and hang them up too! */
02258                      /* but only if it is not bridged yet! */
02259                      /* And take them out of the parking lot */
02260                      if (pl) 
02261                         pl->next = pu->next;
02262                      else
02263                         holdlist = pu->next;
02264                      pt = pu;
02265                      pu = pu->next;
02266                      free(pt);
02267                      break;
02268                   } else {
02269                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02270                      ast_frfree(f);
02271                      goto std;   /* XXX Ick: jumping into an else statement??? XXX */
02272                   }
02273                }
02274             }
02275             if (x >= AST_MAX_FDS) {
02276 std:              for (x=0;x<AST_MAX_FDS;x++) {
02277                   /* Keep this one for next one */
02278                   if (pu->chan->fds[x] > -1) {
02279                      FD_SET(pu->chan->fds[x], &nrfds);
02280                      FD_SET(pu->chan->fds[x], &nefds);
02281                      if (pu->chan->fds[x] > max)
02282                         max = pu->chan->fds[x];
02283                   }
02284                }
02285                /* Keep track of our longest wait */
02286                if ((tms < ms) || (ms < 0))
02287                   ms = tms;
02288                pl = pu;
02289                pu = pu->next;
02290             }
02291       }
02292       ast_mutex_unlock(&holding_lock);
02293       rfds = nrfds;
02294       efds = nefds;
02295       tv.tv_sec = ms / 1000;
02296       tv.tv_usec = (ms % 1000) * 1000;
02297       /* Wait for something to happen */
02298       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02299       pthread_testcancel();
02300    }
02301    return NULL;   /* Never reached */
02302 }

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 1703 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::fdno, ast_channel::fds, ast_frame::frametype, free, ast_channel::generatordata, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, ast_frame::subclass, and VERBOSE_PREFIX_2.

Referenced by load_module().

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

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

Referenced by load_config().

01028 {
01029    struct ast_app *app;
01030    struct ast_call_feature *feature = data;
01031    struct ast_channel *work, *idle;
01032    int res;
01033 
01034    if (!feature) { /* shouldn't ever happen! */
01035       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01036       return -1; 
01037    }
01038 
01039    if (sense == FEATURE_SENSE_CHAN) {
01040       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01041          return FEATURE_RETURN_KEEPTRYING;
01042       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01043          work = chan;
01044          idle = peer;
01045       } else {
01046          work = peer;
01047          idle = chan;
01048       }
01049    } else {
01050       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01051          return FEATURE_RETURN_KEEPTRYING;
01052       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01053          work = peer;
01054          idle = chan;
01055       } else {
01056          work = chan;
01057          idle = peer;
01058       }
01059    }
01060 
01061    if (!(app = pbx_findapp(feature->app))) {
01062       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01063       return -2;
01064    }
01065 
01066    ast_autoservice_start(idle);
01067    
01068    if (!ast_strlen_zero(feature->moh_class))
01069       ast_moh_start(idle, feature->moh_class, NULL);
01070 
01071    res = pbx_exec(work, app, feature->app_args);
01072 
01073    if (!ast_strlen_zero(feature->moh_class))
01074       ast_moh_stop(idle);
01075 
01076    ast_autoservice_stop(idle);
01077 
01078    if (res == AST_PBX_KEEPALIVE)
01079       return FEATURE_RETURN_PBX_KEEPALIVE;
01080    else if (res == AST_PBX_NO_HANGUP_PEER)
01081       return FEATURE_RETURN_NO_HANGUP_PEER;
01082    else if (res)
01083       return FEATURE_RETURN_SUCCESSBREAK;
01084    
01085    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01086 }

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

find a feature by name

Definition at line 1014 of file res_features.c.

References AST_LIST_TRAVERSE, and ast_call_feature::sname.

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

01015 {
01016    struct ast_call_feature *tmp;
01017 
01018    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01019       if (!strcasecmp(tmp->sname, name))
01020          break;
01021    }
01022 
01023    return tmp;
01024 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 693 of file res_features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00694 {
00695         ast_indicate(chan, AST_CONTROL_UNHOLD);
00696   
00697         return ast_autoservice_stop(chan);
00698 }

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

Definition at line 2496 of file res_features.c.

References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), aauser::chan, aauser::context, aauser::exten, aauser::next, and RESULT_SUCCESS.

02497 {
02498    struct aauser *cur;
02499 
02500    ast_cli(fd, "%25s %10s %15s \n", "Channel"
02501       , "Extension", "Context");
02502 
02503    ast_mutex_lock(&autoanswer_lock);
02504 
02505    cur=aalot;
02506    while(cur) {
02507       ast_cli(fd, "%25s %10s %15s\n",cur->chan->name, cur->exten, cur->context);
02508 
02509       cur = cur->next;
02510    }
02511 
02512    ast_mutex_unlock(&autoanswer_lock);
02513 
02514    return RESULT_SUCCESS;
02515 }

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

Definition at line 2355 of file res_features.c.

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

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

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

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

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

static int load_config ( void   )  [static]

Todo:
XXX var_name or app_args ?

Definition at line 2968 of file res_features.c.

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

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

static int load_module ( void   )  [static]

Definition at line 3184 of file res_features.c.

References ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application(), autoanswer_exec(), autoanswer_login_exec(), do_autoanswer_thread(), do_holding_thread(), do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), and retrieve_call_exec().

03185 {
03186    int res;
03187    
03188    memset(parking_ext, 0, sizeof(parking_ext));
03189    memset(parking_con, 0, sizeof(parking_con));
03190 
03191    if ((res = load_config()))
03192       return res;
03193    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03194    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03195    ast_pthread_create(&holding_thread, NULL, do_holding_thread, NULL);
03196    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03197    if (!res)
03198       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03199    if (!res) {
03200       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03201       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03202          "Park a channel", mandescr_park); 
03203    }
03204 
03205    res |= ast_register_application(holdedcall, retrieve_call_exec, synopsis, descrip);
03206    ast_pthread_create(&autoanswer_thread, NULL, do_autoanswer_thread, NULL);
03207    if (!res)
03208       res |= ast_register_application(autoanswerlogin, autoanswer_login_exec, synopsis3, descrip3);
03209    if (!res)
03210       res |= ast_register_application(autoanswer, autoanswer_exec, synopsis4, descrip4);
03211 
03212    res |= ast_devstate_prov_add("Park", metermaidstate);
03213 
03214    return res;
03215 }

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

Definition at line 2442 of file res_features.c.

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

Referenced by load_module().

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

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

Dump lot status.

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

Referenced by load_module().

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

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

metermaids callback from devicestate.c

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

00347 {
00348    int res = AST_DEVICE_INVALID;
00349    char *context = ast_strdupa(data);
00350    char *exten;
00351 
00352    exten = strsep(&context, "@");
00353    if (!context)
00354       return res;
00355    
00356    if (option_debug > 3)
00357       ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00358 
00359    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00360 
00361    if (!res)
00362       return AST_DEVICE_NOT_INUSE;
00363    else
00364       return AST_DEVICE_INUSE;
00365 }

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

Notify metermaids that we've changed an extension.

Definition at line 335 of file res_features.c.

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

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

00336 {
00337    if (option_debug > 3)
00338       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00339 
00340    /* Send notification to devicestate subsystem */
00341    ast_device_state_changed("park:%s@%s", exten, context);
00342    return;
00343 }

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

Add parking hints for all defined parking lots.

Definition at line 2954 of file res_features.c.

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

Referenced by load_config().

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

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

Park a call.

Definition at line 1871 of file res_features.c.

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

Referenced by load_module().

01872 {
01873    /* Cache the original channel name in case we get masqueraded in the middle
01874     * of a park--it is still theoretically possible for a transfer to happen before
01875     * we get here, but it is _really_ unlikely */
01876    char *orig_chan_name = ast_strdupa(chan->name);
01877    /* Data is unused at the moment but could contain a parking
01878       lot context eventually */
01879    int res = 0;
01880    struct ast_module_user *u;
01881 
01882    u = ast_module_user_add(chan);
01883 
01884    /* Setup the exten/priority to be s/1 since we don't know
01885       where this call should return */
01886    strcpy(chan->exten, "s");
01887    chan->priority = 1;
01888    /* Answer if call is not up */
01889    if (chan->_state != AST_STATE_UP)
01890       res = ast_answer(chan);
01891    /* Sleep to allow VoIP streams to settle down */
01892    if (!res)
01893       res = ast_safe_sleep(chan, 1000);
01894    /* Park the call */
01895    if (!res)
01896       res = park_call_full(chan, NULL, 0, NULL, orig_chan_name);
01897 
01898    ast_module_user_remove(u);
01899 
01900    return !res ? AST_PBX_KEEPALIVE : res;
01901 }

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 367 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(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, S_OR, parkeduser::start, strdup, and VERBOSE_PREFIX_2.

Referenced by ast_park_call(), and park_call_exec().

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

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 1904 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(), ast_channel::cdr, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, error(), EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, LOG_WARNING, manager_event(), parkeduser::next, notify_metermaids(), option_verbose, parkeduser::parkingexten, parkeduser::parkingnum, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.

Referenced by load_module().

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

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

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

01687 {
01688    manager_event(EVENT_FLAG_CALL, s,
01689       "Exten: %s\r\n"
01690       "Channel: %s\r\n"
01691       "CallerID: %s\r\n"
01692       "CallerIDName: %s\r\n"
01693       "Uniqueid: %s\r\n\r\n",
01694       parkingexten, 
01695       chan->name,
01696       S_OR(chan->cid.cid_num, "<unknown>"),
01697       S_OR(chan->cid.cid_name, "<unknown>"),
01698       chan->uniqueid
01699       );
01700 }

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

Find the context for the transfer.

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

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

static int reload ( void   )  [static]

Definition at line 3178 of file res_features.c.

References autoanswer_reregister_extensions(), and load_config().

03179 {
03180    autoanswer_reregister_extensions();
03181    return load_config();
03182 }

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

Definition at line 1098 of file res_features.c.

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

Referenced by load_config().

01099 {
01100    int x, res = -1;
01101 
01102    ast_rwlock_wrlock(&features_lock);
01103    for (x = 0; x < FEATURES_COUNT; x++) {
01104       if (strcasecmp(builtin_features[x].sname, name))
01105          continue;
01106 
01107       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01108       res = 0;
01109       break;
01110    }
01111    ast_rwlock_unlock(&features_lock);
01112 
01113    return res;
01114 }

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

Definition at line 2304 of file res_features.c.

References ast_module_user_add, ast_module_user_remove, and ast_retrieve_call().

Referenced by load_module().

02304                                                                     {
02305    int res=0;
02306    struct ast_module_user *u;
02307    char *uniqueid = (char *)data;
02308    u = ast_module_user_add(chan);
02309        res = ast_retrieve_call(chan, uniqueid);
02310    ast_module_user_remove(u);
02311    return res;
02312 }

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

00235 {
00236    ast_copy_string(chan->context, context, sizeof(chan->context));
00237    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00238    chan->priority = pri;
00239 }

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

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

Referenced by ast_bridge_call().

01183 {
01184    int x;
01185    
01186    ast_clear_flag(config, AST_FLAGS_ALL);
01187 
01188    ast_rwlock_rdlock(&features_lock);
01189    for (x = 0; x < FEATURES_COUNT; x++) {
01190       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01191          continue;
01192 
01193       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01194          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01195 
01196       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01197          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01198    }
01199    ast_rwlock_unlock(&features_lock);
01200    
01201    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01202       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01203 
01204       if (dynamic_features) {
01205          char *tmp = ast_strdupa(dynamic_features);
01206          char *tok;
01207          struct ast_call_feature *feature;
01208 
01209          /* while we have a feature */
01210          while ((tok = strsep(&tmp, "#"))) {
01211             AST_LIST_LOCK(&feature_list);
01212             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01213                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01214                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01215                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01216                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01217             }
01218             AST_LIST_UNLOCK(&feature_list);
01219          }
01220       }
01221    }
01222 }

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

References FEATURE_SENSE_PEER.

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

00558 {
00559    if (sense == FEATURE_SENSE_PEER) {
00560       *caller = peer;
00561       *callee = chan;
00562    } else {
00563       *callee = peer;
00564       *caller = chan;
00565    }
00566 }

static int unload_module ( void   )  [static]

static void unmap_features ( void   )  [static]

Definition at line 1088 of file res_features.c.

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

Referenced by load_config().

01089 {
01090    int x;
01091 
01092    ast_rwlock_wrlock(&features_lock);
01093    for (x = 0; x < FEATURES_COUNT; x++)
01094       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01095    ast_rwlock_unlock(&features_lock);
01096 }


Variable Documentation

struct aauser* aalot [static]

Definition at line 198 of file res_features.c.

int adsipark [static]

Definition at line 104 of file res_features.c.

int atxfernoanswertimeout [static]

Definition at line 109 of file res_features.c.

char* autoanswer = "Autoanswer" [static]

Definition at line 144 of file res_features.c.

pthread_t autoanswer_thread [static]

Definition at line 200 of file res_features.c.

char* autoanswerlogin = "AutoanswerLogin" [static]

Definition at line 137 of file res_features.c.

Definition at line 962 of file res_features.c.

struct ast_cli_entry cli_features[] [static]

Definition at line 2517 of file res_features.c.

Initial value:

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

Definition at line 2383 of file res_features.c.

char courtesytone[256] [static]

Courtesy tone

Definition at line 96 of file res_features.c.

char* descrip [static]

Initial value:

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

Definition at line 116 of file res_features.c.

char* descrip2 [static]

Definition at line 126 of file res_features.c.

char* descrip3 [static]

Initial value:

 "AutoanswerLogin([context]|exten):"
"Used to login to the autoanswer application for an extension.\n"

Definition at line 141 of file res_features.c.

char* descrip4 [static]

Initial value:

 "Autoanswer([context]|exten):"
"Used to autoanswer a call for an extension.\n"

Definition at line 148 of file res_features.c.

int featuredigittimeout [static]

Definition at line 107 of file res_features.c.

char* holdedcall = "HoldedCall" [static]

Definition at line 84 of file res_features.c.

pthread_t holding_thread [static]

Definition at line 212 of file res_features.c.

struct holdeduser* holdlist [static]

Definition at line 204 of file res_features.c.

char mandescr_park[] [static]

Definition at line 2435 of file res_features.c.

struct ast_app* monitor_app = NULL [static]

Definition at line 151 of file res_features.c.

int monitor_ok = 1 [static]

Definition at line 152 of file res_features.c.

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 86 of file res_features.c.

char* parkcall = "Park" [static]

Definition at line 122 of file res_features.c.

char* parkedcall = "ParkedCall" [static]

Definition at line 83 of file res_features.c.

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 97 of file res_features.c.

int parkfindnext [static]

Definition at line 102 of file res_features.c.

char parking_con[AST_MAX_EXTENSION] [static]

Context for which parking is made accessible

Definition at line 88 of file res_features.c.

char parking_con_dial[AST_MAX_EXTENSION] [static]

Context for dialback for parking (KLUDGE)

Definition at line 89 of file res_features.c.

char parking_ext[AST_MAX_EXTENSION] [static]

Extension you type to park the call

Definition at line 90 of file res_features.c.

int parking_offset [static]

Definition at line 101 of file res_features.c.

int parking_start [static]

First available extension for parking

Definition at line 93 of file res_features.c.

int parking_stop [static]

Last available extension for parking

Definition at line 94 of file res_features.c.

pthread_t parking_thread [static]

Definition at line 210 of file res_features.c.

struct parkeduser* parkinglot [static]

Definition at line 202 of file res_features.c.

int parkingtime = DEFAULT_PARK_TIME [static]

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

Definition at line 87 of file res_features.c.

char parkmohclass[MAX_MUSICCLASS] [static]

Music class used for parking

Definition at line 92 of file res_features.c.

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 91 of file res_features.c.

char* registrar = "res_features" [static]

Registrar for operations

Definition at line 111 of file res_features.c.

char showautoanswer_help[] [static]

Initial value:

"Usage: show autoanswer\n"
"       Lists currently logged in autoanswer users.\n"

Definition at line 2388 of file res_features.c.

char showfeatures_help[] [static]

Initial value:

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

Definition at line 2351 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 2379 of file res_features.c.

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

Definition at line 114 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 124 of file res_features.c.

char* synopsis3 = "Log in for autoanswer" [static]

Definition at line 139 of file res_features.c.

char* synopsis4 = "Autoanswer a call" [static]

Definition at line 146 of file res_features.c.

int transferdigittimeout [static]

Definition at line 106 of file res_features.c.

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 99 of file res_features.c.

char xfersound[256] [static]

Call transfer sound

Definition at line 98 of file res_features.c.


Generated on Sat Apr 12 07:12:53 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5