Mon Apr 30 07:46:08 2007

Asterisk developer's documentation


res_features.c File Reference

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

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

Include dependency graph for res_features.c:

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  parkeduser

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000
#define DEFAULT_PARK_TIME   45000
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
#define FEATURE_RETURN_HANGUP   -1
#define FEATURE_RETURN_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 struct ast_cli_entry cli_show_features_deprecated
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 parkedplay = 0
static int parkfindnext
static char parking_con [AST_MAX_EXTENSION]
static char parking_con_dial [AST_MAX_EXTENSION]
static char parking_ext [AST_MAX_EXTENSION]
static int parking_offset
static int parking_start
static int parking_stop
static pthread_t parking_thread
static struct parkeduserparkinglot
static int parkingtime = DEFAULT_PARK_TIME
static char parkmohclass [MAX_MUSICCLASS]
static char pickup_ext [AST_MAX_EXTENSION]
static char * registrar = "res_features"
static char showfeatures_help []
static char showparked_help []
static char * synopsis = "Answer a parked call"
static char * synopsis2 = "Park yourself"
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file res_features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

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

Referenced by ast_feature_interpret().

#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 879 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(), ast_adsi_print(), and justify.

Referenced by ast_park_call().

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

References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), ast_cdr_init(), ast_cdr_merge(), ast_cdr_setdestchan(), ast_cdr_setuserfield(), ast_cdr_start(), 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, ast_cdr::channel, config, ast_option_header::data, ast_channel::data, ast_cdr::dstchannel, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, featuredigittimeout, ast_option_header::flag, free, LOG_DEBUG, LOG_WARNING, monitor_app, monitor_ok, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.

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

