Mon Mar 20 08:26:03 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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"

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

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.
void * ast_bridge_call_thread (void *data)
void ast_bridge_call_thread_launch (void *data)
int ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
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)
 AST_LIST_HEAD (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_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set
void ast_unregister_features (void)
int builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
int builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
int builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
int builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
void check_goto_on_transfer (struct ast_channel *chan)
char * description (void)
 Provides a description of the module.
void * do_parking_thread (void *ignore)
int feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
ast_call_featurefind_feature (char *name)
int handle_parkedcalls (int fd, int argc, char *argv[])
int handle_showfeatures (int fd, int argc, char *argv[])
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_config (void)
int load_module (void)
 Initialize the module.
int manager_parking_status (struct mansession *s, struct message *m)
int park_call_exec (struct ast_channel *chan, void *data)
int park_exec (struct ast_channel *chan, void *data)
int reload (void)
 Reload stuff.
int remap_feature (const char *name, const char *value)
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.
void unmap_features (void)
int usecount (void)
 Provides a usecount.

Variables

int adsipark
ast_call_feature builtin_features []
char courtesytone [256]
char * descrip
char * descrip2
int featuredigittimeout
 LOCAL_USER_DECL
ast_appmonitor_app = NULL
int monitor_ok = 1
char * parkcall = "Park"
char * parkedcall = "ParkedCall"
int parkfindnext
char parking_con [AST_MAX_EXTENSION]
char parking_con_dial [AST_MAX_EXTENSION]
char parking_ext [AST_MAX_EXTENSION]
int parking_offset
int parking_start
int parking_stop
pthread_t parking_thread
parkeduserparkinglot
int parkingtime = DEFAULT_PARK_TIME
char pickup_ext [AST_MAX_EXTENSION]
char * registrar = "res_features"
ast_cli_entry showfeatures
char showfeatures_help []
ast_cli_entry showparked
char showparked_help []
 STANDARD_LOCAL_USER
char * synopsis = "Answer a parked call"
char * synopsis2 = "Park yourself"
int transferdigittimeout
char xferfailsound [256]
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.

#define DEFAULT_PARK_TIME   45000
 

Definition at line 69 of file res_features.c.

#define DEFAULT_TRANSFER_DIGIT_TIMEOUT   3000
 

Definition at line 70 of file res_features.c.

#define FEATURE_RETURN_HANGUP   -1
 

Definition at line 435 of file res_features.c.

#define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
 

Definition at line 438 of file res_features.c.

#define FEATURE_RETURN_PASSDIGITS   21
 

Definition at line 439 of file res_features.c.

Referenced by ast_bridge_call().

#define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
 

Definition at line 437 of file res_features.c.

#define FEATURE_RETURN_STOREDIGITS   22
 

Definition at line 440 of file res_features.c.

#define FEATURE_RETURN_SUCCESS   23
 

Definition at line 441 of file res_features.c.

Referenced by ast_bridge_call().

#define FEATURE_RETURN_SUCCESSBREAK   0
 

Definition at line 436 of file res_features.c.

#define FEATURE_SENSE_CHAN   (1 << 0)
 

Definition at line 443 of file res_features.c.

#define FEATURE_SENSE_PEER   (1 << 1)
 

Definition at line 444 of file res_features.c.

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

Definition at line 859 of file res_features.c.

#define FREE   free
 

Definition at line 66 of file res_features.c.


Function Documentation

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(), and adsi_print().

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 1251 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_FLASH, AST_CONTROL_RINGING, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, ast_frfree(), ast_indicate(), ast_log(), ast_strlen_zero(), ast_channel::cdr, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_bridge_config::end_sound, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_option_header::option, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, set_config_flags(), ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::userfield, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

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

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

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 }

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 }

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 980 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, ast_call_feature::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, find_feature(), ast_flags::flags, LOG_DEBUG, ast_channel::name, ast_call_feature::operation, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, strsep(), and VERBOSE_PREFIX_3.

Referenced by ast_bridge_call().

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

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 1081 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_RINGING, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), ast_verbose(), ast_waitfor_n(), builtin_features, ast_channel::cdr, ast_call_feature::exten, ast_frame::frametype, ast_channel::hangupcause, LOG_NOTICE, LOG_WARNING, option_verbose, ast_frame::subclass, type, and VERBOSE_PREFIX_3.

