Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:44 2007

Asterisk developer's documentation :: Codename Pineapple


res_features.c File Reference


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file res_features.c.

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

Include dependency graph for res_features.c:

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  parkeduser

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000
#define DEFAULT_PARK_TIME   45000
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
#define FEATURE_RETURN_HANGUP   -1
#define FEATURE_RETURN_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_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)
static AST_LIST_HEAD_STATIC (feature_list, ast_call_feature)
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Call Features Resource",.load=load_module,.unload=unload_module,.reload=reload,)
 AST_MUTEX_DEFINE_STATIC (parking_lock)
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call and read back parked location.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
 Remove all features in the list.
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
 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_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)
 exec an app by feature
static struct ast_call_featurefind_feature (char *name)
 find a feature by name
static int finishup (struct ast_channel *chan)
static int handle_parkedcalls (int fd, int argc, char *argv[])
static int handle_showfeatures (int fd, int argc, char *argv[])
static int load_config (void)
static int load_module (void)
static int manager_park (struct mansession *s, const struct message *m)
static int manager_parking_status (struct mansession *s, const struct message *m)
 Dump lot status.
static int metermaidstate (const char *data)
 metermaids callback from devicestate.c
static void notify_metermaids (char *exten, char *context)
 Notify metermaids that we've changed an extension.
static void park_add_hints (char *context, int start, int stop)
 Add parking hints for all defined parking lots.
static int park_call_exec (struct ast_channel *chan, void *data)
 Park a call.
static int park_exec (struct ast_channel *chan, void *data)
 Pickup parked call.
static void post_manager_event (const char *s, char *parkingexten, struct ast_channel *chan)
static const char * real_ctx (struct ast_channel *transferer, struct ast_channel *transferee)
 Find the context for the transfer.
static int reload (void)
static int remap_feature (const char *name, const char *value)
static void set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri)
 store context, priority and extension
static void set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
static void set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense)
 set caller and callee according to the direction
static int unload_module (void)
static void unmap_features (void)

Variables

static int adsipark
static int atxfernoanswertimeout
ast_call_feature builtin_features []
static struct ast_cli_entry cli_features []
static int comebacktoorigin = 1
static char courtesytone [256]
static char * descrip
static char * descrip2
static int featuredigittimeout
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 parkedcalltransfers = 0
static int parkedplay = 0
static int parkfindnext
static char parking_con [AST_MAX_EXTENSION]
static char parking_con_dial [AST_MAX_EXTENSION]
static char parking_ext [AST_MAX_EXTENSION]
static int parking_offset
static int parking_start
static int parking_stop
static pthread_t parking_thread
static struct parkeduserparkinglot
static int parkingtime = DEFAULT_PARK_TIME
static char parkmohclass [MAX_MUSICCLASS]
static char pickup_ext [AST_MAX_EXTENSION]
static char * registrar = "res_features"
static char showfeatures_help []
static char showparked_help []
static char * synopsis = "Answer a parked call"
static char * synopsis2 = "Park yourself"
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Define Documentation

#define AST_MAX_WATCHERS   256
 

Definition at line 67 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500
 

Definition at line 64 of file res_features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000
 

Definition at line 65 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000
 

Definition at line 62 of file res_features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
 

Definition at line 63 of file res_features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1
 

Definition at line 468 of file res_features.c.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
 

Definition at line 471 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_PASSDIGITS   21
 

Definition at line 472 of file res_features.c.

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

#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
 

Definition at line 470 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_STOREDIGITS   22
 

Definition at line 473 of file res_features.c.

#define FEATURE_RETURN_SUCCESS   23
 

Definition at line 474 of file res_features.c.

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

#define FEATURE_RETURN_SUCCESSBREAK   0
 

Definition at line 469 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)
 

Definition at line 476 of file res_features.c.

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

#define FEATURE_SENSE_PEER   (1 << 1)
 

Definition at line 477 of file res_features.c.

Referenced by ast_bridge_call(), and set_peers().

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

Definition at line 868 of file res_features.c.

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


Enumeration Type Documentation

anonymous enum
 

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 69 of file res_features.c.

00069      {
00070    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00071    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00072    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00073    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00074    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00075    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00076 };


Function Documentation

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

Definition at line 260 of file res_features.c.

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

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

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

References ast_channel::appl, ast_answer(), ast_cdr_appenduserfield(), ast_cdr_setuserfield(), ast_channel_bridge(), ast_channel_setoption(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_OPTION, AST_CONTROL_RINGING, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree(), ast_indicate(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_channel::cdr, config, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), ast_frame::subclass, and ast_cdr::userfield.

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

01290 {
01291    /* Copy voice back and forth between the two channels.  Give the peer
01292       the ability to transfer calls with '#<extension' syntax. */
01293    struct ast_frame *f;
01294    struct ast_channel *who;
01295    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01296    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01297    int res;
01298    int diff;
01299    int hasfeatures=0;
01300    int hadfeatures=0;
01301    struct ast_option_header *aoh;
01302    struct ast_bridge_config backup_config;
01303 
01304    memset(&backup_config, 0, sizeof(backup_config));
01305 
01306    config->start_time = ast_tvnow();
01307 
01308    if (chan && peer) {
01309       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01310       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01311    } else if (chan)
01312       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01313 
01314    if (monitor_ok) {
01315       const char *monitor_exec;
01316       struct ast_channel *src = NULL;
01317       if (!monitor_app) { 
01318          if (!(monitor_app = pbx_findapp("Monitor")))
01319             monitor_ok=0;
01320       }
01321       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01322          src = chan;
01323       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01324          src = peer;
01325       if (monitor_app && src) {
01326          char *tmp = ast_strdupa(monitor_exec);
01327          pbx_exec(src, monitor_app, tmp);
01328       }
01329    }
01330    
01331    set_config_flags(chan, peer, config);
01332    config->firstpass = 1;
01333 
01334    /* Answer if need be */
01335    if (ast_answer(chan))
01336       return -1;
01337    peer->appl = "Bridged Call";
01338    peer->data = chan->name;
01339 
01340    /* copy the userfield from the B-leg to A-leg if applicable */
01341    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01342       char tmp[256];
01343       if (!ast_strlen_zero(chan->cdr->userfield)) {
01344          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01345          ast_cdr_appenduserfield(chan, tmp);
01346       } else
01347          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01348       /* free the peer's cdr without ast_cdr_free complaining */
01349       free(peer->cdr);
01350       peer->cdr = NULL;
01351    }
01352    for (;;) {
01353       struct ast_channel *other; /* used later */
01354 
01355       res = ast_channel_bridge(chan, peer, config, &f, &who);
01356 
01357       if (config->feature_timer) {
01358          /* Update time limit for next pass */
01359          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01360          config->feature_timer -= diff;
01361          if (hasfeatures) {
01362             /* Running on backup config, meaning a feature might be being
01363                activated, but that's no excuse to keep things going 
01364                indefinitely! */
01365             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01366                if (option_debug)
01367                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01368                config->feature_timer = 0;
01369                who = chan;
01370                if (f)
01371                   ast_frfree(f);
01372                f = NULL;
01373                res = 0;
01374             } else if (config->feature_timer <= 0) {
01375                /* Not *really* out of time, just out of time for
01376                   digits to come in for features. */
01377                if (option_debug)
01378                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01379                if (!ast_strlen_zero(peer_featurecode)) {
01380                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01381                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01382                }
01383                if (!ast_strlen_zero(chan_featurecode)) {
01384                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01385                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01386                }
01387                if (f)
01388                   ast_frfree(f);
01389                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01390                if (!hasfeatures) {
01391                   /* Restore original (possibly time modified) bridge config */
01392                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01393                   memset(&backup_config, 0, sizeof(backup_config));
01394                }
01395                hadfeatures = hasfeatures;
01396                /* Continue as we were */
01397                continue;
01398             } else if (!f) {
01399                /* The bridge returned without a frame and there is a feature in progress.
01400                 * However, we don't think the feature has quite yet timed out, so just
01401                 * go back into the bridge. */
01402                continue;
01403             }
01404          } else {
01405             if (config->feature_timer <=0) {
01406                /* We ran out of time */
01407                config->feature_timer = 0;
01408                who = chan;
01409                if (f)
01410                   ast_frfree(f);
01411                f = NULL;
01412                res = 0;
01413             }
01414          }
01415       }
01416       if (res < 0) {
01417          ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01418          return -1;
01419       }
01420       
01421       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01422             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01423                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01424          res = -1;
01425          break;
01426       }
01427       /* many things should be sent to the 'other' channel */
01428       other = (who == chan) ? peer : chan;
01429       if (f->frametype == AST_FRAME_CONTROL) {
01430          if (f->subclass == AST_CONTROL_RINGING)
01431             ast_indicate(other, AST_CONTROL_RINGING);
01432          else if (f->subclass == -1)
01433             ast_indicate(other, -1);
01434          else if (f->subclass == AST_CONTROL_FLASH)
01435             ast_indicate(other, AST_CONTROL_FLASH);
01436          else if (f->subclass == AST_CONTROL_OPTION) {
01437             aoh = f->data;
01438             /* Forward option Requests */
01439             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST)
01440                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01441          }
01442       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01443          /* eat it */
01444       } else if (f->frametype == AST_FRAME_DTMF) {
01445          char *featurecode;
01446          int sense;
01447 
01448          hadfeatures = hasfeatures;
01449          /* This cannot overrun because the longest feature is one shorter than our buffer */
01450          if (who == chan) {
01451             sense = FEATURE_SENSE_CHAN;
01452             featurecode = chan_featurecode;
01453          } else  {
01454             sense = FEATURE_SENSE_PEER;
01455             featurecode = peer_featurecode;
01456          }
01457          /*! append the event to featurecode. we rely on the string being zero-filled, and
01458           * not overflowing it. 
01459           * \todo XXX how do we guarantee the latter ?
01460           */
01461          featurecode[strlen(featurecode)] = f->subclass;
01462          /* Get rid of the frame before we start doing "stuff" with the channels */
01463          ast_frfree(f);
01464          f = NULL;
01465          config->feature_timer = backup_config.feature_timer;
01466          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01467          switch(res) {
01468          case FEATURE_RETURN_PASSDIGITS:
01469             ast_dtmf_stream(other, who, featurecode, 0);
01470             /* Fall through */
01471          case FEATURE_RETURN_SUCCESS:
01472             memset(featurecode, 0, sizeof(chan_featurecode));
01473             break;
01474          }
01475          if (res >= FEATURE_RETURN_PASSDIGITS) {
01476             res = 0;
01477          } else 
01478             break;
01479          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01480          if (hadfeatures && !hasfeatures) {
01481             /* Restore backup */
01482             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01483             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01484          } else if (hasfeatures) {
01485             if (!hadfeatures) {
01486                /* Backup configuration */
01487                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01488                /* Setup temporary config options */
01489                config->play_warning = 0;
01490                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01491                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01492                config->warning_freq = 0;
01493                config->warning_sound = NULL;
01494                config->end_sound = NULL;
01495                config->start_sound = NULL;
01496                config->firstpass = 0;
01497             }
01498             config->start_time = ast_tvnow();
01499             config->feature_timer = featuredigittimeout;
01500             if (option_debug)
01501                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01502          }
01503       }
01504       if (f)
01505          ast_frfree(f);
01506    }
01507    return res;
01508 }