01309 {
01310    /* Copy voice back and forth between the two channels.  Give the peer
01311       the ability to transfer calls with '#<extension' syntax. */
01312    struct ast_frame *f;
01313    struct ast_channel *who;
01314    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01315    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01316    int res;
01317    int diff;
01318    int hasfeatures=0;
01319    int hadfeatures=0;
01320    struct ast_option_header *aoh;
01321    struct ast_bridge_config backup_config;
01322    struct ast_cdr *bridge_cdr;
01323 
01324    memset(&backup_config, 0, sizeof(backup_config));
01325 
01326    config->start_time = ast_tvnow();
01327 
01328    if (chan && peer) {
01329       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01330       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01331    } else if (chan)
01332       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01333 
01334    if (monitor_ok) {
01335       const char *monitor_exec;
01336       struct ast_channel *src = NULL;
01337       if (!monitor_app) { 
01338          if (!(monitor_app = pbx_findapp("Monitor")))
01339             monitor_ok=0;
01340       }
01341       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01342          src = chan;
01343       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01344          src = peer;
01345       if (monitor_app && src) {
01346          char *tmp = ast_strdupa(monitor_exec);
01347          pbx_exec(src, monitor_app, tmp);
01348       }
01349    }
01350    
01351    set_config_flags(chan, peer, config);
01352    config->firstpass = 1;
01353 
01354    /* Answer if need be */
01355    if (ast_answer(chan))
01356       return -1;
01357    peer->appl = "Bridged Call";
01358    peer->data = chan->name;
01359 
01360    /* copy the userfield from the B-leg to A-leg if applicable */
01361    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01362       char tmp[256];
01363       if (!ast_strlen_zero(chan->cdr->userfield)) {
01364          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01365          ast_cdr_appenduserfield(chan, tmp);
01366       } else
01367          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01368       /* free the peer's cdr without ast_cdr_free complaining */
01369       free(peer->cdr);
01370       peer->cdr = NULL;
01371    }
01372 
01373    for (;;) {
01374       struct ast_channel *other; /* used later */
01375 
01376       res = ast_channel_bridge(chan, peer, config, &f, &who);
01377 
01378       if (config->feature_timer) {
01379          /* Update time limit for next pass */
01380          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01381          config->feature_timer -= diff;
01382          if (hasfeatures) {
01383             /* Running on backup config, meaning a feature might be being
01384                activated, but that's no excuse to keep things going 
01385                indefinitely! */
01386             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01387                if (option_debug)
01388                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01389                config->feature_timer = 0;
01390                who = chan;
01391                if (f)
01392                   ast_frfree(f);
01393                f = NULL;
01394                res = 0;
01395             } else if (config->feature_timer <= 0) {
01396                /* Not *really* out of time, just out of time for
01397                   digits to come in for features. */
01398                if (option_debug)
01399                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01400                if (!ast_strlen_zero(peer_featurecode)) {
01401                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01402                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01403                }
01404                if (!ast_strlen_zero(chan_featurecode)) {
01405                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01406                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01407                }
01408                if (f)
01409                   ast_frfree(f);
01410                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01411                if (!hasfeatures) {
01412                   /* Restore original (possibly time modified) bridge config */
01413                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01414                   memset(&backup_config, 0, sizeof(backup_config));
01415                }
01416                hadfeatures = hasfeatures;
01417                /* Continue as we were */
01418                continue;
01419             } else if (!f) {
01420                /* The bridge returned without a frame and there is a feature in progress.
01421                 * However, we don't think the feature has quite yet timed out, so just
01422                 * go back into the bridge. */
01423                continue;
01424             }
01425          } else {
01426             if (config->feature_timer <=0) {
01427                /* We ran out of time */
01428                config->feature_timer = 0;
01429                who = chan;
01430                if (f)
01431                   ast_frfree(f);
01432                f = NULL;
01433                res = 0;
01434             }
01435          }
01436       }
01437       if (res < 0) {
01438          ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01439          return -1;
01440       }
01441       
01442       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01443             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01444                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01445          res = -1;
01446          break;
01447       }
01448       /* many things should be sent to the 'other' channel */
01449       other = (who == chan) ? peer : chan;
01450       if (f->frametype == AST_FRAME_CONTROL) {
01451          if (f->subclass == AST_CONTROL_RINGING)
01452             ast_indicate(other, AST_CONTROL_RINGING);
01453          else if (f->subclass == -1)
01454             ast_indicate(other, -1);
01455          else if (f->subclass == AST_CONTROL_FLASH)
01456             ast_indicate(other, AST_CONTROL_FLASH);
01457          else if (f->subclass == AST_CONTROL_OPTION) {
01458             aoh = f->data;
01459             /* Forward option Requests */
01460             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST)
01461                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01462          }
01463       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01464          /* eat it */
01465       } else if (f->frametype == AST_FRAME_DTMF) {
01466          char *featurecode;
01467          int sense;
01468 
01469          hadfeatures = hasfeatures;
01470          /* This cannot overrun because the longest feature is one shorter than our buffer */
01471          if (who == chan) {
01472             sense = FEATURE_SENSE_CHAN;
01473             featurecode = chan_featurecode;
01474          } else  {
01475             sense = FEATURE_SENSE_PEER;
01476             featurecode = peer_featurecode;
01477          }
01478          /*! append the event to featurecode. we rely on the string being zero-filled, and
01479           * not overflowing it. 
01480           * \todo XXX how do we guarantee the latter ?
01481           */
01482          featurecode[strlen(featurecode)] = f->subclass;
01483          /* Get rid of the frame before we start doing "stuff" with the channels */
01484          ast_frfree(f);
01485          f = NULL;
01486          config->feature_timer = backup_config.feature_timer;
01487          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01488          switch(res) {
01489          case FEATURE_RETURN_PASSDIGITS:
01490             ast_dtmf_stream(other, who, featurecode, 0);
01491             /* Fall through */
01492          case FEATURE_RETURN_SUCCESS:
01493             memset(featurecode, 0, sizeof(chan_featurecode));
01494             break;
01495          }
01496          if (res >= FEATURE_RETURN_PASSDIGITS) {
01497             res = 0;
01498          } else 
01499             break;
01500          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01501          if (hadfeatures && !hasfeatures) {
01502             /* Restore backup */
01503             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01504             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01505          } else if (hasfeatures) {
01506             if (!hadfeatures) {
01507                /* Backup configuration */
01508                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01509                /* Setup temporary config options */
01510                config->play_warning = 0;
01511                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01512                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01513                config->warning_freq = 0;
01514                config->warning_sound = NULL;
01515                config->end_sound = NULL;
01516                config->start_sound = NULL;
01517                config->firstpass = 0;
01518             }
01519             config->start_time = ast_tvnow();
01520             config->feature_timer = featuredigittimeout;
01521             if (option_debug)
01522                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01523          }
01524       }
01525       if (f)
01526          ast_frfree(f);
01527 
01528    }
01529 
01530    /* arrange the cdrs */
01531    bridge_cdr = ast_cdr_alloc();
01532    if (bridge_cdr) {
01533       if (chan->cdr && peer->cdr) { /* both of them? merge */
01534          ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the  destination as a base, but, really, it's random */
01535          ast_cdr_start(bridge_cdr); /* now is the time to start */
01536 
01537          /* absorb the channel cdr */
01538          ast_cdr_merge(bridge_cdr, chan->cdr);
01539          ast_cdr_discard(chan->cdr); /* no posting these guys */
01540          
01541          /* absorb the peer cdr */
01542          ast_cdr_merge(bridge_cdr, peer->cdr);
01543          ast_cdr_discard(peer->cdr); /* no posting these guys */
01544          peer->cdr = NULL;
01545          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01546       } else if (chan->cdr) {
01547          /* take the cdr from the channel - literally */
01548          ast_cdr_init(bridge_cdr,chan);
01549          /* absorb this data */
01550          ast_cdr_merge(bridge_cdr, chan->cdr);
01551          ast_cdr_discard(chan->cdr); /* no posting these guys */
01552          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01553       } else if (peer->cdr) {
01554          /* take the cdr from the peer - literally */
01555          ast_cdr_init(bridge_cdr,peer);
01556          /* absorb this data */
01557          ast_cdr_merge(bridge_cdr, peer->cdr);
01558          ast_cdr_discard(peer->cdr); /* no posting these guys */
01559          peer->cdr = NULL;
01560          peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01561       } else {
01562          /* make up a new cdr */
01563          ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
01564          chan->cdr = bridge_cdr; /*  */
01565       }
01566       if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01567          if (strcmp(bridge_cdr->channel, peer->name) != 0)
01568             ast_cdr_setdestchan(bridge_cdr, peer->name);
01569          else
01570             ast_cdr_setdestchan(bridge_cdr, chan->name);
01571       }
01572    }
01573    return res;
01574 }

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

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

References ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), builtin_features, config, exten, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, FEATURES_COUNT, find_feature(), ast_channel::flags, LOG_DEBUG, ast_call_feature::operation, option_debug, option_verbose, pbx_builtin_getvar_helper(), strsep(), and VERBOSE_PREFIX_3.

Referenced by ast_bridge_call().

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

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

