Tue Nov 4 13:20:43 2008

Asterisk developer's documentation


res_features.c File Reference

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

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

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  parkeduser

Defines

#define AST_MAX_WATCHERS   256
#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000
#define DEFAULT_PARK_TIME   45000
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
#define FEATURE_RETURN_HANGUP   -1
#define FEATURE_RETURN_KEEPTRYING   24
#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
#define FEATURE_RETURN_PASSDIGITS   21
#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
#define FEATURE_RETURN_STOREDIGITS   22
#define FEATURE_RETURN_SUCCESS   23
#define FEATURE_RETURN_SUCCESSBREAK   0
#define FEATURE_SENSE_CHAN   (1 << 0)
#define FEATURE_SENSE_PEER   (1 << 1)
#define FEATURES_COUNT   (sizeof(builtin_features) / sizeof(builtin_features[0]))

Enumerations

enum  {
  AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
  AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3)
}

Functions

static int adsi_announce_park (struct ast_channel *chan, char *parkingexten)
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
static void * ast_bridge_call_thread (void *data)
static void ast_bridge_call_thread_launch (void *data)
static int ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static struct ast_channelast_feature_request_and_dial (struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language)
static AST_LIST_HEAD_STATIC (feature_list, ast_call_feature)
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Call Features Resource",.load=load_module,.unload=unload_module,.reload=reload,)
 AST_MUTEX_DEFINE_STATIC (parking_lock)
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call and read back parked location.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
 AST_RWLOCK_DEFINE_STATIC (features_lock)
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
 Remove all features in the list.
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 Attended transfer ().
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
static int builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 support routing for one touch call parking
static int check_compat (struct ast_channel *c, struct ast_channel *newchan)
static void check_goto_on_transfer (struct ast_channel *chan)
static void cmd_atxfer (struct ast_channel *a, struct ast_channel *b, struct ast_bridge_config *conf, struct ast_channel *who, char *xferto)
static int do_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, int sense, const char *toExt, const char *toCont)
 Attended transfer implementation.
static void * do_parking_thread (void *ignore)
 Take care of parked calls and unpark them if needed.
static int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 exec an app by feature
static struct ast_call_featurefind_dynamic_feature (const char *name)
 find a feature by name
static int finishup (struct ast_channel *chan)
static int handle_parkedcalls (int fd, int argc, char *argv[])
static int handle_showfeatures (int fd, int argc, char *argv[])
static int load_config (void)
static int load_module (void)
static int manager_park (struct mansession *s, const struct message *m)
static int manager_parking_status (struct mansession *s, const struct message *m)
 Dump lot status.
static int metermaidstate (const char *data)
 metermaids callback from devicestate.c
static void notify_metermaids (char *exten, char *context)
 Notify metermaids that we've changed an extension.
static void park_add_hints (char *context, int start, int stop)
 Add parking hints for all defined parking lots.
static int park_call_exec (struct ast_channel *chan, void *data)
 Park a call.
static int park_call_full (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
static int park_exec (struct ast_channel *chan, void *data)
 Pickup parked call.
static void post_manager_event (const char *s, char *parkingexten, struct ast_channel *chan)
static const char * real_ctx (struct ast_channel *transferer, struct ast_channel *transferee)
 Find the context for the transfer.
static int reload (void)
static int remap_feature (const char *name, const char *value)
static void set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri)
 store context, priority and extension
static void set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
static void set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense)
 set caller and callee according to the direction
static int unload_module (void)
static void unmap_features (void)

Variables

static int adsipark
static 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 parkeduserparkinglot
static int parkingtime = DEFAULT_PARK_TIME
static char parkmohclass [MAX_MUSICCLASS]
static char pickup_ext [AST_MAX_EXTENSION]
static char * registrar = "res_features"
static char showfeatures_help []
static char showparked_help []
static char * synopsis = "Answer a parked call"
static char * synopsis2 = "Park yourself"
static int transferdigittimeout
static char xferfailsound [256]
static char xfersound [256]


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file res_features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 71 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500

Definition at line 68 of file res_features.c.

Referenced by load_config().

#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER   15000

Definition at line 69 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 66 of file res_features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 67 of file res_features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 488 of file res_features.c.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_KEEPTRYING   24

Definition at line 495 of file res_features.c.

Referenced by ast_feature_interpret(), and feature_exec_app().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 491 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_PASSDIGITS   21

Definition at line 492 of file res_features.c.

