Thu May 24 14:23:12 2007

Asterisk developer's documentation


res_features.c File Reference

Routines implementing call parking. More...

#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.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/monitor.h"

Include dependency graph for res_features.c:

Go to the source code of this file.

Data Structures

struct  ast_bridge_thread_obj
struct  parkeduser

Defines

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

Functions

static int adsi_announce_park (struct ast_channel *chan, int parkingnum)
int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
static void * ast_bridge_call_thread (void *data)
static void ast_bridge_call_thread_launch (void *data)
static int ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static struct ast_channelast_feature_request_and_dial (struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name)
static AST_LIST_HEAD_STATIC (feature_list, ast_call_feature)
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 Park a call via a masqueraded channel.
 AST_MUTEX_DEFINE_STATIC (parking_lock)
int ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 Park a call and read back parked location.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
static void ast_unregister_features (void)
static int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static void check_goto_on_transfer (struct ast_channel *chan)
char * description (void)
 Provides a description of the module.
static void * do_parking_thread (void *ignore)
static int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
static struct ast_call_featurefind_feature (char *name)
static int handle_parkedcalls (int fd, int argc, char *argv[])
static int handle_showfeatures (int fd, int argc, char *argv[])
char * key ()
 Returns the ASTERISK_GPL_KEY.
static int load_config (void)
int load_module (void)
 Initialize the module.
static int manager_parking_status (struct mansession *s, struct message *m)
static int park_call_exec (struct ast_channel *chan, void *data)
static int park_exec (struct ast_channel *chan, void *data)
int reload (void)
 Reload stuff.
static int remap_feature (const char *name, const char *value)
static void set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
static void unmap_features (void)
int usecount (void)
 Provides a usecount.

Variables

static int adsipark
ast_call_feature builtin_features []
static char courtesytone [256]
static char * descrip
static char * descrip2
static int featuredigittimeout
 LOCAL_USER_DECL
static struct ast_appmonitor_app = NULL
static int monitor_ok = 1
static char * parkcall = "Park"
static char * parkedcall = "ParkedCall"
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 pickup_ext [AST_MAX_EXTENSION]
static char * registrar = "res_features"
static struct ast_cli_entry showfeatures
static char showfeatures_help []
static struct ast_cli_entry showparked
static char showparked_help []
 STANDARD_LOCAL_USER
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 parking.

Definition in file res_features.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 73 of file res_features.c.

#define DEFAULT_FEATURE_DIGIT_TIMEOUT   500

Definition at line 71 of file res_features.c.

Referenced by load_config().

#define DEFAULT_PARK_TIME   45000

Definition at line 69 of file res_features.c.

Referenced by load_config().

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000

Definition at line 70 of file res_features.c.

Referenced by load_config().

#define FEATURE_RETURN_HANGUP   -1

Definition at line 435 of file res_features.c.

Referenced by builtin_disconnect().

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER

Definition at line 438 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_RETURN_PASSDIGITS   21

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

Referenced by feature_exec_app().

#define FEATURE_RETURN_STOREDIGITS   22

Definition at line 440 of file res_features.c.

Referenced by ast_feature_interpret().

#define FEATURE_RETURN_SUCCESS   23

Definition at line 441 of file res_features.c.

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

#define FEATURE_RETURN_SUCCESSBREAK   0

Definition at line 436 of file res_features.c.

Referenced by feature_exec_app().

#define FEATURE_SENSE_CHAN   (1 << 0)

Definition at line 443 of file res_features.c.

Referenced by ast_bridge_call(), and ast_feature_interpret().

#define FEATURE_SENSE_PEER   (1 << 1)

Definition at line 444 of file res_features.c.

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

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

Definition at line 862 of file res_features.c.

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

#define FREE   free

Definition at line 66 of file res_features.c.


Function Documentation

static int adsi_announce_park ( struct ast_channel chan,
int  parkingnum 
) [static]

Definition at line 259 of file res_features.c.

References ADSI_JUST_CENT, adsi_load_session(), adsi_print(), and justify.

Referenced by ast_park_call().

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

int ast_bridge_call ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config 
)

Bridge a call, optionally allowing redirection.

Definition at line 1264 of file res_features.c.

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

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

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

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

Definition at line 217 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, ast_channel::name, and ast_bridge_thread_obj::peer.

Referenced by ast_bridge_call_thread_launch().

00218 {
00219    struct ast_bridge_thread_obj *tobj = data;
00220 
00221    tobj->chan->appl = "Transferred Call";
00222    tobj->chan->data = tobj->peer->name;
00223    tobj->peer->appl = "Transferred Call";
00224    tobj->peer->data = tobj->chan->name;
00225    if (tobj->chan->cdr) {
00226       ast_cdr_reset(tobj->chan->cdr, NULL);
00227       ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00228    }
00229    if (tobj->peer->cdr) {
00230       ast_cdr_reset(tobj->peer->cdr, NULL);
00231       ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00232    }
00233 
00234    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00235    ast_hangup(tobj->chan);
00236    ast_hangup(tobj->peer);
00237    tobj->chan = tobj->peer = NULL;
00238    free(tobj);
00239    tobj=NULL;
00240    return NULL;
00241 }

static void ast_bridge_call_thread_launch ( void *  data  )  [static]

Definition at line 243 of file res_features.c.

References ast_bridge_call_thread(), and ast_pthread_create.

Referenced by builtin_atxfer().

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

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

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

Referenced by ast_bridge_call().

00988 {
00989    int x;
00990    struct ast_flags features;
00991    int res = FEATURE_RETURN_PASSDIGITS;
00992    struct ast_call_feature *feature;
00993    char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
00994 
00995    if (sense == FEATURE_SENSE_CHAN)
00996       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
00997    else
00998       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
00999    ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
01000 
01001    for (x=0; x < FEATURES_COUNT; x++) {
01002       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01003           !ast_strlen_zero(builtin_features[x].exten)) {
01004          /* Feature is up for consideration */
01005          if (!strcmp(builtin_features[x].exten, code)) {
01006             res = builtin_features[x].operation(chan, peer, config, code, sense);
01007             break;
01008          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01009             if (res == FEATURE_RETURN_PASSDIGITS)
01010                res = FEATURE_RETURN_STOREDIGITS;
01011          }
01012       }
01013    }
01014 
01015 
01016    if (!ast_strlen_zero(dynamic_features)) {
01017       char *tmp = ast_strdupa(dynamic_features);
01018       char *tok;
01019 
01020       if (!tmp)
01021          return res;
01022       
01023       while ((tok = strsep(&tmp, "#")) != NULL) {
01024          feature = find_feature(tok);
01025          
01026          if (feature) {
01027             /* Feature is up for consideration */
01028             if (!strcmp(feature->exten, code)) {
01029                if (option_verbose > 2)
01030                   ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01031                if (sense == FEATURE_SENSE_CHAN)
01032                   res = feature->operation(chan, peer, config, code, sense);
01033                else
01034                   res = feature->operation(peer, chan, config, code, sense);
01035                break;
01036             } else if (!strncmp(feature->exten, code, strlen(code))) {
01037                res = FEATURE_RETURN_STOREDIGITS;
01038             }
01039          }
01040       }
01041    }
01042    
01043    return res;
01044 }

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

Definition at line 1091 of file res_features.c.

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

Referenced by builtin_atxfer().

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

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

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

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