References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), AST_STATE_UP, ast_verbose(), ast_waitfor_n(), builtin_features, ast_channel::cdr, ast_call_feature::exten, f, FEATURES_COUNT, ast_channel::hangupcause, len, LOG_NOTICE, LOG_WARNING, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.

Referenced by builtin_atxfer().

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

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::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree(), ast_log(), ast_park_call(), ast_read(), AST_STATE_DOWN, ast_channel::context, ast_channel::exten, f, LOG_WARNING, ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

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

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, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "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 adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_calloc, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_exists_extension(), ast_free, ast_indicate_data(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_strlen_zero(), ast_verbose(), ast_channel::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, pbx_builtin_getvar_helper(), ast_channel::priority, S_OR, strdup, and VERBOSE_PREFIX_2.

Referenced by ast_masq_park_call(), 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       "CallerID: %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 155 of file res_features.c.

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

00156 {
00157    return parking_ext;
00158 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

02109 {
02110    struct ast_channel *cur = NULL;
02111    int res = -1;
02112 
02113    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02114       if (!cur->pbx && 
02115          (cur != chan) &&
02116          (chan->pickupgroup & cur->callgroup) &&
02117          ((cur->_state == AST_STATE_RINGING) ||
02118           (cur->_state == AST_STATE_RING))) {
02119             break;
02120       }
02121       ast_channel_unlock(cur);
02122    }
02123    if (cur) {
02124       if (option_debug)
02125          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02126       res = ast_answer(chan);
02127       if (res)
02128          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02129       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02130       if (res)
02131          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02132       res = ast_channel_masquerade(cur, chan);
02133       if (res)
02134          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02135       ast_channel_unlock(cur);
02136    } else   {
02137       if (option_debug)
02138          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02139    }
02140    return res;
02141 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 160 of file res_features.c.

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

00161 {
00162    return pickup_ext;
00163 }

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

00895 {
00896    if (!feature) {
00897       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00898          return;
00899    }
00900   
00901    AST_LIST_LOCK(&feature_list);
00902    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00903    AST_LIST_UNLOCK(&feature_list);
00904 
00905    if (option_verbose >= 2) 
00906       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00907 }

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00911 {
00912    if (!feature)
00913       return;
00914 
00915    AST_LIST_LOCK(&feature_list);
00916    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00917    AST_LIST_UNLOCK(&feature_list);
00918    free(feature);
00919 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 922 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

00923 {
00924    struct ast_call_feature *feature;
00925 
00926    AST_LIST_LOCK(&feature_list);
00927    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00928       free(feature);
00929    AST_LIST_UNLOCK(&feature_list);
00930 }

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

References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_masquerade(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_waitfordigit(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), and ast_channel::writeformat.

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

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

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, caller_chan->language, "")) {
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]

Definition at line 639 of file res_features.c.

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

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", transferer->language, 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", transferee->name);
00686       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00687       res=finishup(transferee);
00688       if (!transferer->cdr) {
00689          transferer->cdr=ast_cdr_alloc();
00690          if (transferer) {
00691             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
00692             ast_cdr_start(transferer->cdr);
00693          }
00694       }
00695       if (transferer->cdr) {
00696          ast_cdr_setdestchan(transferer->cdr, transferee->name);
00697          ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00698       }
00699       if (!transferee->pbx) {
00700          /* Doh!  Use our handy async_goto functions */
00701          if (option_verbose > 2) 
00702             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00703                         ,transferee->name, xferto, transferer_real_context);
00704          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00705             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00706          res = -1;
00707       } else {
00708          /* Set the channel's new extension, since it exists, using transferer context */
00709          set_c_e_p(transferee, transferer_real_context, xferto, 0);
00710       }
00711       check_goto_on_transfer(transferer);
00712       return res;
00713    } else {
00714       if (option_verbose > 2) 
00715          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00716    }
00717    if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00718       finishup(transferee);
00719       return -1;
00720    }
00721    ast_stopstream(transferer);
00722    res = finishup(transferee);
00723    if (res) {
00724       if (option_verbose > 1)
00725          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00726       return res;
00727    }
00728    return FEATURE_RETURN_SUCCESS;
00729 }

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

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

Referenced by builtin_atxfer().

00732 {
00733    if (ast_channel_make_compatible(c, newchan) < 0) {
00734       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00735          c->name, newchan->name);
00736       ast_hangup(newchan);
00737       return -1;
00738    }
00739    return 0;
00740 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Definition at line 182 of file res_features.c.

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

Referenced by builtin_blindtransfer().

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, "", "", "", 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 1591 of file res_features.c.