Referenced by ast_bridge_call(), and ast_feature_interpret().

#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE

Definition at line 490 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 493 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_SUCCESS   23

Definition at line 494 of file res_features.c.

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

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 489 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 497 of file res_features.c.

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

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 498 of file res_features.c.

Referenced by ast_bridge_call(), cmd_atxfer(), and set_peers().

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

Definition at line 946 of file res_features.c.

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


Enumeration Type Documentation

anonymous enum

Enumerator:
AST_FEATURE_FLAG_NEEDSDTMF 
AST_FEATURE_FLAG_ONPEER 
AST_FEATURE_FLAG_ONSELF 
AST_FEATURE_FLAG_BYCALLEE 
AST_FEATURE_FLAG_BYCALLER 
AST_FEATURE_FLAG_BYBOTH 

Definition at line 73 of file res_features.c.

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


Function Documentation

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

Definition at line 264 of file res_features.c.

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

Referenced by park_call_full().

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

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 1403 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_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_ATXFERCMD, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, ast_cdr::channel, cmd_atxfer(), config, ast_option_header::data, ast_channel::data, ast_cdr::dstchannel, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.

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

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

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

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

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

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 250 of file res_features.c.

References ast_bridge_call_thread(), ast_pthread_create, and thread.

Referenced by do_atxfer().

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

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

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

Referenced by ast_bridge_call().

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

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

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

Definition at line 1213 of file res_features.c.

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

Referenced by do_atxfer().

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

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

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

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

00456 {
00457    struct ast_channel *chan;
00458    struct ast_frame *f;
00459    char *orig_chan_name = NULL;
00460 
00461    /* Make a new, fake channel that we'll use to masquerade in the real one */
00462    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00463       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00464       return -1;
00465    }
00466 
00467    /* Make formats okay */
00468    chan->readformat = rchan->readformat;
00469    chan->writeformat = rchan->writeformat;
00470    ast_channel_masquerade(chan, rchan);
00471 
00472    /* Setup the extensions and such */
00473    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00474 
00475    /* Make the masq execute */
00476    f = ast_read(chan);
00477    if (f)
00478       ast_frfree(f);
00479 
00480    orig_chan_name = ast_strdupa(chan->name);
00481 
00482    park_call_full(chan, peer, timeout, extout, orig_chan_name);
00483 
00484    return 0;
00485 }

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

AST_MUTEX_DEFINE_STATIC ( parking_lock   ) 

protects all static variables above

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

Park a call and read back parked location.

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

Definition at line 450 of file res_features.c.

References park_call_full().

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

00451 {
00452    return park_call_full(chan, peer, timeout, extout, NULL);
00453 }

char* ast_parking_ext ( void   ) 

Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.

Definition at line 159 of file res_features.c.

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

