#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 | features_parkwatch |
struct | parkeduser |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURE_RETURN_HANGUP -1 |
#define | FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
#define | FEATURE_RETURN_PASSDIGITS 21 |
#define | FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
#define | FEATURE_RETURN_STOREDIGITS 22 |
#define | FEATURE_RETURN_SUCCESS 23 |
#define | FEATURE_RETURN_SUCCESSBREAK 0 |
#define | FEATURE_SENSE_CHAN (1 << 0) |
#define | FEATURE_SENSE_PEER (1 << 1) |
#define | FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
#define | FREE free |
Functions | |
static int | adsi_announce_park (struct ast_channel *chan, int parkingnum) |
int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
Bridge a call, optionally allowing redirection. | |
static void * | ast_bridge_call_thread (void *data) |
static void | ast_bridge_call_thread_launch (void *data) |
static int | ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static struct ast_channel * | ast_feature_request_and_dial (struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name) |
static | AST_LIST_HEAD_STATIC (feature_list, ast_call_feature) |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
AST_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. | |
int | ast_park_metermaid_add (void(*maid)(char *exten, char *context), char *context) |
Add parking watcher (metermaid) to list. These will be notified when we create or remove parking extensions in the dial plan. | |
int | ast_park_metermaid_remove (int id) |
char * | ast_parking_ext (void) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
static void | ast_unregister_features (void) |
static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static void | check_goto_on_transfer (struct ast_channel *chan) |
char * | description (void) |
Provides a description of the module. | |
static void * | do_parking_thread (void *ignore) |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static struct ast_call_feature * | find_feature (char *name) |
static int | handle_parkedcalls (int fd, int argc, char *argv[]) |
static int | handle_showfeatures (int fd, int argc, char *argv[]) |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
static int | load_config (void) |
int | load_module (void) |
Initialize the module. | |
static int | manager_parking_status (struct mansession *s, struct message *m) |
static void | notify_metermaids (char *exten, char *context) |
static void | park_add_hints (char *context, int start, int stop) |
static int | park_call_exec (struct ast_channel *chan, void *data) |
static int | park_exec (struct ast_channel *chan, void *data) |
int | reload (void) |
Reload stuff. | |
static int | remap_feature (const char *name, const char *value) |
static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
static void | unmap_features (void) |
int | usecount (void) |
Provides a usecount. | |
Variables | |
static int | adsipark |
ast_call_feature | builtin_features [] |
static char | courtesytone [256] |
static char * | descrip |
static char * | descrip2 |
static int | featuredigittimeout |
LOCAL_USER_DECL | |
int | metermaidid = 0 |
features_parkwatch * | metermaids |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static int | parkaddhints = 0 |
static char * | parkcall = "Park" |
static char * | parkedcall = "ParkedCall" |
static int | parkfindnext |
static char | parking_con [AST_MAX_EXTENSION] |
static char | parking_con_dial [AST_MAX_EXTENSION] |
static char | parking_ext [AST_MAX_EXTENSION] |
static int | parking_offset |
static int | parking_start |
static int | parking_stop |
static pthread_t | parking_thread |
static struct parkeduser * | parkinglot |
static int | parkingtime = DEFAULT_PARK_TIME |
static char | pickup_ext [AST_MAX_EXTENSION] |
static char * | registrar = "res_features" |
static struct ast_cli_entry | showfeatures |
static char | showfeatures_help [] |
static struct ast_cli_entry | showparked |
static char | showparked_help [] |
STANDARD_LOCAL_USER | |
static char * | synopsis = "Answer a parked call" |
static char * | synopsis2 = "Park yourself" |
static int | transferdigittimeout |
static char | xferfailsound [256] |
static char | xfersound [256] |
Definition in file res_features.c.
#define AST_MAX_WATCHERS 256 |
Definition at line 73 of file res_features.c.
#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 |
Definition at line 536 of file res_features.c.
Referenced by ast_bridge_call(), and ast_feature_interpret().
#define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
#define FEATURE_RETURN_STOREDIGITS 22 |
#define FEATURE_RETURN_SUCCESS 23 |
Definition at line 538 of file res_features.c.
Referenced by ast_bridge_call(), builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and feature_exec_app().
#define FEATURE_RETURN_SUCCESSBREAK 0 |
#define FEATURE_SENSE_CHAN (1 << 0) |
Definition at line 540 of file res_features.c.
Referenced by ast_bridge_call(), and ast_feature_interpret().
#define FEATURE_SENSE_PEER (1 << 1) |
Definition at line 541 of file res_features.c.
Referenced by ast_bridge_call(), builtin_atxfer(), and builtin_blindtransfer().
#define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Definition at line 959 of file res_features.c.
Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), remap_feature(), set_config_flags(), and unmap_features().
#define FREE free |
Definition at line 66 of file res_features.c.
static int adsi_announce_park | ( | struct ast_channel * | chan, | |
int | parkingnum | |||
) | [static] |
Definition at line 273 of file res_features.c.
References ADSI_JUST_CENT, adsi_load_session(), adsi_print(), and justify.
Referenced by ast_park_call().
00274 { 00275 int res; 00276 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00277 char tmp[256]; 00278 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00279 00280 snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum); 00281 message[0] = tmp; 00282 res = adsi_load_session(chan, NULL, 0, 1); 00283 if (res == -1) { 00284 return res; 00285 } 00286 return adsi_print(chan, message, justify, 1); 00287 }
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 1361 of file res_features.c.
References ast_channel::appl, ast_answer(), ast_cdr_appenduserfield(), ast_cdr_setuserfield(), ast_channel_bridge(), ast_channel_setoption(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_OPTION, AST_CONTROL_RINGING, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree(), ast_indicate(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strlen_zero(), ast_channel::cdr, config, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_channel::name, ast_option_header::option, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), ast_frame::subclass, and ast_cdr::userfield.
Referenced by ast_bridge_call_thread(), builtin_atxfer(), dial_exec_full(), park_exec(), and try_calling().
01362 { 01363 /* Copy voice back and forth between the two channels. Give the peer 01364 the ability to transfer calls with '#<extension' syntax. */ 01365 struct ast_frame *f; 01366 struct ast_channel *who; 01367 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01368 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01369 int res; 01370 int diff; 01371 int hasfeatures=0; 01372 int hadfeatures=0; 01373 struct ast_option_header *aoh; 01374 struct timeval start = { 0 , 0 }; 01375 struct ast_bridge_config backup_config; 01376 char *monitor_exec; 01377 01378 memset(&backup_config, 0, sizeof(backup_config)); 01379 01380 config->start_time = ast_tvnow(); 01381 01382 if (chan && peer) { 01383 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01384 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01385 } else if (chan) 01386 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01387 01388 if (monitor_ok) { 01389 if (!monitor_app) { 01390 if (!(monitor_app = pbx_findapp("Monitor"))) 01391 monitor_ok=0; 01392 } 01393 if (monitor_app) { 01394 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01395 pbx_exec(chan, monitor_app, monitor_exec, 1); 01396 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01397 pbx_exec(peer, monitor_app, monitor_exec, 1); 01398 } 01399 } 01400 01401 set_config_flags(chan, peer, config); 01402 config->firstpass = 1; 01403 01404 /* Answer if need be */ 01405 if (ast_answer(chan)) 01406 return -1; 01407 peer->appl = "Bridged Call"; 01408 peer->data = chan->name; 01409 01410 /* copy the userfield from the B-leg to A-leg if applicable */ 01411 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01412 char tmp[256]; 01413 if (!ast_strlen_zero(chan->cdr->userfield)) { 01414 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01415 ast_cdr_appenduserfield(chan, tmp); 01416 } else 01417 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01418 /* free the peer's cdr without ast_cdr_free complaining */ 01419 free(peer->cdr); 01420 peer->cdr = NULL; 01421 } 01422 for (;;) { 01423 if (config->feature_timer) 01424 start = ast_tvnow(); 01425 01426 res = ast_channel_bridge(chan, peer, config, &f, &who); 01427 01428 if (config->feature_timer) { 01429 /* Update time limit for next pass */ 01430 diff = ast_tvdiff_ms(ast_tvnow(), start); 01431 config->feature_timer -= diff; 01432 if (hasfeatures) { 01433 /* Running on backup config, meaning a feature might be being 01434 activated, but that's no excuse to keep things going 01435 indefinitely! */ 01436 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01437 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01438 config->feature_timer = 0; 01439 who = chan; 01440 if (f) 01441 ast_frfree(f); 01442 f = NULL; 01443 res = 0; 01444 } else if (config->feature_timer <= 0) { 01445 /* Not *really* out of time, just out of time for 01446 digits to come in for features. */ 01447 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01448 if (!ast_strlen_zero(peer_featurecode)) { 01449 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01450 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01451 } 01452 if (!ast_strlen_zero(chan_featurecode)) { 01453 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01454 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01455 } 01456 if (f) 01457 ast_frfree(f); 01458 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01459 if (!hasfeatures) { 01460 /* Restore original (possibly time modified) bridge config */ 01461 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01462 memset(&backup_config, 0, sizeof(backup_config)); 01463 } 01464 hadfeatures = hasfeatures; 01465 /* Continue as we were */ 01466 continue; 01467 } 01468 } else { 01469 if (config->feature_timer <=0) { 01470 /* We ran out of time */ 01471 config->feature_timer = 0; 01472 who = chan; 01473 if (f) 01474 ast_frfree(f); 01475 f = NULL; 01476 res = 0; 01477 } 01478 } 01479 } 01480 if (res < 0) { 01481 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01482 return -1; 01483 } 01484 01485 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 01486 (f->subclass == AST_CONTROL_CONGESTION)))) { 01487 res = -1; 01488 break; 01489 } 01490 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) { 01491 if (who == chan) 01492 ast_indicate(peer, AST_CONTROL_RINGING); 01493 else 01494 ast_indicate(chan, AST_CONTROL_RINGING); 01495 } 01496 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) { 01497 if (who == chan) 01498 ast_indicate(peer, -1); 01499 else 01500 ast_indicate(chan, -1); 01501 } 01502 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) { 01503 if (who == chan) 01504 ast_indicate(peer, AST_CONTROL_FLASH); 01505 else 01506 ast_indicate(chan, AST_CONTROL_FLASH); 01507 } 01508 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) { 01509 aoh = f->data; 01510 /* Forward option Requests */ 01511 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) { 01512 if (who == chan) 01513 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01514 else 01515 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01516 } 01517 } 01518 /* check for '*', if we find it it's time to disconnect */ 01519 if (f && (f->frametype == AST_FRAME_DTMF)) { 01520 char *featurecode; 01521 int sense; 01522 struct ast_channel *other; 01523 01524 hadfeatures = hasfeatures; 01525 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01526 if (who == chan) { 01527 other = peer; 01528 sense = FEATURE_SENSE_CHAN; 01529 featurecode = chan_featurecode; 01530 } else { 01531 other = chan; 01532 sense = FEATURE_SENSE_PEER; 01533 featurecode = peer_featurecode; 01534 } 01535 featurecode[strlen(featurecode)] = f->subclass; 01536 /* Get rid of the frame before we start doing "stuff" with the channels */ 01537 ast_frfree(f); 01538 f = NULL; 01539 config->feature_timer = backup_config.feature_timer; 01540 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01541 switch(res) { 01542 case FEATURE_RETURN_PASSDIGITS: 01543 ast_dtmf_stream(other, who, featurecode, 0); 01544 /* Fall through */ 01545 case FEATURE_RETURN_SUCCESS: 01546 memset(featurecode, 0, sizeof(chan_featurecode)); 01547 break; 01548 } 01549 if (res >= FEATURE_RETURN_PASSDIGITS) { 01550 res = 0; 01551 } else 01552 break; 01553 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01554 if (hadfeatures && !hasfeatures) { 01555 /* Restore backup */ 01556 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01557 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01558 } else if (hasfeatures) { 01559 if (!hadfeatures) { 01560 /* Backup configuration */ 01561 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01562 /* Setup temporary config options */ 01563 config->play_warning = 0; 01564 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01565 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01566 config->warning_freq = 0; 01567 config->warning_sound = NULL; 01568 config->end_sound = NULL; 01569 config->start_sound = NULL; 01570 config->firstpass = 0; 01571 } 01572 config->start_time = ast_tvnow(); 01573 config->feature_timer = featuredigittimeout; 01574 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01575 } 01576 } 01577 if (f) 01578 ast_frfree(f); 01579 } 01580 return res; 01581 }
static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
Definition at line 231 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().
00232 { 00233 struct ast_bridge_thread_obj *tobj = data; 00234 00235 tobj->chan->appl = "Transferred Call"; 00236 tobj->chan->data = tobj->peer->name; 00237 tobj->peer->appl = "Transferred Call"; 00238 tobj->peer->data = tobj->chan->name; 00239 if (tobj->chan->cdr) { 00240 ast_cdr_reset(tobj->chan->cdr, NULL); 00241 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name); 00242 } 00243 if (tobj->peer->cdr) { 00244 ast_cdr_reset(tobj->peer->cdr, NULL); 00245 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name); 00246 } 00247 00248 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00249 ast_hangup(tobj->chan); 00250 ast_hangup(tobj->peer); 00251 tobj->chan = tobj->peer = NULL; 00252 free(tobj); 00253 tobj=NULL; 00254 return NULL; 00255 }
static void ast_bridge_call_thread_launch | ( | void * | data | ) | [static] |
Definition at line 257 of file res_features.c.
References ast_bridge_call_thread(), and ast_pthread_create.
Referenced by builtin_atxfer().
00258 { 00259 pthread_t thread; 00260 pthread_attr_t attr; 00261 struct sched_param sched; 00262 00263 pthread_attr_init(&attr); 00264 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00265 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00266 pthread_attr_destroy(&attr); 00267 memset(&sched, 0, sizeof(sched)); 00268 pthread_setschedparam(thread, SCHED_RR, &sched); 00269 }
static int ast_feature_interpret | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense | |||
) | [static] |
Definition at line 1084 of file res_features.c.
References ast_copy_flags, AST_FLAGS_ALL, ast_log(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), builtin_features, config, exten, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, features, FEATURES_COUNT, find_feature(), LOG_DEBUG, ast_channel::name, ast_call_feature::operation, option_verbose, pbx_builtin_getvar_helper(), strsep(), and VERBOSE_PREFIX_3.
Referenced by ast_bridge_call().
01085 { 01086 int x; 01087 struct ast_flags features; 01088 int res = FEATURE_RETURN_PASSDIGITS; 01089 struct ast_call_feature *feature; 01090 char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES"); 01091 01092 if (sense == FEATURE_SENSE_CHAN) 01093 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01094 else 01095 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01096 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags); 01097 01098 for (x=0; x < FEATURES_COUNT; x++) { 01099 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01100 !ast_strlen_zero(builtin_features[x].exten)) { 01101 /* Feature is up for consideration */ 01102 if (!strcmp(builtin_features[x].exten, code)) { 01103 res = builtin_features[x].operation(chan, peer, config, code, sense); 01104 break; 01105 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01106 if (res == FEATURE_RETURN_PASSDIGITS) 01107 res = FEATURE_RETURN_STOREDIGITS; 01108 } 01109 } 01110 } 01111 01112 01113 if (!ast_strlen_zero(dynamic_features)) { 01114 char *tmp = ast_strdupa(dynamic_features); 01115 char *tok; 01116 01117 if (!tmp) 01118 return res; 01119 01120 while ((tok = strsep(&tmp, "#")) != NULL) { 01121 feature = find_feature(tok); 01122 01123 if (feature) { 01124 /* Feature is up for consideration */ 01125 if (!strcmp(feature->exten, code)) { 01126 if (option_verbose > 2) 01127 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01128 if (sense == FEATURE_SENSE_CHAN) 01129 res = feature->operation(chan, peer, config, code, sense); 01130 else 01131 res = feature->operation(peer, chan, config, code, sense); 01132 break; 01133 } else if (!strncmp(feature->exten, code, strlen(code))) { 01134 res = FEATURE_RETURN_STOREDIGITS; 01135 } 01136 } 01137 } 01138 } 01139 01140 return res; 01141 }
static struct ast_channel * ast_feature_request_and_dial | ( | struct ast_channel * | caller, | |
const char * | type, | |||
int | format, | |||
void * | data, | |||
int | timeout, | |||
int * | outstate, | |||
const char * | cid_num, | |||
const char * | cid_name | |||
) | [static] |
Definition at line 1188 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), AST_STATE_UP, ast_verbose(), ast_waitfor_n(), builtin_features, ast_channel::cdr, ast_call_feature::exten, FEATURES_COUNT, ast_frame::frametype, ast_channel::hangupcause, LOG_NOTICE, LOG_WARNING, option_verbose, ast_frame::subclass, and VERBOSE_PREFIX_3.
Referenced by builtin_atxfer().
01189 { 01190 int state = 0; 01191 int cause = 0; 01192 int to; 01193 struct ast_channel *chan; 01194 struct ast_channel *monitor_chans[2]; 01195 struct ast_channel *active_channel; 01196 struct ast_frame *f = NULL; 01197 int res = 0, ready = 0; 01198 01199 if ((chan = ast_request(type, format, data, &cause))) { 01200 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01201 ast_channel_inherit_variables(caller, chan); 01202 if (!ast_call(chan, data, timeout)) { 01203 struct timeval started; 01204 int x, len = 0; 01205 char *disconnect_code = NULL, *dialed_code = NULL; 01206 01207 ast_indicate(caller, AST_CONTROL_RINGING); 01208 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01209 for (x=0; x < FEATURES_COUNT; x++) { 01210 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01211 continue; 01212 01213 disconnect_code = builtin_features[x].exten; 01214 len = strlen(disconnect_code) + 1; 01215 dialed_code = alloca(len); 01216 memset(dialed_code, 0, len); 01217 break; 01218 } 01219 x = 0; 01220 started = ast_tvnow(); 01221 to = timeout; 01222 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01223 monitor_chans[0] = caller; 01224 monitor_chans[1] = chan; 01225 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01226 01227 /* see if the timeout has been violated */ 01228 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01229 state = AST_CONTROL_UNHOLD; 01230 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01231 break; /*doh! timeout*/ 01232 } 01233 01234 if (!active_channel) { 01235 continue; 01236 } 01237 01238 if (chan && (chan == active_channel)){ 01239 f = ast_read(chan); 01240 if (f == NULL) { /*doh! where'd he go?*/ 01241 state = AST_CONTROL_HANGUP; 01242 res = 0; 01243 break; 01244 } 01245 01246 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01247 if (f->subclass == AST_CONTROL_RINGING) { 01248 state = f->subclass; 01249 if (option_verbose > 2) 01250 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01251 ast_indicate(caller, AST_CONTROL_RINGING); 01252 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01253 state = f->subclass; 01254 if (option_verbose > 2) 01255 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01256 ast_indicate(caller, AST_CONTROL_BUSY); 01257 ast_frfree(f); 01258 f = NULL; 01259 break; 01260 } else if (f->subclass == AST_CONTROL_ANSWER) { 01261 /* This is what we are hoping for */ 01262 state = f->subclass; 01263 ast_frfree(f); 01264 f = NULL; 01265 ready=1; 01266 break; 01267 } else { 01268 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01269 } 01270 /* else who cares */ 01271 } 01272 01273 } else if (caller && (active_channel == caller)) { 01274 f = ast_read(caller); 01275 if (f == NULL) { /*doh! where'd he go?*/ 01276 if (caller->_softhangup && !chan->_softhangup) { 01277 /* make this a blind transfer */ 01278 ready = 1; 01279 break; 01280 } 01281 state = AST_CONTROL_HANGUP; 01282 res = 0; 01283 break; 01284 } 01285 01286 if (f->frametype == AST_FRAME_DTMF) { 01287 dialed_code[x++] = f->subclass; 01288 dialed_code[x] = '\0'; 01289 if (strlen(dialed_code) == len) { 01290 x = 0; 01291 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01292 x = 0; 01293 dialed_code[x] = '\0'; 01294 } 01295 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01296 /* Caller Canceled the call */ 01297 state = AST_CONTROL_UNHOLD; 01298 ast_frfree(f); 01299 f = NULL; 01300 break; 01301 } 01302 } 01303 } 01304 if (f) { 01305 ast_frfree(f); 01306 } 01307 } 01308 } else 01309 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01310 } else { 01311 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01312 switch(cause) { 01313 case AST_CAUSE_BUSY: 01314 state = AST_CONTROL_BUSY; 01315 break; 01316 case AST_CAUSE_CONGESTION: 01317 state = AST_CONTROL_CONGESTION; 01318 break; 01319 } 01320 } 01321 01322 ast_indicate(caller, -1); 01323 if (chan && ready) { 01324 if (chan->_state == AST_STATE_UP) 01325 state = AST_CONTROL_ANSWER; 01326 res = 0; 01327 } else if(chan) { 01328 res = -1; 01329 ast_hangup(chan); 01330 chan = NULL; 01331 } else { 01332 res = -1; 01333 } 01334 01335 if (outstate) 01336 *outstate = state; 01337 01338 if (chan && res <= 0) { 01339 if (!chan->cdr) { 01340 chan->cdr = ast_cdr_alloc(); 01341 } 01342 if (chan->cdr) { 01343 char tmp[256]; 01344 ast_cdr_init(chan->cdr, chan); 01345 snprintf(tmp, 256, "%s/%s", type, (char *)data); 01346 ast_cdr_setapp(chan->cdr,"Dial",tmp); 01347 ast_cdr_update(chan); 01348 ast_cdr_start(chan->cdr); 01349 ast_cdr_end(chan->cdr); 01350 /* If the cause wasn't handled properly */ 01351 if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) 01352 ast_cdr_failed(chan->cdr); 01353 } else { 01354 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 01355 } 01356 } 01357 01358 return chan; 01359 }
static AST_LIST_HEAD_STATIC | ( | feature_list | , | |
ast_call_feature | ||||
) | [static] |
int ast_masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call via a masqueraded channel.
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 498 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().
00499 { 00500 struct ast_channel *chan; 00501 struct ast_frame *f; 00502 00503 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00504 chan = ast_channel_alloc(0); 00505 if (chan) { 00506 /* Let us keep track of the channel name */ 00507 snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name); 00508 00509 /* Make formats okay */ 00510 chan->readformat = rchan->readformat; 00511 chan->writeformat = rchan->writeformat; 00512 ast_channel_masquerade(chan, rchan); 00513 00514 /* Setup the extensions and such */ 00515 ast_copy_string(chan->context, rchan->context, sizeof(chan->context)); 00516 ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten)); 00517 chan->priority = rchan->priority; 00518 00519 /* Make the masq execute */ 00520 f = ast_read(chan); 00521 if (f) 00522 ast_frfree(f); 00523 ast_park_call(chan, peer, timeout, extout); 00524 } else { 00525 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00526 return -1; 00527 } 00528 return 0; 00529 }
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.
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 373 of file res_features.c.
References adsi_announce_park(), adsi_available(), adsi_unload_session(), ast_channel::appl, ast_add_extension2(), ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, exten, FREE, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, malloc, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, ast_channel::priority, parkeduser::priority, parkeduser::start, strdup, and VERBOSE_PREFIX_2.
Referenced by ast_masq_park_call(), builtin_blindtransfer(), iax_park_thread(), park_call_exec(), and sip_park_thread().
00374 { 00375 struct parkeduser *pu, *cur; 00376 int i,x,parking_range; 00377 char exten[AST_MAX_EXTENSION]; 00378 struct ast_context *con; 00379 00380 pu = malloc(sizeof(struct parkeduser)); 00381 if (!pu) { 00382 ast_log(LOG_WARNING, "Out of memory\n"); 00383 return -1; 00384 } 00385 memset(pu, 0, sizeof(struct parkeduser)); 00386 ast_mutex_lock(&parking_lock); 00387 parking_range = parking_stop - parking_start+1; 00388 for (i = 0; i < parking_range; i++) { 00389 x = (i + parking_offset) % parking_range + parking_start; 00390 cur = parkinglot; 00391 while(cur) { 00392 if (cur->parkingnum == x) 00393 break; 00394 cur = cur->next; 00395 } 00396 if (!cur) 00397 break; 00398 } 00399 00400 if (!(i < parking_range)) { 00401 ast_log(LOG_WARNING, "No more parking spaces\n"); 00402 free(pu); 00403 ast_mutex_unlock(&parking_lock); 00404 return -1; 00405 } 00406 if (parkfindnext) 00407 parking_offset = x - parking_start + 1; 00408 chan->appl = "Parked Call"; 00409 chan->data = NULL; 00410 00411 pu->chan = chan; 00412 /* Start music on hold */ 00413 if (chan != peer) { 00414 ast_indicate(pu->chan, AST_CONTROL_HOLD); 00415 ast_moh_start(pu->chan, NULL); 00416 } 00417 pu->start = ast_tvnow(); 00418 pu->parkingnum = x; 00419 if (timeout > 0) 00420 pu->parkingtime = timeout; 00421 else 00422 pu->parkingtime = parkingtime; 00423 if (extout) 00424 *extout = x; 00425 if (peer) 00426 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername)); 00427 00428 /* Remember what had been dialed, so that if the parking 00429 expires, we try to come back to the same place */ 00430 if (!ast_strlen_zero(chan->macrocontext)) 00431 ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context)); 00432 else 00433 ast_copy_string(pu->context, chan->context, sizeof(pu->context)); 00434 if (!ast_strlen_zero(chan->macroexten)) 00435 ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten)); 00436 else 00437 ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten)); 00438 if (chan->macropriority) 00439 pu->priority = chan->macropriority; 00440 else 00441 pu->priority = chan->priority; 00442 pu->next = parkinglot; 00443 parkinglot = pu; 00444 /* If parking a channel directly, don't quiet yet get parking running on it */ 00445 if (peer == chan) 00446 pu->notquiteyet = 1; 00447 ast_mutex_unlock(&parking_lock); 00448 /* Wake up the (presumably select()ing) thread */ 00449 pthread_kill(parking_thread, SIGURG); 00450 if (option_verbose > 1) 00451 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)); 00452 00453 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00454 "Exten: %d\r\n" 00455 "Channel: %s\r\n" 00456 "From: %s\r\n" 00457 "Timeout: %ld\r\n" 00458 "CallerID: %s\r\n" 00459 "CallerIDName: %s\r\n" 00460 ,pu->parkingnum, pu->chan->name, peer ? peer->name : "" 00461 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL) 00462 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 00463 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 00464 ); 00465 00466 if (peer) { 00467 if (adsipark && adsi_available(peer)) { 00468 adsi_announce_park(peer, pu->parkingnum); 00469 } 00470 if (adsipark && adsi_available(peer)) { 00471 adsi_unload_session(peer); 00472 } 00473 } 00474 con = ast_context_find(parking_con); 00475 if (!con) { 00476 con = ast_context_create(NULL, parking_con, registrar); 00477 if (!con) { 00478 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00479 } 00480 } 00481 if (con) { 00482 snprintf(exten, sizeof(exten), "%d", x); 00483 00484 if (ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar) == 0) 00485 notify_metermaids(exten, parking_con); /* Notify watchers */ 00486 } 00487 if (peer) 00488 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00489 if (pu->notquiteyet) { 00490 /* Wake up parking thread if we're really done */ 00491 ast_moh_start(pu->chan, NULL); 00492 pu->notquiteyet = 0; 00493 pthread_kill(parking_thread, SIGURG); 00494 } 00495 return 0; 00496 }
Add parking watcher (metermaid) to list. These will be notified when we create or remove parking extensions in the dial plan.
Add parking watcher (metermaid) to list. These will be notified when we create or remove parking extensions in the dial plan
Definition at line 292 of file res_features.c.
References ast_log(), features_parkwatch::callback, features_parkwatch::context, features_parkwatch::id, LOG_DEBUG, LOG_ERROR, malloc, metermaids, features_parkwatch::next, option_debug, and strdup.
Referenced by load_module().
00293 { 00294 struct features_parkwatch *newmaid; 00295 struct features_parkwatch *maids = metermaids; 00296 00297 newmaid = malloc(sizeof(struct features_parkwatch)); 00298 if (!newmaid) { 00299 ast_log(LOG_ERROR, "Can't allocate parking watcher, out of memory.\n"); 00300 return -1; 00301 } 00302 memset(newmaid, 0, sizeof(struct features_parkwatch)); 00303 00304 /* Spool till end of list */ 00305 while(maids && maids->next) { 00306 maids = maids->next; 00307 } 00308 00309 newmaid->callback = maid; 00310 if (context) 00311 newmaid->context = strdup(context); 00312 newmaid->id = metermaidid; 00313 00314 /* Generate new ID */ 00315 metermaidid++; 00316 00317 /* Link the new object to the list */ 00318 if (maids) 00319 maids->next = newmaid; 00320 else 00321 metermaids = newmaid; 00322 if (option_debug > 1) 00323 ast_log(LOG_DEBUG, "Added metermaid # %d\n", metermaidid); 00324 return metermaidid; 00325 }
int ast_park_metermaid_remove | ( | int | id | ) |
Remove parking watcher
Definition at line 328 of file res_features.c.
References features_parkwatch::context, free, features_parkwatch::id, metermaids, and features_parkwatch::next.
Referenced by unload_module().
00329 { 00330 struct features_parkwatch *maids = metermaids; 00331 struct features_parkwatch *prev = NULL; 00332 struct features_parkwatch *kill = NULL; 00333 00334 while (maids && !kill) { 00335 if (maids->id == id) { 00336 if (prev) { 00337 prev->next = maids->next; 00338 } else { 00339 metermaids = maids->next; 00340 } 00341 kill = maids; 00342 } 00343 prev = maids; 00344 maids = maids->next; 00345 } 00346 if (!kill) 00347 return -1; /* Did not find id */ 00348 if (kill->context) 00349 free(kill->context); 00350 free(kill); 00351 return 0; 00352 }
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 177 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().
00178 { 00179 return parking_ext; 00180 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2033 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_mutex_unlock(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), monitor_handle_notowned(), skinny_ss(), and ss_thread().
02034 { 02035 struct ast_channel *cur = NULL; 02036 int res = -1; 02037 02038 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02039 if (!cur->pbx && 02040 (cur != chan) && 02041 (chan->pickupgroup & cur->callgroup) && 02042 ((cur->_state == AST_STATE_RINGING) || 02043 (cur->_state == AST_STATE_RING))) { 02044 break; 02045 } 02046 ast_mutex_unlock(&cur->lock); 02047 } 02048 if (cur) { 02049 if (option_debug) 02050 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02051 res = ast_answer(chan); 02052 if (res) 02053 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02054 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02055 if (res) 02056 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02057 res = ast_channel_masquerade(cur, chan); 02058 if (res) 02059 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02060 ast_mutex_unlock(&cur->lock); 02061 } else { 02062 if (option_debug) 02063 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02064 } 02065 return res; 02066 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 182 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().
00183 { 00184 return pickup_ext; 00185 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_set
feature | an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call. |
Definition at line 972 of file res_features.c.
References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_verbose(), LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.
Referenced by load_config().
00973 { 00974 if (!feature) { 00975 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00976 return; 00977 } 00978 00979 AST_LIST_LOCK(&feature_list); 00980 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00981 AST_LIST_UNLOCK(&feature_list); 00982 00983 if (option_verbose >= 2) 00984 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00985 }
void ast_unregister_feature | ( | struct ast_call_feature * | feature | ) |
unregister feature from feature_set
feature | the ast_call_feature object which was registered before |
Definition at line 988 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.
00989 { 00990 if (!feature) return; 00991 00992 AST_LIST_LOCK(&feature_list); 00993 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00994 AST_LIST_UNLOCK(&feature_list); 00995 free(feature); 00996 }
static void ast_unregister_features | ( | void | ) | [static] |
Definition at line 998 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.
Referenced by load_config().
00999 { 01000 struct ast_call_feature *feature; 01001 01002 AST_LIST_LOCK(&feature_list); 01003 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) 01004 free(feature); 01005 AST_LIST_UNLOCK(&feature_list); 01006 }
static int builtin_atxfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense | |||
) | [static] |
Definition at line 763 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_channel_alloc(), ast_channel_make_compatible(), ast_channel_masquerade(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_read(), ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_waitfordigit(), ast_waitstream(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, cid_name, cid_num, config, ast_channel::context, ast_channel::exten, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_PEER, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, malloc, ast_channel::name, pbx_builtin_getvar_helper(), ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
00764 { 00765 struct ast_channel *transferer; 00766 struct ast_channel *transferee; 00767 struct ast_channel *newchan, *xferchan=NULL; 00768 int outstate=0; 00769 struct ast_bridge_config bconfig; 00770 char *transferer_real_context; 00771 char xferto[256],dialstr[265]; 00772 char *cid_num; 00773 char *cid_name; 00774 int res; 00775 struct ast_frame *f = NULL; 00776 struct ast_bridge_thread_obj *tobj; 00777 00778 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense); 00779 if (sense == FEATURE_SENSE_PEER) { 00780 transferer = peer; 00781 transferee = chan; 00782 } else { 00783 transferer = chan; 00784 transferee = peer; 00785 } 00786 if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) && 00787 !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) { 00788 /* Use the non-macro context to transfer the call */ 00789 if (!ast_strlen_zero(transferer->macrocontext)) 00790 transferer_real_context = transferer->macrocontext; 00791 else 00792 transferer_real_context = transferer->context; 00793 } 00794 /* Start autoservice on chan while we talk 00795 to the originator */ 00796 ast_indicate(transferee, AST_CONTROL_HOLD); 00797 ast_autoservice_start(transferee); 00798 ast_moh_start(transferee, NULL); 00799 memset(xferto, 0, sizeof(xferto)); 00800 /* Transfer */ 00801 if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) { 00802 ast_moh_stop(transferee); 00803 ast_autoservice_stop(transferee); 00804 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00805 return res; 00806 } 00807 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) { 00808 ast_moh_stop(transferee); 00809 ast_autoservice_stop(transferee); 00810 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00811 return res; 00812 } else if(res > 0) { 00813 /* If they've typed a digit already, handle it */ 00814 xferto[0] = (char) res; 00815 } 00816 if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) { 00817 cid_num = transferer->cid.cid_num; 00818 cid_name = transferer->cid.cid_name; 00819 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) { 00820 snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context); 00821 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name); 00822 ast_indicate(transferer, -1); 00823 if (newchan) { 00824 res = ast_channel_make_compatible(transferer, newchan); 00825 if (res < 0) { 00826 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name); 00827 ast_hangup(newchan); 00828 return -1; 00829 } 00830 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00831 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00832 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00833 res = ast_bridge_call(transferer,newchan,&bconfig); 00834 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) { 00835 ast_hangup(newchan); 00836 if (f) { 00837 ast_frfree(f); 00838 f = NULL; 00839 } 00840 if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) { 00841 if (ast_waitstream(transferer, "") < 0) { 00842 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00843 } 00844 } 00845 ast_moh_stop(transferee); 00846 ast_autoservice_stop(transferee); 00847 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00848 transferer->_softhangup = 0; 00849 return FEATURE_RETURN_SUCCESS; 00850 } 00851 00852 res = ast_channel_make_compatible(transferee, newchan); 00853 if (res < 0) { 00854 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name); 00855 ast_hangup(newchan); 00856 return -1; 00857 } 00858 00859 00860 ast_moh_stop(transferee); 00861 00862 if ((ast_autoservice_stop(transferee) < 0) 00863 || (ast_waitfordigit(transferee, 100) < 0) 00864 || (ast_waitfordigit(newchan, 100) < 0) 00865 || ast_check_hangup(transferee) 00866 || ast_check_hangup(newchan)) { 00867 ast_hangup(newchan); 00868 res = -1; 00869 return -1; 00870 } 00871 00872 if ((xferchan = ast_channel_alloc(0))) { 00873 snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name); 00874 /* Make formats okay */ 00875 xferchan->readformat = transferee->readformat; 00876 xferchan->writeformat = transferee->writeformat; 00877 ast_channel_masquerade(xferchan, transferee); 00878 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 00879 xferchan->_state = AST_STATE_UP; 00880 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00881 xferchan->_softhangup = 0; 00882 00883 if ((f = ast_read(xferchan))) { 00884 ast_frfree(f); 00885 f = NULL; 00886 } 00887 00888 } else { 00889 ast_hangup(newchan); 00890 return -1; 00891 } 00892 00893 newchan->_state = AST_STATE_UP; 00894 ast_clear_flag(newchan, AST_FLAGS_ALL); 00895 newchan->_softhangup = 0; 00896 00897 tobj = malloc(sizeof(struct ast_bridge_thread_obj)); 00898 if (tobj) { 00899 memset(tobj,0,sizeof(struct ast_bridge_thread_obj)); 00900 tobj->chan = xferchan; 00901 tobj->peer = newchan; 00902 tobj->bconfig = *config; 00903 00904 if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) { 00905 if (ast_waitstream(newchan, "") < 0) { 00906 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00907 } 00908 } 00909 ast_bridge_call_thread_launch(tobj); 00910 } else { 00911 ast_log(LOG_WARNING, "Out of memory!\n"); 00912 ast_hangup(xferchan); 00913 ast_hangup(newchan); 00914 } 00915 return -1; 00916 00917 } else { 00918 ast_moh_stop(transferee); 00919 ast_autoservice_stop(transferee); 00920 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00921 /* any reason besides user requested cancel and busy triggers the failed sound */ 00922 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) { 00923 res = ast_streamfile(transferer, xferfailsound, transferer->language); 00924 if (!res && (ast_waitstream(transferer, "") < 0)) { 00925 return -1; 00926 } 00927 } 00928 return FEATURE_RETURN_SUCCESS; 00929 } 00930 } else { 00931 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 00932 ast_moh_stop(transferee); 00933 ast_autoservice_stop(transferee); 00934 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00935 res = ast_streamfile(transferer, "beeperr", transferer->language); 00936 if (!res && (ast_waitstream(transferer, "") < 0)) { 00937 return -1; 00938 } 00939 } 00940 } else { 00941 ast_log(LOG_WARNING, "Did not read data.\n"); 00942 ast_moh_stop(transferee); 00943 ast_autoservice_stop(transferee); 00944 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00945 res = ast_streamfile(transferer, "beeperr", transferer->language); 00946 if (ast_waitstream(transferer, "") < 0) { 00947 return -1; 00948 } 00949 } 00950 ast_moh_stop(transferee); 00951 ast_autoservice_stop(transferee); 00952 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00953 00954 return FEATURE_RETURN_SUCCESS; 00955 }
static int builtin_automonitor | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense | |||
) | [static] |
Definition at line 544 of file res_features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_monitor_stop(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, ast_channel::language, LOG_ERROR, LOG_NOTICE, LOG_WARNING, monitor_app, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), and VERBOSE_PREFIX_3.
00545 { 00546 char *touch_monitor = NULL, *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_format = NULL; 00547 int x = 0; 00548 size_t len; 00549 struct ast_channel *caller_chan = NULL, *callee_chan = NULL; 00550 00551 00552 if(sense == 2) { 00553 caller_chan = peer; 00554 callee_chan = chan; 00555 } else { 00556 callee_chan = peer; 00557 caller_chan = chan; 00558 } 00559 00560 if (!monitor_ok) { 00561 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00562 return -1; 00563 } 00564 00565 if (!monitor_app) { 00566 if (!(monitor_app = pbx_findapp("Monitor"))) { 00567 monitor_ok=0; 00568 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00569 return -1; 00570 } 00571 } 00572 if (!ast_strlen_zero(courtesytone)) { 00573 if (ast_autoservice_start(callee_chan)) 00574 return -1; 00575 if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) { 00576 if (ast_waitstream(caller_chan, "") < 0) { 00577 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00578 ast_autoservice_stop(callee_chan); 00579 return -1; 00580 } 00581 } 00582 if (ast_autoservice_stop(callee_chan)) 00583 return -1; 00584 } 00585 00586 if (callee_chan->monitor) { 00587 if (option_verbose > 3) 00588 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00589 ast_monitor_stop(callee_chan, 1); 00590 return FEATURE_RETURN_SUCCESS; 00591 } 00592 00593 if (caller_chan && callee_chan) { 00594 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00595 if (!touch_format) 00596 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00597 00598 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00599 if (!touch_monitor) 00600 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00601 00602 if (touch_monitor) { 00603 len = strlen(touch_monitor) + 50; 00604 args = alloca(len); 00605 snprintf(args, len, "%s|auto-%ld-%s|m", (touch_format) ? touch_format : "wav", time(NULL), touch_monitor); 00606 } else { 00607 caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name); 00608 callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name); 00609 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00610 args = alloca(len); 00611 snprintf(args, len, "%s|auto-%ld-%s-%s|m", (touch_format) ? touch_format : "wav", time(NULL), caller_chan_id, callee_chan_id); 00612 } 00613 00614 for( x = 0; x < strlen(args); x++) 00615 if (args[x] == '/') 00616 args[x] = '-'; 00617 00618 if (option_verbose > 3) 00619 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00620 00621 pbx_exec(callee_chan, monitor_app, args, 1); 00622 00623 return FEATURE_RETURN_SUCCESS; 00624 } 00625 00626 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00627 return -1; 00628 }
static int builtin_blindtransfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense | |||
) | [static] |
Definition at line 637 of file res_features.c.
References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_autoservice_stop(), AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_park_call(), ast_parking_ext(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_PEER, ast_channel::language, LOG_WARNING, ast_channel::macrocontext, ast_channel::name, option_verbose, ast_channel::pbx, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.
00638 { 00639 struct ast_channel *transferer; 00640 struct ast_channel *transferee; 00641 char *transferer_real_context; 00642 char newext[256]; 00643 int res; 00644 00645 if (sense == FEATURE_SENSE_PEER) { 00646 transferer = peer; 00647 transferee = chan; 00648 } else { 00649 transferer = chan; 00650 transferee = peer; 00651 } 00652 if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) && 00653 !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) { 00654 /* Use the non-macro context to transfer the call */ 00655 if (!ast_strlen_zero(transferer->macrocontext)) 00656 transferer_real_context = transferer->macrocontext; 00657 else 00658 transferer_real_context = transferer->context; 00659 } 00660 /* Start autoservice on chan while we talk 00661 to the originator */ 00662 ast_indicate(transferee, AST_CONTROL_HOLD); 00663 ast_autoservice_start(transferee); 00664 ast_moh_start(transferee, NULL); 00665 00666 memset(newext, 0, sizeof(newext)); 00667 00668 /* Transfer */ 00669 if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) { 00670 ast_moh_stop(transferee); 00671 ast_autoservice_stop(transferee); 00672 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00673 return res; 00674 } 00675 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) { 00676 ast_moh_stop(transferee); 00677 ast_autoservice_stop(transferee); 00678 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00679 return res; 00680 } else if (res > 0) { 00681 /* If they've typed a digit already, handle it */ 00682 newext[0] = (char) res; 00683 } 00684 00685 ast_stopstream(transferer); 00686 res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout); 00687 if (res < 0) { 00688 ast_moh_stop(transferee); 00689 ast_autoservice_stop(transferee); 00690 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00691 return res; 00692 } 00693 if (!strcmp(newext, ast_parking_ext())) { 00694 ast_moh_stop(transferee); 00695 00696 res = ast_autoservice_stop(transferee); 00697 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00698 if (res) 00699 res = -1; 00700 else if (!ast_park_call(transferee, transferer, 0, NULL)) { 00701 /* We return non-zero, but tell the PBX not to hang the channel when 00702 the thread dies -- We have to be careful now though. We are responsible for 00703 hanging up the channel, else it will never be hung up! */ 00704 00705 if (transferer == peer) 00706 res = AST_PBX_KEEPALIVE; 00707 else 00708 res = AST_PBX_NO_HANGUP_PEER; 00709 return res; 00710 } else { 00711 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); 00712 } 00713 /* XXX Maybe we should have another message here instead of invalid extension XXX */ 00714 } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) { 00715 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name); 00716 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name); 00717 ast_moh_stop(transferee); 00718 res=ast_autoservice_stop(transferee); 00719 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00720 if (!transferee->pbx) { 00721 /* Doh! Use our handy async_goto functions */ 00722 if (option_verbose > 2) 00723 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00724 ,transferee->name, newext, transferer_real_context); 00725 if (ast_async_goto(transferee, transferer_real_context, newext, 1)) 00726 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00727 res = -1; 00728 } else { 00729 /* Set the channel's new extension, since it exists, using transferer context */ 00730 ast_copy_string(transferee->exten, newext, sizeof(transferee->exten)); 00731 ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context)); 00732 transferee->priority = 0; 00733 } 00734 check_goto_on_transfer(transferer); 00735 return res; 00736 } else { 00737 if (option_verbose > 2) 00738 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context); 00739 } 00740 if (!ast_strlen_zero(xferfailsound)) 00741 res = ast_streamfile(transferer, xferfailsound, transferer->language); 00742 else 00743 res = 0; 00744 if (res) { 00745 ast_moh_stop(transferee); 00746 ast_autoservice_stop(transferee); 00747 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00748 return res; 00749 } 00750 res = ast_waitstream(transferer, AST_DIGIT_ANY); 00751 ast_stopstream(transferer); 00752 ast_moh_stop(transferee); 00753 res = ast_autoservice_stop(transferee); 00754 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00755 if (res) { 00756 if (option_verbose > 1) 00757 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00758 return res; 00759 } 00760 return FEATURE_RETURN_SUCCESS; 00761 }
static int builtin_disconnect | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense | |||
) | [static] |
Definition at line 630 of file res_features.c.
References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.
00631 { 00632 if (option_verbose > 3) 00633 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00634 return FEATURE_RETURN_HANGUP; 00635 }
static void check_goto_on_transfer | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 194 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_channel_alloc(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_STATE_UP, ast_strlen_zero(), ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.
Referenced by builtin_blindtransfer().
00195 { 00196 struct ast_channel *xferchan; 00197 char *goto_on_transfer; 00198 00199 goto_on_transfer = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00200 00201 if (!ast_strlen_zero(goto_on_transfer) && (xferchan = ast_channel_alloc(0))) { 00202 char *x; 00203 struct ast_frame *f; 00204 00205 for (x = goto_on_transfer; x && *x; x++) 00206 if (*x == '^') 00207 *x = '|'; 00208 00209 strcpy(xferchan->name, chan->name); 00210 /* Make formats okay */ 00211 xferchan->readformat = chan->readformat; 00212 xferchan->writeformat = chan->writeformat; 00213 ast_channel_masquerade(xferchan, chan); 00214 ast_parseable_goto(xferchan, goto_on_transfer); 00215 xferchan->_state = AST_STATE_UP; 00216 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00217 xferchan->_softhangup = 0; 00218 if ((f = ast_read(xferchan))) { 00219 ast_frfree(f); 00220 f = NULL; 00221 ast_pbx_start(xferchan); 00222 } else { 00223 ast_hangup(xferchan); 00224 } 00225 } 00226 }
char* description | ( | void | ) |
Provides a description of the module.
Definition at line 2306 of file res_features.c.
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Definition at line 1583 of file res_features.c.
References ast_add_extension2(), ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_pbx_start(), ast_read(), ast_set_flag, ast_strdupa, ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::context, ast_channel::context, EVENT_FLAG_CALL, parkeduser::exten, ast_channel::exten, exten, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, FREE, ast_channel::generatordata, LOG_DEBUG, LOG_ERROR, LOG_WARNING, manager_event(), parkeduser::moh_trys, ast_channel::name, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, parkeduser::priority, ast_channel::priority, parkeduser::start, strdup, ast_frame::subclass, and VERBOSE_PREFIX_2.
Referenced by load_module().
01584 { 01585 int ms, tms, max; 01586 struct parkeduser *pu, *pl, *pt = NULL; 01587 struct timeval tv; 01588 struct ast_frame *f; 01589 char exten[AST_MAX_EXTENSION]; 01590 char *peername,*cp; 01591 char returnexten[AST_MAX_EXTENSION]; 01592 struct ast_context *con; 01593 int x; 01594 fd_set rfds, efds; 01595 fd_set nrfds, nefds; 01596 FD_ZERO(&rfds); 01597 FD_ZERO(&efds); 01598 01599 for (;;) { 01600 ms = -1; 01601 max = -1; 01602 ast_mutex_lock(&parking_lock); 01603 pl = NULL; 01604 pu = parkinglot; 01605 FD_ZERO(&nrfds); 01606 FD_ZERO(&nefds); 01607 while(pu) { 01608 if (pu->notquiteyet) { 01609 /* Pretend this one isn't here yet */ 01610 pl = pu; 01611 pu = pu->next; 01612 continue; 01613 } 01614 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01615 if (tms > pu->parkingtime) { 01616 /* Stop music on hold */ 01617 ast_moh_stop(pu->chan); 01618 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 01619 /* Get chan, exten from derived kludge */ 01620 if (pu->peername[0]) { 01621 peername = ast_strdupa(pu->peername); 01622 cp = strrchr(peername, '-'); 01623 if (cp) 01624 *cp = 0; 01625 con = ast_context_find(parking_con_dial); 01626 if (!con) { 01627 con = ast_context_create(NULL, parking_con_dial, registrar); 01628 if (!con) { 01629 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01630 } 01631 } 01632 if (con) { 01633 snprintf(returnexten, sizeof(returnexten), "%s||t", peername); 01634 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar); 01635 } 01636 ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten)); 01637 ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context)); 01638 pu->chan->priority = 1; 01639 01640 } else { 01641 /* They've been waiting too long, send them back to where they came. Theoretically they 01642 should have their original extensions and such, but we copy to be on the safe side */ 01643 ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)); 01644 ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context)); 01645 pu->chan->priority = pu->priority; 01646 } 01647 01648 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut", 01649 "Exten: %d\r\n" 01650 "Channel: %s\r\n" 01651 "CallerID: %s\r\n" 01652 "CallerIDName: %s\r\n" 01653 ,pu->parkingnum, pu->chan->name 01654 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 01655 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 01656 ); 01657 01658 if (option_verbose > 1) 01659 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); 01660 /* Start up the PBX, or hang them up */ 01661 if (ast_pbx_start(pu->chan)) { 01662 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name); 01663 ast_hangup(pu->chan); 01664 } 01665 /* And take them out of the parking lot */ 01666 if (pl) 01667 pl->next = pu->next; 01668 else 01669 parkinglot = pu->next; 01670 pt = pu; 01671 pu = pu->next; 01672 con = ast_context_find(parking_con); 01673 if (con) { 01674 snprintf(exten, sizeof(exten), "%d", pt->parkingnum); 01675 if (ast_context_remove_extension2(con, exten, 1, NULL)) 01676 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01677 else 01678 notify_metermaids(exten, parking_con); /* Notify watchers */ 01679 } else 01680 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01681 free(pt); 01682 } else { 01683 for (x = 0; x < AST_MAX_FDS; x++) { 01684 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) { 01685 if (FD_ISSET(pu->chan->fds[x], &efds)) 01686 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); 01687 else 01688 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); 01689 pu->chan->fdno = x; 01690 /* See if they need servicing */ 01691 f = ast_read(pu->chan); 01692 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 01693 if (f) 01694 ast_frfree(f); 01695 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp", 01696 "Exten: %d\r\n" 01697 "Channel: %s\r\n" 01698 "CallerID: %s\r\n" 01699 "CallerIDName: %s\r\n" 01700 ,pu->parkingnum, pu->chan->name 01701 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 01702 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 01703 ); 01704 01705 /* There's a problem, hang them up*/ 01706 if (option_verbose > 1) 01707 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name); 01708 ast_hangup(pu->chan); 01709 /* And take them out of the parking lot */ 01710 if (pl) 01711 pl->next = pu->next; 01712 else 01713 parkinglot = pu->next; 01714 pt = pu; 01715 pu = pu->next; 01716 con = ast_context_find(parking_con); 01717 if (con) { 01718 snprintf(exten, sizeof(exten), "%d", pt->parkingnum); 01719 if (ast_context_remove_extension2(con, exten, 1, NULL)) 01720 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01721 else 01722 notify_metermaids(exten, parking_con); 01723 } else 01724 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01725 free(pt); 01726 break; 01727 } else { 01728 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 01729 ast_frfree(f); 01730 if (pu->moh_trys < 3 && !pu->chan->generatordata) { 01731 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 01732 ast_moh_start(pu->chan, NULL); 01733 pu->moh_trys++; 01734 } 01735 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 01736 } 01737 } 01738 } 01739 if (x >= AST_MAX_FDS) { 01740 std: for (x=0; x<AST_MAX_FDS; x++) { 01741 /* Keep this one for next one */ 01742 if (pu->chan->fds[x] > -1) { 01743 FD_SET(pu->chan->fds[x], &nrfds); 01744 FD_SET(pu->chan->fds[x], &nefds); 01745 if (pu->chan->fds[x] > max) 01746 max = pu->chan->fds[x]; 01747 } 01748 } 01749 /* Keep track of our longest wait */ 01750 if ((tms < ms) || (ms < 0)) 01751 ms = tms; 01752 pl = pu; 01753 pu = pu->next; 01754 } 01755 } 01756 } 01757 ast_mutex_unlock(&parking_lock); 01758 rfds = nrfds; 01759 efds = nefds; 01760 tv = ast_samp2tv(ms, 1000); 01761 /* Wait for something to happen */ 01762 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 01763 pthread_testcancel(); 01764 } 01765 return NULL; /* Never reached */ 01766 }
static int feature_exec_app | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense | |||
) | [static] |
Definition at line 1024 of file res_features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, AST_FEATURE_FLAG_CALLEE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_test_flag, ast_call_feature::exten, FEATURE_RETURN_NO_HANGUP_PEER, FEATURE_RETURN_PBX_KEEPALIVE, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, LOG_NOTICE, LOG_WARNING, pbx_exec(), and pbx_findapp().
Referenced by load_config().
01025 { 01026 struct ast_app *app; 01027 struct ast_call_feature *feature; 01028 int res; 01029 01030 AST_LIST_LOCK(&feature_list); 01031 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) { 01032 if (!strcasecmp(feature->exten,code)) break; 01033 } 01034 AST_LIST_UNLOCK(&feature_list); 01035 01036 if (!feature) { /* shouldn't ever happen! */ 01037 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01038 return -1; 01039 } 01040 01041 app = pbx_findapp(feature->app); 01042 if (app) { 01043 struct ast_channel *work = chan; 01044 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE)) 01045 work = peer; 01046 res = pbx_exec(work, app, feature->app_args, 1); 01047 if (res == AST_PBX_KEEPALIVE) 01048 return FEATURE_RETURN_PBX_KEEPALIVE; 01049 else if (res == AST_PBX_NO_HANGUP_PEER) 01050 return FEATURE_RETURN_NO_HANGUP_PEER; 01051 else if (res) 01052 return FEATURE_RETURN_SUCCESSBREAK; 01053 } else { 01054 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01055 return -2; 01056 } 01057 01058 return FEATURE_RETURN_SUCCESS; 01059 }
static struct ast_call_feature* find_feature | ( | char * | name | ) | [static] |
Definition at line 1009 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and ast_call_feature::sname.
Referenced by ast_feature_interpret(), load_config(), and set_config_flags().
01010 { 01011 struct ast_call_feature *tmp; 01012 01013 AST_LIST_LOCK(&feature_list); 01014 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01015 if (!strcasecmp(tmp->sname, name)) 01016 break; 01017 } 01018 AST_LIST_UNLOCK(&feature_list); 01019 01020 return tmp; 01021 }
static int handle_parkedcalls | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1956 of file res_features.c.
References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, ast_channel::name, parkeduser::next, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.
01957 { 01958 struct parkeduser *cur; 01959 int numparked = 0; 01960 01961 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 01962 , "Context", "Extension", "Pri", "Timeout"); 01963 01964 ast_mutex_lock(&parking_lock); 01965 01966 cur = parkinglot; 01967 while(cur) { 01968 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n" 01969 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten 01970 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 01971 01972 cur = cur->next; 01973 numparked++; 01974 } 01975 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 01976 01977 ast_mutex_unlock(&parking_lock); 01978 01979 return RESULT_SUCCESS; 01980 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1908 of file res_features.c.
References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_pickup_ext(), builtin_features, ast_call_feature::default_exten, ast_call_feature::exten, exten, ast_call_feature::fname, format, parking_con, parking_ext, parking_start, parking_stop, RESULT_SUCCESS, and ast_call_feature::sname.
01909 { 01910 int i; 01911 int fcount; 01912 struct ast_call_feature *feature; 01913 char format[] = "%-25s %-7s %-7s\n"; 01914 01915 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 01916 ast_cli(fd, format, "---------------", "-------", "-------"); 01917 01918 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 01919 01920 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]); 01921 01922 for (i = 0; i < fcount; i++) 01923 { 01924 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 01925 } 01926 ast_cli(fd, "\n"); 01927 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 01928 ast_cli(fd, format, "---------------", "-------", "-------"); 01929 if (AST_LIST_EMPTY(&feature_list)) { 01930 ast_cli(fd, "(none)\n"); 01931 } 01932 else { 01933 AST_LIST_LOCK(&feature_list); 01934 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { 01935 ast_cli(fd, format, feature->sname, "no def", feature->exten); 01936 } 01937 AST_LIST_UNLOCK(&feature_list); 01938 } 01939 ast_cli(fd, "\nCall parking\n"); 01940 ast_cli(fd, "------------\n"); 01941 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 01942 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 01943 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 01944 ast_cli(fd,"\n"); 01945 01946 return RESULT_SUCCESS; 01947 }
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; }
Definition at line 2324 of file res_features.c.
References ASTERISK_GPL_KEY.
02325 { 02326 return ASTERISK_GPL_KEY; 02327 }
static int load_config | ( | void | ) | [static] |
Definition at line 2080 of file res_features.c.
References adsipark, ast_call_feature::app, app, ast_call_feature::app_args, ast_add_extension2(), ast_config_destroy(), ast_config_load(), ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_FEATURE_FLAG_CALLEE, AST_FEATURE_FLAG_CALLER, AST_FEATURE_FLAG_NEEDSDTMF, ast_log(), AST_MAX_EXTENSION, ast_parking_ext(), ast_register_feature(), ast_set_flag, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_variable_browse(), ast_verbose(), cfg, courtesytone, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_PARK_TIME, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_SNAME_LEN, featuredigittimeout, find_feature(), FREE, free, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, notify_metermaids(), ast_call_feature::operation, option_verbose, park_add_hints(), parkaddhints, parkcall, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkingtime, pickup_ext, registrar, remap_feature(), ast_call_feature::sname, strdup, strsep(), transferdigittimeout, unmap_features(), var, VERBOSE_PREFIX_2, xferfailsound, and xfersound.
02081 { 02082 int start = 0, end = 0; 02083 int res; 02084 struct ast_context *con = NULL; 02085 struct ast_config *cfg = NULL; 02086 struct ast_variable *var = NULL; 02087 char old_parking_ext[AST_MAX_EXTENSION]; 02088 char old_parking_con[AST_MAX_EXTENSION] = ""; 02089 02090 if (!ast_strlen_zero(parking_con)) { 02091 strcpy(old_parking_ext, parking_ext); 02092 strcpy(old_parking_con, parking_con); 02093 } 02094 02095 /* Reset to defaults */ 02096 strcpy(parking_con, "parkedcalls"); 02097 strcpy(parking_con_dial, "park-dial"); 02098 strcpy(parking_ext, "700"); 02099 strcpy(pickup_ext, "*8"); 02100 courtesytone[0] = '\0'; 02101 strcpy(xfersound, "beep"); 02102 strcpy(xferfailsound, "pbx-invalid"); 02103 parking_start = 701; 02104 parking_stop = 750; 02105 parkfindnext = 0; 02106 parkaddhints = 0; 02107 adsipark = 0; 02108 02109 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02110 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02111 02112 cfg = ast_config_load("features.conf"); 02113 if (!cfg) { 02114 cfg = ast_config_load("parking.conf"); 02115 if (cfg) 02116 ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'. Please rename it.\n"); 02117 } 02118 if (cfg) { 02119 var = ast_variable_browse(cfg, "general"); 02120 while(var) { 02121 if (!strcasecmp(var->name, "parkext")) { 02122 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02123 } else if (!strcasecmp(var->name, "context")) { 02124 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02125 } else if (!strcasecmp(var->name, "parkingtime")) { 02126 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 02127 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02128 parkingtime = DEFAULT_PARK_TIME; 02129 } else 02130 parkingtime = parkingtime * 1000; 02131 } else if (!strcasecmp(var->name, "parkpos")) { 02132 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 02133 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); 02134 } else { 02135 parking_start = start; 02136 parking_stop = end; 02137 } 02138 } else if (!strcasecmp(var->name, "findslot")) { 02139 parkfindnext = (!strcasecmp(var->value, "next")); 02140 } else if (!strcasecmp(var->name, "parkhints")) { 02141 parkaddhints = ast_true(var->value); 02142 } else if (!strcasecmp(var->name, "adsipark")) { 02143 adsipark = ast_true(var->value); 02144 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 02145 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 02146 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 02147 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02148 } else 02149 transferdigittimeout = transferdigittimeout * 1000; 02150 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 02151 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 02152 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 02153 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02154 } 02155 } else if (!strcasecmp(var->name, "courtesytone")) { 02156 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 02157 } else if (!strcasecmp(var->name, "xfersound")) { 02158 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 02159 } else if (!strcasecmp(var->name, "xferfailsound")) { 02160 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 02161 } else if (!strcasecmp(var->name, "pickupexten")) { 02162 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 02163 } 02164 var = var->next; 02165 } 02166 02167 unmap_features(); 02168 var = ast_variable_browse(cfg, "featuremap"); 02169 while(var) { 02170 if (remap_feature(var->name, var->value)) 02171 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 02172 var = var->next; 02173 } 02174 02175 /* Map a key combination to an application*/ 02176 ast_unregister_features(); 02177 var = ast_variable_browse(cfg, "applicationmap"); 02178 while(var) { 02179 char *tmp_val=strdup(var->value); 02180 char *exten, *party=NULL, *app=NULL, *app_args=NULL; 02181 02182 if (!tmp_val) { 02183 ast_log(LOG_ERROR, "res_features: strdup failed"); 02184 continue; 02185 } 02186 02187 02188 exten=strsep(&tmp_val,","); 02189 if (exten) party=strsep(&tmp_val,","); 02190 if (party) app=strsep(&tmp_val,","); 02191 02192 if (app) app_args=strsep(&tmp_val,","); 02193 02194 if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) { 02195 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); 02196 free(tmp_val); 02197 var = var->next; 02198 continue; 02199 } 02200 02201 { 02202 struct ast_call_feature *feature=find_feature(var->name); 02203 int mallocd=0; 02204 02205 if (!feature) { 02206 feature=malloc(sizeof(struct ast_call_feature)); 02207 mallocd=1; 02208 } 02209 if (!feature) { 02210 ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n"); 02211 free(tmp_val); 02212 var = var->next; 02213 continue; 02214 } 02215 02216 memset(feature,0,sizeof(struct ast_call_feature)); 02217 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN); 02218 ast_copy_string(feature->app,app,FEATURE_APP_LEN); 02219 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN); 02220 free(tmp_val); 02221 02222 if (app_args) 02223 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN); 02224 02225 ast_copy_string(feature->exten, exten,sizeof(feature->exten)); 02226 feature->operation=feature_exec_app; 02227 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF); 02228 02229 if (!strcasecmp(party,"caller")) 02230 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER); 02231 else if (!strcasecmp(party, "callee")) 02232 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE); 02233 else { 02234 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name); 02235 var = var->next; 02236 continue; 02237 } 02238 02239 ast_register_feature(feature); 02240 02241 if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten); 02242 } 02243 var = var->next; 02244 } 02245 } 02246 ast_config_destroy(cfg); 02247 02248 /* Remove the old parking extension */ 02249 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 02250 if(!ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 02251 notify_metermaids(old_parking_ext, old_parking_con); 02252 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 02253 } 02254 02255 if (!(con = ast_context_find(parking_con))) { 02256 if (!(con = ast_context_create(NULL, parking_con, registrar))) { 02257 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 02258 return -1; 02259 } 02260 } 02261 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar); 02262 if (parkaddhints) 02263 park_add_hints(parking_con, parking_start, parking_stop); 02264 if (!res) 02265 notify_metermaids(ast_parking_ext(), parking_con); 02266 return res; 02267 }
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.
Definition at line 2273 of file res_features.c.
References ast_cli_register(), ast_manager_register, ast_pthread_create, ast_register_application(), descrip, descrip2, do_parking_thread(), load_config(), manager_parking_status(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, showfeatures, showparked, synopsis, and synopsis2.
02274 { 02275 int res; 02276 02277 memset(parking_ext, 0, sizeof(parking_ext)); 02278 memset(parking_con, 0, sizeof(parking_con)); 02279 02280 if ((res = load_config())) 02281 return res; 02282 ast_cli_register(&showparked); 02283 ast_cli_register(&showfeatures); 02284 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 02285 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 02286 if (!res) 02287 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 02288 if (!res) { 02289 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 02290 } 02291 return res; 02292 }
static int manager_parking_status | ( | struct mansession * | s, | |
struct message * | m | |||
) | [static] |
Definition at line 1990 of file res_features.c.
References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::name, parkeduser::next, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, RESULT_SUCCESS, s, and parkeduser::start.
Referenced by load_module().
01991 { 01992 struct parkeduser *cur; 01993 char *id = astman_get_header(m,"ActionID"); 01994 char idText[256] = ""; 01995 01996 if (!ast_strlen_zero(id)) 01997 snprintf(idText,256,"ActionID: %s\r\n",id); 01998 01999 astman_send_ack(s, m, "Parked calls will follow"); 02000 02001 ast_mutex_lock(&parking_lock); 02002 02003 cur=parkinglot; 02004 while(cur) { 02005 ast_cli(s->fd, "Event: ParkedCall\r\n" 02006 "Exten: %d\r\n" 02007 "Channel: %s\r\n" 02008 "Timeout: %ld\r\n" 02009 "CallerID: %s\r\n" 02010 "CallerIDName: %s\r\n" 02011 "%s" 02012 "\r\n" 02013 ,cur->parkingnum, cur->chan->name 02014 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL) 02015 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "") 02016 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "") 02017 ,idText); 02018 02019 cur = cur->next; 02020 } 02021 02022 ast_cli(s->fd, 02023 "Event: ParkedCallsComplete\r\n" 02024 "%s" 02025 "\r\n",idText); 02026 02027 ast_mutex_unlock(&parking_lock); 02028 02029 return RESULT_SUCCESS; 02030 }
static void notify_metermaids | ( | char * | exten, | |
char * | context | |||
) | [static] |
Notify metermaids that we've changed an extension
Definition at line 355 of file res_features.c.
References ast_log(), features_parkwatch::callback, features_parkwatch::context, LOG_DEBUG, metermaids, features_parkwatch::next, and option_debug.
Referenced by ast_park_call(), do_parking_thread(), load_config(), and park_exec().
00356 { 00357 struct features_parkwatch *maid = metermaids; 00358 if (!maid) 00359 return; 00360 while (maid) { 00361 if (!maid->context || !strcmp(context, maid->context)) 00362 maid->callback(exten, context); 00363 maid = maid->next; 00364 } 00365 if (option_debug > 3) 00366 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context); 00367 return; 00368 }
static void park_add_hints | ( | char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Definition at line 2068 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, PRIORITY_HINT, and registrar.
Referenced by load_config().
02069 { 02070 int numext; 02071 char device[AST_MAX_EXTENSION]; 02072 char exten[10]; 02073 for (numext = start; numext <= stop; numext++) { 02074 snprintf(exten, sizeof(exten), "%d", numext); 02075 snprintf(device, sizeof(device), "Local/%s@%s", exten, context); 02076 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02077 } 02078 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 1768 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_park_call(), AST_PBX_KEEPALIVE, ast_safe_sleep(), AST_STATE_UP, localuser::chan, ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, and ast_channel::priority.
Referenced by load_module().
01769 { 01770 /* Data is unused at the moment but could contain a parking 01771 lot context eventually */ 01772 int res=0; 01773 struct localuser *u; 01774 LOCAL_USER_ADD(u); 01775 /* Setup the exten/priority to be s/1 since we don't know 01776 where this call should return */ 01777 strcpy(chan->exten, "s"); 01778 chan->priority = 1; 01779 if (chan->_state != AST_STATE_UP) 01780 res = ast_answer(chan); 01781 if (!res) 01782 res = ast_safe_sleep(chan, 1000); 01783 if (!res) 01784 res = ast_park_call(chan, chan, 0, NULL); 01785 LOCAL_USER_REMOVE(u); 01786 if (!res) 01787 res = AST_PBX_KEEPALIVE; 01788 return res; 01789 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 1791 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, EVENT_FLAG_CALL, exten, free, ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), option_verbose, parking_con, parkinglot, parkeduser::parkingnum, and VERBOSE_PREFIX_3.
Referenced by load_module().
01792 { 01793 int res=0; 01794 struct localuser *u; 01795 struct ast_channel *peer=NULL; 01796 struct parkeduser *pu, *pl=NULL; 01797 char exten[AST_MAX_EXTENSION]; 01798 struct ast_context *con; 01799 int park; 01800 int dres; 01801 struct ast_bridge_config config; 01802 01803 if (!data) { 01804 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n"); 01805 return -1; 01806 } 01807 LOCAL_USER_ADD(u); 01808 park = atoi((char *)data); 01809 ast_mutex_lock(&parking_lock); 01810 pu = parkinglot; 01811 while(pu) { 01812 if (pu->parkingnum == park) { 01813 if (pl) 01814 pl->next = pu->next; 01815 else 01816 parkinglot = pu->next; 01817 break; 01818 } 01819 pl = pu; 01820 pu = pu->next; 01821 } 01822 ast_mutex_unlock(&parking_lock); 01823 if (pu) { 01824 peer = pu->chan; 01825 con = ast_context_find(parking_con); 01826 if (con) { 01827 snprintf(exten, sizeof(exten), "%d", pu->parkingnum); 01828 if (ast_context_remove_extension2(con, exten, 1, NULL)) 01829 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01830 else 01831 notify_metermaids(exten, parking_con); 01832 } else 01833 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01834 01835 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 01836 "Exten: %d\r\n" 01837 "Channel: %s\r\n" 01838 "From: %s\r\n" 01839 "CallerID: %s\r\n" 01840 "CallerIDName: %s\r\n" 01841 ,pu->parkingnum, pu->chan->name, chan->name 01842 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") 01843 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") 01844 ); 01845 01846 free(pu); 01847 } 01848 /* JK02: it helps to answer the channel if not already up */ 01849 if (chan->_state != AST_STATE_UP) { 01850 ast_answer(chan); 01851 } 01852 01853 if (peer) { 01854 /* Play a courtesy beep in the calling channel to prefix the bridge connecting */ 01855 if (!ast_strlen_zero(courtesytone)) { 01856 if (!ast_streamfile(chan, courtesytone, chan->language)) { 01857 if (ast_waitstream(chan, "") < 0) { 01858 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01859 ast_hangup(peer); 01860 return -1; 01861 } 01862 } 01863 } 01864 01865 ast_moh_stop(peer); 01866 ast_indicate(peer, AST_CONTROL_UNHOLD); 01867 res = ast_channel_make_compatible(chan, peer); 01868 if (res < 0) { 01869 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 01870 ast_hangup(peer); 01871 return -1; 01872 } 01873 /* This runs sorta backwards, since we give the incoming channel control, as if it 01874 were the person called. */ 01875 if (option_verbose > 2) 01876 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 01877 01878 memset(&config, 0, sizeof(struct ast_bridge_config)); 01879 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01880 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 01881 config.timelimit = 0; 01882 config.play_warning = 0; 01883 config.warning_freq = 0; 01884 config.warning_sound=NULL; 01885 res = ast_bridge_call(chan, peer, &config); 01886 01887 /* Simulate the PBX hanging up */ 01888 if (res != AST_PBX_NO_HANGUP_PEER) 01889 ast_hangup(peer); 01890 return res; 01891 } else { 01892 /* XXX Play a message XXX */ 01893 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language); 01894 if (!dres) 01895 dres = ast_waitstream(chan, ""); 01896 else { 01897 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 01898 dres = 0; 01899 } 01900 if (option_verbose > 2) 01901 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 01902 res = -1; 01903 } 01904 LOCAL_USER_REMOVE(u); 01905 return res; 01906 }
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.
Definition at line 2269 of file res_features.c.
References load_config().
02269 { 02270 return load_config(); 02271 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1068 of file res_features.c.
References ast_log(), ast_verbose(), builtin_features, exten, FEATURES_COUNT, LOG_WARNING, option_verbose, and VERBOSE_PREFIX_2.
Referenced by load_config().
01069 { 01070 int x; 01071 int res = -1; 01072 for (x = 0; x < FEATURES_COUNT; x++) { 01073 if (!strcasecmp(name, builtin_features[x].sname)) { 01074 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01075 if (option_verbose > 1) 01076 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); 01077 res = 0; 01078 } else if (!strcmp(value, builtin_features[x].exten)) 01079 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); 01080 } 01081 return res; 01082 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 1143 of file res_features.c.
References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_CALLEE, AST_FEATURE_FLAG_CALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, ast_set_flag, ast_strdupa, ast_test_flag, builtin_features, config, ast_call_feature::feature_mask, FEATURES_COUNT, find_feature(), pbx_builtin_getvar_helper(), and strsep().
Referenced by ast_bridge_call().
01144 { 01145 int x; 01146 01147 ast_clear_flag(config, AST_FLAGS_ALL); 01148 for (x = 0; x < FEATURES_COUNT; x++) { 01149 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) { 01150 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01151 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01152 01153 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01154 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01155 } 01156 } 01157 01158 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01159 char *dynamic_features; 01160 01161 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01162 01163 if (dynamic_features) { 01164 char *tmp = ast_strdupa(dynamic_features); 01165 char *tok; 01166 struct ast_call_feature *feature; 01167 01168 if (!tmp) { 01169 return; 01170 } 01171 01172 /* while we have a feature */ 01173 while (NULL != (tok = strsep(&tmp, "#"))) { 01174 if ((feature = find_feature(tok))) { 01175 if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01176 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER)) 01177 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01178 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE)) 01179 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01180 } 01181 } 01182 } 01183 } 01184 } 01185 }
int unload_module | ( | void | ) |
Cleanup all module structures, sockets, etc.
Standard module functions ...
Definition at line 2295 of file res_features.c.
References ast_cli_unregister(), ast_manager_unregister(), ast_unregister_application(), parkcall, parkedcall, showfeatures, showparked, and STANDARD_HANGUP_LOCALUSERS.
02296 { 02297 STANDARD_HANGUP_LOCALUSERS; 02298 02299 ast_manager_unregister("ParkedCalls"); 02300 ast_cli_unregister(&showfeatures); 02301 ast_cli_unregister(&showparked); 02302 ast_unregister_application(parkcall); 02303 return ast_unregister_application(parkedcall); 02304 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1061 of file res_features.c.
References builtin_features, exten, and FEATURES_COUNT.
Referenced by load_config().
01062 { 01063 int x; 01064 for (x = 0; x < FEATURES_COUNT; x++) 01065 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01066 }
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.
Definition at line 2311 of file res_features.c.
References STANDARD_USECOUNT.
02312 { 02313 /* Never allow parking to be unloaded because it will 02314 unresolve needed symbols in the dialer */ 02315 #if 0 02316 int res; 02317 STANDARD_USECOUNT(res); 02318 return res; 02319 #else 02320 return 1; 02321 #endif 02322 }
int adsipark [static] |
struct ast_call_feature builtin_features[] |
Definition at line 960 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] |
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 132 of file res_features.c.
char* descrip2 [static] |
Definition at line 142 of file res_features.c.
int featuredigittimeout [static] |
Definition at line 175 of file res_features.c.
int metermaidid = 0 |
Definition at line 85 of file res_features.c.
struct features_parkwatch* metermaids |
Metermaid ID
Definition at line 84 of file res_features.c.
Referenced by ast_park_metermaid_add(), ast_park_metermaid_remove(), and notify_metermaids().
struct ast_app* monitor_app = NULL [static] |
Definition at line 149 of file res_features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 150 of file res_features.c.
int parkaddhints = 0 [static] |
char* parkcall = "Park" [static] |
Definition at line 138 of file res_features.c.
Referenced by load_config(), load_module(), and unload_module().
char* parkedcall = "ParkedCall" [static] |
int parkfindnext [static] |
char parking_con[AST_MAX_EXTENSION] [static] |
Definition at line 93 of file res_features.c.
Referenced by handle_showfeatures(), load_config(), load_module(), and park_exec().
char parking_con_dial[AST_MAX_EXTENSION] [static] |
char parking_ext[AST_MAX_EXTENSION] [static] |
Definition at line 99 of file res_features.c.
Referenced by handle_showfeatures(), load_config(), and load_module().
int parking_offset [static] |
Definition at line 116 of file res_features.c.
int parking_start [static] |
Definition at line 111 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
int parking_stop [static] |
Definition at line 114 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
pthread_t parking_thread [static] |
struct parkeduser* parkinglot [static] |
Definition at line 167 of file res_features.c.
Referenced by ast_park_call(), do_parking_thread(), handle_parkedcalls(), manager_parking_status(), and park_exec().
int parkingtime = DEFAULT_PARK_TIME [static] |
char pickup_ext[AST_MAX_EXTENSION] [static] |
char* registrar = "res_features" [static] |
Definition at line 128 of file res_features.c.
struct ast_cli_entry showfeatures [static] |
Initial value:
{ { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help }
Definition at line 1953 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 1949 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 1986 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 1982 of file res_features.c.
Definition at line 173 of file res_features.c.
char* synopsis = "Answer a parked call" [static] |
Definition at line 130 of file res_features.c.
char* synopsis2 = "Park yourself" [static] |
Definition at line 140 of file res_features.c.
int transferdigittimeout [static] |
char xferfailsound[256] [static] |
char xfersound[256] [static] |