References ast_add_extension2(), ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free, ast_frfree(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_read(), ast_select(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parking_con, parking_con_dial, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkmohclass, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), parkeduser::start, strdup, and VERBOSE_PREFIX_2.

Referenced by load_module().

01592 {
01593    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
01594    FD_ZERO(&rfds);
01595    FD_ZERO(&efds);
01596 
01597    for (;;) {
01598       struct parkeduser *pu, *pl, *pt = NULL;
01599       int ms = -1;   /* select timeout, uninitialized */
01600       int max = -1;  /* max fd, none there yet */
01601       fd_set nrfds, nefds; /* args for the next select */
01602       FD_ZERO(&nrfds);
01603       FD_ZERO(&nefds);
01604 
01605       ast_mutex_lock(&parking_lock);
01606       pl = NULL;
01607       pu = parkinglot;
01608       /* navigate the list with prev-cur pointers to support removals */
01609       while (pu) {
01610          struct ast_channel *chan = pu->chan;   /* shorthand */
01611          int tms;        /* timeout for this item */
01612          int x;          /* fd index in channel */
01613          struct ast_context *con;
01614 
01615          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
01616             pl = pu;
01617             pu = pu->next;
01618             continue;
01619          }
01620          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01621          if (tms > pu->parkingtime) {
01622             ast_indicate(chan, AST_CONTROL_UNHOLD);
01623             /* Get chan, exten from derived kludge */
01624             if (pu->peername[0]) {
01625                char *peername = ast_strdupa(pu->peername);
01626                char *cp = strrchr(peername, '-');
01627                if (cp) 
01628                   *cp = 0;
01629                con = ast_context_find(parking_con_dial);
01630                if (!con) {
01631                   con = ast_context_create(NULL, parking_con_dial, registrar);
01632                   if (!con)
01633                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01634                }
01635                if (con) {
01636                   char returnexten[AST_MAX_EXTENSION];
01637                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01638                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01639                }
01640                set_c_e_p(chan, parking_con_dial, peername, 1);
01641             } else {
01642                /* They've been waiting too long, send them back to where they came.  Theoretically they
01643                   should have their original extensions and such, but we copy to be on the safe side */
01644                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
01645             }
01646 
01647             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
01648 
01649             if (option_verbose > 1) 
01650                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);
01651             /* Start up the PBX, or hang them up */
01652             if (ast_pbx_start(chan))  {
01653                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
01654                ast_hangup(chan);
01655             }
01656             /* And take them out of the parking lot */
01657             if (pl) 
01658                pl->next = pu->next;
01659             else
01660                parkinglot = pu->next;
01661             pt = pu;
01662             pu = pu->next;
01663             con = ast_context_find(parking_con);
01664             if (con) {
01665                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01666                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01667                else
01668                   notify_metermaids(pt->parkingexten, parking_con);
01669             } else
01670                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01671             free(pt);
01672          } else { /* still within parking time, process descriptors */
01673             for (x = 0; x < AST_MAX_FDS; x++) {
01674                struct ast_frame *f;
01675 
01676                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
01677                   continue;   /* nothing on this descriptor */
01678 
01679                if (FD_ISSET(chan->fds[x], &efds))
01680                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
01681                else
01682                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
01683                chan->fdno = x;
01684 
01685                /* See if they need servicing */
01686                f = ast_read(chan);
01687                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
01688                   if (f)
01689                      ast_frfree(f);
01690                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
01691 
01692                   /* There's a problem, hang them up*/
01693                   if (option_verbose > 1) 
01694                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
01695                   ast_hangup(chan);
01696                   /* And take them out of the parking lot */
01697                   if (pl) 
01698                      pl->next = pu->next;
01699                   else
01700                      parkinglot = pu->next;
01701                   pt = pu;
01702                   pu = pu->next;
01703                   con = ast_context_find(parking_con);
01704                   if (con) {
01705                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01706                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01707                   else
01708                      notify_metermaids(pt->parkingexten, parking_con);
01709                   } else
01710                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01711                   free(pt);
01712                   break;
01713                } else {
01714                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01715                   ast_frfree(f);
01716                   if (pu->moh_trys < 3 && !chan->generatordata) {
01717                      if (option_debug)
01718                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01719                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01720                         S_OR(parkmohclass, NULL),
01721                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
01722                      pu->moh_trys++;
01723                   }
01724                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
01725                }
01726 
01727             } /* end for */
01728             if (x >= AST_MAX_FDS) {
01729 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
01730                   if (chan->fds[x] > -1) {
01731                      FD_SET(chan->fds[x], &nrfds);
01732                      FD_SET(chan->fds[x], &nefds);
01733                      if (chan->fds[x] > max)
01734                         max = chan->fds[x];
01735                   }
01736                }
01737                /* Keep track of our shortest wait */
01738                if (tms < ms || ms < 0)
01739                   ms = tms;
01740                pl = pu;
01741                pu = pu->next;
01742             }
01743          }
01744       } /* end while */
01745       ast_mutex_unlock(&parking_lock);
01746       rfds = nrfds;
01747       efds = nefds;
01748       {
01749          struct timeval tv = ast_samp2tv(ms, 1000);
01750          /* Wait for something to happen */
01751          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01752       }
01753       pthread_testcancel();
01754    }
01755    return NULL;   /* Never reached */
01756 }

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

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

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

find a feature by name

Definition at line 933 of file res_features.c.

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

Referenced by ast_feature_interpret(), and set_config_flags().

00934 {
00935    struct ast_call_feature *tmp;
00936 
00937    AST_LIST_LOCK(&feature_list);
00938    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00939       if (!strcasecmp(tmp->sname, name))
00940          break;
00941    }
00942    AST_LIST_UNLOCK(&feature_list);
00943 
00944    return tmp;
00945 }

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

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

01963 {
01964    struct parkeduser *cur;
01965    int numparked = 0;
01966 
01967    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01968       , "Context", "Extension", "Pri", "Timeout");
01969 
01970    ast_mutex_lock(&parking_lock);
01971 
01972    for (cur = parkinglot; cur; cur = cur->next) {
01973       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
01974          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
01975          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01976 
01977       numparked++;
01978    }
01979    ast_mutex_unlock(&parking_lock);
01980    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01981 
01982 
01983    return RESULT_SUCCESS;
01984 }

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