00402 {
00403    struct ast_channel *chan;
00404    struct ast_frame *f;
00405 
00406    /* Make a new, fake channel that we'll use to masquerade in the real one */
00407    chan = ast_channel_alloc(0);
00408    if (chan) {
00409       /* Let us keep track of the channel name */
00410       snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
00411 
00412       /* Make formats okay */
00413       chan->readformat = rchan->readformat;
00414       chan->writeformat = rchan->writeformat;
00415       ast_channel_masquerade(chan, rchan);
00416 
00417       /* Setup the extensions and such */
00418       ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
00419       ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
00420       chan->priority = rchan->priority;
00421 
00422       /* Make the masq execute */
00423       f = ast_read(chan);
00424       if (f)
00425          ast_frfree(f);
00426       ast_park_call(chan, peer, timeout, extout);
00427    } else {
00428       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00429       return -1;
00430    }
00431    return 0;
00432 }

AST_MUTEX_DEFINE_STATIC ( parking_lock   ) 

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

Park a call and read back parked location.

Parameters:
chan the channel to actually be parked
host the channel which will have the parked location read to Park the channel chan, and read back the parked location to the host. If the call is not picked up within a specified period of time, then the call will return to the last step that it was in (in terms of exten, priority and context)
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 278 of file res_features.c.

References adsi_announce_park(), adsi_available(), adsi_unload_session(), ast_channel::appl, ast_add_extension2(), ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, exten, FREE, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, malloc, manager_event(), ast_channel::name, parkeduser::next, parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, ast_channel::priority, parkeduser::priority, parkeduser::start, strdup, and VERBOSE_PREFIX_2.

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

00279 {
00280    struct parkeduser *pu, *cur;
00281    int i,x,parking_range;
00282    char exten[AST_MAX_EXTENSION];
00283    struct ast_context *con;
00284 
00285    pu = malloc(sizeof(struct parkeduser));
00286    if (!pu) {
00287       ast_log(LOG_WARNING, "Out of memory\n");
00288       return -1;
00289    }
00290    memset(pu, 0, sizeof(struct parkeduser));
00291    ast_mutex_lock(&parking_lock);
00292    parking_range = parking_stop - parking_start+1;
00293    for (i = 0; i < parking_range; i++) {
00294       x = (i + parking_offset) % parking_range + parking_start;
00295       cur = parkinglot;
00296       while(cur) {
00297          if (cur->parkingnum == x) 
00298             break;
00299          cur = cur->next;
00300       }
00301       if (!cur)
00302          break;
00303    }
00304 
00305    if (!(i < parking_range)) {
00306       ast_log(LOG_WARNING, "No more parking spaces\n");
00307       free(pu);
00308       ast_mutex_unlock(&parking_lock);
00309       return -1;
00310    }
00311    if (parkfindnext) 
00312       parking_offset = x - parking_start + 1;
00313    chan->appl = "Parked Call";
00314    chan->data = NULL; 
00315 
00316    pu->chan = chan;
00317    /* Start music on hold */
00318    if (chan != peer) {
00319       ast_indicate(pu->chan, AST_CONTROL_HOLD);
00320       ast_moh_start(pu->chan, NULL);
00321    }
00322    pu->start = ast_tvnow();
00323    pu->parkingnum = x;
00324    if (timeout > 0)
00325       pu->parkingtime = timeout;
00326    else
00327       pu->parkingtime = parkingtime;
00328    if (extout)
00329       *extout = x;
00330    if (peer) 
00331       ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00332 
00333    /* Remember what had been dialed, so that if the parking
00334       expires, we try to come back to the same place */
00335    if (!ast_strlen_zero(chan->macrocontext))
00336       ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
00337    else
00338       ast_copy_string(pu->context, chan->context, sizeof(pu->context));
00339    if (!ast_strlen_zero(chan->macroexten))
00340       ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
00341    else
00342       ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
00343    if (chan->macropriority)
00344       pu->priority = chan->macropriority;
00345    else
00346       pu->priority = chan->priority;
00347    pu->next = parkinglot;
00348    parkinglot = pu;
00349    /* If parking a channel directly, don't quiet yet get parking running on it */
00350    if (peer == chan) 
00351       pu->notquiteyet = 1;
00352    ast_mutex_unlock(&parking_lock);
00353    /* Wake up the (presumably select()ing) thread */
00354    pthread_kill(parking_thread, SIGURG);
00355    if (option_verbose > 1) 
00356       ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00357 
00358    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00359       "Exten: %d\r\n"
00360       "Channel: %s\r\n"
00361       "From: %s\r\n"
00362       "Timeout: %ld\r\n"
00363       "CallerID: %s\r\n"
00364       "CallerIDName: %s\r\n"
00365       ,pu->parkingnum, pu->chan->name, peer ? peer->name : ""
00366       ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
00367       ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
00368       ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
00369       );
00370 
00371    if (peer) {
00372       if (adsipark && adsi_available(peer)) {
00373          adsi_announce_park(peer, pu->parkingnum);
00374       }
00375       if (adsipark && adsi_available(peer)) {
00376          adsi_unload_session(peer);
00377       }
00378    }
00379    con = ast_context_find(parking_con);
00380    if (!con) {
00381       con = ast_context_create(NULL, parking_con, registrar);
00382       if (!con) {
00383          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00384       }
00385    }
00386    if (con) {
00387       snprintf(exten, sizeof(exten), "%d", x);
00388       ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
00389    }
00390    if (peer) 
00391       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00392    if (pu->notquiteyet) {
00393       /* Wake up parking thread if we're really done */
00394       ast_moh_start(pu->chan, NULL);
00395       pu->notquiteyet = 0;
00396       pthread_kill(parking_thread, SIGURG);
00397    }
00398    return 0;
00399 }

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

Referenced by builtin_blindtransfer(), dp_lookup(), get_refer_info(), handle_request_refer(), load_config(), mgcp_ss(), skinny_ss(), socket_read(), and ss_thread().