00160 {
00161    return parking_ext;
00162 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2253 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.

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

02254 {
02255    struct ast_channel *cur = NULL;
02256    int res = -1;
02257 
02258    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02259       if (!cur->pbx && 
02260          (cur != chan) &&
02261          (chan->pickupgroup & cur->callgroup) &&
02262          ((cur->_state == AST_STATE_RINGING) ||
02263           (cur->_state == AST_STATE_RING))) {
02264             break;
02265       }
02266       ast_channel_unlock(cur);
02267    }
02268    if (cur) {
02269       if (option_debug)
02270          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02271       res = ast_answer(chan);
02272       if (res)
02273          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02274       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02275       if (res)
02276          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02277       res = ast_channel_masquerade(cur, chan);
02278       if (res)
02279          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02280       ast_channel_unlock(cur);
02281    } else   {
02282       if (option_debug)
02283          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02284    }
02285    return res;
02286 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 164 of file res_features.c.

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

00165 {
00166    return pickup_ext;
00167 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_set

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

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

00964 {
00965    if (!feature) {
00966       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00967          return;
00968    }
00969   
00970    AST_LIST_LOCK(&feature_list);
00971    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00972    AST_LIST_UNLOCK(&feature_list);
00973 
00974    if (option_verbose >= 2) 
00975       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00976 }

AST_RWLOCK_DEFINE_STATIC ( features_lock   ) 

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 979 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00980 {
00981    if (!feature)
00982       return;
00983 
00984    AST_LIST_LOCK(&feature_list);
00985    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00986    AST_LIST_UNLOCK(&feature_list);
00987    free(feature);
00988 }

static void ast_unregister_features ( void   )  [static]

Remove all features in the list.

Definition at line 991 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

00992 {
00993    struct ast_call_feature *feature;
00994 
00995    AST_LIST_LOCK(&feature_list);
00996    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00997       free(feature);
00998    AST_LIST_UNLOCK(&feature_list);
00999 }

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

Attended transfer ().

Parameters:
chan 
peer 
config 
code 
sense 
data Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel.
Returns:
-1 means what failure/success both?

Definition at line 940 of file res_features.c.

References config, and do_atxfer().

00941 {
00942    return do_atxfer(chan, peer, config, sense, NULL, NULL);
00943 }

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

Definition at line 549 of file res_features.c.

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

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

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

Definition at line 660 of file res_features.c.

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

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

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

Definition at line 633 of file res_features.c.

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

00634 {
00635    if (option_verbose > 3)
00636       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00637    return FEATURE_RETURN_HANGUP;
00638 }

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

support routing for one touch call parking

Definition at line 516 of file res_features.c.

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

00517 {
00518    struct ast_channel *parker;
00519         struct ast_channel *parkee;
00520    int res = 0;
00521    struct ast_module_user *u;
00522 
00523    u = ast_module_user_add(chan);
00524 
00525    set_peers(&parker, &parkee, peer, chan, sense);
00526    /* Setup the exten/priority to be s/1 since we don't know
00527       where this call should return */
00528    strcpy(chan->exten, "s");
00529    chan->priority = 1;
00530    if (chan->_state != AST_STATE_UP)
00531       res = ast_answer(chan);
00532    if (!res)
00533       res = ast_safe_sleep(chan, 1000);
00534    if (!res)
00535       res = ast_park_call(parkee, parker, 0, NULL);
00536 
00537    ast_module_user_remove(u);
00538 
00539    if (!res) {
00540       if (sense == FEATURE_SENSE_CHAN)
00541          res = AST_PBX_NO_HANGUP_PEER;
00542       else
00543          res = AST_PBX_KEEPALIVE;
00544    }
00545    return res;
00546 
00547 }

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

Definition at line 752 of file res_features.c.

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

Referenced by do_atxfer().

00753 {
00754    if (ast_channel_make_compatible(c, newchan) < 0) {
00755       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00756          c->name, newchan->name);
00757       ast_hangup(newchan);
00758       return -1;
00759    }
00760    return 0;
00761 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

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

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

static void cmd_atxfer ( struct ast_channel a,
struct ast_channel b,
struct ast_bridge_config conf,
struct ast_channel who,
char *  xferto 
) [static]

Definition at line 1394 of file res_features.c.

References context, do_atxfer(), FEATURE_SENSE_CHAN, and FEATURE_SENSE_PEER.

Referenced by ast_bridge_call().

01395 {
01396    int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER;
01397    char *context = strchr(xferto, '@');;
01398    if (context)
01399       *context++ = '\0';
01400    do_atxfer(a, b, conf, sense, xferto, context);
01401 }

static int do_atxfer ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config,
int  sense,
const char *  toExt,
const char *  toCont 
) [static]

Attended transfer implementation.

Parameters:
chan transfered user
peer person transfering call
config 
sense feature options
toExt 
toCont This is the actual implementation of attended transfer, it can be activated as a regular feature or through the AMI. "toExt" is the extension to transfer to (default: ask for it on the transferer channel) "toCont" is the context to transfer to (default: the one in which the transferer is)
Returns:
-1 on failure

Definition at line 778 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_strlen_zero(), ast_waitfordigit(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), S_OR, set_peers(), ast_channel::visible_indication, and ast_channel::writeformat.

Referenced by builtin_atxfer(), and cmd_atxfer().

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

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

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

Referenced by load_module().

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

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

exec an app by feature

Todo:
XXX should probably return res

Definition at line 1015 of file res_features.c.

References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, ast_log(), ast_moh_start(), ast_moh_stop(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_strlen_zero(), ast_test_flag, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_NO_HANGUP_PEER, FEATURE_RETURN_PBX_KEEPALIVE, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().

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

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

find a feature by name

Definition at line 1002 of file res_features.c.

References AST_LIST_TRAVERSE, and ast_call_feature::sname.

Referenced by ast_feature_interpret(), and set_config_flags().

01003 {
01004    struct ast_call_feature *tmp;
01005 
01006    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01007       if (!strcasecmp(tmp->sname, name))
01008          break;
01009    }
01010 
01011    return tmp;
01012 }

static int finishup ( struct ast_channel chan  )  [static]

Definition at line 640 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

00641 {
00642         ast_indicate(chan, AST_CONTROL_UNHOLD);
00643   
00644         return ast_autoservice_stop(chan);
00645 }

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

Definition at line 2107 of file res_features.c.

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

02108 {
02109    struct parkeduser *cur;
02110    int numparked = 0;
02111 
02112    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02113       , "Context", "Extension", "Pri", "Timeout");
02114 
02115    ast_mutex_lock(&parking_lock);
02116 
02117    for (cur = parkinglot; cur; cur = cur->next) {
02118       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02119          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02120          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02121 
02122       numparked++;
02123    }
02124    ast_mutex_unlock(&parking_lock);
02125    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02126 
02127 
02128    return RESULT_SUCCESS;
02129 }

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