static void* ast_bridge_call_thread void *  data  )  [static]
 

Todo:
XXX for safety

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

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

static void ast_bridge_call_thread_launch void *  data  )  [static]
 

Definition at line 246 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by builtin_atxfer().

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

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

References ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strlen_zero(), ast_test_flag, builtin_features, config, exten, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_SENSE_CHAN, FEATURES_COUNT, ast_channel::flags, LOG_DEBUG, ast_call_feature::operation, option_debug, and pbx_builtin_getvar_helper().

Referenced by ast_bridge_call().

01029 {
01030    int x;
01031    struct ast_flags features;
01032    int res = FEATURE_RETURN_PASSDIGITS;
01033    struct ast_call_feature *feature;
01034    const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
01035 
01036    if (sense == FEATURE_SENSE_CHAN)
01037       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
01038    else
01039       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01040    if (option_debug > 2)
01041       ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
01042 
01043    for (x=0; x < FEATURES_COUNT; x++) {
01044       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01045           !ast_strlen_zero(builtin_features[x].exten)) {
01046          /* Feature is up for consideration */
01047          if (!strcmp(builtin_features[x].exten, code)) {
01048             res = builtin_features[x].operation(chan, peer, config, code, sense);
01049             break;
01050          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01051             if (res == FEATURE_RETURN_PASSDIGITS)
01052                res = FEATURE_RETURN_STOREDIGITS;
01053          }
01054       }
01055    }
01056 
01057 
01058    if (!ast_strlen_zero(dynamic_features)) {
01059       char *tmp = ast_strdupa(dynamic_features);
01060       char *tok;
01061 
01062       while ((tok = strsep(&tmp, "#")) != NULL) {
01063          feature = find_feature(tok);
01064          
01065          if (feature) {
01066             /* Feature is up for consideration */
01067             if (!strcmp(feature->exten, code)) {
01068                if (option_verbose > 2)
01069                   ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01070                res = feature->operation(chan, peer, config, code, sense);
01071                break;
01072             } else if (!strncmp(feature->exten, code, strlen(code))) {
01073                res = FEATURE_RETURN_STOREDIGITS;
01074             }
01075          }
01076       }
01077    }
01078    
01079    return res;
01080 }

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]
 

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

Definition at line 1119 of file res_features.c.

References ast_channel::_softhangup, ast_call(), 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_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), AST_STATE_UP, ast_verbose(), ast_waitfor_n(), builtin_features, ast_call_feature::exten, FEATURES_COUNT, ast_frame::frametype, len, LOG_NOTICE, option_verbose, pbx_builtin_setvar_helper(), ast_frame::subclass, and VERBOSE_PREFIX_3.

Referenced by builtin_atxfer().

01120 {
01121    int state = 0;
01122    int cause = 0;
01123    int to;
01124    struct ast_channel *chan;
01125    struct ast_channel *monitor_chans[2];
01126    struct ast_channel *active_channel;
01127    int res = 0, ready = 0;
01128    
01129    if ((chan = ast_request(type, format, data, &cause))) {
01130       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01131       ast_channel_inherit_variables(caller, chan); 
01132       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01133       if (!ast_call(chan, data, timeout)) {
01134          struct timeval started;
01135          int x, len = 0;
01136          char *disconnect_code = NULL, *dialed_code = NULL;
01137 
01138          ast_indicate(caller, AST_CONTROL_RINGING);
01139          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01140          for (x=0; x < FEATURES_COUNT; x++) {
01141             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01142                continue;
01143 
01144             disconnect_code = builtin_features[x].exten;
01145             len = strlen(disconnect_code) + 1;
01146             dialed_code = alloca(len);
01147             memset(dialed_code, 0, len);
01148             break;
01149          }
01150          x = 0;
01151          started = ast_tvnow();
01152          to = timeout;
01153          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01154             struct ast_frame *f = NULL;
01155 
01156             monitor_chans[0] = caller;
01157             monitor_chans[1] = chan;
01158             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01159 
01160             /* see if the timeout has been violated */
01161             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01162                state = AST_CONTROL_UNHOLD;
01163                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01164                break; /*doh! timeout*/
01165             }
01166 
01167             if (!active_channel)
01168                continue;
01169 
01170             if (chan && (chan == active_channel)){
01171                f = ast_read(chan);
01172                if (f == NULL) { /*doh! where'd he go?*/
01173                   state = AST_CONTROL_HANGUP;
01174                   res = 0;
01175                   break;
01176                }
01177                
01178                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01179                   if (f->subclass == AST_CONTROL_RINGING) {
01180                      state = f->subclass;
01181                      if (option_verbose > 2)
01182                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01183                      ast_indicate(caller, AST_CONTROL_RINGING);
01184                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01185                      state = f->subclass;
01186                      if (option_verbose > 2)
01187                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01188                      ast_indicate(caller, AST_CONTROL_BUSY);
01189                      ast_frfree(f);
01190                      f = NULL;
01191                      break;
01192                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01193                      /* This is what we are hoping for */
01194                      state = f->subclass;
01195                      ast_frfree(f);
01196                      f = NULL;
01197                      ready=1;
01198                      break;
01199                   } else {
01200                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01201                   }
01202                   /* else who cares */
01203                }
01204 
01205             } else if (caller && (active_channel == caller)) {
01206                f = ast_read(caller);
01207                if (f == NULL) { /*doh! where'd he go?*/
01208                   if (caller->_softhangup && !chan->_softhangup) {
01209                      /* make this a blind transfer */
01210                      ready = 1;
01211                      break;
01212                   }
01213                   state = AST_CONTROL_HANGUP;
01214                   res = 0;
01215                   break;
01216                }
01217                
01218                if (f->frametype == AST_FRAME_DTMF) {
01219                   dialed_code[x++] = f->subclass;
01220                   dialed_code[x] = '\0';
01221                   if (strlen(dialed_code) == len) {
01222                      x = 0;
01223                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01224                      x = 0;
01225                      dialed_code[x] = '\0';
01226                   }
01227                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01228                      /* Caller Canceled the call */
01229                      state = AST_CONTROL_UNHOLD;
01230                      ast_frfree(f);
01231                      f = NULL;
01232                      break;
01233                   }
01234                }
01235             }
01236             if (f)
01237                ast_frfree(f);
01238          } /* end while */
01239       } else
01240          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01241    } else {
01242       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01243       switch(cause) {
01244       case AST_CAUSE_BUSY:
01245          state = AST_CONTROL_BUSY;
01246          break;
01247       case AST_CAUSE_CONGESTION:
01248          state = AST_CONTROL_CONGESTION;
01249          break;
01250       }
01251    }
01252    
01253    ast_indicate(caller, -1);
01254    if (chan && ready) {
01255       if (chan->_state == AST_STATE_UP) 
01256          state = AST_CONTROL_ANSWER;
01257       res = 0;
01258    } else if(chan) {
01259       res = -1;
01260       ast_hangup(chan);
01261       chan = NULL;
01262    } else {
01263       res = -1;
01264    }
01265    
01266    if (outstate)
01267       *outstate = state;
01268 
01269    if (chan && res <= 0) {
01270       if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
01271          char tmp[256];
01272          ast_cdr_init(chan->cdr, chan);
01273          snprintf(tmp, 256, "%s/%s", type, (char *)data);
01274          ast_cdr_setapp(chan->cdr,"Dial",tmp);
01275          ast_cdr_update(chan);
01276          ast_cdr_start(chan->cdr);
01277          ast_cdr_end(chan->cdr);
01278          /* If the cause wasn't handled properly */
01279          if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01280             ast_cdr_failed(chan->cdr);
01281       } else {
01282          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01283       }
01284    }
01285    
01286    return chan;
01287 }