00164 {
00165    return parking_ext;
00166 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 1930 of file res_features.c.

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

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

01931 {
01932    struct ast_channel *cur = NULL;
01933    int res = -1;
01934 
01935    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01936       if (!cur->pbx && 
01937          (cur != chan) &&
01938          (chan->pickupgroup & cur->callgroup) &&
01939          ((cur->_state == AST_STATE_RINGING) ||
01940           (cur->_state == AST_STATE_RING))) {
01941             break;
01942       }
01943       ast_mutex_unlock(&cur->lock);
01944    }
01945    if (cur) {
01946       if (option_debug)
01947          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01948       res = ast_answer(chan);
01949       if (res)
01950          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01951       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01952       if (res)
01953          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01954       res = ast_channel_masquerade(cur, chan);
01955       if (res)
01956          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
01957       ast_mutex_unlock(&cur->lock);
01958    } else   {
01959       if (option_debug)
01960          ast_log(LOG_DEBUG, "No call pickup possible...\n");
01961    }
01962    return res;
01963 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 168 of file res_features.c.

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

00169 {
00170    return pickup_ext;
00171 }

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

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_verbose(), LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.

Referenced by load_config().

00876 {
00877    if (!feature) {
00878       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00879          return;
00880    }
00881   
00882    AST_LIST_LOCK(&feature_list);
00883    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00884    AST_LIST_UNLOCK(&feature_list);
00885 
00886    if (option_verbose >= 2) 
00887       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00888 }

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00892 {
00893    if (!feature) return;
00894 
00895    AST_LIST_LOCK(&feature_list);
00896    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00897    AST_LIST_UNLOCK(&feature_list);
00898    free(feature);
00899 }

static void ast_unregister_features ( void   )  [static]

Definition at line 901 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

Referenced by load_config().

00902 {
00903    struct ast_call_feature *feature;
00904 
00905    AST_LIST_LOCK(&feature_list);
00906    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00907       free(feature);
00908    AST_LIST_UNLOCK(&feature_list);
00909 }

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

Definition at line 666 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_channel_alloc(), ast_channel_make_compatible(), 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_moh_start(), ast_moh_stop(), ast_read(), ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_waitfordigit(), ast_waitstream(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, cid_name, cid_num, config, ast_channel::context, ast_channel::exten, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_PEER, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, malloc, ast_channel::name, pbx_builtin_getvar_helper(), ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

00667 {
00668    struct ast_channel *transferer;
00669    struct ast_channel *transferee;
00670    struct ast_channel *newchan, *xferchan=NULL;
00671    int outstate=0;
00672    struct ast_bridge_config bconfig;
00673    char *transferer_real_context;
00674    char xferto[256],dialstr[265];
00675    char *cid_num;
00676    char *cid_name;
00677    int res;
00678    struct ast_frame *f = NULL;
00679    struct ast_bridge_thread_obj *tobj;
00680 
00681    ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
00682    if (sense == FEATURE_SENSE_PEER) {
00683       transferer = peer;
00684       transferee = chan;
00685    } else {
00686       transferer = chan;
00687       transferee = peer;
00688    }
00689    if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00690       !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00691       /* Use the non-macro context to transfer the call */
00692       if (!ast_strlen_zero(transferer->macrocontext))
00693          transferer_real_context = transferer->macrocontext;
00694       else
00695          transferer_real_context = transferer->context;
00696    }
00697    /* Start autoservice on chan while we talk
00698       to the originator */
00699    ast_indicate(transferee, AST_CONTROL_HOLD);
00700    ast_autoservice_start(transferee);
00701    ast_moh_start(transferee, NULL);
00702    memset(xferto, 0, sizeof(xferto));
00703    /* Transfer */
00704    if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00705       ast_moh_stop(transferee);
00706       ast_autoservice_stop(transferee);
00707       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00708       return res;
00709    }
00710    if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00711       ast_moh_stop(transferee);
00712       ast_autoservice_stop(transferee);
00713       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00714       return res;
00715    } else if(res > 0) {
00716       /* If they've typed a digit already, handle it */
00717       xferto[0] = (char) res;
00718    }
00719    if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
00720       cid_num = transferer->cid.cid_num;
00721       cid_name = transferer->cid.cid_name;
00722       if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
00723          snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
00724          newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
00725          ast_indicate(transferer, -1);
00726          if (newchan) {
00727             res = ast_channel_make_compatible(transferer, newchan);
00728             if (res < 0) {
00729                ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
00730                ast_hangup(newchan);
00731                return -1;
00732             }
00733             memset(&bconfig,0,sizeof(struct ast_bridge_config));
00734             ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00735             ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00736             res = ast_bridge_call(transferer,newchan,&bconfig);
00737             if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
00738                ast_hangup(newchan);
00739                if (f) {
00740                   ast_frfree(f);
00741                   f = NULL;
00742                }
00743                if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
00744                   if (ast_waitstream(transferer, "") < 0) {
00745                      ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00746                   }
00747                }
00748                ast_moh_stop(transferee);
00749                ast_autoservice_stop(transferee);
00750                ast_indicate(transferee, AST_CONTROL_UNHOLD);
00751                transferer->_softhangup = 0;
00752                return FEATURE_RETURN_SUCCESS;
00753             }
00754             
00755             res = ast_channel_make_compatible(transferee, newchan);
00756             if (res < 0) {
00757                ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
00758                ast_hangup(newchan);
00759                return -1;
00760             }
00761             
00762             
00763             ast_moh_stop(transferee);
00764             
00765             if ((ast_autoservice_stop(transferee) < 0)
00766                || (ast_waitfordigit(transferee, 100) < 0)
00767                || (ast_waitfordigit(newchan, 100) < 0) 
00768                || ast_check_hangup(transferee) 
00769                || ast_check_hangup(newchan)) {
00770                ast_hangup(newchan);
00771                res = -1;
00772                return -1;
00773             }
00774 
00775             if ((xferchan = ast_channel_alloc(0))) {
00776                snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name);
00777                /* Make formats okay */
00778                xferchan->readformat = transferee->readformat;
00779                xferchan->writeformat = transferee->writeformat;
00780                ast_channel_masquerade(xferchan, transferee);
00781                ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00782                xferchan->_state = AST_STATE_UP;
00783                ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00784                xferchan->_softhangup = 0;
00785 
00786                if ((f = ast_read(xferchan))) {
00787                   ast_frfree(f);
00788                   f = NULL;
00789                }
00790                
00791             } else {
00792                ast_hangup(newchan);
00793                return -1;
00794             }
00795 
00796             newchan->_state = AST_STATE_UP;
00797             ast_clear_flag(newchan, AST_FLAGS_ALL);   
00798             newchan->_softhangup = 0;
00799 
00800             tobj = malloc(sizeof(struct ast_bridge_thread_obj));
00801             if (tobj) {
00802                memset(tobj,0,sizeof(struct ast_bridge_thread_obj));
00803                tobj->chan = xferchan;
00804                tobj->peer = newchan;
00805                tobj->bconfig = *config;
00806    
00807                if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
00808                   if (ast_waitstream(newchan, "") < 0) {
00809                      ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00810                   }
00811                }
00812                ast_bridge_call_thread_launch(tobj);
00813             } else {
00814                ast_log(LOG_WARNING, "Out of memory!\n");
00815                ast_hangup(xferchan);
00816                ast_hangup(newchan);
00817             }
00818             return -1;
00819             
00820          } else {
00821             ast_moh_stop(transferee);
00822             ast_autoservice_stop(transferee);
00823             ast_indicate(transferee, AST_CONTROL_UNHOLD);
00824             /* any reason besides user requested cancel and busy triggers the failed sound */
00825             if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
00826                res = ast_streamfile(transferer, xferfailsound, transferer->language);
00827                if (!res && (ast_waitstream(transferer, "") < 0)) {
00828                   return -1;
00829                }
00830             }
00831             return FEATURE_RETURN_SUCCESS;
00832          }
00833       } else {
00834          ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00835          ast_moh_stop(transferee);
00836          ast_autoservice_stop(transferee);
00837          ast_indicate(transferee, AST_CONTROL_UNHOLD);
00838          res = ast_streamfile(transferer, "beeperr", transferer->language);
00839          if (!res && (ast_waitstream(transferer, "") < 0)) {
00840             return -1;
00841          }
00842       }
00843    }  else {
00844       ast_log(LOG_WARNING, "Did not read data.\n");
00845       ast_moh_stop(transferee);
00846       ast_autoservice_stop(transferee);
00847       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00848       res = ast_streamfile(transferer, "beeperr", transferer->language);
00849       if (ast_waitstream(transferer, "") < 0) {
00850          return -1;
00851       }
00852    }
00853    ast_moh_stop(transferee);
00854    ast_autoservice_stop(transferee);
00855    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00856 
00857    return FEATURE_RETURN_SUCCESS;
00858 }

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