Definition at line 1917 of file res_features.c.

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

01918 {
01919    int i;
01920    int fcount;
01921    struct ast_call_feature *feature;
01922    char format[] = "%-25s %-7s %-7s\n";
01923 
01924    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01925    ast_cli(fd, format, "---------------", "-------", "-------");
01926 
01927    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01928 
01929    fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01930 
01931    for (i = 0; i < fcount; i++)
01932    {
01933       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01934    }
01935    ast_cli(fd, "\n");
01936    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01937    ast_cli(fd, format, "---------------", "-------", "-------");
01938    if (AST_LIST_EMPTY(&feature_list)) {
01939       ast_cli(fd, "(none)\n");
01940    }
01941    else {
01942       AST_LIST_LOCK(&feature_list);
01943       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01944          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01945       }
01946       AST_LIST_UNLOCK(&feature_list);
01947    }
01948    ast_cli(fd, "\nCall parking\n");
01949    ast_cli(fd, "------------\n");
01950    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01951    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01952    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01953    ast_cli(fd,"\n");
01954    
01955    return RESULT_SUCCESS;
01956 }

static int load_config ( void   )  [static]

Definition at line 2158 of file res_features.c.

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

02159 {
02160    int start = 0, end = 0;
02161    int res;
02162    struct ast_context *con = NULL;
02163    struct ast_config *cfg = NULL;
02164    struct ast_variable *var = NULL;
02165    char old_parking_ext[AST_MAX_EXTENSION];
02166    char old_parking_con[AST_MAX_EXTENSION] = "";
02167 
02168    if (!ast_strlen_zero(parking_con)) {
02169       strcpy(old_parking_ext, parking_ext);
02170       strcpy(old_parking_con, parking_con);
02171    } 
02172 
02173    /* Reset to defaults */
02174    strcpy(parking_con, "parkedcalls");
02175    strcpy(parking_con_dial, "park-dial");
02176    strcpy(parking_ext, "700");
02177    strcpy(pickup_ext, "*8");
02178    strcpy(parkmohclass, "default");
02179    courtesytone[0] = '\0';
02180    strcpy(xfersound, "beep");
02181    strcpy(xferfailsound, "pbx-invalid");
02182    parking_start = 701;
02183    parking_stop = 750;
02184    parkfindnext = 0;
02185    adsipark = 0;
02186    parkaddhints = 0;
02187 
02188    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02189    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02190    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02191 
02192    cfg = ast_config_load("features.conf");
02193    if (!cfg) {
02194       ast_log(LOG_WARNING,"Could not load features.conf\n");
02195       return AST_MODULE_LOAD_DECLINE;
02196    }
02197    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02198       if (!strcasecmp(var->name, "parkext")) {
02199          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02200       } else if (!strcasecmp(var->name, "context")) {
02201          ast_copy_string(parking_con, var->value, sizeof(parking_con));
02202       } else if (!strcasecmp(var->name, "parkingtime")) {
02203          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02204             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02205             parkingtime = DEFAULT_PARK_TIME;
02206          } else
02207             parkingtime = parkingtime * 1000;
02208       } else if (!strcasecmp(var->name, "parkpos")) {
02209          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02210             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);
02211          } else {
02212             parking_start = start;
02213             parking_stop = end;
02214          }
02215       } else if (!strcasecmp(var->name, "findslot")) {
02216          parkfindnext = (!strcasecmp(var->value, "next"));
02217       } else if (!strcasecmp(var->name, "parkinghints")) {
02218          parkaddhints = ast_true(var->value);
02219       } else if (!strcasecmp(var->name, "adsipark")) {
02220          adsipark = ast_true(var->value);
02221       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02222          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02223             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02224             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02225          } else
02226             transferdigittimeout = transferdigittimeout * 1000;
02227       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02228          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02229             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02230             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02231          }
02232       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
02233          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
02234             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
02235             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02236          } else
02237             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
02238       } else if (!strcasecmp(var->name, "courtesytone")) {
02239          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02240       }  else if (!strcasecmp(var->name, "parkedplay")) {
02241          if (!strcasecmp(var->value, "both"))
02242             parkedplay = 2;
02243          else if (!strcasecmp(var->value, "parked"))
02244             parkedplay = 1;
02245          else
02246             parkedplay = 0;
02247       } else if (!strcasecmp(var->name, "xfersound")) {
02248          ast_copy_string(xfersound, var->value, sizeof(xfersound));
02249       } else if (!strcasecmp(var->name, "xferfailsound")) {
02250          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02251       } else if (!strcasecmp(var->name, "pickupexten")) {
02252          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02253       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
02254          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
02255       }
02256    }
02257 
02258    unmap_features();
02259    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
02260       if (remap_feature(var->name, var->value))
02261          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02262    }
02263 
02264    /* Map a key combination to an application*/
02265    ast_unregister_features();
02266    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
02267       char *tmp_val = ast_strdupa(var->value);
02268       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
02269       struct ast_call_feature *feature;
02270 
02271       /* strsep() sets the argument to NULL if match not found, and it
02272        * is safe to use it with a NULL argument, so we don't check
02273        * between calls.
02274        */
02275       exten = strsep(&tmp_val,",");
02276       activatedby = strsep(&tmp_val,",");
02277       app = strsep(&tmp_val,",");
02278       app_args = strsep(&tmp_val,",");
02279       moh_class = strsep(&tmp_val,",");
02280 
02281       activateon = strsep(&activatedby, "/");   
02282 
02283       /*! \todo XXX var_name or app_args ? */
02284       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
02285          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
02286             app, exten, activateon, var->name);
02287          continue;
02288       }
02289 
02290       if ((feature = find_feature(var->name))) {
02291          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
02292          continue;
02293       }
02294             
02295       if (!(feature = ast_calloc(1, sizeof(*feature))))
02296          continue;               
02297 
02298       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
02299       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
02300       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
02301       
02302       if (app_args) 
02303          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
02304 
02305       if (moh_class)
02306          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
02307          
02308       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
02309       feature->operation = feature_exec_app;
02310       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
02311 
02312       /* Allow caller and calle to be specified for backwards compatability */
02313       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
02314          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
02315       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
02316          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
02317       else {
02318          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
02319             " must be 'self', or 'peer'\n", var->name);
02320          continue;
02321       }
02322 
02323       if (ast_strlen_zero(activatedby))
02324          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02325       else if (!strcasecmp(activatedby, "caller"))
02326          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
02327       else if (!strcasecmp(activatedby, "callee"))
02328          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
02329       else if (!strcasecmp(activatedby, "both"))
02330          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02331       else {
02332          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
02333             " must be 'caller', or 'callee', or 'both'\n", var->name);
02334          continue;
02335       }
02336 
02337       ast_register_feature(feature);
02338          
02339       if (option_verbose >= 1)
02340          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
02341    }   
02342    ast_config_destroy(cfg);
02343 
02344    /* Remove the old parking extension */
02345    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02346       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
02347             notify_metermaids(old_parking_ext, old_parking_con);
02348       if (option_debug)
02349          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02350    }
02351    
02352    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
02353       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02354       return -1;
02355    }
02356    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
02357    if (parkaddhints)
02358       park_add_hints(parking_con, parking_start, parking_stop);
02359    if (!res)
02360       notify_metermaids(ast_parking_ext(), parking_con);
02361    return res;
02362 
02363 }