static AST_LIST_HEAD_STATIC feature_list  ,
ast_call_feature 
[static]
 

int ast_masq_park_call struct ast_channel rchan,
struct ast_channel host,
int  timeout,
int *  extout
 

Park a call via a masqueraded channel.

Parameters:
rchan the real channel to be parked
host the channel to have the parking read to Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want

Definition at line 439 of file res_features.c.

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

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

00440 {
00441    struct ast_channel *chan;
00442    struct ast_frame *f;
00443 
00444    /* Make a new, fake channel that we'll use to masquerade in the real one */
00445    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "Parked/%s",rchan->name))) {
00446       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00447       return -1;
00448    }
00449 
00450    /* Make formats okay */
00451    chan->readformat = rchan->readformat;
00452    chan->writeformat = rchan->writeformat;
00453    ast_channel_masquerade(chan, rchan);
00454 
00455    /* Setup the extensions and such */
00456    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00457 
00458    /* Make the masq execute */
00459    f = ast_read(chan);
00460    if (f)
00461       ast_frfree(f);
00462 
00463    ast_park_call(chan, peer, timeout, extout);
00464    return 0;
00465 }

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

AST_MUTEX_DEFINE_STATIC parking_lock   ) 
 

protects all static variables above

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

Park a call and read back parked location.

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

Definition at line 311 of file res_features.c.

References ast_calloc, ast_exists_extension(), ast_log(), ast_mutex_lock(), ast_strlen_zero(), LOG_WARNING, parkeduser::next, parkinglot, parkeduser::parkingnum, and pbx_builtin_getvar_helper().

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

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

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

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

00158 {
00159    return parking_ext;
00160 }

int ast_pickup_call struct ast_channel chan  ) 
 

Pickup a call.

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

02046 {
02047    struct ast_channel *cur = NULL;
02048    int res = -1;
02049 
02050    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02051       if (!cur->pbx && 
02052          (cur != chan) &&
02053          (chan->pickupgroup & cur->callgroup) &&
02054          ((cur->_state == AST_STATE_RINGING) ||
02055           (cur->_state == AST_STATE_RING))) {
02056             break;
02057       }
02058       ast_channel_unlock(cur);
02059    }
02060    if (cur) {
02061       if (option_debug)
02062          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02063       res = ast_answer(chan);
02064       if (res)
02065          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02066       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02067       if (res)
02068          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02069       res = ast_channel_masquerade(cur, chan);
02070       if (res)
02071          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02072       ast_channel_unlock(cur);
02073    } else   {
02074       if (option_debug)
02075          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02076    }
02077    return res;
02078 }

char* ast_pickup_ext void   ) 
 

Determine system call pickup extension.

Definition at line 162 of file res_features.c.

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

00163 {
00164    return pickup_ext;
00165 }

void ast_register_feature struct ast_call_feature feature  ) 
 

register new feature into feature_set

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

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

00884 {
00885    if (!feature) {
00886       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00887          return;
00888    }
00889   
00890    AST_LIST_LOCK(&feature_list);
00891    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00892    AST_LIST_UNLOCK(&feature_list);
00893 
00894    if (option_verbose >= 2) 
00895       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00896 }

void ast_unregister_feature struct ast_call_feature feature  ) 
 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 899 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00900 {
00901    if (!feature)
00902       return;
00903 
00904    AST_LIST_LOCK(&feature_list);
00905    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00906    AST_LIST_UNLOCK(&feature_list);
00907    free(feature);
00908 }

static void ast_unregister_features void   )  [static]
 

Remove all features in the list.

Definition at line 911 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

00912 {
00913    struct ast_call_feature *feature;
00914 
00915    AST_LIST_LOCK(&feature_list);
00916    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00917       free(feature);
00918    AST_LIST_UNLOCK(&feature_list);
00919 }

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

Definition at line 731 of file res_features.c.

References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_masquerade(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_waitfordigit(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_channel::exten, 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.

00732 {
00733    struct ast_channel *transferer;
00734    struct ast_channel *transferee;
00735    const char *transferer_real_context;
00736    char xferto[256] = "";
00737    int res;
00738    int outstate=0;
00739    struct ast_channel *newchan;
00740    struct ast_channel *xferchan;
00741    struct ast_bridge_thread_obj *tobj;
00742    struct ast_bridge_config bconfig;
00743    struct ast_frame *f;
00744    int l;
00745 
00746    if (option_debug)
00747       ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00748    set_peers(&transferer, &transferee, peer, chan, sense);
00749         transferer_real_context = real_ctx(transferer, transferee);
00750    /* Start autoservice on chan while we talk to the originator */
00751    ast_autoservice_start(transferee);
00752    ast_indicate(transferee, AST_CONTROL_HOLD);
00753    
00754    /* Transfer */
00755    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
00756    if (res < 0) {
00757       finishup(transferee);
00758       return res;
00759    }
00760    if (res > 0) /* If they've typed a digit already, handle it */
00761       xferto[0] = (char) res;
00762 
00763    /* this is specific of atxfer */
00764    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00765         if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00766                 finishup(transferee);
00767                 return res;
00768         }
00769    if (res == 0) {
00770       ast_log(LOG_WARNING, "Did not read data.\n");
00771       finishup(transferee);
00772       if (ast_stream_and_wait(transferer, "beeperr", ""))
00773          return -1;
00774       return FEATURE_RETURN_SUCCESS;
00775    }
00776 
00777    /* valid extension, res == 1 */
00778    if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00779       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00780       finishup(transferee);
00781       if (ast_stream_and_wait(transferer, "beeperr", ""))
00782          return -1;
00783       return FEATURE_RETURN_SUCCESS;
00784    }
00785 
00786    l = strlen(xferto);
00787    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);   /* append context */
00788    newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00789       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name);
00790    ast_indicate(transferer, -1);
00791    if (!newchan) {
00792       finishup(transferee);
00793       /* any reason besides user requested cancel and busy triggers the failed sound */
00794       if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00795             ast_stream_and_wait(transferer, xferfailsound, ""))
00796          return -1;
00797       return FEATURE_RETURN_SUCCESS;
00798    }
00799 
00800    if (check_compat(transferer, newchan))
00801       return -1;
00802    memset(&bconfig,0,sizeof(struct ast_bridge_config));
00803    ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00804    ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00805    res = ast_bridge_call(transferer, newchan, &bconfig);
00806    if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
00807       ast_hangup(newchan);
00808       if (ast_stream_and_wait(transferer, xfersound, ""))
00809          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00810       finishup(transferee);
00811       transferer->_softhangup = 0;
00812       return FEATURE_RETURN_SUCCESS;
00813    }
00814    
00815    if (check_compat(transferee, newchan))
00816       return -1;
00817 
00818    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00819    
00820    if ((ast_autoservice_stop(transferee) < 0)
00821       || (ast_waitfordigit(transferee, 100) < 0)
00822       || (ast_waitfordigit(newchan, 100) < 0) 
00823       || ast_check_hangup(transferee) 
00824       || ast_check_hangup(newchan)) {
00825       ast_hangup(newchan);
00826       return -1;
00827    }
00828 
00829    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "Transfered/%s", transferee->name);
00830    if (!xferchan) {
00831       ast_hangup(newchan);
00832       return -1;
00833    }
00834    /* Make formats okay */
00835    xferchan->readformat = transferee->readformat;
00836    xferchan->writeformat = transferee->writeformat;
00837    ast_channel_masquerade(xferchan, transferee);
00838    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00839    xferchan->_state = AST_STATE_UP;
00840    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00841    xferchan->_softhangup = 0;
00842 
00843    if ((f = ast_read(xferchan)))
00844       ast_frfree(f);
00845 
00846    newchan->_state = AST_STATE_UP;
00847    ast_clear_flag(newchan, AST_FLAGS_ALL);   
00848    newchan->_softhangup = 0;
00849 
00850    tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
00851    if (!tobj) {
00852       ast_hangup(xferchan);
00853       ast_hangup(newchan);
00854       return -1;
00855    }
00856    tobj->chan = xferchan;
00857    tobj->peer = newchan;
00858    tobj->bconfig = *config;
00859 
00860    if (ast_stream_and_wait(newchan, xfersound, ""))
00861       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00862    ast_bridge_call_thread_launch(tobj);
00863    return -1;  /* XXX meaning the channel is bridged ? */
00864 }