Definition at line 447 of file res_features.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_monitor_stop(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, ast_channel::language, LOG_ERROR, LOG_NOTICE, LOG_WARNING, monitor_app, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), and VERBOSE_PREFIX_3.

00448 {
00449    char *touch_monitor = NULL, *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_format = NULL;
00450    int x = 0;
00451    size_t len;
00452    struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
00453 
00454 
00455    if(sense == 2) {
00456       caller_chan = peer;
00457       callee_chan = chan;
00458    } else {
00459       callee_chan = peer;
00460       caller_chan = chan;
00461    }
00462    
00463    if (!monitor_ok) {
00464       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00465       return -1;
00466    }
00467 
00468    if (!monitor_app) { 
00469       if (!(monitor_app = pbx_findapp("Monitor"))) {
00470          monitor_ok=0;
00471          ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00472          return -1;
00473       }
00474    }
00475    if (!ast_strlen_zero(courtesytone)) {
00476       if (ast_autoservice_start(callee_chan))
00477          return -1;
00478       if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
00479          if (ast_waitstream(caller_chan, "") < 0) {
00480             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00481             ast_autoservice_stop(callee_chan);
00482             return -1;
00483          }
00484       }
00485       if (ast_autoservice_stop(callee_chan))
00486          return -1;
00487    }
00488    
00489    if (callee_chan->monitor) {
00490       if (option_verbose > 3)
00491          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00492       ast_monitor_stop(callee_chan, 1);
00493       return FEATURE_RETURN_SUCCESS;
00494    }
00495 
00496    if (caller_chan && callee_chan) {
00497       touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00498       if (!touch_format)
00499          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00500 
00501       touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00502       if (!touch_monitor)
00503          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00504       
00505       if (touch_monitor) {
00506          len = strlen(touch_monitor) + 50;
00507          args = alloca(len);
00508          snprintf(args, len, "%s|auto-%ld-%s|m", (touch_format) ? touch_format : "wav", time(NULL), touch_monitor);
00509       } else {
00510          caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
00511          callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
00512          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00513          args = alloca(len);
00514          snprintf(args, len, "%s|auto-%ld-%s-%s|m", (touch_format) ? touch_format : "wav", time(NULL), caller_chan_id, callee_chan_id);
00515       }
00516 
00517       for( x = 0; x < strlen(args); x++)
00518          if (args[x] == '/')
00519             args[x] = '-';
00520       
00521       if (option_verbose > 3)
00522          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00523 
00524       pbx_exec(callee_chan, monitor_app, args, 1);
00525       
00526       return FEATURE_RETURN_SUCCESS;
00527    }
00528    
00529    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00530    return -1;
00531 }

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

Definition at line 540 of file res_features.c.

References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_autoservice_stop(), AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_park_call(), ast_parking_ext(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_PEER, ast_channel::language, LOG_WARNING, ast_channel::macrocontext, ast_channel::name, option_verbose, ast_channel::pbx, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.

00541 {
00542    struct ast_channel *transferer;
00543    struct ast_channel *transferee;
00544    char *transferer_real_context;
00545    char newext[256];
00546    int res;
00547 
00548    if (sense == FEATURE_SENSE_PEER) {
00549       transferer = peer;
00550       transferee = chan;
00551    } else {
00552       transferer = chan;
00553       transferee = peer;
00554    }
00555    if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00556       !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00557       /* Use the non-macro context to transfer the call */
00558       if (!ast_strlen_zero(transferer->macrocontext))
00559          transferer_real_context = transferer->macrocontext;
00560       else
00561          transferer_real_context = transferer->context;
00562    }
00563    /* Start autoservice on chan while we talk
00564       to the originator */
00565    ast_indicate(transferee, AST_CONTROL_HOLD);
00566    ast_autoservice_start(transferee);
00567    ast_moh_start(transferee, NULL);
00568 
00569    memset(newext, 0, sizeof(newext));
00570    
00571    /* Transfer */
00572    if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00573       ast_moh_stop(transferee);
00574       ast_autoservice_stop(transferee);
00575       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00576       return res;
00577    }
00578    if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00579       ast_moh_stop(transferee);
00580       ast_autoservice_stop(transferee);
00581       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00582       return res;
00583    } else if (res > 0) {
00584       /* If they've typed a digit already, handle it */
00585       newext[0] = (char) res;
00586    }
00587 
00588    ast_stopstream(transferer);
00589    res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
00590    if (res < 0) {
00591       ast_moh_stop(transferee);
00592       ast_autoservice_stop(transferee);
00593       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00594       return res;
00595    }
00596    if (!strcmp(newext, ast_parking_ext())) {
00597       ast_moh_stop(transferee);
00598 
00599       res = ast_autoservice_stop(transferee);
00600       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00601       if (res)
00602          res = -1;
00603       else if (!ast_park_call(transferee, transferer, 0, NULL)) {
00604          /* We return non-zero, but tell the PBX not to hang the channel when
00605             the thread dies -- We have to be careful now though.  We are responsible for 
00606             hanging up the channel, else it will never be hung up! */
00607 
00608          if (transferer == peer)
00609             res = AST_PBX_KEEPALIVE;
00610          else
00611             res = AST_PBX_NO_HANGUP_PEER;
00612          return res;
00613       } else {
00614          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00615       }
00616       /* XXX Maybe we should have another message here instead of invalid extension XXX */
00617    } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
00618       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
00619       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00620       ast_moh_stop(transferee);
00621       res=ast_autoservice_stop(transferee);
00622       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00623       if (!transferee->pbx) {
00624          /* Doh!  Use our handy async_goto functions */
00625          if (option_verbose > 2) 
00626             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00627                         ,transferee->name, newext, transferer_real_context);
00628          if (ast_async_goto(transferee, transferer_real_context, newext, 1))
00629             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00630          res = -1;
00631       } else {
00632          /* Set the channel's new extension, since it exists, using transferer context */
00633          ast_copy_string(transferee->exten, newext, sizeof(transferee->exten));
00634          ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context));
00635          transferee->priority = 0;
00636       }
00637       check_goto_on_transfer(transferer);
00638       return res;
00639    } else {
00640       if (option_verbose > 2) 
00641          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
00642    }
00643    if (!ast_strlen_zero(xferfailsound))
00644       res = ast_streamfile(transferer, xferfailsound, transferer->language);
00645    else
00646       res = 0;
00647    if (res) {
00648       ast_moh_stop(transferee);
00649       ast_autoservice_stop(transferee);
00650       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00651       return res;
00652    }
00653    res = ast_waitstream(transferer, AST_DIGIT_ANY);
00654    ast_stopstream(transferer);
00655    ast_moh_stop(transferee);
00656    res = ast_autoservice_stop(transferee);
00657    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00658    if (res) {
00659       if (option_verbose > 1)
00660          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00661       return res;
00662    }
00663    return FEATURE_RETURN_SUCCESS;
00664 }

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

Definition at line 533 of file res_features.c.

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

00534 {
00535    if (option_verbose > 3)
00536       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00537    return FEATURE_RETURN_HANGUP;
00538 }

static void check_goto_on_transfer ( struct ast_channel chan  )  [static]

Definition at line 180 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_UP, ast_strlen_zero(), ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.