static int load_module ( void   )  [static]

Definition at line 2370 of file res_features.c.

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

02371 {
02372    int res;
02373    
02374    memset(parking_ext, 0, sizeof(parking_ext));
02375    memset(parking_con, 0, sizeof(parking_con));
02376 
02377    if ((res = load_config()))
02378       return res;
02379    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02380    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02381    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02382    if (!res)
02383       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02384    if (!res) {
02385       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02386       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
02387          "Park a channel", mandescr_park); 
02388    }
02389 
02390    res |= ast_devstate_prov_add("Park", metermaidstate);
02391 
02392    return res;
02393 }

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

Definition at line 2053 of file res_features.c.

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

Referenced by load_module().

02054 {
02055    const char *channel = astman_get_header(m, "Channel");
02056    const char *channel2 = astman_get_header(m, "Channel2");
02057    const char *timeout = astman_get_header(m, "Timeout");
02058    char buf[BUFSIZ];
02059    int to = 0;
02060    int res = 0;
02061    int parkExt = 0;
02062    struct ast_channel *ch1, *ch2;
02063 
02064    if (ast_strlen_zero(channel)) {
02065       astman_send_error(s, m, "Channel not specified");
02066       return 0;
02067    }
02068 
02069    if (ast_strlen_zero(channel2)) {
02070       astman_send_error(s, m, "Channel2 not specified");
02071       return 0;
02072    }
02073 
02074    ch1 = ast_get_channel_by_name_locked(channel);
02075    if (!ch1) {
02076       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02077       astman_send_error(s, m, buf);
02078       return 0;
02079    }
02080 
02081    ch2 = ast_get_channel_by_name_locked(channel2);
02082    if (!ch2) {
02083       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02084       astman_send_error(s, m, buf);
02085       ast_channel_unlock(ch1);
02086       return 0;
02087    }
02088 
02089    if (!ast_strlen_zero(timeout)) {
02090       sscanf(timeout, "%d", &to);
02091    }
02092 
02093    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02094    if (!res) {
02095       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02096       astman_send_ack(s, m, "Park successful");
02097    } else {
02098       astman_send_error(s, m, "Park failure");
02099    }
02100 
02101    ast_channel_unlock(ch1);
02102    ast_channel_unlock(ch2);
02103 
02104    return 0;
02105 }

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

Dump lot status.

Definition at line 2006 of file res_features.c.

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

Referenced by load_module().

02007 {
02008    struct parkeduser *cur;
02009    const char *id = astman_get_header(m, "ActionID");
02010    char idText[256] = "";
02011 
02012    if (!ast_strlen_zero(id))
02013       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02014 
02015    astman_send_ack(s, m, "Parked calls will follow");
02016 
02017    ast_mutex_lock(&parking_lock);
02018 
02019    for (cur = parkinglot; cur; cur = cur->next) {
02020       astman_append(s, "Event: ParkedCall\r\n"
02021          "Exten: %d\r\n"
02022          "Channel: %s\r\n"
02023          "From: %s\r\n"
02024          "Timeout: %ld\r\n"
02025          "CallerID: %s\r\n"
02026          "CallerIDName: %s\r\n"
02027          "%s"
02028          "\r\n",
02029          cur->parkingnum, cur->chan->name, cur->peername,
02030          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02031          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02032          S_OR(cur->chan->cid.cid_name, ""),
02033          idText);
02034    }
02035 
02036    astman_append(s,
02037       "Event: ParkedCallsComplete\r\n"
02038       "%s"
02039       "\r\n",idText);
02040 
02041    ast_mutex_unlock(&parking_lock);
02042 
02043    return RESULT_SUCCESS;
02044 }

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 ast_park_call(), 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 2144 of file res_features.c.

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