Referenced by builtin_atxfer().

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

AST_LIST_HEAD   feature_list,
ast_call_feature 
[static]
 

Definition at line 869 of file res_features.c.

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

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

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(), adsipark, ast_channel::appl, ast_add_extension2(), ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_indicate(), ast_log(), 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, FREE, free, ast_channel::language, 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, parkedcall, parking_con, parking_offset, parking_start, parking_stop, parking_thread, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, ast_channel::priority, parkeduser::priority, registrar, 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->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 1915 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_channel::callgroup, ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::name, ast_channel::pbx, and ast_channel::pickupgroup.

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

01916 {
01917    struct ast_channel *cur = NULL;
01918    int res = -1;
01919 
01920    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01921       if (!cur->pbx && 
01922          (cur != chan) &&
01923          (chan->pickupgroup & cur->callgroup) &&
01924          ((cur->_state == AST_STATE_RINGING) ||
01925           (cur->_state == AST_STATE_RING))) {
01926             break;
01927       }
01928       ast_mutex_unlock(&cur->lock);
01929    }
01930    if (cur) {
01931       if (option_debug)
01932          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01933       res = ast_answer(chan);
01934       if (res)
01935          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01936       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01937       if (res)
01938          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01939       res = ast_channel_masquerade(cur, chan);
01940       if (res)
01941          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
01942       ast_mutex_unlock(&cur->lock);
01943    } else   {
01944       if (option_debug)
01945          ast_log(LOG_DEBUG, "No call pickup possible...\n");
01946    }
01947    return res;
01948 }

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

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00889 {
00890    if (!feature) return;
00891 
00892    AST_LIST_LOCK(&feature_list);
00893    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00894    AST_LIST_UNLOCK(&feature_list);
00895    free(feature);
00896 }

void ast_unregister_features void   )  [static]
 

Definition at line 898 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

Referenced by load_config().

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

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, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, malloc, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, transferdigittimeout, ast_channel::writeformat, xferfailsound, and xfersound.

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 courtesy tone!\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 courtesy tone!\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       res = ast_streamfile(transferer, "beeperr", transferer->language);
00846       if (ast_waitstream(transferer, "") < 0) {
00847          return -1;
00848       }
00849    }
00850    ast_moh_stop(transferee);
00851    ast_autoservice_stop(transferee);
00852    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00853 
00854    return FEATURE_RETURN_SUCCESS;
00855 }

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, courtesytone, ast_channel::language, LOG_ERROR, LOG_NOTICE, LOG_WARNING, monitor_app, monitor_ok, 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 }

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_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, 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, transferdigittimeout, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and xferfailsound.

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, transferee->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 }

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(), 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 }

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

02167 {
02168    return "Call Features Resource";
02169 }

void* do_parking_thread void *  ignore  )  [static]
 

Definition at line 1471 of file res_features.c.

References ast_add_extension2(), ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_read(), ast_select(), 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, 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, tv, and VERBOSE_PREFIX_2.

Referenced by load_module().

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

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

References ast_call_feature::app, ast_call_feature::app_args, AST_FEATURE_FLAG_CALLEE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_test_flag, ast_call_feature::exten, LOG_NOTICE, LOG_WARNING, pbx_exec(), and pbx_findapp().

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

struct ast_call_feature* find_feature char *  name  )  [static]
 

Definition at line 909 of file res_features.c.

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

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

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

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

Definition at line 1838 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, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::priority, and parkeduser::start.

01839 {
01840    struct parkeduser *cur;
01841    int numparked = 0;
01842 
01843    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01844       , "Context", "Extension", "Pri", "Timeout");
01845 
01846    ast_mutex_lock(&parking_lock);
01847 
01848    cur = parkinglot;
01849    while(cur) {
01850       ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
01851          ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
01852          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01853 
01854       cur = cur->next;
01855       numparked++;
01856    }
01857    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01858 
01859    ast_mutex_unlock(&parking_lock);
01860 
01861    return RESULT_SUCCESS;
01862 }

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

Definition at line 1790 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::exten, parking_con, parking_ext, parking_start, parking_stop, and ast_call_feature::sname.