Referenced by builtin_blindtransfer().

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

char* description ( void   ) 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 2181 of file res_features.c.

02182 {
02183    return "Call Features Resource";
02184 }

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

Definition at line 1486 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_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_pbx_start(), ast_read(), ast_set_flag, ast_strdupa, ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::context, ast_channel::context, EVENT_FLAG_CALL, parkeduser::exten, ast_channel::exten, exten, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, FREE, ast_channel::generatordata, LOG_DEBUG, LOG_ERROR, LOG_WARNING, manager_event(), parkeduser::moh_trys, ast_channel::name, parkeduser::next, parkeduser::notquiteyet, option_verbose, parking_con, parking_con_dial, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, parkeduser::priority, ast_channel::priority, registrar, parkeduser::start, strdup, ast_frame::subclass, and VERBOSE_PREFIX_2.

Referenced by load_module().

01487 {
01488    int ms, tms, max;
01489    struct parkeduser *pu, *pl, *pt = NULL;
01490    struct timeval tv;
01491    struct ast_frame *f;
01492    char exten[AST_MAX_EXTENSION];
01493    char *peername,*cp;
01494    char returnexten[AST_MAX_EXTENSION];
01495    struct ast_context *con;
01496    int x;
01497    fd_set rfds, efds;
01498    fd_set nrfds, nefds;
01499    FD_ZERO(&rfds);
01500    FD_ZERO(&efds);
01501 
01502    for (;;) {
01503       ms = -1;
01504       max = -1;
01505       ast_mutex_lock(&parking_lock);
01506       pl = NULL;
01507       pu = parkinglot;
01508       FD_ZERO(&nrfds);
01509       FD_ZERO(&nefds);
01510       while(pu) {
01511          if (pu->notquiteyet) {
01512             /* Pretend this one isn't here yet */
01513             pl = pu;
01514             pu = pu->next;
01515             continue;
01516          }
01517          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01518          if (tms > pu->parkingtime) {
01519             /* Stop music on hold */
01520             ast_moh_stop(pu->chan);
01521             ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
01522             /* Get chan, exten from derived kludge */
01523             if (pu->peername[0]) {
01524                peername = ast_strdupa(pu->peername);
01525                cp = strrchr(peername, '-');
01526                if (cp) 
01527                   *cp = 0;
01528                con = ast_context_find(parking_con_dial);
01529                if (!con) {
01530                   con = ast_context_create(NULL, parking_con_dial, registrar);
01531                   if (!con) {
01532                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01533                   }
01534                }
01535                if (con) {
01536                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01537                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
01538                }
01539                ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
01540                ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
01541                pu->chan->priority = 1;
01542 
01543             } else {
01544                /* They've been waiting too long, send them back to where they came.  Theoretically they
01545                   should have their original extensions and such, but we copy to be on the safe side */
01546                ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
01547                ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
01548                pu->chan->priority = pu->priority;
01549             }
01550 
01551             manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
01552                "Exten: %d\r\n"
01553                "Channel: %s\r\n"
01554                "CallerID: %s\r\n"
01555                "CallerIDName: %s\r\n"
01556                ,pu->parkingnum, pu->chan->name
01557                ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01558                ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01559                );
01560 
01561             if (option_verbose > 1) 
01562                ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
01563             /* Start up the PBX, or hang them up */
01564             if (ast_pbx_start(pu->chan))  {
01565                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
01566                ast_hangup(pu->chan);
01567             }
01568             /* And take them out of the parking lot */
01569             if (pl) 
01570                pl->next = pu->next;
01571             else
01572                parkinglot = pu->next;
01573             pt = pu;
01574             pu = pu->next;
01575             con = ast_context_find(parking_con);
01576             if (con) {
01577                snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01578                if (ast_context_remove_extension2(con, exten, 1, NULL))
01579                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01580             } else
01581                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01582             free(pt);
01583          } else {
01584             for (x = 0; x < AST_MAX_FDS; x++) {
01585                if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
01586                   if (FD_ISSET(pu->chan->fds[x], &efds))
01587                      ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
01588                   else
01589                      ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
01590                   pu->chan->fdno = x;
01591                   /* See if they need servicing */
01592                   f = ast_read(pu->chan);
01593                   if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
01594                      if (f)
01595                         ast_frfree(f);
01596                      manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
01597                         "Exten: %d\r\n"
01598                         "Channel: %s\r\n"
01599                         "CallerID: %s\r\n"
01600                         "CallerIDName: %s\r\n"
01601                         ,pu->parkingnum, pu->chan->name
01602                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01603                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01604                         );
01605 
01606                      /* There's a problem, hang them up*/
01607                      if (option_verbose > 1) 
01608                         ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
01609                      ast_hangup(pu->chan);
01610                      /* And take them out of the parking lot */
01611                      if (pl) 
01612                         pl->next = pu->next;
01613                      else
01614                         parkinglot = pu->next;
01615                      pt = pu;
01616                      pu = pu->next;
01617                      con = ast_context_find(parking_con);
01618                      if (con) {
01619                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01620                         if (ast_context_remove_extension2(con, exten, 1, NULL))
01621                            ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01622                      } else
01623                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01624                      free(pt);
01625                      break;
01626                   } else {
01627                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01628                      ast_frfree(f);
01629                      if (pu->moh_trys < 3 && !pu->chan->generatordata) {
01630                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01631                         ast_moh_start(pu->chan, NULL);
01632                         pu->moh_trys++;
01633                      }
01634                      goto std;   /* XXX Ick: jumping into an else statement??? XXX */
01635                   }
01636                }
01637             }
01638             if (x >= AST_MAX_FDS) {
01639 std:              for (x=0; x<AST_MAX_FDS; x++) {
01640                   /* Keep this one for next one */
01641                   if (pu->chan->fds[x] > -1) {
01642                      FD_SET(pu->chan->fds[x], &nrfds);
01643                      FD_SET(pu->chan->fds[x], &nefds);
01644                      if (pu->chan->fds[x] > max)
01645                         max = pu->chan->fds[x];
01646                   }
01647                }
01648                /* Keep track of our longest wait */
01649                if ((tms < ms) || (ms < 0))
01650                   ms = tms;
01651                pl = pu;
01652                pu = pu->next;
01653             }
01654          }
01655       }
01656       ast_mutex_unlock(&parking_lock);
01657       rfds = nrfds;
01658       efds = nefds;
01659       tv = ast_samp2tv(ms, 1000);
01660       /* Wait for something to happen */
01661       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01662       pthread_testcancel();
01663    }
01664    return NULL;   /* Never reached */
01665 }

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

Definition at line 927 of file res_features.c.

References ast_call_feature::app, app, ast_call_feature::app_args, AST_FEATURE_FLAG_CALLEE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_test_flag, ast_call_feature::exten, FEATURE_RETURN_NO_HANGUP_PEER, FEATURE_RETURN_PBX_KEEPALIVE, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, LOG_NOTICE, LOG_WARNING, pbx_exec(), and pbx_findapp().

Referenced by load_config().