Definition at line 2066 of file res_features.c.

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

02067 {
02068    int i;
02069    struct ast_call_feature *feature;
02070    char format[] = "%-25s %-7s %-7s\n";
02071 
02072    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02073    ast_cli(fd, format, "---------------", "-------", "-------");
02074 
02075    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02076 
02077    ast_rwlock_rdlock(&features_lock);
02078    for (i = 0; i < FEATURES_COUNT; i++)
02079       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02080    ast_rwlock_unlock(&features_lock);
02081 
02082    ast_cli(fd, "\n");
02083    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02084    ast_cli(fd, format, "---------------", "-------", "-------");
02085    if (AST_LIST_EMPTY(&feature_list))
02086       ast_cli(fd, "(none)\n");
02087    else {
02088       AST_LIST_LOCK(&feature_list);
02089       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
02090          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
02091       AST_LIST_UNLOCK(&feature_list);
02092    }
02093    ast_cli(fd, "\nCall parking\n");
02094    ast_cli(fd, "------------\n");
02095    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02096    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02097    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02098    ast_cli(fd,"\n");
02099    
02100    return RESULT_SUCCESS;
02101 }

static int load_config ( void   )  [static]

Definition at line 2303 of file res_features.c.

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

02304 {
02305    int start = 0, end = 0;
02306    int res;
02307    struct ast_context *con = NULL;
02308    struct ast_config *cfg = NULL;
02309    struct ast_variable *var = NULL;
02310    char old_parking_ext[AST_MAX_EXTENSION];
02311    char old_parking_con[AST_MAX_EXTENSION] = "";
02312 
02313    if (!ast_strlen_zero(parking_con)) {
02314       strcpy(old_parking_ext, parking_ext);
02315       strcpy(old_parking_con, parking_con);
02316    } 
02317 
02318    /* Reset to defaults */
02319    strcpy(parking_con, "parkedcalls");
02320    strcpy(parking_con_dial, "park-dial");
02321    strcpy(parking_ext, "700");
02322    strcpy(pickup_ext, "*8");
02323    strcpy(parkmohclass, "default");
02324    courtesytone[0] = '\0';
02325    strcpy(xfersound, "beep");
02326    strcpy(xferfailsound, "pbx-invalid");
02327    parking_start = 701;
02328    parking_stop = 750;
02329    parkfindnext = 0;
02330    adsipark = 0;
02331    parkaddhints = 0;
02332 
02333    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02334    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02335    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02336 
02337    cfg = ast_config_load("features.conf");
02338    if (!cfg) {
02339       ast_log(LOG_WARNING,"Could not load features.conf\n");
02340       return AST_MODULE_LOAD_DECLINE;
02341    }
02342    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02343       if (!strcasecmp(var->name, "parkext")) {
02344          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02345       } else if (!strcasecmp(var->name, "context")) {
02346          ast_copy_string(parking_con, var->value, sizeof(parking_con));
02347       } else if (!strcasecmp(var->name, "parkingtime")) {
02348          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02349             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02350             parkingtime = DEFAULT_PARK_TIME;
02351          } else
02352             parkingtime = parkingtime * 1000;
02353       } else if (!strcasecmp(var->name, "parkpos")) {
02354          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02355             ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno);
02356          } else {
02357             parking_start = start;
02358             parking_stop = end;
02359          }
02360       } else if (!strcasecmp(var->name, "findslot")) {
02361          parkfindnext = (!strcasecmp(var->value, "next"));
02362       } else if (!strcasecmp(var->name, "parkinghints")) {
02363          parkaddhints = ast_true(var->value);
02364       } else if (!strcasecmp(var->name, "adsipark")) {
02365          adsipark = ast_true(var->value);
02366       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02367          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02368             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02369             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02370          } else
02371             transferdigittimeout = transferdigittimeout * 1000;
02372       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02373          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02374             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02375             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02376          }
02377       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
02378          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
02379             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
02380             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02381          } else
02382             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
02383       } else if (!strcasecmp(var->name, "courtesytone")) {
02384          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02385       }  else if (!strcasecmp(var->name, "parkedplay")) {
02386          if (!strcasecmp(var->value, "both"))
02387             parkedplay = 2;
02388          else if (!strcasecmp(var->value, "parked"))
02389             parkedplay = 1;
02390          else
02391             parkedplay = 0;
02392       } else if (!strcasecmp(var->name, "xfersound")) {
02393          ast_copy_string(xfersound, var->value, sizeof(xfersound));
02394       } else if (!strcasecmp(var->name, "xferfailsound")) {
02395          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02396       } else if (!strcasecmp(var->name, "pickupexten")) {
02397          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02398       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
02399          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
02400       }
02401    }
02402 
02403    unmap_features();
02404    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
02405       if (remap_feature(var->name, var->value))
02406          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02407    }
02408 
02409    /* Map a key combination to an application*/
02410    ast_unregister_features();
02411    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
02412       char *tmp_val = ast_strdupa(var->value);
02413       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
02414       struct ast_call_feature *feature;
02415 
02416       /* strsep() sets the argument to NULL if match not found, and it
02417        * is safe to use it with a NULL argument, so we don't check
02418        * between calls.
02419        */
02420       exten = strsep(&tmp_val,",");
02421       activatedby = strsep(&tmp_val,",");
02422       app = strsep(&tmp_val,",");
02423       app_args = strsep(&tmp_val,",");
02424       moh_class = strsep(&tmp_val,",");
02425 
02426       activateon = strsep(&activatedby, "/");   
02427 
02428       /*! \todo XXX var_name or app_args ? */
02429       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
02430          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
02431             app, exten, activateon, var->name);
02432          continue;
02433       }
02434 
02435       AST_LIST_LOCK(&feature_list);
02436       if ((feature = find_dynamic_feature(var->name))) {
02437          AST_LIST_UNLOCK(&feature_list);
02438          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
02439          continue;
02440       }
02441       AST_LIST_UNLOCK(&feature_list);
02442             
02443       if (!(feature = ast_calloc(1, sizeof(*feature))))
02444          continue;               
02445 
02446       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
02447       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
02448       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
02449       
02450       if (app_args) 
02451          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
02452 
02453       if (moh_class)
02454          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
02455          
02456       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
02457       feature->operation = feature_exec_app;
02458       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
02459 
02460       /* Allow caller and calle to be specified for backwards compatability */
02461       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
02462          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
02463       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
02464          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
02465       else {
02466          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
02467             " must be 'self', or 'peer'\n", var->name);
02468          continue;
02469       }
02470 
02471       if (ast_strlen_zero(activatedby))
02472          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02473       else if (!strcasecmp(activatedby, "caller"))
02474          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
02475       else if (!strcasecmp(activatedby, "callee"))
02476          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
02477       else if (!strcasecmp(activatedby, "both"))
02478          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02479       else {
02480          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
02481             " must be 'caller', or 'callee', or 'both'\n", var->name);
02482          continue;
02483       }
02484 
02485       ast_register_feature(feature);
02486          
02487       if (option_verbose >= 1)
02488          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
02489    }   
02490    ast_config_destroy(cfg);
02491 
02492    /* Remove the old parking extension */
02493    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02494       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
02495             notify_metermaids(old_parking_ext, old_parking_con);
02496       if (option_debug)
02497          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02498    }
02499    
02500    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
02501       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02502       return -1;
02503    }
02504    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
02505    if (parkaddhints)
02506       park_add_hints(parking_con, parking_start, parking_stop);
02507    if (!res)
02508       notify_metermaids(ast_parking_ext(), parking_con);
02509    return res;
02510 
02511 }