02145 {
02146    int numext;
02147    char device[AST_MAX_EXTENSION];
02148    char exten[10];
02149 
02150    for (numext = start; numext <= stop; numext++) {
02151       snprintf(exten, sizeof(exten), "%d", numext);
02152       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02153       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02154    }
02155 }

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

Park a call.

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

01760 {
01761    /* Data is unused at the moment but could contain a parking
01762       lot context eventually */
01763    int res = 0;
01764    struct ast_module_user *u;
01765 
01766    u = ast_module_user_add(chan);
01767 
01768    /* Setup the exten/priority to be s/1 since we don't know
01769       where this call should return */
01770    strcpy(chan->exten, "s");
01771    chan->priority = 1;
01772    /* Answer if call is not up */
01773    if (chan->_state != AST_STATE_UP)
01774       res = ast_answer(chan);
01775    /* Sleep to allow VoIP streams to settle down */
01776    if (!res)
01777       res = ast_safe_sleep(chan, 1000);
01778    /* Park the call */
01779    if (!res)
01780       res = ast_park_call(chan, chan, 0, NULL);
01781 
01782    ast_module_user_remove(u);
01783 
01784    return !res ? AST_PBX_KEEPALIVE : res;
01785 }

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

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

Referenced by load_module().

01789 {
01790    int res = 0;
01791    struct ast_module_user *u;
01792    struct ast_channel *peer=NULL;
01793    struct parkeduser *pu, *pl=NULL;
01794    struct ast_context *con;
01795 
01796    int park;
01797    struct ast_bridge_config config;
01798 
01799    if (!data) {
01800       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
01801       return -1;
01802    }
01803    
01804    u = ast_module_user_add(chan);
01805 
01806    park = atoi((char *)data);
01807    ast_mutex_lock(&parking_lock);
01808    pu = parkinglot;
01809    while(pu) {
01810       if (pu->parkingnum == park) {
01811          if (pl)
01812             pl->next = pu->next;
01813          else
01814             parkinglot = pu->next;
01815          break;
01816       }
01817       pl = pu;
01818       pu = pu->next;
01819    }
01820    ast_mutex_unlock(&parking_lock);
01821    if (pu) {
01822       peer = pu->chan;
01823       con = ast_context_find(parking_con);
01824       if (con) {
01825          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
01826             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01827          else
01828             notify_metermaids(pu->parkingexten, parking_con);
01829       } else
01830          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01831 
01832       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01833          "Exten: %s\r\n"
01834          "Channel: %s\r\n"
01835          "From: %s\r\n"
01836          "CallerID: %s\r\n"
01837          "CallerIDName: %s\r\n",
01838          pu->parkingexten, pu->chan->name, chan->name,
01839          S_OR(pu->chan->cid.cid_num, "<unknown>"),
01840          S_OR(pu->chan->cid.cid_name, "<unknown>")
01841          );
01842 
01843       free(pu);
01844    }
01845    /* JK02: it helps to answer the channel if not already up */
01846    if (chan->_state != AST_STATE_UP)
01847       ast_answer(chan);
01848 
01849    if (peer) {
01850       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
01851       
01852       if (!ast_strlen_zero(courtesytone)) {
01853          int error = 0;
01854          ast_indicate(peer, AST_CONTROL_UNHOLD);
01855          if (parkedplay == 0) {
01856             error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
01857          } else if (parkedplay == 1) {
01858             error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
01859          } else if (parkedplay == 2) {
01860             if (!ast_streamfile(chan, courtesytone, chan->language) &&
01861                   !ast_streamfile(peer, courtesytone, chan->language)) {
01862                /*! \todo XXX we would like to wait on both! */
01863                res = ast_waitstream(chan, "");
01864                if (res >= 0)
01865                   res = ast_waitstream(peer, "");
01866                if (res < 0)
01867                   error = 1;
01868             }
01869                         }
01870          if (error) {
01871             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01872             ast_hangup(peer);
01873             return -1;
01874          }
01875       } else
01876          ast_indicate(peer, AST_CONTROL_UNHOLD); 
01877 
01878       res = ast_channel_make_compatible(chan, peer);
01879       if (res < 0) {
01880          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01881          ast_hangup(peer);
01882          return -1;
01883       }
01884       /* This runs sorta backwards, since we give the incoming channel control, as if it
01885          were the person called. */
01886       if (option_verbose > 2) 
01887          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01888 
01889       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
01890       ast_cdr_setdestchan(chan->cdr, peer->name);
01891       memset(&config, 0, sizeof(struct ast_bridge_config));
01892       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01893       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01894       res = ast_bridge_call(chan, peer, &config);
01895 
01896       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
01897       ast_cdr_setdestchan(chan->cdr, peer->name);
01898 
01899       /* Simulate the PBX hanging up */
01900       if (res != AST_PBX_NO_HANGUP_PEER)
01901          ast_hangup(peer);
01902       return res;
01903    } else {
01904       /*! \todo XXX Play a message XXX */
01905       if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
01906          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01907       if (option_verbose > 2) 
01908          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01909       res = -1;
01910    }
01911 
01912    ast_module_user_remove(u);
01913 
01914    return res;
01915 }

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

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