static int builtin_automonitor struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense
[static]
 

Definition at line 528 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_WARNING, ast_channel::monitor, monitor_app, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3.

00529 {
00530    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00531    int x = 0;
00532    size_t len;
00533    struct ast_channel *caller_chan, *callee_chan;
00534 
00535    if (!monitor_ok) {
00536       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00537       return -1;
00538    }
00539 
00540    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00541       monitor_ok = 0;
00542       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00543       return -1;
00544    }
00545 
00546    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00547 
00548    if (!ast_strlen_zero(courtesytone)) {
00549       if (ast_autoservice_start(callee_chan))
00550          return -1;
00551       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
00552          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00553          ast_autoservice_stop(callee_chan);
00554          return -1;
00555       }
00556       if (ast_autoservice_stop(callee_chan))
00557          return -1;
00558    }
00559    
00560    if (callee_chan->monitor) {
00561       if (option_verbose > 3)
00562          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00563       ast_monitor_stop(callee_chan, 1);
00564       return FEATURE_RETURN_SUCCESS;
00565    }
00566 
00567    if (caller_chan && callee_chan) {
00568       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00569       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00570 
00571       if (!touch_format)
00572          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00573 
00574       if (!touch_monitor)
00575          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00576    
00577       if (touch_monitor) {
00578          len = strlen(touch_monitor) + 50;
00579          args = alloca(len);
00580          touch_filename = alloca(len);
00581          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00582          snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00583       } else {
00584          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00585          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00586          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00587          args = alloca(len);
00588          touch_filename = alloca(len);
00589          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00590          snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00591       }
00592 
00593       for( x = 0; x < strlen(args); x++) {
00594          if (args[x] == '/')
00595             args[x] = '-';
00596       }
00597       
00598       if (option_verbose > 3)
00599          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00600 
00601       pbx_exec(callee_chan, monitor_app, args);
00602       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00603       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00604    
00605       return FEATURE_RETURN_SUCCESS;
00606    }
00607    
00608    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00609    return -1;
00610 }

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

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

Definition at line 639 of file res_features.c.

References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_indicate(), ast_log(), ast_park_call(), ast_parking_ext(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_stopstream(), ast_stream_and_wait(), ast_verbose(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, finishup(), LOG_WARNING, option_verbose, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.

00640 {
00641    struct ast_channel *transferer;
00642    struct ast_channel *transferee;
00643    const char *transferer_real_context;
00644    char xferto[256];
00645    int res;
00646 
00647    set_peers(&transferer, &transferee, peer, chan, sense);
00648    transferer_real_context = real_ctx(transferer, transferee);
00649    /* Start autoservice on chan while we talk to the originator */
00650    ast_autoservice_start(transferee);
00651    ast_indicate(transferee, AST_CONTROL_HOLD);
00652 
00653    memset(xferto, 0, sizeof(xferto));
00654    
00655    /* Transfer */
00656    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
00657    if (res < 0) {
00658       finishup(transferee);
00659       return -1; /* error ? */
00660    }
00661    if (res > 0)   /* If they've typed a digit already, handle it */
00662       xferto[0] = (char) res;
00663 
00664    ast_stopstream(transferer);
00665    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00666    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00667       finishup(transferee);
00668       return res;
00669    }
00670    if (!strcmp(xferto, ast_parking_ext())) {
00671       res = finishup(transferee);
00672       if (res)
00673          res = -1;
00674       else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
00675          /* We return non-zero, but tell the PBX not to hang the channel when
00676             the thread dies -- We have to be careful now though.  We are responsible for 
00677             hanging up the channel, else it will never be hung up! */
00678 
00679          return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
00680       } else {
00681          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00682       }
00683       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
00684    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00685       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
00686       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00687       res=finishup(transferee);
00688       if (!transferee->pbx) {
00689          /* Doh!  Use our handy async_goto functions */
00690          if (option_verbose > 2) 
00691             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00692                         ,transferee->name, xferto, transferer_real_context);
00693          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00694             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00695          res = -1;
00696       } else {
00697          /* Set the channel's new extension, since it exists, using transferer context */
00698          set_c_e_p(transferee, transferer_real_context, xferto, 0);
00699       }
00700       check_goto_on_transfer(transferer);
00701       return res;
00702    } else {
00703       if (option_verbose > 2) 
00704          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00705    }
00706    if (ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0 ) {
00707       finishup(transferee);
00708       return -1;
00709    }
00710    ast_stopstream(transferer);
00711    res = finishup(transferee);
00712    if (res) {
00713       if (option_verbose > 1)
00714          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00715       return res;
00716    }
00717    return FEATURE_RETURN_SUCCESS;
00718 }

static int builtin_disconnect struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense
[static]
 

Definition at line 612 of file res_features.c.

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

00613 {
00614    if (option_verbose > 3)
00615       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00616    return FEATURE_RETURN_HANGUP;
00617 }

static int builtin_parkcall struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense
[static]
 

support routing for one touch call parking

Definition at line 495 of file res_features.c.

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

00496 {
00497    struct ast_channel *parker;
00498         struct ast_channel *parkee;
00499    int res = 0;
00500    struct ast_module_user *u;
00501 
00502    u = ast_module_user_add(chan);
00503 
00504    set_peers(&parker, &parkee, peer, chan, sense);
00505    /* Setup the exten/priority to be s/1 since we don't know
00506       where this call should return */
00507    strcpy(chan->exten, "s");
00508    chan->priority = 1;
00509    if (chan->_state != AST_STATE_UP)
00510       res = ast_answer(chan);
00511    if (!res)
00512       res = ast_safe_sleep(chan, 1000);
00513    if (!res)
00514       res = ast_park_call(parkee, parker, 0, NULL);
00515 
00516    ast_module_user_remove(u);
00517 
00518    if (!res) {
00519       if (sense == FEATURE_SENSE_CHAN)
00520          res = AST_PBX_NO_HANGUP_PEER;
00521       else
00522          res = AST_PBX_KEEPALIVE;
00523    }
00524    return res;
00525 
00526 }

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

Definition at line 720 of file res_features.c.

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

Referenced by builtin_atxfer().

00721 {
00722    if (ast_channel_make_compatible(c, newchan) < 0) {
00723       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00724          c->name, newchan->name);
00725       ast_hangup(newchan);
00726       return -1;
00727    }
00728    return 0;
00729 }