00928 {
00929    struct ast_app *app;
00930    struct ast_call_feature *feature;
00931    int res;
00932 
00933    AST_LIST_LOCK(&feature_list);
00934    AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
00935       if (!strcasecmp(feature->exten,code)) break;
00936    }
00937    AST_LIST_UNLOCK(&feature_list);
00938 
00939    if (!feature) { /* shouldn't ever happen! */
00940       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
00941       return -1; 
00942    }
00943    
00944    app = pbx_findapp(feature->app);
00945    if (app) {
00946       struct ast_channel *work = chan;
00947       if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
00948          work = peer;
00949       res = pbx_exec(work, app, feature->app_args, 1);
00950       if (res == AST_PBX_KEEPALIVE)
00951          return FEATURE_RETURN_PBX_KEEPALIVE;
00952       else if (res == AST_PBX_NO_HANGUP_PEER)
00953          return FEATURE_RETURN_NO_HANGUP_PEER;
00954       else if (res)
00955          return FEATURE_RETURN_SUCCESSBREAK;
00956    } else {
00957       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
00958       return -2;
00959    }
00960    
00961    return FEATURE_RETURN_SUCCESS;
00962 }

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

Definition at line 912 of file res_features.c.

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

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

00913 {
00914    struct ast_call_feature *tmp;
00915 
00916    AST_LIST_LOCK(&feature_list);
00917    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00918       if (!strcasecmp(tmp->sname, name))
00919          break;
00920    }
00921    AST_LIST_UNLOCK(&feature_list);
00922 
00923    return tmp;
00924 }

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

Definition at line 1853 of file res_features.c.

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

01854 {
01855    struct parkeduser *cur;
01856    int numparked = 0;
01857 
01858    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01859       , "Context", "Extension", "Pri", "Timeout");
01860 
01861    ast_mutex_lock(&parking_lock);
01862 
01863    cur = parkinglot;
01864    while(cur) {
01865       ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
01866          ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
01867          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01868 
01869       cur = cur->next;
01870       numparked++;
01871    }
01872    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01873 
01874    ast_mutex_unlock(&parking_lock);
01875 
01876    return RESULT_SUCCESS;
01877 }

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

Definition at line 1805 of file res_features.c.

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

01806 {
01807    int i;
01808    int fcount;
01809    struct ast_call_feature *feature;
01810    char format[] = "%-25s %-7s %-7s\n";
01811 
01812    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01813    ast_cli(fd, format, "---------------", "-------", "-------");
01814 
01815    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01816 
01817    fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01818 
01819    for (i = 0; i < fcount; i++)
01820    {
01821       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01822    }
01823    ast_cli(fd, "\n");
01824    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01825    ast_cli(fd, format, "---------------", "-------", "-------");
01826    if (AST_LIST_EMPTY(&feature_list)) {
01827       ast_cli(fd, "(none)\n");
01828    }
01829    else {
01830       AST_LIST_LOCK(&feature_list);
01831       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01832          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01833       }
01834       AST_LIST_UNLOCK(&feature_list);
01835    }
01836    ast_cli(fd, "\nCall parking\n");
01837    ast_cli(fd, "------------\n");
01838    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01839    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01840    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01841    ast_cli(fd,"\n");
01842    
01843    return RESULT_SUCCESS;
01844 }

char* key ( void   ) 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 2199 of file res_features.c.

References ASTERISK_GPL_KEY.

02200 {
02201    return ASTERISK_GPL_KEY;
02202 }

static int load_config ( void   )  [static]

Definition at line 1965 of file res_features.c.

References adsipark, ast_call_feature::app, app, ast_call_feature::app_args, ast_add_extension2(), ast_config_destroy(), ast_config_load(), ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_FEATURE_FLAG_CALLEE, AST_FEATURE_FLAG_CALLER, AST_FEATURE_FLAG_NEEDSDTMF, ast_log(), AST_MAX_EXTENSION, ast_parking_ext(), ast_register_feature(), ast_set_flag, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_variable_browse(), ast_verbose(), cfg, courtesytone, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_PARK_TIME, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_SNAME_LEN, featuredigittimeout, find_feature(), FREE, free, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, ast_call_feature::operation, option_verbose, parkcall, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkingtime, pickup_ext, registrar, remap_feature(), ast_call_feature::sname, strdup, strsep(), transferdigittimeout, unmap_features(), var, VERBOSE_PREFIX_2, xferfailsound, and xfersound.

01966 {
01967    int start = 0, end = 0;
01968    struct ast_context *con = NULL;
01969    struct ast_config *cfg = NULL;
01970    struct ast_variable *var = NULL;
01971    char old_parking_ext[AST_MAX_EXTENSION];
01972    char old_parking_con[AST_MAX_EXTENSION] = "";
01973 
01974    if (!ast_strlen_zero(parking_con)) {
01975       strcpy(old_parking_ext, parking_ext);
01976       strcpy(old_parking_con, parking_con);
01977    } 
01978 
01979    /* Reset to defaults */
01980    strcpy(parking_con, "parkedcalls");
01981    strcpy(parking_con_dial, "park-dial");
01982    strcpy(parking_ext, "700");
01983    strcpy(pickup_ext, "*8");
01984    courtesytone[0] = '\0';
01985    strcpy(xfersound, "beep");
01986    strcpy(xferfailsound, "pbx-invalid");
01987    parking_start = 701;
01988    parking_stop = 750;
01989    parkfindnext = 0;
01990    adsipark = 0;
01991 
01992    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
01993    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
01994 
01995    cfg = ast_config_load("features.conf");
01996    if (!cfg) {
01997       cfg = ast_config_load("parking.conf");
01998       if (cfg)
01999          ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
02000    }
02001    if (cfg) {
02002       var = ast_variable_browse(cfg, "general");
02003       while(var) {
02004          if (!strcasecmp(var->name, "parkext")) {
02005             ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02006          } else if (!strcasecmp(var->name, "context")) {
02007             ast_copy_string(parking_con, var->value, sizeof(parking_con));
02008          } else if (!strcasecmp(var->name, "parkingtime")) {
02009             if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02010                ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02011                parkingtime = DEFAULT_PARK_TIME;
02012             } else
02013                parkingtime = parkingtime * 1000;
02014          } else if (!strcasecmp(var->name, "parkpos")) {
02015             if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02016                ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno);
02017             } else {
02018                parking_start = start;
02019                parking_stop = end;
02020             }
02021          } else if (!strcasecmp(var->name, "findslot")) {
02022             parkfindnext = (!strcasecmp(var->value, "next"));
02023          } else if (!strcasecmp(var->name, "adsipark")) {
02024             adsipark = ast_true(var->value);
02025          } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02026             if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02027                ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02028                transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02029             } else
02030                transferdigittimeout = transferdigittimeout * 1000;
02031          } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02032             if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02033                ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02034                featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02035             }
02036          } else if (!strcasecmp(var->name, "courtesytone")) {
02037             ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02038          } else if (!strcasecmp(var->name, "xfersound")) {
02039             ast_copy_string(xfersound, var->value, sizeof(xfersound));
02040          } else if (!strcasecmp(var->name, "xferfailsound")) {
02041             ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02042          } else if (!strcasecmp(var->name, "pickupexten")) {
02043             ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02044          }
02045          var = var->next;
02046       }
02047 
02048       unmap_features();
02049       var = ast_variable_browse(cfg, "featuremap");
02050       while(var) {
02051          if (remap_feature(var->name, var->value))
02052             ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02053          var = var->next;
02054       }
02055 
02056       /* Map a key combination to an application*/
02057       ast_unregister_features();
02058       var = ast_variable_browse(cfg, "applicationmap");
02059       while(var) {
02060          char *tmp_val=strdup(var->value);
02061          char *exten, *party=NULL, *app=NULL, *app_args=NULL; 
02062 
02063          if (!tmp_val) { 
02064             ast_log(LOG_ERROR, "res_features: strdup failed");
02065             continue;
02066          }
02067          
02068 
02069          exten=strsep(&tmp_val,",");
02070          if (exten) party=strsep(&tmp_val,",");
02071          if (party) app=strsep(&tmp_val,",");
02072 
02073          if (app) app_args=strsep(&tmp_val,",");
02074 
02075          if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
02076             ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",app,exten,party,var->name);
02077             free(tmp_val);
02078             var = var->next;
02079             continue;
02080          }
02081 
02082          {
02083             struct ast_call_feature *feature=find_feature(var->name);
02084             int mallocd=0;
02085             
02086             if (!feature) {
02087                feature=malloc(sizeof(struct ast_call_feature));
02088                mallocd=1;
02089             }
02090             if (!feature) {
02091                ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n");
02092                free(tmp_val);
02093                var = var->next;
02094                continue;
02095             }
02096 
02097             memset(feature,0,sizeof(struct ast_call_feature));
02098             ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
02099             ast_copy_string(feature->app,app,FEATURE_APP_LEN);
02100             ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
02101             free(tmp_val);
02102             
02103             if (app_args) 
02104                ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
02105             
02106             ast_copy_string(feature->exten, exten,sizeof(feature->exten));
02107             feature->operation=feature_exec_app;
02108             ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
02109             
02110             if (!strcasecmp(party,"caller"))
02111                ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
02112             else if (!strcasecmp(party, "callee"))
02113                ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
02114             else {
02115                ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
02116                var = var->next;
02117                continue;
02118             }
02119 
02120             ast_register_feature(feature);
02121             
02122             if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);  
02123          }
02124          var = var->next;
02125       }   
02126    }
02127    ast_config_destroy(cfg);
02128 
02129    /* Remove the old parking extension */
02130    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02131       ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
02132       ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02133    }
02134    
02135    if (!(con = ast_context_find(parking_con))) {
02136       if (!(con = ast_context_create(NULL, parking_con, registrar))) {
02137          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02138          return -1;
02139       }
02140    }
02141    return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
02142 }