static int load_module ( void   )  [static]

Definition at line 2518 of file res_features.c.

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

02519 {
02520    int res;
02521    
02522    memset(parking_ext, 0, sizeof(parking_ext));
02523    memset(parking_con, 0, sizeof(parking_con));
02524 
02525    if ((res = load_config()))
02526       return res;
02527    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02528    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02529    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02530    if (!res)
02531       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02532    if (!res) {
02533       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02534       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
02535          "Park a channel", mandescr_park); 
02536    }
02537 
02538    res |= ast_devstate_prov_add("Park", metermaidstate);
02539 
02540    return res;
02541 }

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

Definition at line 2198 of file res_features.c.

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

Referenced by load_module().

02199 {
02200    const char *channel = astman_get_header(m, "Channel");
02201    const char *channel2 = astman_get_header(m, "Channel2");
02202    const char *timeout = astman_get_header(m, "Timeout");
02203    char buf[BUFSIZ];
02204    int to = 0;
02205    int res = 0;
02206    int parkExt = 0;
02207    struct ast_channel *ch1, *ch2;
02208 
02209    if (ast_strlen_zero(channel)) {
02210       astman_send_error(s, m, "Channel not specified");
02211       return 0;
02212    }
02213 
02214    if (ast_strlen_zero(channel2)) {
02215       astman_send_error(s, m, "Channel2 not specified");
02216       return 0;
02217    }
02218 
02219    ch1 = ast_get_channel_by_name_locked(channel);
02220    if (!ch1) {
02221       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02222       astman_send_error(s, m, buf);
02223       return 0;
02224    }
02225 
02226    ch2 = ast_get_channel_by_name_locked(channel2);
02227    if (!ch2) {
02228       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02229       astman_send_error(s, m, buf);
02230       ast_channel_unlock(ch1);
02231       return 0;
02232    }
02233 
02234    if (!ast_strlen_zero(timeout)) {
02235       sscanf(timeout, "%d", &to);
02236    }
02237 
02238    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02239    if (!res) {
02240       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02241       astman_send_ack(s, m, "Park successful");
02242    } else {
02243       astman_send_error(s, m, "Park failure");
02244    }
02245 
02246    ast_channel_unlock(ch1);
02247    ast_channel_unlock(ch2);
02248 
02249    return 0;
02250 }

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