static void check_goto_on_transfer struct ast_channel chan  )  [static]
 

Definition at line 182 of file res_features.c.

References ast_channel_alloc(), AST_STATE_DOWN, ast_strdupa, ast_strlen_zero(), and pbx_builtin_getvar_helper().

Referenced by builtin_blindtransfer().

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

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 1525 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_pbx_start(), ast_read(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::exten, parkeduser::exten, ast_channel::fds, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, and VERBOSE_PREFIX_2.

Referenced by load_module().

01526 {
01527    char parkingslot[AST_MAX_EXTENSION];
01528    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
01529 
01530    FD_ZERO(&rfds);
01531    FD_ZERO(&efds);
01532 
01533    for (;;) {
01534       struct parkeduser *pu, *pl, *pt = NULL;
01535       int ms = -1;   /* select timeout, uninitialized */
01536       int max = -1;  /* max fd, none there yet */
01537       fd_set nrfds, nefds; /* args for the next select */
01538       FD_ZERO(&nrfds);
01539       FD_ZERO(&nefds);
01540 
01541       ast_mutex_lock(&parking_lock);
01542       pl = NULL;
01543       pu = parkinglot;
01544       /* navigate the list with prev-cur pointers to support removals */
01545       while (pu) {
01546          struct ast_channel *chan = pu->chan;   /* shorthand */
01547          int tms;        /* timeout for this item */
01548          int x;          /* fd index in channel */
01549          struct ast_context *con;
01550 
01551          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
01552             pl = pu;
01553             pu = pu->next;
01554             continue;
01555          }
01556          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01557          if (tms > pu->parkingtime) {
01558             ast_indicate(chan, AST_CONTROL_UNHOLD);
01559             /* Get chan, exten from derived kludge */
01560             if (pu->peername[0]) {
01561                char *peername = ast_strdupa(pu->peername);
01562                char *cp = strrchr(peername, '-');
01563                if (cp) 
01564                   *cp = 0;
01565                con = ast_context_find(parking_con_dial);
01566                if (!con) {
01567                   con = ast_context_create(NULL, parking_con_dial, registrar);
01568                   if (!con)
01569                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01570                }
01571                if (con) {
01572                   char returnexten[AST_MAX_EXTENSION];
01573                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01574                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01575                }
01576                if (comebacktoorigin) { 
01577                         set_c_e_p(chan, parking_con_dial, peername, 1);
01578                } else {
01579                      ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
01580                      snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
01581                      pbx_builtin_setvar_helper(pu->chan, "PARKINGSLOT", parkingslot);
01582                      set_c_e_p(chan, "parkedcallstimeout", peername, 1);
01583                      }
01584             } else {
01585                /* They've been waiting too long, send them back to where they came.  Theoretically they
01586                   should have their original extensions and such, but we copy to be on the safe side */
01587                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
01588             }
01589 
01590             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
01591 
01592             if (option_verbose > 1) 
01593                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);
01594             /* Start up the PBX, or hang them up */
01595             if (ast_pbx_start(chan))  {
01596                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
01597                ast_hangup(chan);
01598             }
01599             /* And take them out of the parking lot */
01600             if (pl) 
01601                pl->next = pu->next;
01602             else
01603                parkinglot = pu->next;
01604             pt = pu;
01605             pu = pu->next;
01606             con = ast_context_find(parking_con);
01607             if (con) {
01608                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01609                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01610                else
01611                   notify_metermaids(pt->parkingexten, parking_con);
01612             } else
01613                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01614             free(pt);
01615          } else { /* still within parking time, process descriptors */
01616             for (x = 0; x < AST_MAX_FDS; x++) {
01617                struct ast_frame *f;
01618 
01619                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
01620                   continue;   /* nothing on this descriptor */
01621 
01622                if (FD_ISSET(chan->fds[x], &efds))
01623                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
01624                else
01625                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
01626                chan->fdno = x;
01627 
01628                /* See if they need servicing */
01629                f = ast_read(chan);
01630                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
01631                   if (f)
01632                      ast_frfree(f);
01633                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
01634 
01635                   /* There's a problem, hang them up*/
01636                   if (option_verbose > 1) 
01637                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
01638                   ast_hangup(chan);
01639                   /* And take them out of the parking lot */
01640                   if (pl) 
01641                      pl->next = pu->next;
01642                   else
01643                      parkinglot = pu->next;
01644                   pt = pu;
01645                   pu = pu->next;
01646                   con = ast_context_find(parking_con);
01647                   if (con) {
01648                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01649                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01650                   else
01651                      notify_metermaids(pt->parkingexten, parking_con);
01652                   } else
01653                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01654                   free(pt);
01655                   break;
01656                } else {
01657                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01658                   ast_frfree(f);
01659                   if (pu->moh_trys < 3 && !chan->generatordata) {
01660                      if (option_debug)
01661                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01662                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01663                         S_OR(parkmohclass, NULL),
01664                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
01665                      pu->moh_trys++;
01666                   }
01667                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
01668                }
01669 
01670             } /* end for */
01671             if (x >= AST_MAX_FDS) {
01672 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
01673                   if (chan->fds[x] > -1) {
01674                      FD_SET(chan->fds[x], &nrfds);
01675                      FD_SET(chan->fds[x], &nefds);
01676                      if (chan->fds[x] > max)
01677                         max = chan->fds[x];
01678                   }
01679                }
01680                /* Keep track of our shortest wait */
01681                if (tms < ms || ms < 0)
01682                   ms = tms;
01683                pl = pu;
01684                pu = pu->next;
01685             }
01686          }
01687       } /* end while */
01688       ast_mutex_unlock(&parking_lock);
01689       rfds = nrfds;
01690       efds = nefds;
01691       {
01692          struct timeval tv = ast_samp2tv(ms, 1000);
01693          /* Wait for something to happen */
01694          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01695       }
01696       pthread_testcancel();
01697    }
01698    return NULL;   /* Never reached */
01699 }

static int feature_exec_app struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
char *  code,
int  sense
[static]
 

exec an app by feature

Todo:
XXX should probably return res

Definition at line 937 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_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_moh_start(), ast_moh_stop(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_strlen_zero(), ast_test_flag, ast_call_feature::exten, FEATURE_RETURN_NO_HANGUP_PEER, FEATURE_RETURN_PASSDIGITS, 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().

00938 {
00939    struct ast_app *app;
00940    struct ast_call_feature *feature;
00941    struct ast_channel *work, *idle;
00942    int res;
00943 
00944    AST_LIST_LOCK(&feature_list);
00945    AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
00946       if (!strcasecmp(feature->exten, code))
00947          break;
00948    }
00949    AST_LIST_UNLOCK(&feature_list);
00950 
00951    if (!feature) { /* shouldn't ever happen! */
00952       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
00953       return -1; 
00954    }
00955 
00956    if (sense == FEATURE_SENSE_CHAN) {
00957       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
00958          return FEATURE_RETURN_PASSDIGITS;
00959       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
00960          work = chan;
00961          idle = peer;
00962       } else {
00963          work = peer;
00964          idle = chan;
00965       }
00966    } else {
00967       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
00968          return FEATURE_RETURN_PASSDIGITS;
00969       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
00970          work = peer;
00971          idle = chan;
00972       } else {
00973          work = chan;
00974          idle = peer;
00975       }
00976    }
00977 
00978    if (!(app = pbx_findapp(feature->app))) {
00979       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
00980       return -2;
00981    }
00982 
00983    ast_autoservice_start(idle);
00984    
00985    if (!ast_strlen_zero(feature->moh_class))
00986       ast_moh_start(idle, feature->moh_class, NULL);
00987 
00988    res = pbx_exec(work, app, feature->app_args);
00989 
00990    if (!ast_strlen_zero(feature->moh_class))
00991       ast_moh_stop(idle);
00992 
00993    ast_autoservice_stop(idle);
00994 
00995    if (res == AST_PBX_KEEPALIVE)
00996       return FEATURE_RETURN_PBX_KEEPALIVE;
00997    else if (res == AST_PBX_NO_HANGUP_PEER)
00998       return FEATURE_RETURN_NO_HANGUP_PEER;
00999    else if (res)
01000       return FEATURE_RETURN_SUCCESSBREAK;
01001    
01002    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01003 }

static struct ast_call_feature* find_feature char *  name  )  [static]
 

find a feature by name

Definition at line 922 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and ast_call_feature::sname.