int load_module ( void   ) 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 2148 of file res_features.c.

References ast_cli_register(), ast_manager_register, ast_pthread_create, ast_register_application(), descrip, descrip2, do_parking_thread(), load_config(), manager_parking_status(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, showfeatures, showparked, synopsis, and synopsis2.

02149 {
02150    int res;
02151    
02152    memset(parking_ext, 0, sizeof(parking_ext));
02153    memset(parking_con, 0, sizeof(parking_con));
02154 
02155    if ((res = load_config()))
02156       return res;
02157    ast_cli_register(&showparked);
02158    ast_cli_register(&showfeatures);
02159    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02160    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02161    if (!res)
02162       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02163    if (!res) {
02164       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02165    }
02166    return res;
02167 }

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

Definition at line 1887 of file res_features.c.

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

Referenced by load_module().

01888 {
01889    struct parkeduser *cur;
01890    char *id = astman_get_header(m,"ActionID");
01891    char idText[256] = "";
01892 
01893    if (!ast_strlen_zero(id))
01894       snprintf(idText,256,"ActionID: %s\r\n",id);
01895 
01896    astman_send_ack(s, m, "Parked calls will follow");
01897 
01898         ast_mutex_lock(&parking_lock);
01899 
01900         cur=parkinglot;
01901         while(cur) {
01902          ast_cli(s->fd, "Event: ParkedCall\r\n"
01903          "Exten: %d\r\n"
01904          "Channel: %s\r\n"
01905          "Timeout: %ld\r\n"
01906          "CallerID: %s\r\n"
01907          "CallerIDName: %s\r\n"
01908          "%s"
01909          "\r\n"
01910                         ,cur->parkingnum, cur->chan->name
01911                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
01912          ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
01913          ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
01914          ,idText);
01915 
01916             cur = cur->next;
01917         }
01918 
01919    ast_cli(s->fd,
01920    "Event: ParkedCallsComplete\r\n"
01921    "%s"
01922    "\r\n",idText);
01923 
01924         ast_mutex_unlock(&parking_lock);
01925 
01926         return RESULT_SUCCESS;
01927 }

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

Definition at line 1667 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_park_call(), AST_PBX_KEEPALIVE, ast_safe_sleep(), AST_STATE_UP, localuser::chan, ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, and ast_channel::priority.

Referenced by load_module().

01668 {
01669    /* Data is unused at the moment but could contain a parking
01670       lot context eventually */
01671    int res=0;
01672    struct localuser *u;
01673    LOCAL_USER_ADD(u);
01674    /* Setup the exten/priority to be s/1 since we don't know
01675       where this call should return */
01676    strcpy(chan->exten, "s");
01677    chan->priority = 1;
01678    if (chan->_state != AST_STATE_UP)
01679       res = ast_answer(chan);
01680    if (!res)
01681       res = ast_safe_sleep(chan, 1000);
01682    if (!res)
01683       res = ast_park_call(chan, chan, 0, NULL);
01684    LOCAL_USER_REMOVE(u);
01685    if (!res)
01686       res = AST_PBX_KEEPALIVE;
01687    return res;
01688 }

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

Definition at line 1690 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, EVENT_FLAG_CALL, exten, free, ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, option_verbose, parking_con, parkinglot, parkeduser::parkingnum, and VERBOSE_PREFIX_3.

Referenced by load_module().

01691 {
01692    int res=0;
01693    struct localuser *u;
01694    struct ast_channel *peer=NULL;
01695    struct parkeduser *pu, *pl=NULL;
01696    char exten[AST_MAX_EXTENSION];
01697    struct ast_context *con;
01698    int park;
01699    int dres;
01700    struct ast_bridge_config config;
01701 
01702    if (!data) {
01703       ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
01704       return -1;
01705    }
01706    LOCAL_USER_ADD(u);
01707    park = atoi((char *)data);
01708    ast_mutex_lock(&parking_lock);
01709    pu = parkinglot;
01710    while(pu) {
01711       if (pu->parkingnum == park) {
01712          if (pl)
01713             pl->next = pu->next;
01714          else
01715             parkinglot = pu->next;
01716          break;
01717       }
01718       pl = pu;
01719       pu = pu->next;
01720    }
01721    ast_mutex_unlock(&parking_lock);
01722    if (pu) {
01723       peer = pu->chan;
01724       con = ast_context_find(parking_con);
01725       if (con) {
01726          snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
01727          if (ast_context_remove_extension2(con, exten, 1, NULL))
01728             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01729       } else
01730          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01731 
01732       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01733          "Exten: %d\r\n"
01734          "Channel: %s\r\n"
01735          "From: %s\r\n"
01736          "CallerID: %s\r\n"
01737          "CallerIDName: %s\r\n"
01738          ,pu->parkingnum, pu->chan->name, chan->name
01739          ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01740          ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01741          );
01742 
01743       free(pu);
01744    }
01745    /* JK02: it helps to answer the channel if not already up */
01746    if (chan->_state != AST_STATE_UP) {
01747       ast_answer(chan);
01748    }
01749 
01750    if (peer) {
01751       /* Play a courtesy beep in the calling channel to prefix the bridge connecting */   
01752       if (!ast_strlen_zero(courtesytone)) {
01753          if (!ast_streamfile(chan, courtesytone, chan->language)) {
01754             if (ast_waitstream(chan, "") < 0) {
01755                ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01756                ast_hangup(peer);
01757                return -1;
01758             }
01759          }
01760       }
01761  
01762       ast_moh_stop(peer);
01763       ast_indicate(peer, AST_CONTROL_UNHOLD);
01764       res = ast_channel_make_compatible(chan, peer);
01765       if (res < 0) {
01766          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01767          ast_hangup(peer);
01768          return -1;
01769       }
01770       /* This runs sorta backwards, since we give the incoming channel control, as if it
01771          were the person called. */
01772       if (option_verbose > 2) 
01773          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01774 
01775       memset(&config, 0, sizeof(struct ast_bridge_config));
01776       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01777       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01778       config.timelimit = 0;
01779       config.play_warning = 0;
01780       config.warning_freq = 0;
01781       config.warning_sound=NULL;
01782       res = ast_bridge_call(chan, peer, &config);
01783 
01784       /* Simulate the PBX hanging up */
01785       if (res != AST_PBX_NO_HANGUP_PEER)
01786          ast_hangup(peer);
01787       return res;
01788    } else {
01789       /* XXX Play a message XXX */
01790       dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
01791       if (!dres)
01792             dres = ast_waitstream(chan, "");
01793       else {
01794          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01795          dres = 0;
01796       }
01797       if (option_verbose > 2) 
01798          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01799       res = -1;
01800    }
01801    LOCAL_USER_REMOVE(u);
01802    return res;
01803 }