Dump lot status.

Definition at line 2151 of file res_features.c.

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

Referenced by load_module().

02152 {
02153    struct parkeduser *cur;
02154    const char *id = astman_get_header(m, "ActionID");
02155    char idText[256] = "";
02156 
02157    if (!ast_strlen_zero(id))
02158       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02159 
02160    astman_send_ack(s, m, "Parked calls will follow");
02161 
02162    ast_mutex_lock(&parking_lock);
02163 
02164    for (cur = parkinglot; cur; cur = cur->next) {
02165       astman_append(s, "Event: ParkedCall\r\n"
02166          "Exten: %d\r\n"
02167          "Channel: %s\r\n"
02168          "From: %s\r\n"
02169          "Timeout: %ld\r\n"
02170          "CallerID: %s\r\n"
02171          "CallerIDName: %s\r\n"
02172          "%s"
02173          "\r\n",
02174          cur->parkingnum, cur->chan->name, cur->peername,
02175          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02176          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02177          S_OR(cur->chan->cid.cid_name, ""),
02178          idText);
02179    }
02180 
02181    astman_append(s,
02182       "Event: ParkedCallsComplete\r\n"
02183       "%s"
02184       "\r\n",idText);
02185 
02186    ast_mutex_unlock(&parking_lock);
02187 
02188    return RESULT_SUCCESS;
02189 }

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

metermaids callback from devicestate.c

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

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

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

Notify metermaids that we've changed an extension.

Definition at line 280 of file res_features.c.

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

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

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

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

Add parking hints for all defined parking lots.

Definition at line 2289 of file res_features.c.

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

02290 {
02291    int numext;
02292    char device[AST_MAX_EXTENSION];
02293    char exten[10];
02294 
02295    for (numext = start; numext <= stop; numext++) {
02296       snprintf(exten, sizeof(exten), "%d", numext);
02297       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02298       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02299    }
02300 }

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

Park a call.

Definition at line 1888 of file res_features.c.

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

Referenced by load_module().