00923 {
00924    struct ast_call_feature *tmp;
00925 
00926    AST_LIST_LOCK(&feature_list);
00927    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00928       if (!strcasecmp(tmp->sname, name))
00929          break;
00930    }
00931    AST_LIST_UNLOCK(&feature_list);
00932 
00933    return tmp;
00934 }

static int finishup struct ast_channel chan  )  [static]
 

Definition at line 619 of file res_features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00620 {
00621         ast_indicate(chan, AST_CONTROL_UNHOLD);
00622   
00623         return ast_autoservice_stop(chan);
00624 }

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

Definition at line 1904 of file res_features.c.

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

01905 {
01906    struct parkeduser *cur;
01907    int numparked = 0;
01908 
01909    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01910       , "Context", "Extension", "Pri", "Timeout");
01911 
01912    ast_mutex_lock(&parking_lock);
01913 
01914    for (cur = parkinglot; cur; cur = cur->next) {
01915       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
01916          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
01917          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01918 
01919       numparked++;
01920    }
01921    ast_mutex_unlock(&parking_lock);
01922    ast_cli(fd, "%d parked call%s.\n", numparked, ESS(numparked));
01923 
01924 
01925    return RESULT_SUCCESS;
01926 }

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

Definition at line 1859 of file res_features.c.

References ast_cli(), ast_pickup_ext(), builtin_features, ast_call_feature::default_exten, exten, ast_call_feature::fname, and format.

01860 {
01861    int i;
01862    int fcount;
01863    struct ast_call_feature *feature;
01864    char format[] = "%-25s %-7s %-7s\n";
01865 
01866    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01867    ast_cli(fd, format, "---------------", "-------", "-------");
01868 
01869    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01870 
01871    fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01872 
01873    for (i = 0; i < fcount; i++)
01874    {
01875       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01876    }
01877    ast_cli(fd, "\n");
01878    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01879    ast_cli(fd, format, "---------------", "-------", "-------");
01880    if (AST_LIST_EMPTY(&feature_list)) {
01881       ast_cli(fd, "(none)\n");
01882    }
01883    else {
01884       AST_LIST_LOCK(&feature_list);
01885       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01886          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01887       }
01888       AST_LIST_UNLOCK(&feature_list);
01889    }
01890    ast_cli(fd, "\nCall parking\n");
01891    ast_cli(fd, "------------\n");
01892    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01893    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01894    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01895    ast_cli(fd,"\n");
01896    
01897    return RESULT_SUCCESS;
01898 }

static int load_config void   )  [static]
 

Todo:
XXX var_name or app_args ?

Definition at line 2095 of file res_features.c.

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

Referenced by load_module(), and reload().

02096 {
02097    int start = 0, end = 0;
02098    int res;
02099    struct ast_context *con = NULL;
02100    struct ast_config *cfg = NULL;
02101    struct ast_variable *var = NULL;
02102    char old_parking_ext[AST_MAX_EXTENSION];
02103    char old_parking_con[AST_MAX_EXTENSION] = "";
02104 
02105    if (!ast_strlen_zero(parking_con)) {
02106       strcpy(old_parking_ext, parking_ext);
02107       strcpy(old_parking_con, parking_con);
02108    } 
02109 
02110    /* Reset to defaults */
02111    strcpy(parking_con, "parkedcalls");
02112    strcpy(parking_con_dial, "park-dial");
02113    strcpy(parking_ext, "700");
02114    strcpy(pickup_ext, "*8");
02115    strcpy(parkmohclass, "default");
02116    courtesytone[0] = '\0';
02117    strcpy(xfersound, "beep");
02118    strcpy(xferfailsound, "pbx-invalid");
02119    parking_start = 701;
02120    parking_stop = 750;
02121    parkfindnext = 0;
02122    adsipark = 0;
02123    comebacktoorigin = 1;
02124    parkaddhints = 0;
02125    parkedcalltransfers = 0;
02126 
02127    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02128    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02129    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02130 
02131    cfg = ast_config_load("features.conf");
02132    if (!cfg) {
02133       ast_log(LOG_WARNING,"Could not load features.conf\n");
02134       return AST_MODULE_LOAD_DECLINE;
02135    }
02136    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02137       if (!strcasecmp(var->name, "parkext")) {
02138          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02139       } else if (!strcasecmp(var->name, "context")) {
02140          ast_copy_string(parking_con, var->value, sizeof(parking_con));
02141       } else if (!strcasecmp(var->name, "parkingtime")) {
02142          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02143             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02144             parkingtime = DEFAULT_PARK_TIME;
02145          } else
02146             parkingtime = parkingtime * 1000;
02147       } else if (!strcasecmp(var->name, "parkpos")) {
02148          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02149             ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno);
02150          } else {
02151             parking_start = start;
02152             parking_stop = end;
02153          }
02154       } else if (!strcasecmp(var->name, "findslot")) {
02155          parkfindnext = (!strcasecmp(var->value, "next"));
02156       } else if (!strcasecmp(var->name, "parkinghints")) {
02157          parkaddhints = ast_true(var->value);
02158       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
02159          parkedcalltransfers = ast_true(var->value);
02160       } else if (!strcasecmp(var->name, "adsipark")) {
02161          adsipark = ast_true(var->value);
02162       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02163          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02164             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02165             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02166          } else
02167             transferdigittimeout = transferdigittimeout * 1000;
02168       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02169          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02170             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02171             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02172          }
02173       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
02174          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
02175             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
02176             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02177          } else
02178             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
02179       } else if (!strcasecmp(var->name, "courtesytone")) {
02180          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02181       }  else if (!strcasecmp(var->name, "parkedplay")) {
02182          if (!strcasecmp(var->value, "both"))
02183             parkedplay = 2;
02184          else if (!strcasecmp(var->value, "parked"))
02185             parkedplay = 1;
02186          else
02187             parkedplay = 0;
02188       } else if (!strcasecmp(var->name, "xfersound")) {
02189          ast_copy_string(xfersound, var->value, sizeof(xfersound));
02190       } else if (!strcasecmp(var->name, "xferfailsound")) {
02191          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02192       } else if (!strcasecmp(var->name, "pickupexten")) {
02193          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02194       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
02195          comebacktoorigin = ast_true(var->value);
02196       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
02197          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
02198       }
02199    }
02200 
02201    unmap_features();
02202    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
02203       if (remap_feature(var->name, var->value))
02204          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02205    }
02206 
02207    /* Map a key combination to an application*/
02208    ast_unregister_features();
02209    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
02210       char *tmp_val = ast_strdupa(var->value);
02211       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
02212       struct ast_call_feature *feature;
02213 
02214       /* strsep() sets the argument to NULL if match not found, and it
02215        * is safe to use it with a NULL argument, so we don't check
02216        * between calls.
02217        */
02218       exten = strsep(&tmp_val,",");
02219       activatedby = strsep(&tmp_val,",");
02220       app = strsep(&tmp_val,",");
02221       app_args = strsep(&tmp_val,",");
02222       moh_class = strsep(&tmp_val,",");
02223 
02224       activateon = strsep(&activatedby, "/");   
02225 
02226       /*! \todo XXX var_name or app_args ? */
02227       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
02228          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
02229             app, exten, activateon, var->name);
02230          continue;
02231       }
02232 
02233       if ((feature = find_feature(var->name))) {
02234          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
02235          continue;
02236       }
02237             
02238       if (!(feature = ast_calloc(1, sizeof(*feature))))
02239          continue;               
02240 
02241       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
02242       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
02243       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
02244       
02245       if (app_args) 
02246          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
02247 
02248       if (moh_class)
02249          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
02250          
02251       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
02252       feature->operation = feature_exec_app;
02253       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
02254 
02255       /* Allow caller and calle to be specified for backwards compatability */
02256       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
02257          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
02258       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
02259          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
02260       else {
02261          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
02262             " must be 'self', or 'peer'\n", var->name);
02263          continue;
02264       }
02265 
02266       if (ast_strlen_zero(activatedby))
02267          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02268       else if (!strcasecmp(activatedby, "caller"))
02269          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
02270       else if (!strcasecmp(activatedby, "callee"))
02271          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
02272       else if (!strcasecmp(activatedby, "both"))
02273          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02274       else {
02275          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
02276             " must be 'caller', or 'callee', or 'both'\n", var->name);
02277          continue;
02278       }
02279 
02280       ast_register_feature(feature);
02281          
02282       if (option_verbose >= 1)
02283          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
02284    }   
02285    ast_config_destroy(cfg);
02286 
02287    /* Remove the old parking extension */
02288    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02289       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
02290             notify_metermaids(old_parking_ext, old_parking_con);
02291       if (option_debug)
02292          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02293    }
02294    
02295    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
02296       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02297       return -1;
02298    }
02299    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
02300    if (parkaddhints)
02301       park_add_hints(parking_con, parking_start, parking_stop);
02302    if (!res)
02303       notify_metermaids(ast_parking_ext(), parking_con);
02304    return res;
02305 
02306 }