01577 {
01578    manager_event(EVENT_FLAG_CALL, s,
01579       "Exten: %s\r\n"
01580       "Channel: %s\r\n"
01581       "CallerID: %s\r\n"
01582       "CallerIDName: %s\r\n\r\n",
01583       parkingexten, 
01584       chan->name,
01585       S_OR(chan->cid.cid_num, "<unknown>"),
01586       S_OR(chan->cid.cid_name, "<unknown>")
01587       );
01588 }

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

References load_config().

02366 {
02367    return load_config();
02368 }

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

Definition at line 1023 of file res_features.c.

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

01024 {
01025    int x;
01026    int res = -1;
01027    for (x = 0; x < FEATURES_COUNT; x++) {
01028       if (!strcasecmp(name, builtin_features[x].sname)) {
01029          ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01030          if (option_verbose > 1)
01031             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);
01032          res = 0;
01033       } else if (!strcmp(value, builtin_features[x].exten)) 
01034          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);
01035    }
01036    return res;
01037 }

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

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, config, ast_call_feature::feature_mask, FEATURES_COUNT, find_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

01094 {
01095    int x;
01096    
01097    ast_clear_flag(config, AST_FLAGS_ALL); 
01098    for (x = 0; x < FEATURES_COUNT; x++) {
01099       if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
01100          if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01101             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01102 
01103          if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01104             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01105       }
01106    }
01107    
01108    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01109       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01110 
01111       if (dynamic_features) {
01112          char *tmp = ast_strdupa(dynamic_features);
01113          char *tok;
01114          struct ast_call_feature *feature;
01115 
01116          /* while we have a feature */
01117          while ((tok = strsep(&tmp, "#"))) {
01118             if ((feature = find_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01119                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01120                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01121                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01122                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01123             }
01124          }
01125       }
01126    }
01127 }

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

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

02397 {
02398    ast_module_user_hangup_all();
02399 
02400    ast_manager_unregister("ParkedCalls");
02401    ast_manager_unregister("Park");
02402    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02403    ast_unregister_application(parkcall);
02404    ast_devstate_prov_del("Park");
02405    return ast_unregister_application(parkedcall);
02406 }

static void unmap_features ( void   )  [static]

Definition at line 1016 of file res_features.c.

References builtin_features, exten, and FEATURES_COUNT.

01017 {
01018    int x;
01019    for (x = 0; x < FEATURES_COUNT; x++)
01020       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01021 }


Variable Documentation

int adsipark [static]

Definition at line 98 of file res_features.c.

Referenced by load_config().

int atxfernoanswertimeout [static]

Definition at line 103 of file res_features.c.

Referenced by load_config().

struct ast_call_feature builtin_features[]

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

struct ast_cli_entry cli_show_features_deprecated [static]

Initial value:

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

Definition at line 1990 of file res_features.c.

char courtesytone[256] [static]

Courtesy tone

Definition at line 90 of file res_features.c.

Referenced by load_config(), and park_exec().

char* descrip [static]

Initial value:

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

Definition at line 110 of file res_features.c.

char* descrip2 [static]

Definition at line 120 of file res_features.c.

int featuredigittimeout [static]

Definition at line 101 of file res_features.c.

char mandescr_park[] [static]

Definition at line 2046 of file res_features.c.

Referenced by load_module().

struct ast_app* monitor_app = NULL [static]

Definition at line 131 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 132 of file res_features.c.

Referenced by ast_bridge_call().

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 80 of file res_features.c.

Referenced by load_config().

char* parkcall = "Park" [static]

Definition at line 116 of file res_features.c.

Referenced by load_module(), and unload_module().

char* parkedcall = "ParkedCall" [static]

Definition at line 78 of file res_features.c.

Referenced by load_module(), and unload_module().

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 91 of file res_features.c.

Referenced by park_exec().

int parkfindnext [static]

Definition at line 96 of file res_features.c.

Referenced by load_config().

char parking_con[AST_MAX_EXTENSION] [static]

Context for which parking is made accessible

Definition at line 82 of file res_features.c.

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

char parking_con_dial[AST_MAX_EXTENSION] [static]

Context for dialback for parking (KLUDGE)

Definition at line 83 of file res_features.c.

Referenced by do_parking_thread(), and load_config().

char parking_ext[AST_MAX_EXTENSION] [static]

Extension you type to park the call

Definition at line 84 of file res_features.c.

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

int parking_offset [static]

Definition at line 95 of file res_features.c.

int parking_start [static]

First available extension for parking

Definition at line 87 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

int parking_stop [static]

Last available extension for parking

Definition at line 88 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

pthread_t parking_thread [static]

Definition at line 153 of file res_features.c.

Referenced by load_module().

struct parkeduser* parkinglot [static]

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

char parkmohclass[MAX_MUSICCLASS] [static]

Music class used for parking

Definition at line 86 of file res_features.c.

Referenced by do_parking_thread(), and load_config().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 85 of file res_features.c.

Referenced by load_config().

char* registrar = "res_features" [static]

Registrar for operations

Definition at line 105 of file res_features.c.

char showfeatures_help[] [static]

Initial value:

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

Definition at line 1958 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 1986 of file res_features.c.

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

Definition at line 108 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 118 of file res_features.c.

int transferdigittimeout [static]

Definition at line 100 of file res_features.c.

Referenced by load_config().

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 93 of file res_features.c.

Referenced by load_config().

char xfersound[256] [static]

Call transfer sound

Definition at line 92 of file res_features.c.

Referenced by load_config().


Generated on Mon Apr 30 07:46:10 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1