01791 {
01792    int i;
01793    int fcount;
01794    struct ast_call_feature *feature;
01795    char format[] = "%-25s %-7s %-7s\n";
01796 
01797    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01798    ast_cli(fd, format, "---------------", "-------", "-------");
01799 
01800    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01801 
01802    fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01803 
01804    for (i = 0; i < fcount; i++)
01805    {
01806       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01807    }
01808    ast_cli(fd, "\n");
01809    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01810    ast_cli(fd, format, "---------------", "-------", "-------");
01811    if (AST_LIST_EMPTY(&feature_list)) {
01812       ast_cli(fd, "(none)\n");
01813    }
01814    else {
01815       AST_LIST_LOCK(&feature_list);
01816       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01817          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01818       }
01819       AST_LIST_UNLOCK(&feature_list);
01820    }
01821    ast_cli(fd, "\nCall parking\n");
01822    ast_cli(fd, "------------\n");
01823    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01824    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01825    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01826    ast_cli(fd,"\n");
01827    
01828    return RESULT_SUCCESS;
01829 }

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

02185 {
02186    return ASTERISK_GPL_KEY;
02187 }

int load_config void   )  [static]
 

Definition at line 1950 of file res_features.c.

References adsipark, ast_call_feature::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_parking_ext(), ast_register_feature(), ast_set_flag, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_variable_browse(), ast_verbose(), cfg, courtesytone, ast_call_feature::exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, FEATURE_EXTEN_LEN, FEATURE_SNAME_LEN, featuredigittimeout, find_feature(), FREE, free, ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, ast_variable::name, ast_variable::next, 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(), ast_variable::value, var, VERBOSE_PREFIX_2, xferfailsound, and xfersound.

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

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

References ast_cli_register(), AST_LIST_HEAD_INIT, 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.

02133 {
02134    int res;
02135    
02136    AST_LIST_HEAD_INIT(&feature_list);
02137    memset(parking_ext, 0, sizeof(parking_ext));
02138    memset(parking_con, 0, sizeof(parking_con));
02139 
02140    if ((res = load_config()))
02141       return res;
02142    ast_cli_register(&showparked);
02143    ast_cli_register(&showfeatures);
02144    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02145    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02146    if (!res)
02147       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02148    if (!res) {
02149       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02150    }
02151    return res;
02152 }

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

Definition at line 1872 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, mansession::fd, ast_channel::name, parkeduser::next, parkeduser::parkingnum, parkeduser::parkingtime, s, and parkeduser::start.

Referenced by load_module().

01873 {
01874    struct parkeduser *cur;
01875    char *id = astman_get_header(m,"ActionID");
01876    char idText[256] = "";
01877 
01878    if (!ast_strlen_zero(id))
01879       snprintf(idText,256,"ActionID: %s\r\n",id);
01880 
01881    astman_send_ack(s, m, "Parked calls will follow");
01882 
01883         ast_mutex_lock(&parking_lock);
01884 
01885         cur=parkinglot;
01886         while(cur) {
01887          ast_cli(s->fd, "Event: ParkedCall\r\n"
01888          "Exten: %d\r\n"
01889          "Channel: %s\r\n"
01890          "Timeout: %ld\r\n"
01891          "CallerID: %s\r\n"
01892          "CallerIDName: %s\r\n"
01893          "%s"
01894          "\r\n"
01895                         ,cur->parkingnum, cur->chan->name
01896                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
01897          ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
01898          ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
01899          ,idText);
01900 
01901             cur = cur->next;
01902         }
01903 
01904    ast_cli(s->fd,
01905    "Event: ParkedCallsComplete\r\n"
01906    "%s"
01907    "\r\n",idText);
01908 
01909         ast_mutex_unlock(&parking_lock);
01910 
01911         return RESULT_SUCCESS;
01912 }

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

Definition at line 1652 of file res_features.c.

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

Referenced by load_module().