static int load_module void   )  [static]
 

Definition at line 2313 of file res_features.c.

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

02314 {
02315    int res;
02316    
02317    memset(parking_ext, 0, sizeof(parking_ext));
02318    memset(parking_con, 0, sizeof(parking_con));
02319 
02320    if ((res = load_config()))
02321       return res;
02322    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02323    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02324    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02325    if (!res)
02326       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02327    if (!res) {
02328       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02329       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
02330          "Park a channel", mandescr_park); 
02331    }
02332 
02333    res |= ast_devstate_prov_add("Park", metermaidstate);
02334 
02335    return res;
02336 }

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

Definition at line 1990 of file res_features.c.

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

Referenced by load_module().

01991 {
01992    const char *channel = astman_get_header(m, "Channel");
01993    const char *channel2 = astman_get_header(m, "Channel2");
01994    const char *timeout = astman_get_header(m, "Timeout");
01995    char buf[BUFSIZ];
01996    int to = 0;
01997    int res = 0;
01998    int parkExt = 0;
01999    struct ast_channel *ch1, *ch2;
02000 
02001    if (ast_strlen_zero(channel)) {
02002       astman_send_error(s, m, "Channel not specified");
02003       return 0;
02004    }
02005 
02006    if (ast_strlen_zero(channel2)) {
02007       astman_send_error(s, m, "Channel2 not specified");
02008       return 0;
02009    }
02010 
02011    ch1 = ast_get_channel_by_name_locked(channel);
02012    if (!ch1) {
02013       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02014       astman_send_error(s, m, buf);
02015       return 0;
02016    }
02017 
02018    ch2 = ast_get_channel_by_name_locked(channel2);
02019    if (!ch2) {
02020       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02021       astman_send_error(s, m, buf);
02022       ast_channel_unlock(ch1);
02023       return 0;
02024    }
02025 
02026    if (!ast_strlen_zero(timeout)) {
02027       sscanf(timeout, "%d", &to);
02028    }
02029 
02030    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02031    if (!res) {
02032       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02033       astman_send_ack(s, m, "Park successful");
02034    } else {
02035       astman_send_error(s, m, "Park failure");
02036    }
02037 
02038    ast_channel_unlock(ch1);
02039    ast_channel_unlock(ch2);
02040 
02041    return 0;
02042 }

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

Dump lot status.

Definition at line 1943 of file res_features.c.

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

Referenced by load_module().

01944 {
01945    struct parkeduser *cur;
01946    const char *id = astman_get_header(m,"ActionID");
01947    char idText[256] = "";
01948 
01949    if (!ast_strlen_zero(id))
01950       snprintf(idText, 256, "ActionID: %s\r\n", id);
01951 
01952    astman_send_ack(s, m, "Parked calls will follow");
01953 
01954         ast_mutex_lock(&parking_lock);
01955 
01956    for (cur=parkinglot; cur; cur = cur->next) {
01957       astman_append(s, "Event: ParkedCall\r\n"
01958          "Exten: %d\r\n"
01959          "Channel: %s\r\n"
01960          "From: %s\r\n"
01961          "Timeout: %ld\r\n"
01962          "CallerIDNum: %s\r\n"
01963          "CallerIDName: %s\r\n"
01964          "%s"
01965          "\r\n",
01966                         cur->parkingnum, cur->chan->name, cur->peername,
01967                         (long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL),
01968          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
01969          S_OR(cur->chan->cid.cid_name, ""),
01970          idText);
01971         }
01972 
01973    astman_append(s,
01974       "Event: ParkedCallsComplete\r\n"
01975       "%s"
01976       "\r\n",idText);
01977 
01978         ast_mutex_unlock(&parking_lock);
01979 
01980         return RESULT_SUCCESS;
01981 }

static int metermaidstate const char *  data  )  [static]
 

metermaids callback from devicestate.c

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

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

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

Notify metermaids that we've changed an extension.

Definition at line 276 of file res_features.c.

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

Referenced by do_parking_thread(), and park_exec().

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

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

Add parking hints for all defined parking lots.

Definition at line 2081 of file res_features.c.

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

02082 {
02083    int numext;
02084    char device[AST_MAX_EXTENSION];
02085    char exten[10];
02086 
02087    for (numext = start; numext <= stop; numext++) {
02088       snprintf(exten, sizeof(exten), "%d", numext);
02089       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02090       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02091    }
02092 }

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

Park a call.

Definition at line 1702 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_safe_sleep(), AST_STATE_UP, ast_module_user::chan, ast_channel::exten, and ast_channel::priority.

Referenced by load_module().

01703 {
01704    /* Data is unused at the moment but could contain a parking
01705       lot context eventually */
01706    int res = 0;
01707    struct ast_module_user *u;
01708 
01709    u = ast_module_user_add(chan);
01710 
01711    /* Setup the exten/priority to be s/1 since we don't know
01712       where this call should return */
01713    strcpy(chan->exten, "s");
01714    chan->priority = 1;
01715    /* Answer if call is not up */
01716    if (chan->_state != AST_STATE_UP)
01717       res = ast_answer(chan);
01718    /* Sleep to allow VoIP streams to settle down */
01719    if (!res)
01720       res = ast_safe_sleep(chan, 1000);
01721    /* Park the call */
01722    if (!res)
01723       res = ast_park_call(chan, chan, 0, NULL);
01724 
01725    ast_module_user_remove(u);
01726 
01727    return !res ? AST_PBX_KEEPALIVE : res;
01728 }

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

References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, error(), EVENT_FLAG_CALL, free, LOG_WARNING, manager_event, parkeduser::next, notify_metermaids(), option_verbose, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.

Referenced by load_module().

01732 {
01733    int res = 0;
01734    struct ast_module_user *u;
01735    struct ast_channel *peer=NULL;
01736    struct parkeduser *pu, *pl=NULL;
01737    struct ast_context *con;
01738    int park;
01739    struct ast_bridge_config config;
01740 
01741    if (!data) {
01742       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
01743       return -1;
01744    }
01745    
01746    u = ast_module_user_add(chan);
01747 
01748    park = atoi((char *)data);
01749    ast_mutex_lock(&parking_lock);
01750    pu = parkinglot;
01751    while(pu) {
01752       if (pu->parkingnum == park) {
01753          if (pl)
01754             pl->next = pu->next;
01755          else
01756             parkinglot = pu->next;
01757          break;
01758       }
01759       pl = pu;
01760       pu = pu->next;
01761    }
01762    ast_mutex_unlock(&parking_lock);
01763    if (pu) {
01764       peer = pu->chan;
01765       con = ast_context_find(parking_con);
01766       if (con) {
01767          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
01768             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01769          else
01770             notify_metermaids(pu->parkingexten, parking_con);
01771       } else
01772          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01773 
01774       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01775          "Exten: %s\r\n"
01776          "Channel: %s\r\n"
01777          "From: %s\r\n"
01778          "CallerIDNum: %s\r\n"
01779          "CallerIDName: %s\r\n",
01780          pu->parkingexten, pu->chan->name, chan->name,
01781          S_OR(pu->chan->cid.cid_num, "<unknown>"),
01782          S_OR(pu->chan->cid.cid_name, "<unknown>")
01783          );
01784 
01785       free(pu);
01786    }
01787    /* JK02: it helps to answer the channel if not already up */
01788    if (chan->_state != AST_STATE_UP)
01789       ast_answer(chan);
01790 
01791    if (peer) {
01792       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
01793       
01794       if (!ast_strlen_zero(courtesytone)) {
01795          int error = 0;
01796          ast_indicate(peer, AST_CONTROL_UNHOLD);
01797          if (parkedplay == 0) {
01798             error = ast_stream_and_wait(chan, courtesytone, "");
01799          } else if (parkedplay == 1) {
01800             error = ast_stream_and_wait(peer, courtesytone, "");
01801          } else if (parkedplay == 2) {
01802             if (!ast_streamfile(chan, courtesytone, chan->language) &&
01803                   !ast_streamfile(peer, courtesytone, chan->language)) {
01804                /*! \todo XXX we would like to wait on both! */
01805                res = ast_waitstream(chan, "");
01806                if (res >= 0)
01807                   res = ast_waitstream(peer, "");
01808                if (res < 0)
01809                   error = 1;
01810             }
01811                         }
01812          if (error) {
01813             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01814             ast_hangup(peer);
01815             return -1;
01816          }
01817       } else
01818          ast_indicate(peer, AST_CONTROL_UNHOLD); 
01819 
01820       res = ast_channel_make_compatible(chan, peer);
01821       if (res < 0) {
01822          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01823          ast_hangup(peer);
01824          return -1;
01825       }
01826       /* This runs sorta backwards, since we give the incoming channel control, as if it
01827          were the person called. */
01828       if (option_verbose > 2) 
01829          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01830 
01831       memset(&config, 0, sizeof(struct ast_bridge_config));
01832       if (parkedcalltransfers) {
01833          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01834          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01835       }
01836       res = ast_bridge_call(chan, peer, &config);
01837 
01838       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
01839       ast_cdr_setdestchan(chan->cdr, peer->name);
01840 
01841       /* Simulate the PBX hanging up */
01842       if (res != AST_PBX_NO_HANGUP_PEER)
01843          ast_hangup(peer);
01844       return res;
01845    } else {
01846       /*! \todo XXX Play a message XXX */
01847       if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
01848          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01849       if (option_verbose > 2) 
01850          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01851       res = -1;
01852    }
01853 
01854    ast_module_user_remove(u);
01855 
01856    return res;
01857 }

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

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