01889 {
01890    /* Cache the original channel name in case we get masqueraded in the middle
01891     * of a park--it is still theoretically possible for a transfer to happen before
01892     * we get here, but it is _really_ unlikely */
01893    char *orig_chan_name = ast_strdupa(chan->name);
01894    char orig_exten[AST_MAX_EXTENSION];
01895    int orig_priority = chan->priority;
01896 
01897    /* Data is unused at the moment but could contain a parking
01898       lot context eventually */
01899    int res = 0;
01900    struct ast_module_user *u;
01901 
01902    u = ast_module_user_add(chan);
01903 
01904    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
01905 
01906    /* Setup the exten/priority to be s/1 since we don't know
01907       where this call should return */
01908    strcpy(chan->exten, "s");
01909    chan->priority = 1;
01910    /* Answer if call is not up */
01911    if (chan->_state != AST_STATE_UP)
01912       res = ast_answer(chan);
01913    /* Sleep to allow VoIP streams to settle down */
01914    if (!res)
01915       res = ast_safe_sleep(chan, 1000);
01916    /* Park the call */
01917    if (!res) {
01918       res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
01919       /* Continue on in the dialplan */
01920       if (res == 1) {
01921          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
01922          chan->priority = orig_priority;
01923          res = 0;
01924       } else if (!res)
01925          res = AST_PBX_KEEPALIVE;
01926    }
01927 
01928    ast_module_user_remove(u);
01929 
01930    return res;
01931 }

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

Definition at line 312 of file res_features.c.

References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_calloc, ast_clear_flag, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_exists_extension(), AST_FLAG_MASQ_NOSTREAM, ast_free, ast_indicate_data(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_set_flag, ast_strlen_zero(), ast_verbose(), ast_channel::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, pbx_builtin_getvar_helper(), ast_channel::priority, S_OR, strdup, and VERBOSE_PREFIX_2.

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

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

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

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

Referenced by load_module().

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

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

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

01706 {
01707    manager_event(EVENT_FLAG_CALL, s,
01708       "Exten: %s\r\n"
01709       "Channel: %s\r\n"
01710       "CallerID: %s\r\n"
01711       "CallerIDName: %s\r\n\r\n",
01712       parkingexten, 
01713       chan->name,
01714       S_OR(chan->cid.cid_num, "<unknown>"),
01715       S_OR(chan->cid.cid_name, "<unknown>")
01716       );
01717 }

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

Find the context for the transfer.

Definition at line 648 of file res_features.c.

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

Referenced by builtin_blindtransfer(), and do_atxfer().

00649 {
00650         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00651         if (ast_strlen_zero(s))
00652                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00653         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00654                 s = transferer->macrocontext;
00655         if (ast_strlen_zero(s))
00656                 s = transferer->context;
00657         return s;  
00658 }

static int reload ( void   )  [static]

Definition at line 2513 of file res_features.c.

References load_config().

02514 {
02515    return load_config();
02516 }

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

Definition at line 1086 of file res_features.c.

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

01087 {
01088    int x, res = -1;
01089 
01090    ast_rwlock_wrlock(&features_lock);
01091    for (x = 0; x < FEATURES_COUNT; x++) {
01092       if (strcasecmp(builtin_features[x].sname, name))
01093          continue;
01094 
01095       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01096       res = 0;
01097       break;
01098    }
01099    ast_rwlock_unlock(&features_lock);
01100 
01101    return res;
01102 }

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

References ast_channel::context, ast_channel::exten, and ast_channel::priority.

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

00180 {
00181    ast_copy_string(chan->context, context, sizeof(chan->context));
00182    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00183    chan->priority = pri;
00184 }

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

Definition at line 1170 of file res_features.c.

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

Referenced by ast_bridge_call().

01171 {
01172    int x;
01173    
01174    ast_clear_flag(config, AST_FLAGS_ALL);
01175 
01176    ast_rwlock_rdlock(&features_lock);
01177    for (x = 0; x < FEATURES_COUNT; x++) {
01178       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01179          continue;
01180 
01181       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01182          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01183 
01184       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01185          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01186    }
01187    ast_rwlock_unlock(&features_lock);
01188    
01189    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01190       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01191 
01192       if (dynamic_features) {
01193          char *tmp = ast_strdupa(dynamic_features);
01194          char *tok;
01195          struct ast_call_feature *feature;
01196 
01197          /* while we have a feature */
01198          while ((tok = strsep(&tmp, "#"))) {
01199             AST_LIST_LOCK(&feature_list);
01200             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01201                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01202                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01203                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01204                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01205             }
01206             AST_LIST_UNLOCK(&feature_list);
01207          }
01208       }
01209    }
01210 }

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

References FEATURE_SENSE_PEER.

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

00505 {
00506    if (sense == FEATURE_SENSE_PEER) {
00507       *caller = peer;
00508       *callee = chan;
00509    } else {
00510       *callee = peer;
00511       *caller = chan;
00512    }
00513 }

static int unload_module ( void   )  [static]

