Wed Aug 15 01:25:28 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_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 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.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_list
 AST_RWLOCK_DEFINE_STATIC (features_lock)
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_list
static void ast_unregister_features (void)
 Remove all features in the list.
static int 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_feature
find_dynamic_feature (const char *name)
 find a feature by name
static int finishup (struct ast_channel *chan)
static int handle_parkedcalls (int fd, int argc, char *argv[])
static int handle_showfeatures (int fd, int argc, char *argv[])
static int load_config (void)
static int load_module (void)
static int manager_park (struct mansession *s, const struct message *m)
static int manager_parking_status (struct mansession *s, const struct message *m)
 Dump lot status.
static int metermaidstate (const char *data)
 metermaids callback from devicestate.c
static void notify_metermaids (char *exten, char *context)
 Notify metermaids that we've changed an extension.
static void park_add_hints (char *context, int start, int stop)
 Add parking hints for all defined parking lots.
static int park_call_exec (struct ast_channel *chan, void *data)
 Park a call.
static int park_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
static struct
ast_call_feature 
builtin_features []
static struct
ast_cli_entry 
cli_features []
static struct
ast_cli_entry 
cli_show_features_deprecated
static char courtesytone [256]
static char * descrip
static char * descrip2
static int featuredigittimeout
static char mandescr_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
parkeduser
parkinglot
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.

Referenced by load_config().

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

Referenced by builtin_disconnect().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 474 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_PASSDIGITS   21

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

Referenced by feature_exec_app().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 476 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_SUCCESS   23

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

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 479 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 480 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 878 of file res_features.c.

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


Enumeration Type Documentation

anonymous enum

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

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