01511 {
01512    manager_event(EVENT_FLAG_CALL, s,
01513       "Exten: %s\r\n"
01514       "Channel: %s\r\n"
01515       "CallerIDNum: %s\r\n"
01516       "CallerIDName: %s\r\n\r\n",
01517       parkingexten, 
01518       chan->name,
01519       S_OR(chan->cid.cid_num, "<unknown>"),
01520       S_OR(chan->cid.cid_name, "<unknown>")
01521       );
01522 }

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

Find the context for the transfer.

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

00628 {
00629         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00630         if (ast_strlen_zero(s))
00631                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00632         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00633                 s = transferer->macrocontext;
00634         if (ast_strlen_zero(s))
00635                 s = transferer->context;
00636         return s;  
00637 }

static int reload void   )  [static]
 

Definition at line 2308 of file res_features.c.

References load_config().

02309 {
02310    return load_config();
02311 }

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

Definition at line 1012 of file res_features.c.

References ast_verbose(), builtin_features, exten, FEATURES_COUNT, option_verbose, and VERBOSE_PREFIX_2.

01013 {
01014    int x;
01015    int res = -1;
01016    for (x = 0; x < FEATURES_COUNT; x++) {
01017       if (!strcasecmp(name, builtin_features[x].sname)) {
01018          ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01019          if (option_verbose > 1)
01020             ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
01021          res = 0;
01022       } else if (!strcmp(value, builtin_features[x].exten)) 
01023          ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name);
01024    }
01025    return res;
01026 }

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

00176 {
00177    ast_copy_string(chan->context, context, sizeof(chan->context));
00178    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00179    chan->priority = pri;
00180 }

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

Definition at line 1082 of file res_features.c.

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, builtin_features, config, ast_call_feature::feature_mask, and FEATURES_COUNT.

Referenced by ast_bridge_call().

01083 {
01084    int x;
01085    
01086    ast_clear_flag(config, AST_FLAGS_ALL); 
01087    for (x = 0; x < FEATURES_COUNT; x++) {
01088       if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
01089          if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01090             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01091 
01092          if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01093             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01094       }
01095    }
01096    
01097    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01098       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01099 
01100       if (dynamic_features) {
01101          char *tmp = ast_strdupa(dynamic_features);
01102          char *tok;
01103          struct ast_call_feature *feature;
01104 
01105          /* while we have a feature */
01106          while ((tok = strsep(&tmp, "#"))) {
01107             if ((feature = find_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01108                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01109                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01110                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01111                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01112             }
01113          }
01114       }
01115    }
01116 }

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

References FEATURE_SENSE_PEER.

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

00484 {
00485    if (sense == FEATURE_SENSE_PEER) {
00486       *caller = peer;
00487       *callee = chan;
00488    } else {
00489       *callee = peer;
00490       *caller = chan;
00491    }
00492 }

static int unload_module void   )  [static]
 

Definition at line 2339 of file res_features.c.

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

02340 {
02341    ast_module_user_hangup_all();
02342 
02343    ast_manager_unregister("ParkedCalls");
02344    ast_manager_unregister("Park");
02345    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02346    ast_unregister_application(parkcall);
02347    ast_devstate_prov_del("Park");
02348    return ast_unregister_application(parkedcall);
02349 }

static void unmap_features void   )  [static]
 

Definition at line 1005 of file res_features.c.

References builtin_features, exten, and FEATURES_COUNT.

01006 {
01007    int x;
01008    for (x = 0; x < FEATURES_COUNT; x++)
01009       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01010 }


Variable Documentation

int adsipark [static]
 

Definition at line 99 of file res_features.c.

int atxfernoanswertimeout [static]
 

Definition at line 105 of file res_features.c.

struct ast_call_feature builtin_features[]
 

Definition at line 870 of file res_features.c.

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

struct ast_cli_entry cli_features[] [static]
 

Definition at line 1932 of file res_features.c.

int comebacktoorigin = 1 [static]
 

Definition at line 103 of file res_features.c.

char courtesytone[256] [static]
 

Courtesy tone

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

char* descrip2 [static]
 

Definition at line 122 of file res_features.c.

int featuredigittimeout [static]
 

Definition at line 102 of file res_features.c.

char mandescr_park[] [static]
 

Definition at line 1983 of file res_features.c.

Referenced by load_module().

struct ast_app* monitor_app = NULL [static]
 

Definition at line 133 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]
 

Definition at line 134 of file res_features.c.

int parkaddhints = 0 [static]
 

Add parking hints automatically

Definition at line 80 of file res_features.c.

char* parkcall = "Park" [static]
 

Definition at line 118 of file res_features.c.

char* parkedcall = "ParkedCall" [static]
 

Definition at line 78 of file res_features.c.

int parkedcalltransfers = 0 [static]
 

Enable DTMF based transfers on bridge when picking up parked calls

Definition at line 81 of file res_features.c.

int parkedplay = 0 [static]
 

Who to play the courtesy tone to

Definition at line 92 of file res_features.c.

int parkfindnext [static]
 

Definition at line 97 of file res_features.c.

char parking_con[AST_MAX_EXTENSION] [static]
 

Context for which parking is made accessible

Definition at line 83 of file res_features.c.

char parking_con_dial[AST_MAX_EXTENSION] [static]
 

Context for dialback for parking (KLUDGE)

Definition at line 84 of file res_features.c.

char parking_ext[AST_MAX_EXTENSION] [static]
 

Extension you type to park the call

Definition at line 85 of file res_features.c.

int parking_offset [static]
 

Definition at line 96 of file res_features.c.

int parking_start [static]
 

First available extension for parking

Definition at line 88 of file res_features.c.

int parking_stop [static]
 

Last available extension for parking

Definition at line 89 of file res_features.c.

pthread_t parking_thread [static]
 

Definition at line 155 of file res_features.c.

struct parkeduser* parkinglot [static]
 

Definition at line 151 of file res_features.c.

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

int parkingtime = DEFAULT_PARK_TIME [static]
 

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

Definition at line 82 of file res_features.c.

char parkmohclass[MAX_MUSICCLASS] [static]
 

Music class used for parking

Definition at line 87 of file res_features.c.

char pickup_ext[AST_MAX_EXTENSION] [static]
 

Call pickup extension

Definition at line 86 of file res_features.c.

char* registrar = "res_features" [static]
 

Registrar for operations

Definition at line 107 of file res_features.c.

char showfeatures_help[] [static]
 

Initial value:

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

Definition at line 1900 of file res_features.c.

char showparked_help[] [static]
 

Initial value:

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

Definition at line 1928 of file res_features.c.

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

Definition at line 110 of file res_features.c.

char* synopsis2 = "Park yourself" [static]
 

Definition at line 120 of file res_features.c.

int transferdigittimeout [static]
 

Definition at line 101 of file res_features.c.

char xferfailsound[256] [static]
 

Call transfer failure sound

Definition at line 94 of file