Definition at line 2544 of file res_features.c.

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

02545 {
02546    ast_module_user_hangup_all();
02547 
02548    ast_manager_unregister("ParkedCalls");
02549    ast_manager_unregister("Park");
02550    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02551    ast_unregister_application(parkcall);
02552    ast_devstate_prov_del("Park");
02553    return ast_unregister_application(parkedcall);
02554 }

static void unmap_features ( void   )  [static]

Definition at line 1076 of file res_features.c.

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

01077 {
01078    int x;
01079 
01080    ast_rwlock_wrlock(&features_lock);
01081    for (x = 0; x < FEATURES_COUNT; x++)
01082       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01083    ast_rwlock_unlock(&features_lock);
01084 }


Variable Documentation

int adsipark [static]

Definition at line 102 of file res_features.c.

Referenced by load_config().

int atxfernoanswertimeout [static]

Definition at line 107 of file res_features.c.

Referenced by load_config().

struct ast_call_feature builtin_features[] [static]

Definition at line 950 of file res_features.c.

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

struct ast_cli_entry cli_features[] [static]

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

char courtesytone[256] [static]

Courtesy tone

Definition at line 94 of file res_features.c.

Referenced by load_config(), and park_exec().

char* descrip [static]

Initial value:

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

Definition at line 114 of file res_features.c.

char* descrip2 [static]

Definition at line 124 of file res_features.c.

int featuredigittimeout [static]

Definition at line 105 of file res_features.c.

char mandescr_park[] [static]

Definition at line 2191 of file res_features.c.

Referenced by load_module().

struct ast_app* monitor_app = NULL [static]

Definition at line 135 of file res_features.c.

Referenced by ast_bridge_call(), and builtin_automonitor().

int monitor_ok = 1 [static]

Definition at line 136 of file res_features.c.

int parkaddhints = 0 [static]

Add parking hints automatically

Definition at line 84 of file res_features.c.

Referenced by load_config().

char* parkcall = "Park" [static]

Definition at line 120 of file res_features.c.

Referenced by load_module(), and unload_module().

char* parkedcall = "ParkedCall" [static]

Definition at line 82 of file res_features.c.

Referenced by load_module(), and unload_module().

int parkedplay = 0 [static]

Who to play the courtesy tone to

Definition at line 95 of file res_features.c.

Referenced by park_exec().

int parkfindnext [static]

Definition at line 100 of file res_features.c.

Referenced by load_config().

char parking_con[AST_MAX_EXTENSION] [static]

Context for which parking is made accessible

Definition at line 86 of file res_features.c.

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

char parking_con_dial[AST_MAX_EXTENSION] [static]

Context for dialback for parking (KLUDGE)

Definition at line 87 of file res_features.c.

Referenced by load_config().

char parking_ext[AST_MAX_EXTENSION] [static]

Extension you type to park the call

Definition at line 88 of file res_features.c.

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

int parking_offset [static]

Definition at line 99 of file res_features.c.

int parking_start [static]

First available extension for parking

Definition at line 91 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

int parking_stop [static]

Last available extension for parking

Definition at line 92 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

pthread_t parking_thread [static]

Definition at line 157 of file res_features.c.

Referenced by load_module().

struct parkeduser* parkinglot [static]

Definition at line 153 of file res_features.c.

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

int parkingtime = DEFAULT_PARK_TIME [static]

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

Definition at line 85 of file res_features.c.

char parkmohclass[MAX_MUSICCLASS] [static]

Music class used for parking

Definition at line 90 of file res_features.c.

Referenced by load_config().

char pickup_ext[AST_MAX_EXTENSION] [static]

Call pickup extension

Definition at line 89 of file res_features.c.

Referenced by load_config().

char* registrar = "res_features" [static]

Registrar for operations

Definition at line 109 of file res_features.c.

char showfeatures_help[] [static]

Initial value:

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

Definition at line 2103 of file res_features.c.

char showparked_help[] [static]

Initial value:

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

Definition at line 2131 of file res_features.c.

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

Definition at line 112 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 122 of file res_features.c.

int transferdigittimeout [static]

Definition at line 104 of file res_features.c.

Referenced by load_config().

char xferfailsound[256] [static]

Call transfer failure sound

Definition at line 97 of file res_features.c.

Referenced by load_config().

char xfersound[256] [static]

Call transfer sound

Definition at line 96 of file res_features.c.

Referenced by load_config().


Generated on Tue Nov 4 13:20:43 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7