References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), AST_CDR_FLAG_LOCKED, ast_cdr_init(), ast_cdr_merge(), ast_cdr_setdestchan(), ast_cdr_setuserfield(), ast_cdr_start(), ast_channel_bridge(), ast_channel_setoption(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree(), ast_indicate(), ast_indicate_data(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, ast_cdr::channel, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dstchannel, ast_bridge_config::end_sound, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, set_config_flags(), ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::userfield, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

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

Todo:
XXX for safety

Definition at line 221 of file res_features.c.

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

Referenced by ast_bridge_call_thread_launch().

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

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 246 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by builtin_atxfer().

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

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

Definition at line 1043 of file res_features.c.

References ast_copy_flags, AST_FLAGS_ALL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, find_dynamic_feature(), ast_flags::flags, LOG_DEBUG, ast_call_feature::operation, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, strsep(), and VERBOSE_PREFIX_3.

Referenced by ast_bridge_call().

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

static struct ast_channel * ast_feature_request_and_dial ( struct ast_channel caller,
const char *  type,
int  format,
void *  data,
int  timeout,
int *  outstate,
const char *  cid_num,
const char *  cid_name 
) [static, read]

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

Definition at line 1146 of file res_features.c.

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

Referenced by builtin_atxfer().

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

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

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

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.

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

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

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.

00156 {
00157    return parking_ext;
00158 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

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

02135 {
02136    struct ast_channel *cur = NULL;
02137    int res = -1;
02138 
02139    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02140       if (!cur->pbx && 
02141          (cur != chan) &&
02142          (chan->pickupgroup & cur->callgroup) &&
02143          ((cur->_state == AST_STATE_RINGING) ||
02144           (cur->_state == AST_STATE_RING))) {
02145             break;
02146       }
02147       ast_channel_unlock(cur);
02148    }
02149    if (cur) {
02150       if (option_debug)
02151          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02152       res = ast_answer(chan);
02153       if (res)
02154          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02155       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02156       if (res)
02157          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02158       res = ast_channel_masquerade(cur, chan);
02159       if (res)
02160          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02161       ast_channel_unlock(cur);
02162    } else   {
02163       if (option_debug)
02164          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02165    }
02166    return res;
02167 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 160 of file res_features.c.

00161 {
00162    return pickup_ext;
00163 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_list

register new feature into feature_set

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

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

AST_RWLOCK_DEFINE_STATIC ( features_lock   ) 

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_list

unregister feature from feature_set

Definition at line 911 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

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

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 923 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

Referenced by load_config().

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

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

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

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

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

References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_monitor_stop(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verbose(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, len, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::monitor, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3.

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

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

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

Definition at line 642 of file res_features.c.

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

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

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

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

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

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

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

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

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

Definition at line 730 of file res_features.c.

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

Referenced by builtin_atxfer().

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

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

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

Referenced by load_module().

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

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

Referenced by load_config().

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

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

find a feature by name

Definition at line 934 of file res_features.c.

References AST_LIST_TRAVERSE, and ast_call_feature::sname.

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

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

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 622 of file res_features.c.

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

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00623 {
00624         ast_indicate(chan, AST_CONTROL_UNHOLD);
00625   
00626         return ast_autoservice_stop(chan);
00627 }

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

Definition at line 1988 of file res_features.c.

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

01989 {
01990    struct parkeduser *cur;
01991    int numparked = 0;
01992 
01993    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01994       , "Context", "Extension", "Pri", "Timeout");
01995 
01996    ast_mutex_lock(&parking_lock);
01997 
01998    for (cur = parkinglot; cur; cur = cur->next) {
01999       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02000          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02001          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02002 
02003       numparked++;
02004    }
02005    ast_mutex_unlock(&parking_lock);
02006    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02007 
02008 
02009    return RESULT_SUCCESS;
02010 }

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

Definition at line 1947 of file res_features.c.

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

01948 {
01949    int i;
01950    struct ast_call_feature *feature;
01951    char format[] = "%-25s %-7s %-7s\n";
01952 
01953    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01954    ast_cli(fd, format, "---------------", "-------", "-------");
01955 
01956    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01957 
01958    ast_rwlock_rdlock(&features_lock);
01959    for (i = 0; i < FEATURES_COUNT; i++)
01960       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01961    ast_rwlock_unlock(&features_lock);
01962 
01963    ast_cli(fd, "\n");
01964    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01965    ast_cli(fd, format, "---------------", "-------", "-------");
01966    if (AST_LIST_EMPTY(&feature_list))
01967       ast_cli(fd, "(none)\n");
01968    else {
01969       AST_LIST_LOCK(&feature_list);
01970       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
01971          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01972       AST_LIST_UNLOCK(&feature_list);
01973    }
01974    ast_cli(fd, "\nCall parking\n");
01975    ast_cli(fd, "------------\n");
01976    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01977    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01978    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01979    ast_cli(fd,"\n");
01980    
01981    return RESULT_SUCCESS;
01982 }

static int load_config ( void   )  [static]

Todo:
XXX var_name or app_args ?

Definition at line 2184 of file res_features.c.

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

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

static int load_module ( void   )  [static]

Definition at line 2399 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(), do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), and park_exec().

02400 {
02401    int res;
02402    
02403    memset(parking_ext, 0, sizeof(parking_ext));
02404    memset(parking_con, 0, sizeof(parking_con));
02405 
02406    if ((res = load_config()))
02407       return res;
02408    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02409    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02410    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02411    if (!res)
02412       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02413    if (!res) {
02414       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02415       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
02416          "Park a channel", mandescr_park); 
02417    }
02418 
02419    res |= ast_devstate_prov_add("Park", metermaidstate);
02420 
02421    return res;
02422 }

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

Definition at line 2079 of file res_features.c.

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

Referenced by load_module().

02080 {
02081    const char *channel = astman_get_header(m, "Channel");
02082    const char *channel2 = astman_get_header(m, "Channel2");
02083    const char *timeout = astman_get_header(m, "Timeout");
02084    char buf[BUFSIZ];
02085    int to = 0;
02086    int res = 0;
02087    int parkExt = 0;
02088    struct ast_channel *ch1, *ch2;
02089 
02090    if (ast_strlen_zero(channel)) {
02091       astman_send_error(s, m, "Channel not specified");
02092       return 0;
02093    }
02094 
02095    if (ast_strlen_zero(channel2)) {
02096       astman_send_error(s, m, "Channel2 not specified");
02097       return 0;
02098    }
02099 
02100    ch1 = ast_get_channel_by_name_locked(channel);
02101    if (!ch1) {
02102       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02103       astman_send_error(s, m, buf);
02104       return 0;
02105    }
02106 
02107    ch2 = ast_get_channel_by_name_locked(channel2);
02108    if (!ch2) {
02109       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02110       astman_send_error(s, m, buf);
02111       ast_channel_unlock(ch1);
02112       return 0;
02113    }
02114 
02115    if (!ast_strlen_zero(timeout)) {
02116       sscanf(timeout, "%d", &to);
02117    }
02118 
02119    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02120    if (!res) {
02121       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02122       astman_send_ack(s, m, "Park successful");
02123    } else {
02124       astman_send_error(s, m, "Park failure");
02125    }
02126 
02127    ast_channel_unlock(ch1);
02128    ast_channel_unlock(ch2);
02129 
02130    return 0;
02131 }

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

Dump lot status.

Definition at line 2032 of file res_features.c.

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

Referenced by load_module().

02033 {
02034    struct parkeduser *cur;
02035    const char *id = astman_get_header(m, "ActionID");
02036    char idText[256] = "";
02037 
02038    if (!ast_strlen_zero(id))
02039       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02040 
02041    astman_send_ack(s, m, "Parked calls will follow");
02042 
02043    ast_mutex_lock(&parking_lock);
02044 
02045    for (cur = parkinglot; cur; cur = cur->next) {
02046       astman_append(s, "Event: ParkedCall\r\n"
02047          "Exten: %d\r\n"
02048          "Channel: %s\r\n"
02049          "From: %s\r\n"
02050          "Timeout: %ld\r\n"
02051          "CallerID: %s\r\n"
02052          "CallerIDName: %s\r\n"
02053          "%s"
02054          "\r\n",
02055          cur->parkingnum, cur->chan->name, cur->peername,
02056          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02057          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02058          S_OR(cur->chan->cid.cid_name, ""),
02059          idText);
02060    }
02061 
02062    astman_append(s,
02063       "Event: ParkedCallsComplete\r\n"
02064       "%s"
02065       "\r\n",idText);
02066 
02067    ast_mutex_unlock(&parking_lock);
02068 
02069    return RESULT_SUCCESS;
02070 }

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

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

Referenced by load_config().

02171 {
02172    int numext;
02173    char device[AST_MAX_EXTENSION];
02174    char exten[10];
02175 
02176    for (numext = start; numext <= stop; numext++) {
02177       snprintf(exten, sizeof(exten), "%d", numext);
02178       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02179       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02180    }
02181 }

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

Park a call.

Definition at line 1789 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_channel::exten, and ast_channel::priority.

Referenced by load_module().

01790 {
01791    /* Data is unused at the moment but could contain a parking
01792       lot context eventually */
01793    int res = 0;
01794    struct ast_module_user *u;
01795 
01796    u = ast_module_user_add(chan);
01797 
01798    /* Setup the exten/priority to be s/1 since we don't know
01799       where this call should return */
01800    strcpy(chan->exten, "s");
01801    chan->priority = 1;
01802    /* Answer if call is not up */
01803    if (chan->_state != AST_STATE_UP)
01804       res = ast_answer(chan);
01805    /* Sleep to allow VoIP streams to settle down */
01806    if (!res)
01807       res = ast_safe_sleep(chan, 1000);
01808    /* Park the call */
01809    if (!res)
01810       res = ast_park_call(chan, chan, 0, NULL);
01811 
01812    ast_module_user_remove(u);
01813 
01814    return !res ? AST_PBX_KEEPALIVE : res;
01815 }

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

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

Referenced by load_module().

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

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

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

01607 {
01608    manager_event(EVENT_FLAG_CALL, s,
01609       "Exten: %s\r\n"
01610       "Channel: %s\r\n"
01611       "CallerID: %s\r\n"
01612       "CallerIDName: %s\r\n\r\n",
01613       parkingexten, 
01614       chan->name,
01615       S_OR(chan->cid.cid_num, "<unknown>"),
01616       S_OR(chan->cid.cid_name, "<unknown>")
01617       );
01618 }

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

Find the context for the transfer.

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

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

static int reload ( void   )  [static]

Definition at line 2394 of file res_features.c.

References load_config().

02395 {
02396    return load_config();
02397 }

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

Definition at line 1025 of file res_features.c.

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

Referenced by load_config().

01026 {
01027    int x, res = -1;
01028 
01029    ast_rwlock_wrlock(&features_lock);
01030    for (x = 0; x < FEATURES_COUNT; x++) {
01031       if (strcasecmp(builtin_features[x].sname, name))
01032          continue;
01033 
01034       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01035       res = 0;
01036       break;
01037    }
01038    ast_rwlock_unlock(&features_lock);
01039 
01040    return res;
01041 }

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

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_flag, ast_strdupa, ast_test_flag, ast_call_feature::feature_mask, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

01104 {
01105    int x;
01106    
01107    ast_clear_flag(config, AST_FLAGS_ALL);
01108 
01109    ast_rwlock_rdlock(&features_lock);
01110    for (x = 0; x < FEATURES_COUNT; x++) {
01111       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01112          continue;
01113 
01114       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01115          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01116 
01117       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01118          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01119    }
01120    ast_rwlock_unlock(&features_lock);
01121    
01122    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01123       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01124 
01125       if (dynamic_features) {
01126          char *tmp = ast_strdupa(dynamic_features);
01127          char *tok;
01128          struct ast_call_feature *feature;
01129 
01130          /* while we have a feature */
01131          while ((tok = strsep(&tmp, "#"))) {
01132             AST_LIST_LOCK(&feature_list);
01133             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01134                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01135                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01136                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01137                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01138             }
01139             AST_LIST_UNLOCK(&feature_list);
01140          }
01141       }
01142    }
01143 }

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

References FEATURE_SENSE_PEER.

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

00487 {
00488    if (sense == FEATURE_SENSE_PEER) {
00489       *caller = peer;
00490       *callee = chan;
00491    } else {
00492       *callee = peer;
00493       *caller = chan;
00494    }
00495 }

static int unload_module ( void   )  [static]

Definition at line 2425 of file res_features.c.

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

02426 {
02427    ast_module_user_hangup_all();
02428 
02429    ast_manager_unregister("ParkedCalls");
02430    ast_manager_unregister("Park");
02431    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02432    ast_unregister_application(parkcall);
02433    ast_devstate_prov_del("Park");
02434    return ast_unregister_application(parkedcall);
02435 }

static void unmap_features ( void   )  [static]

Definition at line 1015 of file res_features.c.

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

Referenced by load_config().

01016 {
01017    int x;
01018 
01019    ast_rwlock_wrlock(&features_lock);
01020    for (x = 0; x < FEATURES_COUNT; x++)
01021       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01022    ast_rwlock_unlock(&features_lock);
01023 }


Variable Documentation

int adsipark [static]

Definition at line 98 of file res_features.c.

int atxfernoanswertimeout [static]

Definition at line 103 of file res_features.c.

struct ast_call_feature builtin_features[] [static]

Definition at line 882 of file res_features.c.

struct ast_cli_entry cli_features[] [static]

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

char courtesytone[256] [static]

Courtesy tone

Definition at line 90 of file res_features.c.

char* descrip [static]

Initial value:

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

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

struct ast_app* monitor_app = NULL [static]

Definition at line 131 of file res_features.c.

int monitor_ok = 1 [static]

Definition at line 132 of file res_features.c.

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 80 of file res_features.c.

char* parkcall = "Park" [static]

Definition at line 116 of file res_features.c.

char* parkedcall = "ParkedCall" [static]

Definition at line 78 of file res_features.c.

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 91 of file res_features.c.

int parkfindnext [static]

Definition at line 96 of file res_features.c.

char parking_con[AST_MAX_EXTENSION] [static]

Context for which parking is made accessible

Definition at line 82 of file res_features.c.

char parking_con_dial[AST_MAX_EXTENSION] [static]

Context for dialback for parking (KLUDGE)

Definition at line 83 of file res_features.c.

char parking_ext[AST_MAX_EXTENSION] [static]

Extension you type to park the call

Definition at line 84 of file res_features.c.

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.

int parking_stop [static]

Last available extension for parking

Definition at line 88 of file res_features.c.

pthread_t parking_thread [static]

Definition at line 153 of file res_features.c.

struct parkeduser* parkinglot [static]

Definition at line 149 of file res_features.c.

int parkingtime = DEFAULT_PARK_TIME [static]

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

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

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 85 of file res_features.c.

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

char showparked_help[] [static]

Initial value:

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

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

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 93 of file res_features.c.

char xfersound[256] [static]

Call transfer sound

Definition at line 92 of file res_features.c.


Generated on Wed Aug 15 01:25:29 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3