int reload ( void   ) 

Reload stuff.

This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.

Returns:
The return value is not used.

Definition at line 2144 of file res_features.c.

References load_config().

02144                  {
02145    return load_config();
02146 }

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

Definition at line 971 of file res_features.c.

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

Referenced by load_config().

00972 {
00973    int x;
00974    int res = -1;
00975    for (x = 0; x < FEATURES_COUNT; x++) {
00976       if (!strcasecmp(name, builtin_features[x].sname)) {
00977          ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
00978          if (option_verbose > 1)
00979             ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
00980          res = 0;
00981       } else if (!strcmp(value, builtin_features[x].exten)) 
00982          ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name);
00983    }
00984    return res;
00985 }

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

Definition at line 1046 of file res_features.c.

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

Referenced by ast_bridge_call().

01047 {
01048    int x;
01049    
01050    ast_clear_flag(config, AST_FLAGS_ALL); 
01051    for (x = 0; x < FEATURES_COUNT; x++) {
01052       if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
01053          if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01054             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01055 
01056          if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01057             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01058       }
01059    }
01060    
01061    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01062       char *dynamic_features;
01063 
01064       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01065 
01066       if (dynamic_features) {
01067          char *tmp = ast_strdupa(dynamic_features);
01068          char *tok;
01069          struct ast_call_feature *feature;
01070 
01071          if (!tmp) {
01072             return;
01073          }
01074 
01075          /* while we have a feature */
01076          while (NULL != (tok = strsep(&tmp, "#"))) {
01077             if ((feature = find_feature(tok))) {
01078                if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01079                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
01080                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01081                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
01082                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01083                }
01084             }
01085          }
01086       }
01087    }
01088 }

int unload_module ( void   ) 

Cleanup all module structures, sockets, etc.

Standard module functions ...

Definition at line 2170 of file res_features.c.

References ast_cli_unregister(), ast_manager_unregister(), ast_unregister_application(), parkcall, parkedcall, showfeatures, showparked, and STANDARD_HANGUP_LOCALUSERS.

static void unmap_features ( void   )  [static]

Definition at line 964 of file res_features.c.

References builtin_features, exten, and FEATURES_COUNT.

Referenced by load_config().

00965 {
00966    int x;
00967    for (x = 0; x < FEATURES_COUNT; x++)
00968       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
00969 }

int usecount ( void   ) 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 2186 of file res_features.c.

References STANDARD_USECOUNT.

02187 {
02188    /* Never allow parking to be unloaded because it will
02189       unresolve needed symbols in the dialer */
02190 #if 0
02191    int res;
02192    STANDARD_USECOUNT(res);
02193    return res;
02194 #else
02195    return 1;
02196 #endif
02197 }


Variable Documentation

int adsipark [static]

Definition at line 106 of file res_features.c.

Referenced by load_config().

struct ast_call_feature builtin_features[]

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

char courtesytone[256] [static]

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

char* descrip2 [static]

Definition at line 128 of file res_features.c.

int featuredigittimeout [static]

Definition at line 109 of file res_features.c.

Referenced by ast_bridge_call(), and load_config().

LOCAL_USER_DECL

Definition at line 161 of file res_features.c.

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.

Referenced by ast_bridge_call().

char* parkcall = "Park" [static]

Definition at line 124 of file res_features.c.

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

char* parkedcall = "ParkedCall" [static]

Definition at line 75 of file res_features.c.

Referenced by load_module(), and unload_module().

int parkfindnext [static]

Definition at line 104 of file res_features.c.

Referenced by load_config().

char parking_con[AST_MAX_EXTENSION] [static]

Definition at line 81 of file res_features.c.

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

char parking_con_dial[AST_MAX_EXTENSION] [static]

Definition at line 84 of file res_features.c.

Referenced by do_parking_thread(), and load_config().

char parking_ext[AST_MAX_EXTENSION] [static]

Definition at line 87 of file res_features.c.

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

int parking_offset [static]

Definition at line 102 of file res_features.c.

int parking_start [static]

Definition at line 97 of file res_features.c.

Referenced by handle_showfeatures(), and load_config().

int parking_stop [static]

Definition at line 100 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 ast_park_call(), do_parking_thread(), handle_parkedcalls(), manager_parking_status(), and park_exec().

int parkingtime = DEFAULT_PARK_TIME [static]

Definition at line 78 of file res_features.c.

Referenced by load_config().

char pickup_ext[AST_MAX_EXTENSION] [static]

Definition at line 89 of file res_features.c.

Referenced by load_config().

char* registrar = "res_features" [static]

Definition at line 114 of file res_features.c.

struct ast_cli_entry showfeatures [static]

Initial value:

{ { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help }

Definition at line 1850 of file res_features.c.

Referenced by load_module(), and unload_module().

char showfeatures_help[] [static]

Initial value:

"Usage: show features\n"
"       Lists currently configured features.\n"

Definition at line 1846 of file res_features.c.

struct ast_cli_entry showparked [static]

Initial value:

{ { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help }

Definition at line 1883 of file res_features.c.

Referenced by load_module(), and unload_module().

char showparked_help[] [static]

Initial value:

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

Definition at line 1879 of file res_features.c.

STANDARD_LOCAL_USER

Definition at line 159 of file res_features.c.

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

Definition at line 116 of file res_features.c.

char* synopsis2 = "Park yourself" [static]

Definition at line 126 of file res_features.c.

int transferdigittimeout [static]

Definition at line 108 of file res_features.c.

Referenced by load_config().

char xferfailsound[256] [static]

Definition at line 94 of file res_features.c.

Referenced by load_config().

char xfersound[256] [static]

Definition at line 93 of file res_features.c.

Referenced by load_config().


Generated on Thu May 24 14:23:13 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.7