01653 {
01654    /* Data is unused at the moment but could contain a parking
01655       lot context eventually */
01656    int res=0;
01657    struct localuser *u;
01658    LOCAL_USER_ADD(u);
01659    /* Setup the exten/priority to be s/1 since we don't know
01660       where this call should return */
01661    strcpy(chan->exten, "s");
01662    chan->priority = 1;
01663    if (chan->_state != AST_STATE_UP)
01664       res = ast_answer(chan);
01665    if (!res)
01666       res = ast_safe_sleep(chan, 1000);
01667    if (!res)
01668       res = ast_park_call(chan, chan, 0, NULL);
01669    LOCAL_USER_REMOVE(u);
01670    if (!res)
01671       res = AST_PBX_KEEPALIVE;
01672    return res;
01673 }

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

Definition at line 1675 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_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, courtesytone, EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, 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, ast_bridge_config::play_warning, ast_bridge_config::timelimit, VERBOSE_PREFIX_3, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by load_module().

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

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

References load_config().

02128                  {
02129    return load_config();
02130 }

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

Definition at line 964 of file res_features.c.

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

Referenced by load_config().

00965 {
00966    int x;
00967    int res = -1;
00968    for (x = 0; x < FEATURES_COUNT; x++) {
00969       if (!strcasecmp(name, builtin_features[x].sname)) {
00970          ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
00971          if (option_verbose > 1)
00972             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);
00973          res = 0;
00974       } else if (!strcmp(value, builtin_features[x].exten)) 
00975          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);
00976    }
00977    return res;
00978 }

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

Definition at line 1036 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, ast_call_feature::feature_mask, ast_bridge_config::features_callee, ast_bridge_config::features_caller, find_feature(), pbx_builtin_getvar_helper(), and strsep().

Referenced by ast_bridge_call().

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

int unload_module void   ) 
 

Cleanup all module structures, sockets, etc.

Standard module functions ...

Definition at line 2155 of file res_features.c.

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

02156 {
02157    STANDARD_HANGUP_LOCALUSERS;
02158 
02159    ast_manager_unregister("ParkedCalls");
02160    ast_cli_unregister(&showfeatures);
02161    ast_cli_unregister(&showparked);
02162    ast_unregister_application(parkcall);
02163    return ast_unregister_application(parkedcall);
02164 }

void unmap_features void   )  [static]
 

Definition at line 957 of file res_features.c.

References builtin_features.

Referenced by load_config().

00958 {
00959    int x;
00960    for (x = 0; x < FEATURES_COUNT; x++)
00961       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
00962 }

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

References STANDARD_USECOUNT.

02172 {
02173    /* Never allow parking to be unloaded because it will
02174       unresolve needed symbols in the dialer */
02175 #if 0
02176    int res;
02177    STANDARD_USECOUNT(res);
02178    return res;
02179 #else
02180    return 1;
02181 #endif
02182 }


Variable Documentation

int adsipark [static]
 

Definition at line 106 of file res_features.c.

Referenced by ast_park_call(), and load_config().

struct ast_call_feature builtin_features[]
 

Definition at line 860 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 builtin_automonitor(), 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.

Referenced by load_module().

char* descrip2 [static]
 

Definition at line 128 of file res_features.c.

Referenced by load_module().

int featuredigittimeout [static]
 

Definition at line 109 of file res_features.c.

Referenced by 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(), and builtin_automonitor().

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 ast_park_call(), 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 ast_park_call(), 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.

Referenced by ast_park_call().

int parking_start [static]
 

Definition at line 97 of file res_features.c.

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

int parking_stop [static]
 

Definition at line 100 of file res_features.c.

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

pthread_t parking_thread [static]
 

Definition at line 157 of file res_features.c.

Referenced by ast_park_call(), and load_module().

struct parkeduser* parkinglot [static]
 

Definition at line 153 of file res_features.c.

Referenced by ast_park_call(), do_parking_thread(), 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.

Referenced by ast_park_call(), do_parking_thread(), and load_config().

struct ast_cli_entry showfeatures [static]
 

Initial value:

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

Definition at line 1835 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 1831 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 1868 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 1864 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.

Referenced by load_module().

char* synopsis2 = "Park yourself" [static]
 

Definition at line 126 of file res_features.c.

Referenced by load_module().

int transferdigittimeout [static]
 

Definition at line 108 of file res_features.c.

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

char xferfailsound[256] [static]
 

Definition at line 94 of file res_features.c.

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

char xfersound[256] [static]
 

Definition at line 93 of file res_features.c.

Referenced by builtin_atxfer(), and load_config().


Generated on Mon Mar 20 08:26:03 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1